Finished implementation

This commit is contained in:
Daniel Gonzalez
2026-03-18 20:26:01 -04:00
parent d29db05d5f
commit a920b4c293
9 changed files with 347 additions and 33 deletions
+3 -6
View File
@@ -22,15 +22,12 @@ export LOCAL_RESTURL=http://localhost:5942/v6
export PORT=5942
# x402 payments required to access this API?
# Facilitators https://docs.cdp.coinbase.com/x402/quickstart-for-sellers
export X402_ENABLED=true
export SERVER_BASE_ADDRESS=0xd32585CE60815654C50CAf350e18de8096061e63
export FACILITATOR_URL=https://x402.org/facilitator #Testnet Facilitator
export X402_PRICE_USDC=0.01
export X402_PRICE_USDC=0.1
export x402_NETWORK=base
export x402_FACILITATOR_URL=http://localhost:4022
# Mainnet facilitator access keys
export FACILITATOR_KEY_ID=
export FACILITATOR_SECRET_KEY=
# Basic Authentication required to access this API?
export USE_BASIC_AUTH=true
+4
View File
@@ -0,0 +1,4 @@
export EVM_PRIVATE_KEY=
export NETWORK=base
node facilitator-server.js
+1
View File
@@ -4,3 +4,4 @@ logs/
docs/
coverage/
start.sh
start-facilitator.sh
+4 -9
View File
@@ -16,7 +16,7 @@ import { dirname, join } from 'path'
import config from '../src/config/index.js'
import Controllers from '../src/controllers/index.js'
import wlogger from '../src/adapters/wlogger.js'
import { buildX402Routes, getX402Settings, getBasicAuthSettings } from '../src/config/x402.js'
import { buildX402Routes, getX402Settings, getBasicAuthSettings, createAuthHeader } from '../src/config/x402.js'
import { basicAuthMiddleware } from '../src/middleware/basic-auth.js'
// Load environment variables
@@ -111,10 +111,7 @@ class Server {
if (facilitatorOptions) {
facilitatorOptions = {
url: x402Settings.facilitatorUrl,
/** TODO : Auth headers for request mainnet facilitator needed */
createAuthHeaders: async () => {
return {}
}
createAuthHeaders: createAuthHeader
}
}
@@ -122,6 +119,7 @@ class Server {
// Create conditional x402 middleware that bypasses if basic auth is valid
const conditionalX402Middleware = (req, res, next) => {
// req.headers['accept'] = 'application/json';
// If basic auth is valid, bypass x402
if (req.locals?.basicAuthValid === true) {
return next()
@@ -144,10 +142,7 @@ class Server {
if (facilitatorOptions) {
facilitatorOptions = {
url: x402Settings.facilitatorUrl,
/** TODO : Auth headers for request mainnet facilitator needed */
createAuthHeaders: async () => {
return {}
}
createAuthHeaders: createAuthHeader
}
}
@@ -1,26 +1,32 @@
import axios from 'axios'
import { withPaymentInterceptor } from 'x402-axios'
import { mnemonicToAccount } from 'viem/accounts'
import { baseSepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
// import { baseSepolia } from 'viem/chains' // Testnet
import { createWalletClient, http } from 'viem'
const baseURL = 'http://localhost:5942'
const endpointPath = '/v6/full-node/blockchain/getBlockchainInfo'
const mnemonic = process.env.MNEMONIC || ''
if (!mnemonic) throw new Error('MNEMONIC env required!')
const pKey = process.env.PRIVATE_KEY || ''
// PRIVATE_KEY=0x... node examples/08-x402-axios-client.js
if (!pKey) throw new Error('PRIVATE_KEY env required!')
console.log('pKey', pKey)
// Create a wallet client
const account = mnemonicToAccount(mnemonic)
const account = privateKeyToAccount(pKey)
const client = createWalletClient({
account,
transport: http(),
chain: baseSepolia
chain: base
})
const api = withPaymentInterceptor(
axios.create({
baseURL
baseURL,
headers: {
'Content-Type': 'application/json'
}
}),
client
)
+265 -4
View File
@@ -9,7 +9,10 @@
"version": "7.0.0",
"license": "MIT",
"dependencies": {
"@coinbase/cdp-sdk": "1.45.0",
"@psf/bch-js": "7.1.11",
"@x402/core": "2.6.0",
"@x402/evm": "2.6.0",
"axios": "1.7.7",
"cors": "2.8.5",
"dotenv": "16.3.1",
@@ -19,8 +22,9 @@
"slp-token-media": "1.2.10",
"winston": "3.11.0",
"winston-daily-rotate-file": "4.7.1",
"x402-axios": "^1.1.0",
"x402-express": "1.1.0"
"x402-axios": "1.1.0",
"x402-express": "1.1.0",
"x402-fetch": "1.1.0"
},
"devDependencies": {
"apidoc": "1.2.0",
@@ -4182,6 +4186,49 @@
"node": ">=20"
}
},
"node_modules/@spruceid/siwe-parser": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@spruceid/siwe-parser/-/siwe-parser-2.1.2.tgz",
"integrity": "sha512-d/r3S1LwJyMaRAKQ0awmo9whfXeE88Qt00vRj91q5uv5ATtWIQEGJ67Yr5eSZw5zp1/fZCXZYuEckt8lSkereQ==",
"license": "Apache-2.0",
"dependencies": {
"@noble/hashes": "^1.1.2",
"apg-js": "^4.3.0",
"uri-js": "^4.4.1",
"valid-url": "^1.0.9"
}
},
"node_modules/@stablelib/binary": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz",
"integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==",
"license": "MIT",
"dependencies": {
"@stablelib/int": "^1.0.1"
}
},
"node_modules/@stablelib/int": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz",
"integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==",
"license": "MIT"
},
"node_modules/@stablelib/random": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz",
"integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==",
"license": "MIT",
"dependencies": {
"@stablelib/binary": "^1.0.1",
"@stablelib/wipe": "^1.0.1"
}
},
"node_modules/@stablelib/wipe": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz",
"integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==",
"license": "MIT"
},
"node_modules/@swc/helpers": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz",
@@ -5253,6 +5300,64 @@
}
}
},
"node_modules/@x402/core": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@x402/core/-/core-2.6.0.tgz",
"integrity": "sha512-ISC/JeVss6xlKvor2rp18tJf9K5OQlIDDfZW1VZJQGDI2F4gy+HWxxkFfcQalCsPp4YUlwqh0YOkUxP+LTZWVg==",
"license": "Apache-2.0",
"dependencies": {
"zod": "^3.24.2"
}
},
"node_modules/@x402/evm": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@x402/evm/-/evm-2.6.0.tgz",
"integrity": "sha512-wPkNHf483gie1Up2sJSvERnW+VIEvMoT1KRXr09wSoSWgelglsJm+ug3gPPXKnT3C6AcmNAKZ12rBnu9Paff7g==",
"license": "Apache-2.0",
"dependencies": {
"@x402/core": "~2.6.0",
"@x402/extensions": "~2.6.0",
"viem": "^2.39.3",
"zod": "^3.24.2"
}
},
"node_modules/@x402/extensions": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@x402/extensions/-/extensions-2.6.0.tgz",
"integrity": "sha512-aLY9xAOOiRLKDN9HT2r9TYUXbD+IsoBces9qPZNVJGO2TBi2rfmbIBc3pcKCtWKn3iTvG2QFr3gpOFdpJRzqww==",
"license": "Apache-2.0",
"dependencies": {
"@scure/base": "^1.2.6",
"@x402/core": "~2.6.0",
"ajv": "^8.17.1",
"siwe": "^2.3.2",
"tweetnacl": "^1.0.3",
"viem": "^2.43.5",
"zod": "^3.24.2"
}
},
"node_modules/@x402/extensions/node_modules/ajv": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@x402/extensions/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -5333,6 +5438,13 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/aes-js": {
"version": "4.0.0-beta.5",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==",
"license": "MIT",
"peer": true
},
"node_modules/agentkeepalive": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
@@ -5438,6 +5550,12 @@
"node": ">= 8"
}
},
"node_modules/apg-js": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/apg-js/-/apg-js-4.4.0.tgz",
"integrity": "sha512-fefmXFknJmtgtNEXfPwZKYkMFX4Fyeyz+fNF6JWp87biGOPslJbCBVU158zvKRZfHBKnJDy8CMM40oLFGkXT8Q==",
"license": "BSD-2-Clause"
},
"node_modules/apidoc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/apidoc/-/apidoc-1.2.0.tgz",
@@ -9010,6 +9128,114 @@
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/ethers": {
"version": "6.16.0",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz",
"integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/ethers-io/"
},
{
"type": "individual",
"url": "https://www.buymeacoffee.com/ricmoo"
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2",
"@types/node": "22.7.5",
"aes-js": "4.0.0-beta.5",
"tslib": "2.7.0",
"ws": "8.17.1"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/ethers/node_modules/@adraffy/ens-normalize": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==",
"license": "MIT",
"peer": true
},
"node_modules/ethers/node_modules/@noble/curves": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@noble/hashes": "1.3.2"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/ethers/node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/ethers/node_modules/@types/node": {
"version": "22.7.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/ethers/node_modules/tslib": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"license": "0BSD",
"peer": true
},
"node_modules/ethers/node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"license": "MIT",
"peer": true
},
"node_modules/ethers/node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/eventemitter2": {
"version": "6.4.9",
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz",
@@ -13046,7 +13272,6 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -14173,6 +14398,21 @@
"url": "https://opencollective.com/sinon"
}
},
"node_modules/siwe": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/siwe/-/siwe-2.3.2.tgz",
"integrity": "sha512-aSf+6+Latyttbj5nMu6GF3doMfv2UYj83hhwZgUF20ky6fTS83uVhkQABdIVnEuS8y1bBdk7p6ltb9SmlhTTlA==",
"license": "Apache-2.0",
"dependencies": {
"@spruceid/siwe-parser": "^2.1.2",
"@stablelib/random": "^1.0.1",
"uri-js": "^4.4.1",
"valid-url": "^1.0.9"
},
"peerDependencies": {
"ethers": "^5.6.8 || ^6.0.8"
}
},
"node_modules/slp-mdm": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/slp-mdm/-/slp-mdm-0.0.7.tgz",
@@ -14978,6 +15218,12 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/tweetnacl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
"license": "Unlicense"
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -15377,7 +15623,6 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
@@ -15467,6 +15712,11 @@
"node": ">=10.12.0"
}
},
"node_modules/valid-url": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz",
"integrity": "sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA=="
},
"node_modules/valtio": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz",
@@ -16939,6 +17189,17 @@
"node": ">= 0.6"
}
},
"node_modules/x402-fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/x402-fetch/-/x402-fetch-1.1.0.tgz",
"integrity": "sha512-cbuUrb258+5n/oZxnvw454+iuhBoFkLptr4WEvlcCi8Hg1utIA6n0O1KqXdBV7GgNmQ8LoUDOiVv9DEyIvnlTw==",
"license": "Apache-2.0",
"dependencies": {
"viem": "^2.21.26",
"x402": "^1.1.0",
"zod": "^3.24.2"
}
},
"node_modules/xdg-basedir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+5 -1
View File
@@ -15,7 +15,10 @@
"license": "MIT",
"description": "REST API proxy to Bitcoin Cash infrastructure",
"dependencies": {
"@coinbase/cdp-sdk": "1.45.0",
"@psf/bch-js": "7.1.11",
"@x402/core": "2.6.0",
"@x402/evm": "2.6.0",
"axios": "1.7.7",
"cors": "2.8.5",
"dotenv": "16.3.1",
@@ -26,7 +29,8 @@
"winston": "3.11.0",
"winston-daily-rotate-file": "4.7.1",
"x402-axios": "1.1.0",
"x402-express": "1.1.0"
"x402-express": "1.1.0",
"x402-fetch": "1.1.0"
},
"devDependencies": {
"apidoc": "1.2.0",
+2 -1
View File
@@ -33,10 +33,11 @@ const priceUSDC = Number.isFinite(parsedPrice) && parsedPrice > 0 ? parsedPrice
const x402Defaults = {
enabled: normalizeBoolean(process.env.X402_ENABLED, true),
facilitatorUrl: process.env.FACILITATOR_URL || 'http://localhost:4345/facilitator',
facilitatorUrl: process.env.x402_FACILITATOR_URL || 'http://localhost:4022',
serverAddress: process.env.SERVER_BASE_ADDRESS || 'bitcoincash:qqsrke9lh257tqen99dkyy2emh4uty0vky9y0z0lsr',
facilitatorKeyId: process.env.FACILITATOR_KEY_ID || '',
facilitatorSecretKey: process.env.FACILITATOR_SECRET_KEY || '',
network: process.env.x402_NETWORK || 'base-sepolia',
priceUSDC
}
+49 -4
View File
@@ -1,8 +1,10 @@
import config from './index.js'
import { generateJwt } from '@coinbase/cdp-sdk/auth'
const DEFAULT_DESCRIPTION = 'Access to protected psf-bch-api resources'
const DEFAULT_TIMEOUT_SECONDS = 60
const NETWORK = 'base-sepolia'
const DEFAULT_TIMEOUT_SECONDS = 120
const NETWORK = config.x402.network
if (!NETWORK) throw new Error('x402_NETWORK env required!')
/**
* Builds a route configuration map for x402-bch middleware.
@@ -27,7 +29,15 @@ export function buildX402Routes (apiPrefix = '/v6') {
network: NETWORK,
config: {
description: `${DEFAULT_DESCRIPTION} (${config.x402.priceUSDC} USDC)`,
maxTimeoutSeconds: DEFAULT_TIMEOUT_SECONDS
maxTimeoutSeconds: DEFAULT_TIMEOUT_SECONDS,
mimeType: 'application/json',
outputSchema: {
input: {
type: 'http',
method: 'GET',
discoverable: true
}
}
}
}
}
@@ -36,7 +46,7 @@ export function buildX402Routes (apiPrefix = '/v6') {
export function getX402Settings () {
return {
enabled: Boolean(config.x402?.enabled),
facilitatorUrl: config.x402?.facilitatorUrl, // https://docs.cdp.coinbase.com/x402/quickstart-for-sellers
facilitatorUrl: config.x402?.facilitatorUrl, // https://docs.cdp.coinbase.com/x402/quickstart-for-sellers
facilitatorKeyId: config.x402?.facilitatorKeyId,
facilitatorSecretKey: config.x402?.facilitatorSecretKey,
serverAddress: config.x402?.serverAddress,
@@ -50,3 +60,38 @@ export function getBasicAuthSettings () {
token: config.basicAuth?.token || ''
}
}
/**
*
* Auth headers for interact with mainnet coin base facilitator endpoints.
*
*/
// https://docs.cdp.coinbase.com/get-started/authentication/jwt-authentication#javascript-2
// https://docs.cdp.coinbase.com/api-reference/v2/rest-api/x402-facilitator/verify-a-payment
export async function createAuthHeader () {
// /verify endpoint jwt
const verifyToken = await generateJwt({
apiKeyId: config.x402?.facilitatorKeyId,
apiKeySecret: config.x402?.facilitatorSecretKey,
requestMethod: 'POST',
requestHost: 'api.cdp.coinbase.com',
requestPath: '/platform/v2/x402/verify'
})
// /settle endpoint jwt
const settleToken = await generateJwt({
apiKeyId: config.x402?.facilitatorKeyId,
apiKeySecret: config.x402?.facilitatorSecretKey,
requestMethod: 'POST',
requestHost: 'api.cdp.coinbase.com',
requestPath: '/platform/v2/x402/settle'
})
return {
verify: {
Authorization: `Bearer ${verifyToken}`
},
settle: {
Authorization: `Bearer ${settleToken}`
}
}
}