mirror of
https://github.com/Permissionless-Software-Foundation/x402-base-facilitator.git
synced 2026-09-21 16:52:01 -07:00
Merge pull request #1 from Permissionless-Software-Foundation/dh-base-facilitator
feat(x402): Implemented x402 Base facilitator
This commit is contained in:
Vendored
+5
-1
@@ -158,5 +158,9 @@ export default {
|
||||
disableNewAccounts: process.env.DISABLE_NEW_ACCOUNTS ? true : false,
|
||||
|
||||
// Admin password
|
||||
adminPassword: process.env.ADMIN_PASSWORD
|
||||
adminPassword: process.env.ADMIN_PASSWORD,
|
||||
|
||||
// Facilitator Configuration
|
||||
network: process.env.NETWORK || 'base-sepolia',
|
||||
evmPrivateKey: process.env.EVM_PRIVATE_KEY ? process.env.EVM_PRIVATE_KEY : '0x47e17173e204a3007023e19f210b31e1398d50a1df270243df997e0b57b1208a'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export DISABLE_IPFS=1
|
||||
export NO_MONGO=1
|
||||
export PORT=4022
|
||||
export EVM_PRIVATE_KEY=
|
||||
export NETWORK=base
|
||||
|
||||
npm start
|
||||
Generated
+3649
-1637
File diff suppressed because it is too large
Load Diff
@@ -25,10 +25,13 @@
|
||||
},
|
||||
"repository": "Permissionless-Software-Foundation/ipfs-service-provider",
|
||||
"dependencies": {
|
||||
"@x402/core": "^2.7.0",
|
||||
"@x402/evm": "^2.7.0",
|
||||
"axios": "0.27.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"glob": "7.1.6",
|
||||
"helia-coord": "2.0.3",
|
||||
"install": "^0.13.0",
|
||||
"jsonrpc-lite": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jwt-bch-lib": "1.3.0",
|
||||
@@ -48,8 +51,10 @@
|
||||
"mongoose": "5.13.14",
|
||||
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
||||
"nodemailer": "6.7.5",
|
||||
"npm": "^11.11.1",
|
||||
"passport-local": "1.0.0",
|
||||
"public-ip": "6.0.1",
|
||||
"viem": "^2.47.4",
|
||||
"winston": "3.3.3",
|
||||
"winston-daily-rotate-file": "4.5.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
import { x402Facilitator as X402Facilitator } from '@x402/core/facilitator'
|
||||
import { registerExactEvmScheme } from '@x402/evm/exact/facilitator'
|
||||
import { toFacilitatorEvmSigner } from '@x402/evm'
|
||||
import { createWalletClient, http, publicActions } from 'viem'
|
||||
import { privateKeyToAccount } from 'viem/accounts'
|
||||
import { baseSepolia, base } from 'viem/chains'
|
||||
|
||||
class FacilitatorAdapter {
|
||||
constructor (localConfig = {}) {
|
||||
this.config = localConfig
|
||||
|
||||
this.facilitator = new X402Facilitator()
|
||||
|
||||
this.NETWORK = this.config.network || 'base'
|
||||
this.EVM_PRIVATE_KEY = this.config.evmPrivateKey
|
||||
|
||||
this.createWalletClient = createWalletClient
|
||||
this.registerExactEvmScheme = registerExactEvmScheme
|
||||
this.privateKeyToAccount = privateKeyToAccount
|
||||
this.toFacilitatorEvmSigner = toFacilitatorEvmSigner
|
||||
|
||||
this.start = this.start.bind(this)
|
||||
}
|
||||
|
||||
async start () {
|
||||
try {
|
||||
if (!this.EVM_PRIVATE_KEY) {
|
||||
throw new Error("Property 'EVM_PRIVATE_KEY' must be a string!")
|
||||
}
|
||||
|
||||
const _chainId = this.NETWORK === 'base' ? base?.id : baseSepolia?.id
|
||||
const chainId = `eip155:${_chainId}`
|
||||
// Initialize the EVM account from private key
|
||||
const evmAccount = this.privateKeyToAccount(this.EVM_PRIVATE_KEY)
|
||||
console.info(`EVM Facilitator account: ${evmAccount.address}`)
|
||||
|
||||
// Create a Viem client with both wallet and public capabilities
|
||||
const viemClient = this.createWalletClient({
|
||||
account: evmAccount,
|
||||
chain: this.NETWORK === 'base' ? base : baseSepolia,
|
||||
transport: http()
|
||||
}).extend(publicActions)
|
||||
|
||||
// Initialize the x402 Facilitator with EVM support
|
||||
|
||||
const evmSigner = this.toFacilitatorEvmSigner({
|
||||
getCode: (args) => viemClient.getCode(args),
|
||||
address: evmAccount.address,
|
||||
readContract: (args) =>
|
||||
viemClient.readContract({
|
||||
...args,
|
||||
args: args.args || []
|
||||
}),
|
||||
verifyTypedData: (args) => viemClient.verifyTypedData(args),
|
||||
writeContract: (args) =>
|
||||
viemClient.writeContract({
|
||||
...args,
|
||||
args: args.args || []
|
||||
}),
|
||||
sendTransaction: (args) => viemClient.sendTransaction(args),
|
||||
waitForTransactionReceipt: (args) => viemClient.waitForTransactionReceipt(args)
|
||||
})
|
||||
|
||||
this.registerExactEvmScheme(this.facilitator, {
|
||||
signer: evmSigner,
|
||||
networks: [chainId]
|
||||
|
||||
})
|
||||
|
||||
this.facilitator
|
||||
.onBeforeVerify(async (ctx) => { console.log('Before verify', ctx) })
|
||||
.onAfterVerify(async (ctx) => { console.log('After verify', ctx) })
|
||||
.onVerifyFailure(async (ctx) => { console.log('Verify failure', ctx) })
|
||||
.onBeforeSettle(async (ctx) => { console.log('Before settle', ctx) })
|
||||
.onAfterSettle(async (ctx) => { console.log('After settle', ctx) })
|
||||
.onSettleFailure(async (ctx) => { console.log('Settle failure', ctx) })
|
||||
|
||||
return this.facilitator
|
||||
} catch (error) {
|
||||
console.error('Error in facilitator.js/start()')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default FacilitatorAdapter
|
||||
@@ -18,6 +18,7 @@ import JSONFiles from './json-files.js'
|
||||
import FullStackJWT from './fullstack-jwt.js'
|
||||
import config from '../../config/index.js'
|
||||
import Wallet from './wallet.adapter.js'
|
||||
import FacilitatorAdapter from './facilitator.js'
|
||||
|
||||
class Adapters {
|
||||
constructor (localConfig = {}) {
|
||||
@@ -31,7 +32,7 @@ class Adapters {
|
||||
this.bchjs = new BCHJS({ restURL: config.apiServer })
|
||||
this.config = config
|
||||
this.wallet = new Wallet(localConfig)
|
||||
|
||||
this.facilitator = new FacilitatorAdapter(config)
|
||||
// Get a valid JWT API key and instance bch-js.
|
||||
this.fullStackJwt = new FullStackJWT(config)
|
||||
}
|
||||
@@ -65,6 +66,10 @@ class Adapters {
|
||||
console.log('Not starting IPFS node since this is an e2e test.')
|
||||
}
|
||||
|
||||
await this.facilitator.start()
|
||||
|
||||
console.log('Facilitator Adapter is ready.')
|
||||
|
||||
console.log('Async Adapters have been started.')
|
||||
|
||||
return true
|
||||
|
||||
@@ -14,6 +14,9 @@ import LogsRESTController from './logs/index.js'
|
||||
import IpfsRESTController from './ipfs/index.js'
|
||||
import config from '../../../config/index.js'
|
||||
import UsageRESTController from './usage/index.js'
|
||||
import SettleRouter from './settle/index.js'
|
||||
import VerifyRouter from './verify/index.js'
|
||||
import SupportedRouter from './supported/index.js'
|
||||
|
||||
class RESTControllers {
|
||||
constructor (localConfig = {}) {
|
||||
@@ -54,6 +57,18 @@ class RESTControllers {
|
||||
userRouter.attach(app)
|
||||
}
|
||||
|
||||
// Attach the REST API Controllers associated with the /settle route
|
||||
const settleRouter = new SettleRouter(dependencies)
|
||||
settleRouter.attach(app)
|
||||
|
||||
// Attach the REST API Controllers associated with the /verify route
|
||||
const verifyRouter = new VerifyRouter(dependencies)
|
||||
verifyRouter.attach(app)
|
||||
|
||||
// Attach the REST API Controllers associated with the /supported route
|
||||
const supportedRouter = new SupportedRouter(dependencies)
|
||||
supportedRouter.attach(app)
|
||||
|
||||
// Attach the REST API Controllers associated with the /contact route
|
||||
const contactRESTController = new ContactRESTController(dependencies)
|
||||
contactRESTController.attach(app)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
REST API Controller library for the /settle route
|
||||
*/
|
||||
|
||||
class SettleRESTControllerLib {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating /settle REST Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantifying /settle REST Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
this.settle = this.settle.bind(this)
|
||||
this.handleError = this.handleError.bind(this)
|
||||
}
|
||||
|
||||
async settle (ctx) {
|
||||
try {
|
||||
const inputObj = ctx.request.body
|
||||
|
||||
const result = await this.useCases.settle.settle(inputObj)
|
||||
|
||||
ctx.body = result
|
||||
} catch (err) {
|
||||
// console.log(`err.message: ${err.message}`)
|
||||
// console.log('err: ', err)
|
||||
// ctx.throw(422, err.message)
|
||||
this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
// DRY error handler
|
||||
handleError (ctx, err) {
|
||||
// If an HTTP status is specified by the buisiness logic, use that.
|
||||
if (err.status) {
|
||||
if (err.message) {
|
||||
ctx.throw(err.status, err.message)
|
||||
} else {
|
||||
ctx.throw(err.status)
|
||||
}
|
||||
} else {
|
||||
// By default use a 422 error if the HTTP status is not specified.
|
||||
ctx.throw(422, err.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SettleRESTControllerLib
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
REST API library for /settle route.
|
||||
*/
|
||||
|
||||
// Public npm libraries.
|
||||
import Router from 'koa-router'
|
||||
|
||||
// Local libraries.
|
||||
import SettleRESTControllerLib from './controller.js'
|
||||
|
||||
import config from '../../../../config/index.js'
|
||||
|
||||
class SettleRouter {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating Settle Router.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating Settle Router.'
|
||||
)
|
||||
}
|
||||
|
||||
const dependencies = {
|
||||
adapters: this.adapters,
|
||||
useCases: this.useCases
|
||||
}
|
||||
|
||||
// Encapsulate dependencies.
|
||||
this.config = config
|
||||
this.settleRESTController = new SettleRESTControllerLib(dependencies)
|
||||
|
||||
// Instantiate the router and set the base route.
|
||||
const baseUrl = '/settle'
|
||||
this.router = new Router({ prefix: baseUrl })
|
||||
}
|
||||
|
||||
attach (app) {
|
||||
if (!app) {
|
||||
throw new Error(
|
||||
'Must pass app object when attaching REST API controllers.'
|
||||
)
|
||||
}
|
||||
|
||||
// Define the routes and attach the controller.
|
||||
this.router.post('/', this.settleRESTController.settle)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
app.use(this.router.allowedMethods())
|
||||
}
|
||||
}
|
||||
export default SettleRouter
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
REST API Controller library for the /supported route
|
||||
*/
|
||||
|
||||
class SupportedRESTControllerLib {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating /supported REST Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantifying /supported REST Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
this.supported = this.supported.bind(this)
|
||||
this.handleError = this.handleError.bind(this)
|
||||
}
|
||||
|
||||
async supported (ctx) {
|
||||
try {
|
||||
const result = await this.useCases.supported.supported()
|
||||
ctx.body = result
|
||||
} catch (err) {
|
||||
// console.log(`err.message: ${err.message}`)
|
||||
// console.log('err: ', err)
|
||||
// ctx.throw(422, err.message)
|
||||
this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
// DRY error handler
|
||||
handleError (ctx, err) {
|
||||
// If an HTTP status is specified by the buisiness logic, use that.
|
||||
if (err.status) {
|
||||
if (err.message) {
|
||||
ctx.throw(err.status, err.message)
|
||||
} else {
|
||||
ctx.throw(err.status)
|
||||
}
|
||||
} else {
|
||||
// By default use a 422 error if the HTTP status is not specified.
|
||||
ctx.throw(422, err.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SupportedRESTControllerLib
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
REST API library for /supported route.
|
||||
*/
|
||||
|
||||
// Public npm libraries.
|
||||
import Router from 'koa-router'
|
||||
|
||||
// Local libraries.
|
||||
import SupportedRESTControllerLib from './controller.js'
|
||||
|
||||
import config from '../../../../config/index.js'
|
||||
|
||||
class SupportedRouter {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating Supported Router.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating Supported Router.'
|
||||
)
|
||||
}
|
||||
|
||||
const dependencies = {
|
||||
adapters: this.adapters,
|
||||
useCases: this.useCases
|
||||
}
|
||||
|
||||
// Encapsulate dependencies.
|
||||
this.config = config
|
||||
this.supportedRESTController = new SupportedRESTControllerLib(dependencies)
|
||||
|
||||
// Instantiate the router and set the base route.
|
||||
const baseUrl = '/supported'
|
||||
this.router = new Router({ prefix: baseUrl })
|
||||
}
|
||||
|
||||
attach (app) {
|
||||
if (!app) {
|
||||
throw new Error(
|
||||
'Must pass app object when attaching REST API controllers.'
|
||||
)
|
||||
}
|
||||
|
||||
// Define the routes and attach the controller.
|
||||
this.router.get('/', this.supportedRESTController.supported)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
app.use(this.router.allowedMethods())
|
||||
}
|
||||
}
|
||||
export default SupportedRouter
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
REST API Controller library for the /verify route
|
||||
*/
|
||||
|
||||
class VerifyRESTControllerLib {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating /verify REST Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantifying /verify REST Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
this.verify = this.verify.bind(this)
|
||||
this.handleError = this.handleError.bind(this)
|
||||
}
|
||||
|
||||
async verify (ctx) {
|
||||
try {
|
||||
const inputObj = ctx.request.body
|
||||
|
||||
const result = await this.useCases.verify.verify(inputObj)
|
||||
|
||||
ctx.body = result
|
||||
} catch (err) {
|
||||
// console.log(`err.message: ${err.message}`)
|
||||
// console.log('err: ', err)
|
||||
// ctx.throw(422, err.message)
|
||||
this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
// DRY error handler
|
||||
handleError (ctx, err) {
|
||||
// If an HTTP status is specified by the buisiness logic, use that.
|
||||
if (err.status) {
|
||||
if (err.message) {
|
||||
ctx.throw(err.status, err.message)
|
||||
} else {
|
||||
ctx.throw(err.status)
|
||||
}
|
||||
} else {
|
||||
// By default use a 422 error if the HTTP status is not specified.
|
||||
ctx.throw(422, err.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default VerifyRESTControllerLib
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
REST API library for /verify route.
|
||||
*/
|
||||
|
||||
// Public npm libraries.
|
||||
import Router from 'koa-router'
|
||||
|
||||
// Local libraries.
|
||||
import VerifyRESTControllerLib from './controller.js'
|
||||
|
||||
import config from '../../../../config/index.js'
|
||||
|
||||
class VerifyRouter {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating Verify Router.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating Verify Router.'
|
||||
)
|
||||
}
|
||||
|
||||
const dependencies = {
|
||||
adapters: this.adapters,
|
||||
useCases: this.useCases
|
||||
}
|
||||
|
||||
// Encapsulate dependencies.
|
||||
this.config = config
|
||||
this.verifyRESTController = new VerifyRESTControllerLib(dependencies)
|
||||
|
||||
// Instantiate the router and set the base route.
|
||||
const baseUrl = '/verify'
|
||||
this.router = new Router({ prefix: baseUrl })
|
||||
}
|
||||
|
||||
attach (app) {
|
||||
if (!app) {
|
||||
throw new Error(
|
||||
'Must pass app object when attaching REST API controllers.'
|
||||
)
|
||||
}
|
||||
|
||||
// Define the routes and attach the controller.
|
||||
this.router.post('/', this.verifyRESTController.verify)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
app.use(this.router.allowedMethods())
|
||||
}
|
||||
}
|
||||
export default VerifyRouter
|
||||
@@ -7,6 +7,9 @@
|
||||
// Local libraries
|
||||
import UserUseCases from './user.js'
|
||||
import { UsageUseCases } from './usage-use-cases.js'
|
||||
import SettleUseCases from './settle.js'
|
||||
import VerifyUseCases from './verify.js'
|
||||
import SupportedUseCases from './supported.js'
|
||||
|
||||
class UseCases {
|
||||
constructor (localConfig = {}) {
|
||||
@@ -20,6 +23,9 @@ class UseCases {
|
||||
// console.log('use-cases/index.js localConfig: ', localConfig)
|
||||
this.user = new UserUseCases(localConfig)
|
||||
this.usage = new UsageUseCases(localConfig)
|
||||
this.settle = new SettleUseCases(localConfig)
|
||||
this.verify = new VerifyUseCases(localConfig)
|
||||
this.supported = new SupportedUseCases(localConfig)
|
||||
}
|
||||
|
||||
// Run any startup Use Cases at the start of the app.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This library contains business-logic for dealing with settle x402 payment transactions.
|
||||
*/
|
||||
|
||||
import wlogger from '../adapters/wlogger.js'
|
||||
|
||||
class SettleLib {
|
||||
constructor (localConfig = {}) {
|
||||
// console.log('User localConfig: ', localConfig)
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of adapters must be passed in when instantiating Settle Use Cases library.'
|
||||
)
|
||||
}
|
||||
this.facilitator = this.adapters.facilitator.facilitator
|
||||
}
|
||||
|
||||
async settle (inputObj = {}) {
|
||||
try {
|
||||
const { paymentPayload, paymentRequirements } = inputObj
|
||||
|
||||
if (!paymentPayload || !paymentRequirements) {
|
||||
throw new Error('Missing paymentPayload or paymentRequirements')
|
||||
}
|
||||
|
||||
const response = await this.facilitator.settle(
|
||||
paymentPayload,
|
||||
paymentRequirements
|
||||
)
|
||||
console.log('Payment Successfully with txId', response.transaction)
|
||||
return response
|
||||
} catch (err) {
|
||||
// console.log('createUser() error: ', err)
|
||||
wlogger.error('Error in lib/settle.js/settle()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SettleLib
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
This library contains business-logic for dealing with supported x402 payment transactions.
|
||||
*/
|
||||
|
||||
import wlogger from '../adapters/wlogger.js'
|
||||
|
||||
class SupportedLib {
|
||||
constructor (localConfig = {}) {
|
||||
// console.log('User localConfig: ', localConfig)
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of adapters must be passed in when instantiating Supported Use Cases library.'
|
||||
)
|
||||
}
|
||||
this.facilitator = this.adapters.facilitator.facilitator
|
||||
}
|
||||
|
||||
async supported () {
|
||||
try {
|
||||
const response = this.facilitator.getSupported()
|
||||
return response
|
||||
} catch (err) {
|
||||
// console.log('createUser() error: ', err)
|
||||
wlogger.error('Error in lib/supported.js/supported()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SupportedLib
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This library contains business-logic for dealing with verify x402 payment transactions.
|
||||
*/
|
||||
|
||||
import wlogger from '../adapters/wlogger.js'
|
||||
|
||||
class VerifyLib {
|
||||
constructor (localConfig = {}) {
|
||||
// console.log('User localConfig: ', localConfig)
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of adapters must be passed in when instantiating Verify Use Cases library.'
|
||||
)
|
||||
}
|
||||
this.facilitator = this.adapters.facilitator.facilitator
|
||||
}
|
||||
|
||||
async verify (inputObj = {}) {
|
||||
try {
|
||||
const { paymentPayload, paymentRequirements } = inputObj
|
||||
|
||||
if (!paymentPayload || !paymentRequirements) {
|
||||
throw new Error('Missing paymentPayload or paymentRequirements')
|
||||
}
|
||||
|
||||
const response = await this.facilitator.verify(
|
||||
paymentPayload,
|
||||
paymentRequirements
|
||||
)
|
||||
return response
|
||||
} catch (err) {
|
||||
console.log('error: ', err)
|
||||
// console.log('createUser() error: ', err)
|
||||
wlogger.error('Error in lib/verify.js/verify()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default VerifyLib
|
||||
@@ -0,0 +1,66 @@
|
||||
import { assert } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
import FacilitatorLib from '../../../src/adapters/facilitator.js'
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
describe('Facilitator', () => {
|
||||
beforeEach(() => {
|
||||
uut = new FacilitatorLib()
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('start()', () => {
|
||||
it('should throw error if EVM_PRIVATE_KEY property is not provided', async () => {
|
||||
try {
|
||||
await uut.start()
|
||||
assert(false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
assert.include(err.message, "Property 'EVM_PRIVATE_KEY' must be a string!")
|
||||
}
|
||||
})
|
||||
|
||||
it('should start the facilitator', async () => {
|
||||
try {
|
||||
uut.EVM_PRIVATE_KEY = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
|
||||
|
||||
const viewClientMock = {
|
||||
getCode: sandbox.stub().resolves('0x1'),
|
||||
readContract: sandbox.stub().resolves({}),
|
||||
verifyTypedData: sandbox.stub().resolves(true),
|
||||
writeContract: sandbox.stub().resolves('0xhash'),
|
||||
sendTransaction: sandbox.stub().resolves('0xhash'),
|
||||
waitForTransactionReceipt: sandbox.stub().resolves({})
|
||||
}
|
||||
|
||||
sandbox.stub(uut, 'privateKeyToAccount').returns({
|
||||
address: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
|
||||
privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
|
||||
})
|
||||
|
||||
sandbox.stub(uut, 'createWalletClient').returns({
|
||||
extend: () => viewClientMock
|
||||
})
|
||||
|
||||
const signerStub = sandbox.stub(uut, 'toFacilitatorEvmSigner').returns({ address: '0x123' })
|
||||
|
||||
await uut.start()
|
||||
|
||||
// Cover all the methods of the signer
|
||||
const signerConfig = signerStub.firstCall.args[0]
|
||||
|
||||
await signerConfig.getCode({ address: '0x1' })
|
||||
await signerConfig.readContract({ address: '0x1', abi: [], functionName: 'test' })
|
||||
await signerConfig.verifyTypedData({})
|
||||
await signerConfig.writeContract({ address: '0x1', abi: [], functionName: 'test' })
|
||||
await signerConfig.sendTransaction({})
|
||||
await signerConfig.waitForTransactionReceipt({})
|
||||
} catch (err) {
|
||||
assert(false, 'Unexpected result')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /settle endpoints.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
|
||||
import sinon from 'sinon'
|
||||
|
||||
// Local support libraries
|
||||
import adapters from '../../../mocks/adapters/index.js'
|
||||
|
||||
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||
|
||||
// const app = require('../../../mocks/app-mock')
|
||||
|
||||
import SettleRESTController from '../../../../../src/controllers/rest-api/settle/controller.js'
|
||||
|
||||
import { context as mockContext } from '../../../mocks/ctx-mock.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
let ctx
|
||||
|
||||
describe('#Settle-REST-Controller', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new SettleRESTController({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
ctx = mockContext()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SettleRESTController()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating /settle REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new SettleRESTController({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantifying /settle REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#settle', () => {
|
||||
it('should return the settle result', async () => {
|
||||
// Mock dependencies
|
||||
ctx.body = {}
|
||||
const result = {
|
||||
transaction: '1234567890'
|
||||
}
|
||||
sandbox.stub(uut.useCases.settle, 'settle').resolves(result)
|
||||
|
||||
await uut.settle(ctx)
|
||||
|
||||
assert.isObject(ctx.body)
|
||||
assert.property(ctx.body, 'transaction')
|
||||
})
|
||||
|
||||
it('should catch and throw useCases error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox.stub(uut.useCases.settle, 'settle').throws(new Error('test error'))
|
||||
|
||||
await uut.settle(ctx)
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#handleError', () => {
|
||||
it('should still throw error if there is no message', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 404
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Not Found')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw error with message', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 422,
|
||||
message: 'test error'
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /settle endpoints.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
|
||||
import sinon from 'sinon'
|
||||
|
||||
// Local support libraries
|
||||
import adapters from '../../../mocks/adapters/index.js'
|
||||
|
||||
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||
|
||||
// const app = require('../../../mocks/app-mock')
|
||||
|
||||
import SettleRouter from '../../../../../src/controllers/rest-api/settle/index.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
// let ctx
|
||||
|
||||
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||
|
||||
describe('#Settle-REST-Router', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new SettleRouter({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
// ctx = mockContext()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SettleRouter()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating Settle Router.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new SettleRouter({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantiating Settle Router.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#attach', () => {
|
||||
it('should throw an error if app is not passed in.', () => {
|
||||
try {
|
||||
uut.attach()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Must pass app object when attaching REST API controllers.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /supported endpoints.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
|
||||
import sinon from 'sinon'
|
||||
|
||||
// Local support libraries
|
||||
import adapters from '../../../mocks/adapters/index.js'
|
||||
|
||||
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||
|
||||
// const app = require('../../../mocks/app-mock')
|
||||
|
||||
import SupportedRESTController from '../../../../../src/controllers/rest-api/supported/controller.js'
|
||||
|
||||
import { context as mockContext } from '../../../mocks/ctx-mock.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
let ctx
|
||||
|
||||
describe('#Supported-REST-Controller', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new SupportedRESTController({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
ctx = mockContext()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SupportedRESTController()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating /supported REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new SupportedRESTController({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantifying /supported REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#supported', () => {
|
||||
it('should return the supported payment kinds and extensions', async () => {
|
||||
// Mock dependencies
|
||||
ctx.body = {}
|
||||
const result = {
|
||||
paymentKinds: ['x402'],
|
||||
extensions: ['x402']
|
||||
}
|
||||
sandbox.stub(uut.useCases.supported, 'supported').resolves(result)
|
||||
|
||||
await uut.supported(ctx)
|
||||
|
||||
assert.isObject(ctx.body)
|
||||
assert.property(ctx.body, 'paymentKinds')
|
||||
assert.property(ctx.body, 'extensions')
|
||||
})
|
||||
|
||||
it('should catch and throw useCases error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox.stub(uut.useCases.supported, 'supported').throws(new Error('test error'))
|
||||
|
||||
await uut.supported(ctx)
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#handleError', () => {
|
||||
it('should still throw error if there is no message', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 404
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Not Found')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw error with message', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 422,
|
||||
message: 'test error'
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /supported endpoints.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
|
||||
import sinon from 'sinon'
|
||||
|
||||
// Local support libraries
|
||||
import adapters from '../../../mocks/adapters/index.js'
|
||||
|
||||
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||
|
||||
// const app = require('../../../mocks/app-mock')
|
||||
|
||||
import SupportedRouter from '../../../../../src/controllers/rest-api/supported/index.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
// let ctx
|
||||
|
||||
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||
|
||||
describe('#Supported-REST-Router', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new SupportedRouter({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
// ctx = mockContext()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SupportedRouter()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating Supported Router.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new SupportedRouter({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantiating Supported Router.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#attach', () => {
|
||||
it('should throw an error if app is not passed in.', () => {
|
||||
try {
|
||||
uut.attach()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Must pass app object when attaching REST API controllers.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /verify endpoints.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
|
||||
import sinon from 'sinon'
|
||||
|
||||
// Local support libraries
|
||||
import adapters from '../../../mocks/adapters/index.js'
|
||||
|
||||
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||
|
||||
// const app = require('../../../mocks/app-mock')
|
||||
|
||||
import VerifyRESTController from '../../../../../src/controllers/rest-api/verify/controller.js'
|
||||
|
||||
import { context as mockContext } from '../../../mocks/ctx-mock.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
let ctx
|
||||
|
||||
describe('#Verify-REST-Controller', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new VerifyRESTController({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
ctx = mockContext()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new VerifyRESTController()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating /verify REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new VerifyRESTController({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantifying /verify REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#verify', () => {
|
||||
it('should return the verify result', async () => {
|
||||
// Mock dependencies
|
||||
ctx.body = {}
|
||||
const result = {
|
||||
valid: true
|
||||
}
|
||||
sandbox.stub(uut.useCases.verify, 'verify').resolves(result)
|
||||
|
||||
await uut.verify(ctx)
|
||||
|
||||
assert.isObject(ctx.body)
|
||||
assert.property(ctx.body, 'valid')
|
||||
})
|
||||
|
||||
it('should catch and throw useCases error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox.stub(uut.useCases.verify, 'verify').throws(new Error('test error'))
|
||||
|
||||
await uut.verify(ctx)
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#handleError', () => {
|
||||
it('should still throw error if there is no message', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 404
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Not Found')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw error with message', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 422,
|
||||
message: 'test error'
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /verify endpoints.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
|
||||
import sinon from 'sinon'
|
||||
|
||||
// Local support libraries
|
||||
import adapters from '../../../mocks/adapters/index.js'
|
||||
|
||||
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||
|
||||
// const app = require('../../../mocks/app-mock')
|
||||
|
||||
import VerifyRouter from '../../../../../src/controllers/rest-api/verify/index.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
// let ctx
|
||||
|
||||
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||
|
||||
describe('#Verify-REST-Router', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new VerifyRouter({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
// ctx = mockContext()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new VerifyRouter()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating Verify Router.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new VerifyRouter({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantiating Verify Router.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#attach', () => {
|
||||
it('should throw an error if app is not passed in.', () => {
|
||||
try {
|
||||
uut.attach()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Must pass app object when attaching REST API controllers.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -108,4 +108,26 @@ const localdb = {
|
||||
}
|
||||
}
|
||||
|
||||
export default { ipfs, localdb };
|
||||
const facilitator = {
|
||||
facilitator: {
|
||||
getSupported: async () => {
|
||||
return {
|
||||
paymentKinds: ['x402'],
|
||||
extensions: ['x402']
|
||||
}
|
||||
},
|
||||
settle: async () => {
|
||||
return {
|
||||
paymentKinds: ['x402'],
|
||||
extensions: ['x402']
|
||||
}
|
||||
},
|
||||
verify: async () => {
|
||||
return {
|
||||
paymentKinds: ['x402'],
|
||||
extensions: ['x402']
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
export default { ipfs, localdb, facilitator };
|
||||
|
||||
@@ -57,6 +57,32 @@ class UsageUseCaseMock {
|
||||
}
|
||||
}
|
||||
|
||||
class SupportedUseCaseMock {
|
||||
async supported() {
|
||||
return {
|
||||
paymentKinds: ['x402'],
|
||||
extensions: ['x402']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SettleUseCaseMock {
|
||||
async settle() {
|
||||
return {
|
||||
paymentKinds: ['x402'],
|
||||
extensions: ['x402']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VerifyUseCaseMock {
|
||||
async verify() {
|
||||
return {
|
||||
paymentKinds: ['x402'],
|
||||
extensions: ['x402']
|
||||
}
|
||||
}
|
||||
}
|
||||
class UseCasesMock {
|
||||
constuctor(localConfig = {}) {
|
||||
// this.user = new UserUseCaseMock(localConfig)
|
||||
@@ -64,6 +90,10 @@ class UseCasesMock {
|
||||
|
||||
user = new UserUseCaseMock()
|
||||
usage = new UsageUseCaseMock()
|
||||
supported = new SupportedUseCaseMock()
|
||||
settle = new SettleUseCaseMock()
|
||||
verify = new VerifyUseCaseMock()
|
||||
}
|
||||
|
||||
|
||||
export default UseCasesMock;
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Unit tests for the src/use-cases/settle.js business logic library.
|
||||
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import SettleUseCases from '../../../src/use-cases/settle.js'
|
||||
|
||||
import adapters from '../mocks/adapters/index.js'
|
||||
describe('#settle-use-case', () => {
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
before(async () => {
|
||||
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
uut = new SettleUseCases({ adapters })
|
||||
console.log('SupportedLib adapters: ', adapters.facilitatorMock)
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SettleUseCases()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of adapters must be passed in when instantiating Settle Use Cases library.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#settle', () => {
|
||||
it('should return the supported payment kinds and extensions', async () => {
|
||||
const result = await uut.settle({ paymentPayload: {}, paymentRequirements: {} })
|
||||
|
||||
assert.isObject(result)
|
||||
})
|
||||
it('should throw an error if paymentPayload are not provided', async () => {
|
||||
try {
|
||||
await uut.settle({})
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'Missing paymentPayload or paymentRequirements')
|
||||
}
|
||||
})
|
||||
it('should throw an error if paymentRequirements are not provided', async () => {
|
||||
try {
|
||||
await uut.settle({ paymentPayload: {} })
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'Missing paymentPayload or paymentRequirements')
|
||||
}
|
||||
})
|
||||
it('should handle facilitator errors', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.facilitator, 'settle').throws(new Error('test error'))
|
||||
await uut.settle({ paymentPayload: {}, paymentRequirements: {} })
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Unit tests for the src/use-cases/supported.js business logic library.
|
||||
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import SupportedUseCases from '../../../src/use-cases/supported.js'
|
||||
|
||||
import adapters from '../mocks/adapters/index.js'
|
||||
describe('#supported-use-case', () => {
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
before(async () => {
|
||||
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
uut = new SupportedUseCases({ adapters })
|
||||
console.log('SupportedLib adapters: ', adapters.facilitatorMock)
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SupportedUseCases()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of adapters must be passed in when instantiating Supported Use Cases library.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#supported', () => {
|
||||
it('should return the supported payment kinds and extensions', async () => {
|
||||
const result = await uut.supported()
|
||||
|
||||
assert.isObject(result)
|
||||
})
|
||||
it('should handle errors', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.facilitator, 'getSupported').throws(new Error('test error'))
|
||||
await uut.supported()
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Unit tests for the src/use-cases/verify.js business logic library.
|
||||
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import VerifyUseCases from '../../../src/use-cases/verify.js'
|
||||
|
||||
import adapters from '../mocks/adapters/index.js'
|
||||
describe('#verify-use-case', () => {
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
before(async () => {
|
||||
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
uut = new VerifyUseCases({ adapters })
|
||||
console.log('SupportedLib adapters: ', adapters.facilitatorMock)
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new VerifyUseCases()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of adapters must be passed in when instantiating Verify Use Cases library.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#verify', () => {
|
||||
it('should return the supported payment kinds and extensions', async () => {
|
||||
const result = await uut.verify({ paymentPayload: {}, paymentRequirements: {} })
|
||||
|
||||
assert.isObject(result)
|
||||
})
|
||||
it('should throw an error if paymentPayload are not provided', async () => {
|
||||
try {
|
||||
await uut.verify({})
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'Missing paymentPayload or paymentRequirements')
|
||||
}
|
||||
})
|
||||
it('should throw an error if paymentRequirements are not provided', async () => {
|
||||
try {
|
||||
await uut.verify({ paymentPayload: {} })
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'Missing paymentPayload or paymentRequirements')
|
||||
}
|
||||
})
|
||||
it('should handle facilitator errors', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.facilitator, 'verify').throws(new Error('test error'))
|
||||
await uut.verify({ paymentPayload: {}, paymentRequirements: {} })
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user