moltspay 0.9.5 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +68 -45
  2. package/dist/cdp/index.d.mts +1 -1
  3. package/dist/cdp/index.d.ts +1 -1
  4. package/dist/cdp/index.js +63 -0
  5. package/dist/cdp/index.js.map +1 -1
  6. package/dist/cdp/index.mjs +63 -0
  7. package/dist/cdp/index.mjs.map +1 -1
  8. package/dist/chains/index.d.mts +9 -5
  9. package/dist/chains/index.d.ts +9 -5
  10. package/dist/chains/index.js +85 -0
  11. package/dist/chains/index.js.map +1 -1
  12. package/dist/chains/index.mjs +83 -0
  13. package/dist/chains/index.mjs.map +1 -1
  14. package/dist/cli/index.js +201 -38
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/index.mjs +201 -38
  17. package/dist/cli/index.mjs.map +1 -1
  18. package/dist/client/index.d.mts +18 -3
  19. package/dist/client/index.d.ts +18 -3
  20. package/dist/client/index.js +112 -15
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/client/index.mjs +112 -15
  23. package/dist/client/index.mjs.map +1 -1
  24. package/dist/{index-Dg8n6wdW.d.mts → index-B3v8IWjM.d.mts} +11 -1
  25. package/dist/{index-Dg8n6wdW.d.ts → index-B3v8IWjM.d.ts} +11 -1
  26. package/dist/index.d.mts +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +203 -42
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +203 -42
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/server/index.d.mts +19 -1
  33. package/dist/server/index.d.ts +19 -1
  34. package/dist/server/index.js +71 -19
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/index.mjs +71 -19
  37. package/dist/server/index.mjs.map +1 -1
  38. package/dist/verify/index.d.mts +7 -0
  39. package/dist/verify/index.d.ts +7 -0
  40. package/dist/verify/index.js +83 -8
  41. package/dist/verify/index.js.map +1 -1
  42. package/dist/verify/index.mjs +83 -8
  43. package/dist/verify/index.mjs.map +1 -1
  44. package/dist/wallet/index.d.mts +16 -8
  45. package/dist/wallet/index.d.ts +16 -8
  46. package/dist/wallet/index.js +114 -18
  47. package/dist/wallet/index.js.map +1 -1
  48. package/dist/wallet/index.mjs +114 -18
  49. package/dist/wallet/index.mjs.map +1 -1
  50. package/package.json +1 -1
  51. package/schemas/moltspay.services.schema.json +13 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/index.ts","../../src/facilitators/interface.ts","../../src/facilitators/cdp.ts","../../src/facilitators/registry.ts"],"sourcesContent":["/**\n * MoltsPay Server - Payment infrastructure for AI Agents\n * \n * Now uses pluggable Facilitator abstraction for payment verification/settlement.\n * \n * Environment variables (from ~/.moltspay/.env or process.env):\n * USE_MAINNET=true - Use Base mainnet (requires CDP keys)\n * CDP_API_KEY_ID=xxx - Coinbase Developer Platform API key ID\n * CDP_API_KEY_SECRET=xxx - CDP API key secret\n * \n * Usage:\n * const server = new MoltsPayServer('./moltspay.services.json');\n * server.skill('text-to-video', async (params) => { ... });\n * server.listen(3000);\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { createServer, IncomingMessage, ServerResponse } from 'http';\nimport * as path from 'path';\nimport {\n FacilitatorRegistry,\n FacilitatorSelection,\n X402PaymentPayload,\n X402PaymentRequirements,\n} from '../facilitators/index.js';\nimport {\n ServicesManifest,\n ServiceConfig,\n SkillFunction,\n RegisteredSkill,\n MoltsPayServerOptions,\n} from './types.js';\n\nexport * from './types.js';\n\n// x402 constants\nconst X402_VERSION = 2;\nconst PAYMENT_REQUIRED_HEADER = 'x-payment-required';\nconst PAYMENT_HEADER = 'x-payment';\nconst PAYMENT_RESPONSE_HEADER = 'x-payment-response';\n\n// USDC contract addresses\nconst USDC_ADDRESSES: Record<string, string> = {\n 'eip155:8453': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Base mainnet\n 'eip155:84532': '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Base Sepolia\n};\n\n// EIP-712 domain info for USDC\nconst USDC_DOMAIN = {\n name: 'USD Coin',\n version: '2',\n};\n\n/**\n * Load environment from .env files\n */\nfunction loadEnvFile(): void {\n const envPaths = [\n path.join(process.cwd(), '.env'),\n path.join(process.env.HOME || '', '.moltspay', '.env'),\n ];\n \n for (const envPath of envPaths) {\n if (existsSync(envPath)) {\n try {\n const content = readFileSync(envPath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIndex = trimmed.indexOf('=');\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n if (!process.env[key]) {\n process.env[key] = value;\n }\n }\n console.log(`[MoltsPay] Loaded config from ${envPath}`);\n break;\n } catch {\n // Ignore errors\n }\n }\n }\n}\n\n/**\n * Extended server options with facilitator config\n */\nexport interface MoltsPayServerOptionsExtended extends MoltsPayServerOptions {\n /** Facilitator selection configuration */\n facilitators?: FacilitatorSelection;\n}\n\nexport class MoltsPayServer {\n private manifest: ServicesManifest;\n private skills: Map<string, RegisteredSkill> = new Map();\n private options: MoltsPayServerOptionsExtended;\n private registry: FacilitatorRegistry;\n private networkId: string;\n private useMainnet: boolean;\n\n constructor(servicesPath: string, options: MoltsPayServerOptionsExtended = {}) {\n // Load env files FIRST (before reading USE_MAINNET)\n loadEnvFile();\n \n // Load services manifest\n const content = readFileSync(servicesPath, 'utf-8');\n this.manifest = JSON.parse(content) as ServicesManifest;\n \n this.options = {\n port: options.port || 3000,\n host: options.host || '0.0.0.0',\n ...options,\n };\n\n // Determine mainnet vs testnet from env\n this.useMainnet = process.env.USE_MAINNET?.toLowerCase() === 'true';\n this.networkId = this.useMainnet ? 'eip155:8453' : 'eip155:84532';\n\n // Create facilitator registry with config (env vars take precedence)\n const facilitatorConfig: FacilitatorSelection = options.facilitators || {\n primary: process.env.FACILITATOR_PRIMARY || 'cdp',\n fallback: process.env.FACILITATOR_FALLBACK?.split(',').filter(Boolean),\n strategy: (process.env.FACILITATOR_STRATEGY as any) || 'failover',\n config: {\n cdp: { useMainnet: this.useMainnet },\n },\n };\n this.registry = new FacilitatorRegistry(facilitatorConfig);\n\n // Get primary facilitator for logging\n const primaryFacilitator = this.registry.get(facilitatorConfig.primary);\n const networkName = this.useMainnet ? 'Base mainnet' : 'Base Sepolia (testnet)';\n \n console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);\n console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);\n console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);\n console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);\n console.log(`[MoltsPay] Facilitator: ${primaryFacilitator.displayName} (${facilitatorConfig.strategy || 'failover'})`);\n console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);\n }\n\n /**\n * Register a skill handler for a service\n */\n skill(serviceId: string, handler: SkillFunction): this {\n const config = this.manifest.services.find(s => s.id === serviceId);\n if (!config) {\n throw new Error(`Service '${serviceId}' not found in manifest`);\n }\n this.skills.set(serviceId, { id: serviceId, config, handler });\n return this;\n }\n\n /**\n * Start HTTP server\n */\n listen(port?: number): void {\n const p = port || this.options.port || 3000;\n const host = this.options.host || '0.0.0.0';\n\n const server = createServer((req, res) => this.handleRequest(req, res));\n server.listen(p, host, () => {\n console.log(`[MoltsPay] Server listening on http://${host}:${p}`);\n console.log(`[MoltsPay] Endpoints:`);\n console.log(` GET /services - List available services`);\n console.log(` POST /execute - Execute service (x402 payment)`);\n console.log(` POST /proxy - Proxy payment for external services`);\n console.log(` GET /health - Health check (incl. facilitators)`);\n });\n }\n\n /**\n * Handle incoming request\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // CORS\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Payment');\n res.setHeader('Access-Control-Expose-Headers', 'X-Payment-Required, X-Payment-Response');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n const url = new URL(req.url || '/', `http://${req.headers.host}`);\n \n if (url.pathname === '/services' && req.method === 'GET') {\n return this.handleGetServices(res);\n }\n\n // Standard discovery endpoint\n if (url.pathname === '/.well-known/agent-services.json' && req.method === 'GET') {\n return this.handleAgentServicesDiscovery(res);\n }\n\n if (url.pathname === '/health' && req.method === 'GET') {\n return await this.handleHealthCheck(res);\n }\n\n if (url.pathname === '/execute' && req.method === 'POST') {\n const body = await this.readBody(req);\n const paymentHeader = req.headers[PAYMENT_HEADER] as string | undefined;\n return await this.handleExecute(body, paymentHeader, res);\n }\n\n if (url.pathname === '/proxy' && req.method === 'POST') {\n // Check IP whitelist\n const clientIP = (req.headers['x-real-ip'] as string) || \n (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim() ||\n req.socket.remoteAddress || '';\n if (!this.isProxyAllowed(clientIP)) {\n return this.sendJson(res, 403, { error: 'Forbidden: IP not allowed' });\n }\n const body = await this.readBody(req);\n const paymentHeader = req.headers[PAYMENT_HEADER] as string | undefined;\n return await this.handleProxy(body, paymentHeader, res);\n }\n\n // Not found\n this.sendJson(res, 404, { error: 'Not found' });\n } catch (err: any) {\n console.error('[MoltsPay] Error:', err);\n this.sendJson(res, 500, { error: err.message || 'Internal error' });\n }\n }\n\n /**\n * GET /.well-known/agent-services.json - Standard discovery endpoint\n */\n private handleAgentServicesDiscovery(res: ServerResponse): void {\n const services = this.manifest.services.map(s => ({\n id: s.id,\n name: s.name,\n description: s.description,\n price: s.price,\n currency: s.currency,\n input: s.input,\n output: s.output,\n available: this.skills.has(s.id),\n }));\n\n this.sendJson(res, 200, {\n version: '1.0',\n provider: {\n name: this.manifest.provider.name,\n description: this.manifest.provider.description,\n wallet: this.manifest.provider.wallet,\n chain: this.manifest.provider.chain || 'base',\n },\n services,\n endpoints: {\n services: '/services',\n execute: '/execute',\n health: '/health',\n },\n payment: {\n protocol: 'x402',\n version: X402_VERSION,\n network: this.networkId,\n schemes: ['exact'],\n mainnet: this.useMainnet,\n },\n });\n }\n\n /**\n * GET /services - List available services\n */\n private handleGetServices(res: ServerResponse): void {\n const services = this.manifest.services.map(s => ({\n id: s.id,\n name: s.name,\n description: s.description,\n price: s.price,\n currency: s.currency,\n input: s.input,\n output: s.output,\n available: this.skills.has(s.id),\n }));\n\n const selection = this.registry.getSelection();\n \n this.sendJson(res, 200, {\n provider: this.manifest.provider,\n services,\n x402: {\n version: X402_VERSION,\n network: this.networkId,\n schemes: ['exact'],\n facilitators: {\n primary: selection.primary,\n fallback: selection.fallback,\n strategy: selection.strategy,\n },\n mainnet: this.useMainnet,\n },\n });\n }\n\n /**\n * GET /health - Health check endpoint\n */\n private async handleHealthCheck(res: ServerResponse): Promise<void> {\n const facilitatorHealth = await this.registry.healthCheckAll();\n \n const allHealthy = Object.values(facilitatorHealth).every(h => h.healthy);\n \n this.sendJson(res, allHealthy ? 200 : 503, {\n status: allHealthy ? 'healthy' : 'degraded',\n network: this.networkId,\n facilitators: facilitatorHealth,\n services: this.manifest.services.length,\n registered: this.skills.size,\n });\n }\n\n /**\n * POST /execute - Execute service with x402 payment\n */\n private async handleExecute(\n body: any,\n paymentHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { service, params } = body;\n\n if (!service) {\n return this.sendJson(res, 400, { error: 'Missing service' });\n }\n\n const skill = this.skills.get(service);\n if (!skill) {\n return this.sendJson(res, 404, { error: `Service '${service}' not found or not registered` });\n }\n\n // Validate required params\n for (const [key, field] of Object.entries(skill.config.input)) {\n if (field.required && (!params || params[key] === undefined)) {\n return this.sendJson(res, 400, { error: `Missing required param: ${key}` });\n }\n }\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendPaymentRequired(skill.config, res);\n }\n\n // Parse payment payload\n let payment: X402PaymentPayload;\n try {\n const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');\n payment = JSON.parse(decoded);\n } catch {\n return this.sendJson(res, 400, { error: 'Invalid X-Payment header' });\n }\n\n // Validate basic payment fields\n const validation = this.validatePayment(payment, skill.config);\n if (!validation.valid) {\n return this.sendJson(res, 402, { error: validation.error });\n }\n\n // Build requirements for facilitator\n const requirements = this.buildPaymentRequirements(skill.config);\n\n // Verify payment with facilitator (via registry)\n console.log(`[MoltsPay] Verifying payment...`);\n const verifyResult = await this.registry.verify(payment, requirements);\n if (!verifyResult.valid) {\n return this.sendJson(res, 402, { \n error: `Payment verification failed: ${verifyResult.error}`,\n facilitator: verifyResult.facilitator,\n });\n }\n console.log(`[MoltsPay] Verified by ${verifyResult.facilitator}`);\n\n // Execute skill FIRST (pay-for-success) with timeout\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n console.log(`[MoltsPay] Executing skill: ${service} (timeout: ${timeoutSeconds}s)`);\n let result: any;\n try {\n result = await Promise.race([\n skill.handler(params || {}),\n new Promise((_, reject) => \n setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1000)\n )\n ]);\n } catch (err: any) {\n console.error('[MoltsPay] Skill execution failed:', err.message);\n return this.sendJson(res, 500, {\n error: 'Service execution failed',\n message: err.message,\n });\n }\n\n // Skill succeeded - now settle payment with facilitator\n console.log(`[MoltsPay] Skill succeeded, settling payment...`);\n let settlement: any = null;\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] Settlement failed:', err.message);\n }\n\n // Build response\n const responseHeaders: Record<string, string> = {};\n if (settlement?.success) {\n const responsePayload = {\n success: true,\n transaction: settlement.transaction,\n network: payment.network || payment.accepted?.network,\n facilitator: settlement.facilitator,\n };\n responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(\n JSON.stringify(responsePayload)\n ).toString('base64');\n }\n\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: settlement?.success \n ? { transaction: settlement.transaction, status: 'settled', facilitator: settlement.facilitator }\n : { status: 'pending' },\n }, responseHeaders);\n }\n\n /**\n * Return 402 with x402 payment requirements (v2 format)\n */\n private sendPaymentRequired(config: ServiceConfig, res: ServerResponse): void {\n const requirements = this.buildPaymentRequirements(config);\n\n const paymentRequired = {\n x402Version: X402_VERSION,\n accepts: [requirements],\n resource: {\n url: `/execute?service=${config.id}`,\n description: `${config.name} - $${config.price} ${config.currency}`,\n mimeType: 'application/json',\n },\n };\n\n const encoded = Buffer.from(JSON.stringify(paymentRequired)).toString('base64');\n\n res.writeHead(402, {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n });\n res.end(JSON.stringify({\n error: 'Payment required',\n message: `Service requires $${config.price} ${config.currency}`,\n x402: paymentRequired,\n }, null, 2));\n }\n\n /**\n * Basic payment validation\n */\n private validatePayment(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): { valid: boolean; error?: string } {\n if (payment.x402Version !== X402_VERSION) {\n return { valid: false, error: `Unsupported x402 version: ${payment.x402Version}` };\n }\n\n const scheme = payment.accepted?.scheme || payment.scheme;\n const network = payment.accepted?.network || payment.network;\n\n if (scheme !== 'exact') {\n return { valid: false, error: `Unsupported scheme: ${scheme}` };\n }\n\n if (network !== this.networkId) {\n return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${network}` };\n }\n\n return { valid: true };\n }\n\n /**\n * Build payment requirements for facilitator\n */\n private buildPaymentRequirements(config: ServiceConfig): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const usdcAddress = USDC_ADDRESSES[this.networkId];\n\n return {\n scheme: 'exact',\n network: this.networkId,\n asset: usdcAddress,\n amount: amountInUnits,\n payTo: this.manifest.provider.wallet,\n maxTimeoutSeconds: 300,\n extra: USDC_DOMAIN,\n };\n }\n\n private async readBody(req: IncomingMessage): Promise<any> {\n return new Promise((resolve, reject) => {\n let body = '';\n req.on('data', chunk => body += chunk);\n req.on('end', () => {\n try {\n resolve(body ? JSON.parse(body) : {});\n } catch {\n reject(new Error('Invalid JSON'));\n }\n });\n req.on('error', reject);\n });\n }\n\n private sendJson(\n res: ServerResponse, \n status: number, \n data: any,\n extraHeaders?: Record<string, string>\n ): void {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (extraHeaders) {\n Object.assign(headers, extraHeaders);\n }\n res.writeHead(status, headers);\n res.end(JSON.stringify(data, null, 2));\n }\n\n /**\n * Check if IP is allowed for /proxy endpoint\n */\n private isProxyAllowed(clientIP: string): boolean {\n const allowedIPs = process.env.PROXY_ALLOWED_IPS?.split(',').map(ip => ip.trim()) || [];\n \n // If no whitelist configured, deny all (secure by default)\n if (allowedIPs.length === 0) {\n console.log(`[MoltsPay] /proxy denied: no PROXY_ALLOWED_IPS configured`);\n return false;\n }\n \n // Normalize IPv6 localhost\n const normalizedIP = clientIP === '::1' ? '127.0.0.1' : clientIP.replace('::ffff:', '');\n \n const allowed = allowedIPs.includes(normalizedIP) || allowedIPs.includes(clientIP);\n if (!allowed) {\n console.log(`[MoltsPay] /proxy denied for IP: ${clientIP} (normalized: ${normalizedIP})`);\n }\n return allowed;\n }\n\n /**\n * POST /proxy - Handle payment for external services (moltspay-creators)\n * \n * This endpoint allows other services to delegate x402 payment handling.\n * It does NOT execute any skill - just handles payment verification/settlement.\n * \n * Request body:\n * { wallet, amount, currency, chain, memo, serviceId, description }\n * \n * Without X-Payment header: returns 402 with payment requirements\n * With X-Payment header: verifies payment and returns result\n */\n private async handleProxy(\n body: any,\n paymentHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { wallet, amount, currency, chain, memo, serviceId, description } = body;\n\n // Validate required fields\n if (!wallet || !amount) {\n return this.sendJson(res, 400, { error: 'Missing required fields: wallet, amount' });\n }\n\n // Validate wallet format\n if (!/^0x[a-fA-F0-9]{40}$/.test(wallet)) {\n return this.sendJson(res, 400, { error: 'Invalid wallet address format' });\n }\n\n // Validate amount\n const amountNum = parseFloat(amount);\n if (isNaN(amountNum) || amountNum <= 0) {\n return this.sendJson(res, 400, { error: 'Invalid amount' });\n }\n\n // Build a synthetic service config for payment\n const proxyConfig: ServiceConfig = {\n id: serviceId || 'proxy',\n name: description || 'Proxy Payment',\n description: description || '',\n price: amountNum,\n currency: currency || 'USDC',\n function: '', // Not used\n input: {},\n output: {},\n };\n\n // Build payment requirements with the provided wallet\n const requirements = this.buildProxyPaymentRequirements(proxyConfig, wallet);\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendProxyPaymentRequired(proxyConfig, wallet, memo, res);\n }\n\n // Parse payment payload\n let payment: X402PaymentPayload;\n try {\n const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');\n payment = JSON.parse(decoded);\n } catch {\n return this.sendJson(res, 400, { error: 'Invalid X-Payment header' });\n }\n\n // Validate basic payment fields\n if (payment.x402Version !== X402_VERSION) {\n return this.sendJson(res, 402, { error: `Unsupported x402 version: ${payment.x402Version}` });\n }\n\n const scheme = payment.accepted?.scheme || payment.scheme;\n const network = payment.accepted?.network || payment.network;\n\n if (scheme !== 'exact') {\n return this.sendJson(res, 402, { error: `Unsupported scheme: ${scheme}` });\n }\n\n if (network !== this.networkId) {\n return this.sendJson(res, 402, { error: `Network mismatch: expected ${this.networkId}, got ${network}` });\n }\n\n // Verify payment with facilitator\n console.log(`[MoltsPay] /proxy: Verifying payment for ${wallet}...`);\n const verifyResult = await this.registry.verify(payment, requirements);\n if (!verifyResult.valid) {\n return this.sendJson(res, 402, { \n success: false,\n error: `Payment verification failed: ${verifyResult.error}`,\n facilitator: verifyResult.facilitator,\n });\n }\n console.log(`[MoltsPay] /proxy: Verified by ${verifyResult.facilitator}`);\n\n // Check if execution requested\n const { execute, service, params } = body;\n \n // If execute requested, run skill BEFORE settling (pay on success)\n if (execute && service) {\n console.log(`[MoltsPay] /proxy: Executing skill first (pay on success): ${service}`);\n const skill = this.skills.get(service);\n if (!skill) {\n // Service not found - don't settle, return error\n console.log(`[MoltsPay] /proxy: Service not found: ${service} - NOT settling`);\n return this.sendJson(res, 404, {\n success: false,\n paymentSettled: false,\n error: `Service not found: ${service}`,\n });\n }\n\n // Execute skill first (with timeout)\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n let result: any;\n try {\n result = await Promise.race([\n skill.handler(params || {}),\n new Promise((_, reject) => \n setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1000)\n )\n ]);\n console.log(`[MoltsPay] /proxy: Skill succeeded, now settling payment...`);\n } catch (err: any) {\n // Skill failed or timeout - don't settle, client keeps their money\n console.error(`[MoltsPay] /proxy: Skill failed: ${err.message} - NOT settling`);\n return this.sendJson(res, 500, {\n success: false,\n paymentSettled: false,\n error: `Service execution failed: ${err.message}`,\n });\n }\n\n // Skill succeeded - now settle payment\n let settlement: any = null;\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] /proxy: Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] /proxy: Settlement failed:', err.message);\n // Skill succeeded but settlement failed - return result anyway with warning\n return this.sendJson(res, 200, {\n success: true,\n verified: true,\n settled: false,\n settlementError: err.message,\n from: (payment.payload as any)?.authorization?.from, // Buyer's wallet address\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n memo,\n result,\n });\n }\n\n return this.sendJson(res, 200, {\n success: true,\n verified: true,\n settled: settlement?.success || false,\n txHash: settlement?.transaction,\n from: (payment.payload as any)?.authorization?.from, // Buyer's wallet address\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n facilitator: settlement?.facilitator,\n memo,\n result,\n });\n }\n\n // No execution requested - settle immediately (payment-only mode)\n console.log(`[MoltsPay] /proxy: Settling payment (no execution)...`);\n let settlement: any = null;\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] /proxy: Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] /proxy: Settlement failed:', err.message);\n return this.sendJson(res, 500, {\n success: false,\n error: `Settlement failed: ${err.message}`,\n });\n }\n\n // Return success (payment only, no execution)\n this.sendJson(res, 200, {\n success: true,\n verified: true,\n settled: settlement?.success || false,\n txHash: settlement?.transaction,\n from: (payment.payload as any)?.authorization?.from, // Buyer's wallet address\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n facilitator: settlement?.facilitator,\n memo,\n });\n }\n\n /**\n * Build payment requirements for proxy endpoint (uses provided wallet)\n */\n private buildProxyPaymentRequirements(config: ServiceConfig, wallet: string): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const usdcAddress = USDC_ADDRESSES[this.networkId];\n\n return {\n scheme: 'exact',\n network: this.networkId,\n asset: usdcAddress,\n amount: amountInUnits,\n payTo: wallet, // Use provided wallet, not manifest\n maxTimeoutSeconds: 300,\n extra: USDC_DOMAIN,\n };\n }\n\n /**\n * Return 402 with x402 payment requirements for proxy endpoint\n */\n private sendProxyPaymentRequired(\n config: ServiceConfig, \n wallet: string,\n memo: string | undefined,\n res: ServerResponse\n ): void {\n const requirements = this.buildProxyPaymentRequirements(config, wallet);\n\n const paymentRequired = {\n x402Version: X402_VERSION,\n accepts: [requirements],\n resource: {\n url: `/proxy`,\n description: `${config.name} - $${config.price} ${config.currency}`,\n mimeType: 'application/json',\n memo,\n },\n };\n\n const encoded = Buffer.from(JSON.stringify(paymentRequired)).toString('base64');\n\n res.writeHead(402, {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n });\n res.end(JSON.stringify({\n error: 'Payment required',\n message: `Payment requires $${config.price} ${config.currency}`,\n x402: paymentRequired,\n }, null, 2));\n }\n}\n","/**\n * Facilitator Interface\n * \n * A facilitator is a service that handles x402 payment verification and settlement.\n * This abstraction allows MoltsPay to support multiple facilitators.\n * \n * @see https://www.x402.org/ecosystem?category=facilitators\n */\n\n/**\n * x402 Payment Payload (from client)\n */\nexport interface X402PaymentPayload {\n x402Version: number;\n scheme?: string;\n network?: string;\n accepted?: {\n scheme: string;\n network: string;\n asset: string;\n amount: string;\n payTo: string;\n maxTimeoutSeconds: number;\n extra?: Record<string, unknown>;\n };\n payload: unknown;\n}\n\n/**\n * x402 Payment Requirements (server specifies what it accepts)\n */\nexport interface X402PaymentRequirements {\n scheme: string;\n network: string;\n asset: string;\n amount: string;\n payTo: string;\n maxTimeoutSeconds: number;\n extra?: Record<string, unknown>;\n}\n\n/**\n * Result of payment verification\n */\nexport interface VerifyResult {\n valid: boolean;\n error?: string;\n details?: Record<string, unknown>;\n}\n\n/**\n * Result of payment settlement\n */\nexport interface SettleResult {\n success: boolean;\n transaction?: string;\n error?: string;\n status?: string;\n}\n\n/**\n * Facilitator health check result\n */\nexport interface HealthCheckResult {\n healthy: boolean;\n latencyMs?: number;\n error?: string;\n}\n\n/**\n * Facilitator fee information (for selection strategies)\n */\nexport interface FacilitatorFee {\n perTx: number;\n currency: string;\n freeQuota?: number;\n}\n\n/**\n * Facilitator configuration\n */\nexport interface FacilitatorConfig {\n /** Facilitator endpoint URL */\n endpoint?: string;\n /** API key (if required) */\n apiKey?: string;\n /** API secret (if required) */\n apiSecret?: string;\n /** Additional config specific to facilitator */\n [key: string]: unknown;\n}\n\n/**\n * Facilitator Interface\n * \n * All facilitators must implement this interface.\n */\nexport interface Facilitator {\n /** Unique identifier for this facilitator */\n readonly name: string;\n \n /** Human-readable display name */\n readonly displayName: string;\n \n /** Supported networks (e.g., [\"eip155:8453\", \"eip155:84532\"]) */\n readonly supportedNetworks: string[];\n \n /**\n * Check if facilitator is available and responsive\n */\n healthCheck(): Promise<HealthCheckResult>;\n \n /**\n * Verify a payment signature without executing it\n * \n * @param paymentPayload - The x402 payment payload from client\n * @param requirements - The payment requirements from server\n */\n verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult>;\n \n /**\n * Settle a payment on-chain\n * \n * @param paymentPayload - The x402 payment payload from client\n * @param requirements - The payment requirements from server\n */\n settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult>;\n \n /**\n * Get current fee information (optional, for selection strategies)\n */\n getFee?(): Promise<FacilitatorFee>;\n \n /**\n * Check if this facilitator supports a given network\n */\n supportsNetwork(network: string): boolean;\n}\n\n/**\n * Base class with common functionality\n */\nexport abstract class BaseFacilitator implements Facilitator {\n abstract readonly name: string;\n abstract readonly displayName: string;\n abstract readonly supportedNetworks: string[];\n \n abstract healthCheck(): Promise<HealthCheckResult>;\n abstract verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult>;\n abstract settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult>;\n \n supportsNetwork(network: string): boolean {\n return this.supportedNetworks.includes(network);\n }\n}\n","/**\n * CDP Facilitator\n * \n * Coinbase Developer Platform x402 facilitator implementation.\n * Supports both mainnet (Base) and testnet (Base Sepolia).\n * \n * @see https://docs.cdp.coinbase.com/x402/core-concepts/facilitator\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport * as path from 'path';\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n FacilitatorFee,\n FacilitatorConfig,\n} from './interface.js';\n\n// x402 protocol version\nconst X402_VERSION = 2;\n\n// CDP Facilitator URLs\nconst CDP_MAINNET_URL = 'https://api.cdp.coinbase.com/platform/v2/x402';\nconst CDP_TESTNET_URL = 'https://www.x402.org/facilitator';\n\nexport interface CDPFacilitatorConfig extends FacilitatorConfig {\n /** Use mainnet (true) or testnet (false, default) */\n useMainnet?: boolean;\n /** CDP API Key ID (required for mainnet) */\n apiKeyId?: string;\n /** CDP API Key Secret (required for mainnet) */\n apiKeySecret?: string;\n}\n\n/**\n * Load environment from .env files\n */\nfunction loadEnvFile(): void {\n const envPaths = [\n path.join(process.cwd(), '.env'),\n path.join(process.env.HOME || '', '.moltspay', '.env'),\n ];\n \n for (const envPath of envPaths) {\n if (existsSync(envPath)) {\n try {\n const content = readFileSync(envPath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIndex = trimmed.indexOf('=');\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n if (!process.env[key]) {\n process.env[key] = value;\n }\n }\n break;\n } catch {\n // Ignore errors\n }\n }\n }\n}\n\n/**\n * CDP (Coinbase Developer Platform) Facilitator\n * \n * Handles payment verification and settlement via Coinbase's x402 facilitator.\n */\nexport class CDPFacilitator extends BaseFacilitator {\n readonly name = 'cdp';\n readonly displayName = 'Coinbase CDP';\n readonly supportedNetworks: string[];\n \n private endpoint: string;\n private useMainnet: boolean;\n private apiKeyId?: string;\n private apiKeySecret?: string;\n \n constructor(config: CDPFacilitatorConfig = {}) {\n super();\n \n // Load env files for credentials\n loadEnvFile();\n \n // Determine mainnet vs testnet\n this.useMainnet = config.useMainnet ?? \n (process.env.USE_MAINNET?.toLowerCase() === 'true');\n \n // Get credentials\n this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;\n this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;\n \n // Set endpoint\n this.endpoint = this.useMainnet ? CDP_MAINNET_URL : CDP_TESTNET_URL;\n \n // Set supported networks\n this.supportedNetworks = this.useMainnet \n ? ['eip155:8453'] // Base mainnet only\n : ['eip155:8453', 'eip155:84532']; // Both mainnet and testnet via x402.org\n \n // Warn if mainnet without credentials\n if (this.useMainnet && (!this.apiKeyId || !this.apiKeySecret)) {\n console.warn('[CDPFacilitator] WARNING: Mainnet mode but missing CDP credentials!');\n console.warn('[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET');\n }\n }\n \n /**\n * Get auth headers for CDP API requests\n */\n private async getAuthHeaders(\n method: string,\n urlPath: string,\n body?: unknown\n ): Promise<Record<string, string>> {\n if (!this.useMainnet) {\n // Testnet (x402.org) doesn't require auth\n return {};\n }\n \n if (!this.apiKeyId || !this.apiKeySecret) {\n throw new Error('CDP credentials required for mainnet');\n }\n \n try {\n const { getAuthHeaders } = await import('@coinbase/cdp-sdk/auth');\n \n return await getAuthHeaders({\n apiKeyId: this.apiKeyId,\n apiKeySecret: this.apiKeySecret,\n requestMethod: method,\n requestHost: 'api.cdp.coinbase.com',\n requestPath: urlPath,\n requestBody: body,\n });\n } catch (err: any) {\n throw new Error(`Failed to generate CDP auth: ${err.message}`);\n }\n }\n \n /**\n * Health check - verify facilitator is reachable\n */\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n \n try {\n // For testnet, just check if x402.org responds\n // For mainnet, we could hit a health endpoint or just check DNS\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n \n const response = await fetch(this.endpoint.replace('/x402', ''), {\n method: 'HEAD',\n signal: controller.signal,\n }).catch(() => null);\n \n clearTimeout(timeout);\n \n const latencyMs = Date.now() - start;\n \n return {\n healthy: response !== null,\n latencyMs,\n };\n } catch (err: any) {\n return {\n healthy: false,\n error: err.message,\n latencyMs: Date.now() - start,\n };\n }\n }\n \n /**\n * Verify payment signature with facilitator\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n const requestBody = {\n x402Version: X402_VERSION,\n paymentPayload,\n paymentRequirements: requirements,\n };\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n \n if (this.useMainnet) {\n const authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/verify',\n requestBody\n );\n Object.assign(headers, authHeaders);\n }\n \n const response = await fetch(`${this.endpoint}/verify`, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\n });\n \n const result = await response.json() as any;\n \n if (!response.ok || !result.isValid) {\n return {\n valid: false,\n error: result.invalidReason || result.error || 'Verification failed',\n details: result,\n };\n }\n \n return { valid: true, details: result };\n } catch (err: any) {\n return {\n valid: false,\n error: `Facilitator error: ${err.message}`,\n };\n }\n }\n \n /**\n * Settle payment on-chain via facilitator\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n try {\n const requestBody = {\n x402Version: X402_VERSION,\n paymentPayload,\n paymentRequirements: requirements,\n };\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n \n if (this.useMainnet) {\n const authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/settle',\n requestBody\n );\n Object.assign(headers, authHeaders);\n }\n \n const response = await fetch(`${this.endpoint}/settle`, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\n });\n \n const result = await response.json() as any;\n \n if (!response.ok || !result.success) {\n return {\n success: false,\n error: result.error || result.errorReason || 'Settlement failed',\n };\n }\n \n return {\n success: true,\n transaction: result.transaction,\n status: result.status || 'settled',\n };\n } catch (err: any) {\n return {\n success: false,\n error: `Settlement error: ${err.message}`,\n };\n }\n }\n \n /**\n * Get CDP fee information\n */\n async getFee(): Promise<FacilitatorFee> {\n // CDP pricing: 1000 free/month, then $0.001/tx\n return {\n perTx: 0.001,\n currency: 'USD',\n freeQuota: 1000,\n };\n }\n \n /**\n * Get configuration summary (for logging)\n */\n getConfigSummary(): string {\n const mode = this.useMainnet ? 'mainnet' : 'testnet';\n const hasCredentials = !!(this.apiKeyId && this.apiKeySecret);\n return `CDP Facilitator (${mode}, credentials: ${hasCredentials ? 'yes' : 'no'})`;\n }\n}\n","/**\n * Facilitator Registry\n * \n * Central registry for all available facilitators.\n * Supports selection strategies for failover, load balancing, etc.\n */\n\nimport {\n Facilitator,\n FacilitatorConfig,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { CDPFacilitator, CDPFacilitatorConfig } from './cdp.js';\n\n/**\n * Selection strategy for choosing facilitators\n */\nexport type SelectionStrategy = \n | 'failover' // Use primary, switch to fallback on failure\n | 'cheapest' // Use facilitator with lowest fees\n | 'fastest' // Use first responder\n | 'random' // Random selection (load balancing)\n | 'roundrobin'; // Rotate through facilitators\n\n/**\n * Facilitator selection configuration\n */\nexport interface FacilitatorSelection {\n /** Primary facilitator to use */\n primary: string;\n /** Fallback facilitators (in order of preference) */\n fallback?: string[];\n /** Selection strategy */\n strategy?: SelectionStrategy;\n /** Per-facilitator config overrides */\n config?: Record<string, FacilitatorConfig>;\n}\n\n/**\n * Factory function type for creating facilitators\n */\ntype FacilitatorFactory = (config?: FacilitatorConfig) => Facilitator;\n\n/**\n * Facilitator Registry\n * \n * Manages available facilitators and provides selection logic.\n */\nexport class FacilitatorRegistry {\n private factories: Map<string, FacilitatorFactory> = new Map();\n private instances: Map<string, Facilitator> = new Map();\n private selection: FacilitatorSelection;\n private roundRobinIndex = 0;\n \n constructor(selection?: FacilitatorSelection) {\n // Register built-in facilitators\n this.registerFactory('cdp', (config) => new CDPFacilitator(config as CDPFacilitatorConfig));\n \n // Default selection\n this.selection = selection || { primary: 'cdp', strategy: 'failover' };\n }\n \n /**\n * Register a new facilitator factory\n */\n registerFactory(name: string, factory: FacilitatorFactory): void {\n this.factories.set(name, factory);\n }\n \n /**\n * Get or create a facilitator instance\n */\n get(name: string, config?: FacilitatorConfig): Facilitator {\n // Check cache first\n if (this.instances.has(name)) {\n return this.instances.get(name)!;\n }\n \n // Look up factory\n const factory = this.factories.get(name);\n if (!factory) {\n throw new Error(`Unknown facilitator: ${name}. Available: ${Array.from(this.factories.keys()).join(', ')}`);\n }\n \n // Merge config from selection\n const mergedConfig = {\n ...this.selection.config?.[name],\n ...config,\n };\n \n // Create and cache instance\n const instance = factory(mergedConfig);\n this.instances.set(name, instance);\n return instance;\n }\n \n /**\n * Get all configured facilitator names\n */\n getConfiguredNames(): string[] {\n const names = [this.selection.primary];\n if (this.selection.fallback) {\n names.push(...this.selection.fallback);\n }\n return names;\n }\n \n /**\n * Get list of facilitators based on selection strategy\n */\n private async getOrderedFacilitators(network: string): Promise<Facilitator[]> {\n const names = this.getConfiguredNames();\n const facilitators: Facilitator[] = [];\n \n for (const name of names) {\n try {\n const f = this.get(name);\n if (f.supportsNetwork(network)) {\n facilitators.push(f);\n }\n } catch (err) {\n console.warn(`[Registry] Failed to get facilitator ${name}:`, err);\n }\n }\n \n if (facilitators.length === 0) {\n throw new Error(`No facilitators available for network: ${network}`);\n }\n \n // Apply strategy\n switch (this.selection.strategy) {\n case 'random':\n return this.shuffle(facilitators);\n \n case 'roundrobin':\n this.roundRobinIndex = (this.roundRobinIndex + 1) % facilitators.length;\n return [\n ...facilitators.slice(this.roundRobinIndex),\n ...facilitators.slice(0, this.roundRobinIndex),\n ];\n \n case 'cheapest':\n return this.sortByCheapest(facilitators);\n \n case 'fastest':\n return this.sortByFastest(facilitators);\n \n case 'failover':\n default:\n return facilitators;\n }\n }\n \n private shuffle<T>(array: T[]): T[] {\n const result = [...array];\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [result[i], result[j]] = [result[j], result[i]];\n }\n return result;\n }\n \n private async sortByCheapest(facilitators: Facilitator[]): Promise<Facilitator[]> {\n const withFees = await Promise.all(\n facilitators.map(async (f) => {\n try {\n const fee = await f.getFee?.();\n return { facilitator: f, perTx: fee?.perTx ?? Infinity };\n } catch {\n return { facilitator: f, perTx: Infinity };\n }\n })\n );\n withFees.sort((a, b) => a.perTx - b.perTx);\n return withFees.map(w => w.facilitator);\n }\n \n private async sortByFastest(facilitators: Facilitator[]): Promise<Facilitator[]> {\n const withLatency = await Promise.all(\n facilitators.map(async (f) => {\n try {\n const health = await f.healthCheck();\n return { facilitator: f, latency: health.latencyMs ?? Infinity };\n } catch {\n return { facilitator: f, latency: Infinity };\n }\n })\n );\n withLatency.sort((a, b) => a.latency - b.latency);\n return withLatency.map(w => w.facilitator);\n }\n \n /**\n * Verify payment using configured facilitators\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult & { facilitator: string }> {\n const network = paymentPayload.accepted?.network || paymentPayload.network || requirements.network;\n const facilitators = await this.getOrderedFacilitators(network);\n \n let lastError: string | undefined;\n \n for (const f of facilitators) {\n try {\n console.log(`[Registry] Trying ${f.name} for verify...`);\n const result = await f.verify(paymentPayload, requirements);\n \n if (result.valid) {\n console.log(`[Registry] ${f.name} verify succeeded`);\n return { ...result, facilitator: f.name };\n }\n \n lastError = result.error;\n console.log(`[Registry] ${f.name} verify failed: ${result.error}`);\n \n // For failover strategy, only try next if it's a network/server error\n if (this.selection.strategy === 'failover' && !this.isTransientError(result.error)) {\n // Permanent error (e.g., invalid signature) - don't try others\n break;\n }\n } catch (err: any) {\n lastError = err.message;\n console.error(`[Registry] ${f.name} error:`, err.message);\n }\n }\n \n return {\n valid: false,\n error: lastError || 'All facilitators failed',\n facilitator: 'none',\n };\n }\n \n /**\n * Settle payment using configured facilitators\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult & { facilitator: string }> {\n const network = paymentPayload.accepted?.network || paymentPayload.network || requirements.network;\n const facilitators = await this.getOrderedFacilitators(network);\n \n let lastError: string | undefined;\n \n for (const f of facilitators) {\n try {\n console.log(`[Registry] Trying ${f.name} for settle...`);\n const result = await f.settle(paymentPayload, requirements);\n \n if (result.success) {\n console.log(`[Registry] ${f.name} settle succeeded: ${result.transaction}`);\n return { ...result, facilitator: f.name };\n }\n \n lastError = result.error;\n console.log(`[Registry] ${f.name} settle failed: ${result.error}`);\n } catch (err: any) {\n lastError = err.message;\n console.error(`[Registry] ${f.name} error:`, err.message);\n }\n }\n \n return {\n success: false,\n error: lastError || 'All facilitators failed',\n facilitator: 'none',\n };\n }\n \n /**\n * Check health of all configured facilitators\n */\n async healthCheckAll(): Promise<Record<string, HealthCheckResult>> {\n const results: Record<string, HealthCheckResult> = {};\n \n for (const name of this.getConfiguredNames()) {\n try {\n const f = this.get(name);\n results[name] = await f.healthCheck();\n } catch (err: any) {\n results[name] = { healthy: false, error: err.message };\n }\n }\n \n return results;\n }\n \n /**\n * Check if an error is transient (network/server issue) vs permanent (bad request)\n */\n private isTransientError(error?: string): boolean {\n if (!error) return true;\n const transientPatterns = [\n /timeout/i,\n /network/i,\n /connection/i,\n /ECONNREFUSED/i,\n /ETIMEDOUT/i,\n /503/,\n /502/,\n /500/,\n ];\n return transientPatterns.some(p => p.test(error));\n }\n \n /**\n * Update selection configuration\n */\n setSelection(selection: FacilitatorSelection): void {\n this.selection = selection;\n // Clear cached instances to pick up new config\n this.instances.clear();\n }\n \n /**\n * Get current selection configuration\n */\n getSelection(): FacilitatorSelection {\n return { ...this.selection };\n }\n}\n\n// Default registry instance\nlet defaultRegistry: FacilitatorRegistry | null = null;\n\n/**\n * Get the default facilitator registry\n */\nexport function getDefaultRegistry(): FacilitatorRegistry {\n if (!defaultRegistry) {\n defaultRegistry = new FacilitatorRegistry();\n }\n return defaultRegistry;\n}\n\n/**\n * Create a new registry with custom selection\n */\nexport function createRegistry(selection?: FacilitatorSelection): FacilitatorRegistry {\n return new FacilitatorRegistry(selection);\n}\n"],"mappings":"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","names":["readFileSync","existsSync","path","X402_VERSION","loadEnvFile","existsSync","readFileSync","settlement"]}
1
+ {"version":3,"sources":["../../src/server/index.ts","../../src/facilitators/interface.ts","../../src/facilitators/cdp.ts","../../src/facilitators/registry.ts"],"sourcesContent":["/**\n * MoltsPay Server - Payment infrastructure for AI Agents\n * \n * Now uses pluggable Facilitator abstraction for payment verification/settlement.\n * \n * Environment variables (from ~/.moltspay/.env or process.env):\n * USE_MAINNET=true - Use Base mainnet (requires CDP keys)\n * CDP_API_KEY_ID=xxx - Coinbase Developer Platform API key ID\n * CDP_API_KEY_SECRET=xxx - CDP API key secret\n * \n * Usage:\n * const server = new MoltsPayServer('./moltspay.services.json');\n * server.skill('text-to-video', async (params) => { ... });\n * server.listen(3000);\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { createServer, IncomingMessage, ServerResponse } from 'http';\nimport * as path from 'path';\nimport {\n FacilitatorRegistry,\n FacilitatorSelection,\n X402PaymentPayload,\n X402PaymentRequirements,\n} from '../facilitators/index.js';\nimport {\n ServicesManifest,\n ServiceConfig,\n SkillFunction,\n RegisteredSkill,\n MoltsPayServerOptions,\n} from './types.js';\n\nexport * from './types.js';\n\n// x402 constants\nconst X402_VERSION = 2;\nconst PAYMENT_REQUIRED_HEADER = 'x-payment-required';\nconst PAYMENT_HEADER = 'x-payment';\nconst PAYMENT_RESPONSE_HEADER = 'x-payment-response';\n\n// Token contract addresses by network\nconst TOKEN_ADDRESSES: Record<string, Record<string, string>> = {\n 'eip155:8453': {\n USDC: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n USDT: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',\n },\n 'eip155:84532': {\n USDC: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n USDT: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Same as USDC on testnet\n },\n};\n\n// EIP-712 domain info for tokens\nconst TOKEN_DOMAINS: Record<string, { name: string; version: string }> = {\n USDC: { name: 'USD Coin', version: '2' },\n USDT: { name: 'Tether USD', version: '2' },\n};\n\n// Helper to get accepted currencies with backward compatibility\nfunction getAcceptedCurrencies(config: ServiceConfig): string[] {\n return config.acceptedCurrencies ?? [config.currency];\n}\n\n/**\n * Load environment from .env files\n */\nfunction loadEnvFile(): void {\n const envPaths = [\n path.join(process.cwd(), '.env'),\n path.join(process.env.HOME || '', '.moltspay', '.env'),\n ];\n \n for (const envPath of envPaths) {\n if (existsSync(envPath)) {\n try {\n const content = readFileSync(envPath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIndex = trimmed.indexOf('=');\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n if (!process.env[key]) {\n process.env[key] = value;\n }\n }\n console.log(`[MoltsPay] Loaded config from ${envPath}`);\n break;\n } catch {\n // Ignore errors\n }\n }\n }\n}\n\n/**\n * Extended server options with facilitator config\n */\nexport interface MoltsPayServerOptionsExtended extends MoltsPayServerOptions {\n /** Facilitator selection configuration */\n facilitators?: FacilitatorSelection;\n}\n\nexport class MoltsPayServer {\n private manifest: ServicesManifest;\n private skills: Map<string, RegisteredSkill> = new Map();\n private options: MoltsPayServerOptionsExtended;\n private registry: FacilitatorRegistry;\n private networkId: string;\n private useMainnet: boolean;\n\n constructor(servicesPath: string, options: MoltsPayServerOptionsExtended = {}) {\n // Load env files FIRST (before reading USE_MAINNET)\n loadEnvFile();\n \n // Load services manifest\n const content = readFileSync(servicesPath, 'utf-8');\n this.manifest = JSON.parse(content) as ServicesManifest;\n \n this.options = {\n port: options.port || 3000,\n host: options.host || '0.0.0.0',\n ...options,\n };\n\n // Determine mainnet vs testnet from env\n this.useMainnet = process.env.USE_MAINNET?.toLowerCase() === 'true';\n this.networkId = this.useMainnet ? 'eip155:8453' : 'eip155:84532';\n\n // Create facilitator registry with config (env vars take precedence)\n const facilitatorConfig: FacilitatorSelection = options.facilitators || {\n primary: process.env.FACILITATOR_PRIMARY || 'cdp',\n fallback: process.env.FACILITATOR_FALLBACK?.split(',').filter(Boolean),\n strategy: (process.env.FACILITATOR_STRATEGY as any) || 'failover',\n config: {\n cdp: { useMainnet: this.useMainnet },\n },\n };\n this.registry = new FacilitatorRegistry(facilitatorConfig);\n\n // Get primary facilitator for logging\n const primaryFacilitator = this.registry.get(facilitatorConfig.primary);\n const networkName = this.useMainnet ? 'Base mainnet' : 'Base Sepolia (testnet)';\n \n console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);\n console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);\n console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);\n console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);\n console.log(`[MoltsPay] Facilitator: ${primaryFacilitator.displayName} (${facilitatorConfig.strategy || 'failover'})`);\n console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);\n }\n\n /**\n * Register a skill handler for a service\n */\n skill(serviceId: string, handler: SkillFunction): this {\n const config = this.manifest.services.find(s => s.id === serviceId);\n if (!config) {\n throw new Error(`Service '${serviceId}' not found in manifest`);\n }\n this.skills.set(serviceId, { id: serviceId, config, handler });\n return this;\n }\n\n /**\n * Start HTTP server\n */\n listen(port?: number): void {\n const p = port || this.options.port || 3000;\n const host = this.options.host || '0.0.0.0';\n\n const server = createServer((req, res) => this.handleRequest(req, res));\n server.listen(p, host, () => {\n console.log(`[MoltsPay] Server listening on http://${host}:${p}`);\n console.log(`[MoltsPay] Endpoints:`);\n console.log(` GET /services - List available services`);\n console.log(` POST /execute - Execute service (x402 payment)`);\n console.log(` POST /proxy - Proxy payment for external services`);\n console.log(` GET /health - Health check (incl. facilitators)`);\n });\n }\n\n /**\n * Handle incoming request\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // CORS\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Payment');\n res.setHeader('Access-Control-Expose-Headers', 'X-Payment-Required, X-Payment-Response');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n const url = new URL(req.url || '/', `http://${req.headers.host}`);\n \n if (url.pathname === '/services' && req.method === 'GET') {\n return this.handleGetServices(res);\n }\n\n // Standard discovery endpoint\n if (url.pathname === '/.well-known/agent-services.json' && req.method === 'GET') {\n return this.handleAgentServicesDiscovery(res);\n }\n\n if (url.pathname === '/health' && req.method === 'GET') {\n return await this.handleHealthCheck(res);\n }\n\n if (url.pathname === '/execute' && req.method === 'POST') {\n const body = await this.readBody(req);\n const paymentHeader = req.headers[PAYMENT_HEADER] as string | undefined;\n return await this.handleExecute(body, paymentHeader, res);\n }\n\n if (url.pathname === '/proxy' && req.method === 'POST') {\n // Check IP whitelist\n const clientIP = (req.headers['x-real-ip'] as string) || \n (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim() ||\n req.socket.remoteAddress || '';\n if (!this.isProxyAllowed(clientIP)) {\n return this.sendJson(res, 403, { error: 'Forbidden: IP not allowed' });\n }\n const body = await this.readBody(req);\n const paymentHeader = req.headers[PAYMENT_HEADER] as string | undefined;\n return await this.handleProxy(body, paymentHeader, res);\n }\n\n // Not found\n this.sendJson(res, 404, { error: 'Not found' });\n } catch (err: any) {\n console.error('[MoltsPay] Error:', err);\n this.sendJson(res, 500, { error: err.message || 'Internal error' });\n }\n }\n\n /**\n * GET /.well-known/agent-services.json - Standard discovery endpoint\n */\n private handleAgentServicesDiscovery(res: ServerResponse): void {\n const services = this.manifest.services.map(s => ({\n id: s.id,\n name: s.name,\n description: s.description,\n price: s.price,\n currency: s.currency,\n acceptedCurrencies: getAcceptedCurrencies(s),\n input: s.input,\n output: s.output,\n available: this.skills.has(s.id),\n }));\n\n this.sendJson(res, 200, {\n version: '1.0',\n provider: {\n name: this.manifest.provider.name,\n description: this.manifest.provider.description,\n wallet: this.manifest.provider.wallet,\n chain: this.manifest.provider.chain || 'base',\n },\n services,\n endpoints: {\n services: '/services',\n execute: '/execute',\n health: '/health',\n },\n payment: {\n protocol: 'x402',\n version: X402_VERSION,\n network: this.networkId,\n schemes: ['exact'],\n mainnet: this.useMainnet,\n },\n });\n }\n\n /**\n * GET /services - List available services\n */\n private handleGetServices(res: ServerResponse): void {\n const services = this.manifest.services.map(s => ({\n id: s.id,\n name: s.name,\n description: s.description,\n price: s.price,\n currency: s.currency,\n acceptedCurrencies: getAcceptedCurrencies(s),\n input: s.input,\n output: s.output,\n available: this.skills.has(s.id),\n }));\n\n const selection = this.registry.getSelection();\n \n this.sendJson(res, 200, {\n provider: this.manifest.provider,\n services,\n x402: {\n version: X402_VERSION,\n network: this.networkId,\n schemes: ['exact'],\n facilitators: {\n primary: selection.primary,\n fallback: selection.fallback,\n strategy: selection.strategy,\n },\n mainnet: this.useMainnet,\n },\n });\n }\n\n /**\n * GET /health - Health check endpoint\n */\n private async handleHealthCheck(res: ServerResponse): Promise<void> {\n const facilitatorHealth = await this.registry.healthCheckAll();\n \n const allHealthy = Object.values(facilitatorHealth).every(h => h.healthy);\n \n this.sendJson(res, allHealthy ? 200 : 503, {\n status: allHealthy ? 'healthy' : 'degraded',\n network: this.networkId,\n facilitators: facilitatorHealth,\n services: this.manifest.services.length,\n registered: this.skills.size,\n });\n }\n\n /**\n * POST /execute - Execute service with x402 payment\n */\n private async handleExecute(\n body: any,\n paymentHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { service, params } = body;\n\n if (!service) {\n return this.sendJson(res, 400, { error: 'Missing service' });\n }\n\n const skill = this.skills.get(service);\n if (!skill) {\n return this.sendJson(res, 404, { error: `Service '${service}' not found or not registered` });\n }\n\n // Validate required params\n for (const [key, field] of Object.entries(skill.config.input)) {\n if (field.required && (!params || params[key] === undefined)) {\n return this.sendJson(res, 400, { error: `Missing required param: ${key}` });\n }\n }\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendPaymentRequired(skill.config, res);\n }\n\n // Parse payment payload\n let payment: X402PaymentPayload;\n try {\n const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');\n payment = JSON.parse(decoded);\n } catch {\n return this.sendJson(res, 400, { error: 'Invalid X-Payment header' });\n }\n\n // Validate basic payment fields\n const validation = this.validatePayment(payment, skill.config);\n if (!validation.valid) {\n return this.sendJson(res, 402, { error: validation.error });\n }\n\n // Detect which token is being used\n const paymentToken = this.detectPaymentToken(payment);\n if (paymentToken && !this.isTokenAccepted(skill.config, paymentToken)) {\n const accepted = getAcceptedCurrencies(skill.config);\n return this.sendJson(res, 402, { \n error: `Token ${paymentToken} not accepted. Accepted: ${accepted.join(', ')}` \n });\n }\n\n // Build requirements for facilitator using the detected token\n const requirements = this.buildPaymentRequirements(skill.config, paymentToken);\n\n // Verify payment with facilitator (via registry)\n console.log(`[MoltsPay] Verifying payment...`);\n const verifyResult = await this.registry.verify(payment, requirements);\n if (!verifyResult.valid) {\n return this.sendJson(res, 402, { \n error: `Payment verification failed: ${verifyResult.error}`,\n facilitator: verifyResult.facilitator,\n });\n }\n console.log(`[MoltsPay] Verified by ${verifyResult.facilitator}`);\n\n // Execute skill FIRST (pay-for-success) with timeout\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n console.log(`[MoltsPay] Executing skill: ${service} (timeout: ${timeoutSeconds}s)`);\n let result: any;\n try {\n result = await Promise.race([\n skill.handler(params || {}),\n new Promise((_, reject) => \n setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1000)\n )\n ]);\n } catch (err: any) {\n console.error('[MoltsPay] Skill execution failed:', err.message);\n return this.sendJson(res, 500, {\n error: 'Service execution failed',\n message: err.message,\n });\n }\n\n // Skill succeeded - now settle payment with facilitator\n console.log(`[MoltsPay] Skill succeeded, settling payment...`);\n let settlement: any = null;\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] Settlement failed:', err.message);\n }\n\n // Build response\n const responseHeaders: Record<string, string> = {};\n if (settlement?.success) {\n const responsePayload = {\n success: true,\n transaction: settlement.transaction,\n network: payment.network || payment.accepted?.network,\n facilitator: settlement.facilitator,\n };\n responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(\n JSON.stringify(responsePayload)\n ).toString('base64');\n }\n\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: settlement?.success \n ? { transaction: settlement.transaction, status: 'settled', facilitator: settlement.facilitator }\n : { status: 'pending' },\n }, responseHeaders);\n }\n\n /**\n * Return 402 with x402 payment requirements (v2 format)\n * Includes requirements for all accepted currencies\n */\n private sendPaymentRequired(config: ServiceConfig, res: ServerResponse): void {\n const acceptedTokens = getAcceptedCurrencies(config);\n \n // Build requirements for each accepted token\n const accepts = acceptedTokens.map(token => this.buildPaymentRequirements(config, token));\n\n const paymentRequired = {\n x402Version: X402_VERSION,\n accepts,\n acceptedCurrencies: acceptedTokens,\n resource: {\n url: `/execute?service=${config.id}`,\n description: `${config.name} - $${config.price} ${config.currency}`,\n mimeType: 'application/json',\n },\n };\n\n const encoded = Buffer.from(JSON.stringify(paymentRequired)).toString('base64');\n\n res.writeHead(402, {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n });\n res.end(JSON.stringify({\n error: 'Payment required',\n message: `Service requires $${config.price} ${config.currency}`,\n acceptedCurrencies: acceptedTokens,\n x402: paymentRequired,\n }, null, 2));\n }\n\n /**\n * Basic payment validation\n */\n private validatePayment(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): { valid: boolean; error?: string } {\n if (payment.x402Version !== X402_VERSION) {\n return { valid: false, error: `Unsupported x402 version: ${payment.x402Version}` };\n }\n\n const scheme = payment.accepted?.scheme || payment.scheme;\n const network = payment.accepted?.network || payment.network;\n\n if (scheme !== 'exact') {\n return { valid: false, error: `Unsupported scheme: ${scheme}` };\n }\n\n if (network !== this.networkId) {\n return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${network}` };\n }\n\n return { valid: true };\n }\n\n /**\n * Build payment requirements for facilitator\n * Returns requirements for the primary currency (USDC by default)\n * Server accepts any of the acceptedCurrencies\n */\n private buildPaymentRequirements(config: ServiceConfig, token?: string): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const acceptedTokens = getAcceptedCurrencies(config);\n \n // Use specified token or default to first accepted\n const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];\n const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};\n const tokenAddress = tokenAddresses[selectedToken];\n const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;\n\n return {\n scheme: 'exact',\n network: this.networkId,\n asset: tokenAddress,\n amount: amountInUnits,\n payTo: this.manifest.provider.wallet,\n maxTimeoutSeconds: 300,\n extra: tokenDomain,\n };\n }\n\n /**\n * Detect which token is being used in the payment\n */\n private detectPaymentToken(payment: X402PaymentPayload): string | undefined {\n const asset = payment.accepted?.asset || (payment.payload as any)?.asset;\n if (!asset) return undefined;\n\n const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};\n for (const [symbol, address] of Object.entries(tokenAddresses)) {\n if (address.toLowerCase() === asset.toLowerCase()) {\n return symbol;\n }\n }\n return undefined;\n }\n\n /**\n * Check if payment token is accepted for service\n */\n private isTokenAccepted(config: ServiceConfig, token: string): boolean {\n const accepted = getAcceptedCurrencies(config);\n return accepted.includes(token);\n }\n\n private async readBody(req: IncomingMessage): Promise<any> {\n return new Promise((resolve, reject) => {\n let body = '';\n req.on('data', chunk => body += chunk);\n req.on('end', () => {\n try {\n resolve(body ? JSON.parse(body) : {});\n } catch {\n reject(new Error('Invalid JSON'));\n }\n });\n req.on('error', reject);\n });\n }\n\n private sendJson(\n res: ServerResponse, \n status: number, \n data: any,\n extraHeaders?: Record<string, string>\n ): void {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (extraHeaders) {\n Object.assign(headers, extraHeaders);\n }\n res.writeHead(status, headers);\n res.end(JSON.stringify(data, null, 2));\n }\n\n /**\n * Check if IP is allowed for /proxy endpoint\n */\n private isProxyAllowed(clientIP: string): boolean {\n const allowedIPs = process.env.PROXY_ALLOWED_IPS?.split(',').map(ip => ip.trim()) || [];\n \n // If no whitelist configured, deny all (secure by default)\n if (allowedIPs.length === 0) {\n console.log(`[MoltsPay] /proxy denied: no PROXY_ALLOWED_IPS configured`);\n return false;\n }\n \n // Normalize IPv6 localhost\n const normalizedIP = clientIP === '::1' ? '127.0.0.1' : clientIP.replace('::ffff:', '');\n \n const allowed = allowedIPs.includes(normalizedIP) || allowedIPs.includes(clientIP);\n if (!allowed) {\n console.log(`[MoltsPay] /proxy denied for IP: ${clientIP} (normalized: ${normalizedIP})`);\n }\n return allowed;\n }\n\n /**\n * POST /proxy - Handle payment for external services (moltspay-creators)\n * \n * This endpoint allows other services to delegate x402 payment handling.\n * It does NOT execute any skill - just handles payment verification/settlement.\n * \n * Request body:\n * { wallet, amount, currency, chain, memo, serviceId, description }\n * \n * Without X-Payment header: returns 402 with payment requirements\n * With X-Payment header: verifies payment and returns result\n */\n private async handleProxy(\n body: any,\n paymentHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { wallet, amount, currency, chain, memo, serviceId, description } = body;\n\n // Validate required fields\n if (!wallet || !amount) {\n return this.sendJson(res, 400, { error: 'Missing required fields: wallet, amount' });\n }\n\n // Validate wallet format\n if (!/^0x[a-fA-F0-9]{40}$/.test(wallet)) {\n return this.sendJson(res, 400, { error: 'Invalid wallet address format' });\n }\n\n // Validate amount\n const amountNum = parseFloat(amount);\n if (isNaN(amountNum) || amountNum <= 0) {\n return this.sendJson(res, 400, { error: 'Invalid amount' });\n }\n\n // Build a synthetic service config for payment\n const proxyConfig: ServiceConfig = {\n id: serviceId || 'proxy',\n name: description || 'Proxy Payment',\n description: description || '',\n price: amountNum,\n currency: currency || 'USDC',\n function: '', // Not used\n input: {},\n output: {},\n };\n\n // Build payment requirements with the provided wallet\n const requirements = this.buildProxyPaymentRequirements(proxyConfig, wallet);\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendProxyPaymentRequired(proxyConfig, wallet, memo, res);\n }\n\n // Parse payment payload\n let payment: X402PaymentPayload;\n try {\n const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');\n payment = JSON.parse(decoded);\n } catch {\n return this.sendJson(res, 400, { error: 'Invalid X-Payment header' });\n }\n\n // Validate basic payment fields\n if (payment.x402Version !== X402_VERSION) {\n return this.sendJson(res, 402, { error: `Unsupported x402 version: ${payment.x402Version}` });\n }\n\n const scheme = payment.accepted?.scheme || payment.scheme;\n const network = payment.accepted?.network || payment.network;\n\n if (scheme !== 'exact') {\n return this.sendJson(res, 402, { error: `Unsupported scheme: ${scheme}` });\n }\n\n if (network !== this.networkId) {\n return this.sendJson(res, 402, { error: `Network mismatch: expected ${this.networkId}, got ${network}` });\n }\n\n // Verify payment with facilitator\n console.log(`[MoltsPay] /proxy: Verifying payment for ${wallet}...`);\n const verifyResult = await this.registry.verify(payment, requirements);\n if (!verifyResult.valid) {\n return this.sendJson(res, 402, { \n success: false,\n error: `Payment verification failed: ${verifyResult.error}`,\n facilitator: verifyResult.facilitator,\n });\n }\n console.log(`[MoltsPay] /proxy: Verified by ${verifyResult.facilitator}`);\n\n // Check if execution requested\n const { execute, service, params } = body;\n \n // If execute requested, run skill BEFORE settling (pay on success)\n if (execute && service) {\n console.log(`[MoltsPay] /proxy: Executing skill first (pay on success): ${service}`);\n const skill = this.skills.get(service);\n if (!skill) {\n // Service not found - don't settle, return error\n console.log(`[MoltsPay] /proxy: Service not found: ${service} - NOT settling`);\n return this.sendJson(res, 404, {\n success: false,\n paymentSettled: false,\n error: `Service not found: ${service}`,\n });\n }\n\n // Execute skill first (with timeout)\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n let result: any;\n try {\n result = await Promise.race([\n skill.handler(params || {}),\n new Promise((_, reject) => \n setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1000)\n )\n ]);\n console.log(`[MoltsPay] /proxy: Skill succeeded, now settling payment...`);\n } catch (err: any) {\n // Skill failed or timeout - don't settle, client keeps their money\n console.error(`[MoltsPay] /proxy: Skill failed: ${err.message} - NOT settling`);\n return this.sendJson(res, 500, {\n success: false,\n paymentSettled: false,\n error: `Service execution failed: ${err.message}`,\n });\n }\n\n // Skill succeeded - now settle payment\n let settlement: any = null;\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] /proxy: Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] /proxy: Settlement failed:', err.message);\n // Skill succeeded but settlement failed - return result anyway with warning\n return this.sendJson(res, 200, {\n success: true,\n verified: true,\n settled: false,\n settlementError: err.message,\n from: (payment.payload as any)?.authorization?.from, // Buyer's wallet address\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n memo,\n result,\n });\n }\n\n return this.sendJson(res, 200, {\n success: true,\n verified: true,\n settled: settlement?.success || false,\n txHash: settlement?.transaction,\n from: (payment.payload as any)?.authorization?.from, // Buyer's wallet address\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n facilitator: settlement?.facilitator,\n memo,\n result,\n });\n }\n\n // No execution requested - settle immediately (payment-only mode)\n console.log(`[MoltsPay] /proxy: Settling payment (no execution)...`);\n let settlement: any = null;\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] /proxy: Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] /proxy: Settlement failed:', err.message);\n return this.sendJson(res, 500, {\n success: false,\n error: `Settlement failed: ${err.message}`,\n });\n }\n\n // Return success (payment only, no execution)\n this.sendJson(res, 200, {\n success: true,\n verified: true,\n settled: settlement?.success || false,\n txHash: settlement?.transaction,\n from: (payment.payload as any)?.authorization?.from, // Buyer's wallet address\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n facilitator: settlement?.facilitator,\n memo,\n });\n }\n\n /**\n * Build payment requirements for proxy endpoint (uses provided wallet)\n */\n private buildProxyPaymentRequirements(config: ServiceConfig, wallet: string, token?: string): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const acceptedTokens = getAcceptedCurrencies(config);\n \n // Use specified token or default to first accepted\n const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];\n const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};\n const tokenAddress = tokenAddresses[selectedToken];\n const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;\n\n return {\n scheme: 'exact',\n network: this.networkId,\n asset: tokenAddress,\n amount: amountInUnits,\n payTo: wallet, // Use provided wallet, not manifest\n maxTimeoutSeconds: 300,\n extra: tokenDomain,\n };\n }\n\n /**\n * Return 402 with x402 payment requirements for proxy endpoint\n */\n private sendProxyPaymentRequired(\n config: ServiceConfig, \n wallet: string,\n memo: string | undefined,\n res: ServerResponse\n ): void {\n const requirements = this.buildProxyPaymentRequirements(config, wallet);\n\n const paymentRequired = {\n x402Version: X402_VERSION,\n accepts: [requirements],\n resource: {\n url: `/proxy`,\n description: `${config.name} - $${config.price} ${config.currency}`,\n mimeType: 'application/json',\n memo,\n },\n };\n\n const encoded = Buffer.from(JSON.stringify(paymentRequired)).toString('base64');\n\n res.writeHead(402, {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n });\n res.end(JSON.stringify({\n error: 'Payment required',\n message: `Payment requires $${config.price} ${config.currency}`,\n x402: paymentRequired,\n }, null, 2));\n }\n}\n","/**\n * Facilitator Interface\n * \n * A facilitator is a service that handles x402 payment verification and settlement.\n * This abstraction allows MoltsPay to support multiple facilitators.\n * \n * @see https://www.x402.org/ecosystem?category=facilitators\n */\n\n/**\n * x402 Payment Payload (from client)\n */\nexport interface X402PaymentPayload {\n x402Version: number;\n scheme?: string;\n network?: string;\n accepted?: {\n scheme: string;\n network: string;\n asset: string;\n amount: string;\n payTo: string;\n maxTimeoutSeconds: number;\n extra?: Record<string, unknown>;\n };\n payload: unknown;\n}\n\n/**\n * x402 Payment Requirements (server specifies what it accepts)\n */\nexport interface X402PaymentRequirements {\n scheme: string;\n network: string;\n asset: string;\n amount: string;\n payTo: string;\n maxTimeoutSeconds: number;\n extra?: Record<string, unknown>;\n}\n\n/**\n * Result of payment verification\n */\nexport interface VerifyResult {\n valid: boolean;\n error?: string;\n details?: Record<string, unknown>;\n}\n\n/**\n * Result of payment settlement\n */\nexport interface SettleResult {\n success: boolean;\n transaction?: string;\n error?: string;\n status?: string;\n}\n\n/**\n * Facilitator health check result\n */\nexport interface HealthCheckResult {\n healthy: boolean;\n latencyMs?: number;\n error?: string;\n}\n\n/**\n * Facilitator fee information (for selection strategies)\n */\nexport interface FacilitatorFee {\n perTx: number;\n currency: string;\n freeQuota?: number;\n}\n\n/**\n * Facilitator configuration\n */\nexport interface FacilitatorConfig {\n /** Facilitator endpoint URL */\n endpoint?: string;\n /** API key (if required) */\n apiKey?: string;\n /** API secret (if required) */\n apiSecret?: string;\n /** Additional config specific to facilitator */\n [key: string]: unknown;\n}\n\n/**\n * Facilitator Interface\n * \n * All facilitators must implement this interface.\n */\nexport interface Facilitator {\n /** Unique identifier for this facilitator */\n readonly name: string;\n \n /** Human-readable display name */\n readonly displayName: string;\n \n /** Supported networks (e.g., [\"eip155:8453\", \"eip155:84532\"]) */\n readonly supportedNetworks: string[];\n \n /**\n * Check if facilitator is available and responsive\n */\n healthCheck(): Promise<HealthCheckResult>;\n \n /**\n * Verify a payment signature without executing it\n * \n * @param paymentPayload - The x402 payment payload from client\n * @param requirements - The payment requirements from server\n */\n verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult>;\n \n /**\n * Settle a payment on-chain\n * \n * @param paymentPayload - The x402 payment payload from client\n * @param requirements - The payment requirements from server\n */\n settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult>;\n \n /**\n * Get current fee information (optional, for selection strategies)\n */\n getFee?(): Promise<FacilitatorFee>;\n \n /**\n * Check if this facilitator supports a given network\n */\n supportsNetwork(network: string): boolean;\n}\n\n/**\n * Base class with common functionality\n */\nexport abstract class BaseFacilitator implements Facilitator {\n abstract readonly name: string;\n abstract readonly displayName: string;\n abstract readonly supportedNetworks: string[];\n \n abstract healthCheck(): Promise<HealthCheckResult>;\n abstract verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult>;\n abstract settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult>;\n \n supportsNetwork(network: string): boolean {\n return this.supportedNetworks.includes(network);\n }\n}\n","/**\n * CDP Facilitator\n * \n * Coinbase Developer Platform x402 facilitator implementation.\n * Supports both mainnet (Base) and testnet (Base Sepolia).\n * \n * @see https://docs.cdp.coinbase.com/x402/core-concepts/facilitator\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport * as path from 'path';\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n FacilitatorFee,\n FacilitatorConfig,\n} from './interface.js';\n\n// x402 protocol version\nconst X402_VERSION = 2;\n\n// CDP Facilitator URLs\nconst CDP_MAINNET_URL = 'https://api.cdp.coinbase.com/platform/v2/x402';\nconst CDP_TESTNET_URL = 'https://www.x402.org/facilitator';\n\nexport interface CDPFacilitatorConfig extends FacilitatorConfig {\n /** Use mainnet (true) or testnet (false, default) */\n useMainnet?: boolean;\n /** CDP API Key ID (required for mainnet) */\n apiKeyId?: string;\n /** CDP API Key Secret (required for mainnet) */\n apiKeySecret?: string;\n}\n\n/**\n * Load environment from .env files\n */\nfunction loadEnvFile(): void {\n const envPaths = [\n path.join(process.cwd(), '.env'),\n path.join(process.env.HOME || '', '.moltspay', '.env'),\n ];\n \n for (const envPath of envPaths) {\n if (existsSync(envPath)) {\n try {\n const content = readFileSync(envPath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIndex = trimmed.indexOf('=');\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n if (!process.env[key]) {\n process.env[key] = value;\n }\n }\n break;\n } catch {\n // Ignore errors\n }\n }\n }\n}\n\n/**\n * CDP (Coinbase Developer Platform) Facilitator\n * \n * Handles payment verification and settlement via Coinbase's x402 facilitator.\n */\nexport class CDPFacilitator extends BaseFacilitator {\n readonly name = 'cdp';\n readonly displayName = 'Coinbase CDP';\n readonly supportedNetworks: string[];\n \n private endpoint: string;\n private useMainnet: boolean;\n private apiKeyId?: string;\n private apiKeySecret?: string;\n \n constructor(config: CDPFacilitatorConfig = {}) {\n super();\n \n // Load env files for credentials\n loadEnvFile();\n \n // Determine mainnet vs testnet\n this.useMainnet = config.useMainnet ?? \n (process.env.USE_MAINNET?.toLowerCase() === 'true');\n \n // Get credentials\n this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;\n this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;\n \n // Set endpoint\n this.endpoint = this.useMainnet ? CDP_MAINNET_URL : CDP_TESTNET_URL;\n \n // Set supported networks\n this.supportedNetworks = this.useMainnet \n ? ['eip155:8453'] // Base mainnet only\n : ['eip155:8453', 'eip155:84532']; // Both mainnet and testnet via x402.org\n \n // Warn if mainnet without credentials\n if (this.useMainnet && (!this.apiKeyId || !this.apiKeySecret)) {\n console.warn('[CDPFacilitator] WARNING: Mainnet mode but missing CDP credentials!');\n console.warn('[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET');\n }\n }\n \n /**\n * Get auth headers for CDP API requests\n */\n private async getAuthHeaders(\n method: string,\n urlPath: string,\n body?: unknown\n ): Promise<Record<string, string>> {\n if (!this.useMainnet) {\n // Testnet (x402.org) doesn't require auth\n return {};\n }\n \n if (!this.apiKeyId || !this.apiKeySecret) {\n throw new Error('CDP credentials required for mainnet');\n }\n \n try {\n const { getAuthHeaders } = await import('@coinbase/cdp-sdk/auth');\n \n return await getAuthHeaders({\n apiKeyId: this.apiKeyId,\n apiKeySecret: this.apiKeySecret,\n requestMethod: method,\n requestHost: 'api.cdp.coinbase.com',\n requestPath: urlPath,\n requestBody: body,\n });\n } catch (err: any) {\n throw new Error(`Failed to generate CDP auth: ${err.message}`);\n }\n }\n \n /**\n * Health check - verify facilitator is reachable\n */\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n \n try {\n // For testnet, just check if x402.org responds\n // For mainnet, we could hit a health endpoint or just check DNS\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n \n const response = await fetch(this.endpoint.replace('/x402', ''), {\n method: 'HEAD',\n signal: controller.signal,\n }).catch(() => null);\n \n clearTimeout(timeout);\n \n const latencyMs = Date.now() - start;\n \n return {\n healthy: response !== null,\n latencyMs,\n };\n } catch (err: any) {\n return {\n healthy: false,\n error: err.message,\n latencyMs: Date.now() - start,\n };\n }\n }\n \n /**\n * Verify payment signature with facilitator\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n const requestBody = {\n x402Version: X402_VERSION,\n paymentPayload,\n paymentRequirements: requirements,\n };\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n \n if (this.useMainnet) {\n const authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/verify',\n requestBody\n );\n Object.assign(headers, authHeaders);\n }\n \n const response = await fetch(`${this.endpoint}/verify`, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\n });\n \n const result = await response.json() as any;\n \n if (!response.ok || !result.isValid) {\n return {\n valid: false,\n error: result.invalidReason || result.error || 'Verification failed',\n details: result,\n };\n }\n \n return { valid: true, details: result };\n } catch (err: any) {\n return {\n valid: false,\n error: `Facilitator error: ${err.message}`,\n };\n }\n }\n \n /**\n * Settle payment on-chain via facilitator\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n try {\n const requestBody = {\n x402Version: X402_VERSION,\n paymentPayload,\n paymentRequirements: requirements,\n };\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n \n if (this.useMainnet) {\n const authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/settle',\n requestBody\n );\n Object.assign(headers, authHeaders);\n }\n \n const response = await fetch(`${this.endpoint}/settle`, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\n });\n \n const result = await response.json() as any;\n \n if (!response.ok || !result.success) {\n return {\n success: false,\n error: result.error || result.errorReason || 'Settlement failed',\n };\n }\n \n return {\n success: true,\n transaction: result.transaction,\n status: result.status || 'settled',\n };\n } catch (err: any) {\n return {\n success: false,\n error: `Settlement error: ${err.message}`,\n };\n }\n }\n \n /**\n * Get CDP fee information\n */\n async getFee(): Promise<FacilitatorFee> {\n // CDP pricing: 1000 free/month, then $0.001/tx\n return {\n perTx: 0.001,\n currency: 'USD',\n freeQuota: 1000,\n };\n }\n \n /**\n * Get configuration summary (for logging)\n */\n getConfigSummary(): string {\n const mode = this.useMainnet ? 'mainnet' : 'testnet';\n const hasCredentials = !!(this.apiKeyId && this.apiKeySecret);\n return `CDP Facilitator (${mode}, credentials: ${hasCredentials ? 'yes' : 'no'})`;\n }\n}\n","/**\n * Facilitator Registry\n * \n * Central registry for all available facilitators.\n * Supports selection strategies for failover, load balancing, etc.\n */\n\nimport {\n Facilitator,\n FacilitatorConfig,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { CDPFacilitator, CDPFacilitatorConfig } from './cdp.js';\n\n/**\n * Selection strategy for choosing facilitators\n */\nexport type SelectionStrategy = \n | 'failover' // Use primary, switch to fallback on failure\n | 'cheapest' // Use facilitator with lowest fees\n | 'fastest' // Use first responder\n | 'random' // Random selection (load balancing)\n | 'roundrobin'; // Rotate through facilitators\n\n/**\n * Facilitator selection configuration\n */\nexport interface FacilitatorSelection {\n /** Primary facilitator to use */\n primary: string;\n /** Fallback facilitators (in order of preference) */\n fallback?: string[];\n /** Selection strategy */\n strategy?: SelectionStrategy;\n /** Per-facilitator config overrides */\n config?: Record<string, FacilitatorConfig>;\n}\n\n/**\n * Factory function type for creating facilitators\n */\ntype FacilitatorFactory = (config?: FacilitatorConfig) => Facilitator;\n\n/**\n * Facilitator Registry\n * \n * Manages available facilitators and provides selection logic.\n */\nexport class FacilitatorRegistry {\n private factories: Map<string, FacilitatorFactory> = new Map();\n private instances: Map<string, Facilitator> = new Map();\n private selection: FacilitatorSelection;\n private roundRobinIndex = 0;\n \n constructor(selection?: FacilitatorSelection) {\n // Register built-in facilitators\n this.registerFactory('cdp', (config) => new CDPFacilitator(config as CDPFacilitatorConfig));\n \n // Default selection\n this.selection = selection || { primary: 'cdp', strategy: 'failover' };\n }\n \n /**\n * Register a new facilitator factory\n */\n registerFactory(name: string, factory: FacilitatorFactory): void {\n this.factories.set(name, factory);\n }\n \n /**\n * Get or create a facilitator instance\n */\n get(name: string, config?: FacilitatorConfig): Facilitator {\n // Check cache first\n if (this.instances.has(name)) {\n return this.instances.get(name)!;\n }\n \n // Look up factory\n const factory = this.factories.get(name);\n if (!factory) {\n throw new Error(`Unknown facilitator: ${name}. Available: ${Array.from(this.factories.keys()).join(', ')}`);\n }\n \n // Merge config from selection\n const mergedConfig = {\n ...this.selection.config?.[name],\n ...config,\n };\n \n // Create and cache instance\n const instance = factory(mergedConfig);\n this.instances.set(name, instance);\n return instance;\n }\n \n /**\n * Get all configured facilitator names\n */\n getConfiguredNames(): string[] {\n const names = [this.selection.primary];\n if (this.selection.fallback) {\n names.push(...this.selection.fallback);\n }\n return names;\n }\n \n /**\n * Get list of facilitators based on selection strategy\n */\n private async getOrderedFacilitators(network: string): Promise<Facilitator[]> {\n const names = this.getConfiguredNames();\n const facilitators: Facilitator[] = [];\n \n for (const name of names) {\n try {\n const f = this.get(name);\n if (f.supportsNetwork(network)) {\n facilitators.push(f);\n }\n } catch (err) {\n console.warn(`[Registry] Failed to get facilitator ${name}:`, err);\n }\n }\n \n if (facilitators.length === 0) {\n throw new Error(`No facilitators available for network: ${network}`);\n }\n \n // Apply strategy\n switch (this.selection.strategy) {\n case 'random':\n return this.shuffle(facilitators);\n \n case 'roundrobin':\n this.roundRobinIndex = (this.roundRobinIndex + 1) % facilitators.length;\n return [\n ...facilitators.slice(this.roundRobinIndex),\n ...facilitators.slice(0, this.roundRobinIndex),\n ];\n \n case 'cheapest':\n return this.sortByCheapest(facilitators);\n \n case 'fastest':\n return this.sortByFastest(facilitators);\n \n case 'failover':\n default:\n return facilitators;\n }\n }\n \n private shuffle<T>(array: T[]): T[] {\n const result = [...array];\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [result[i], result[j]] = [result[j], result[i]];\n }\n return result;\n }\n \n private async sortByCheapest(facilitators: Facilitator[]): Promise<Facilitator[]> {\n const withFees = await Promise.all(\n facilitators.map(async (f) => {\n try {\n const fee = await f.getFee?.();\n return { facilitator: f, perTx: fee?.perTx ?? Infinity };\n } catch {\n return { facilitator: f, perTx: Infinity };\n }\n })\n );\n withFees.sort((a, b) => a.perTx - b.perTx);\n return withFees.map(w => w.facilitator);\n }\n \n private async sortByFastest(facilitators: Facilitator[]): Promise<Facilitator[]> {\n const withLatency = await Promise.all(\n facilitators.map(async (f) => {\n try {\n const health = await f.healthCheck();\n return { facilitator: f, latency: health.latencyMs ?? Infinity };\n } catch {\n return { facilitator: f, latency: Infinity };\n }\n })\n );\n withLatency.sort((a, b) => a.latency - b.latency);\n return withLatency.map(w => w.facilitator);\n }\n \n /**\n * Verify payment using configured facilitators\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult & { facilitator: string }> {\n const network = paymentPayload.accepted?.network || paymentPayload.network || requirements.network;\n const facilitators = await this.getOrderedFacilitators(network);\n \n let lastError: string | undefined;\n \n for (const f of facilitators) {\n try {\n console.log(`[Registry] Trying ${f.name} for verify...`);\n const result = await f.verify(paymentPayload, requirements);\n \n if (result.valid) {\n console.log(`[Registry] ${f.name} verify succeeded`);\n return { ...result, facilitator: f.name };\n }\n \n lastError = result.error;\n console.log(`[Registry] ${f.name} verify failed: ${result.error}`);\n \n // For failover strategy, only try next if it's a network/server error\n if (this.selection.strategy === 'failover' && !this.isTransientError(result.error)) {\n // Permanent error (e.g., invalid signature) - don't try others\n break;\n }\n } catch (err: any) {\n lastError = err.message;\n console.error(`[Registry] ${f.name} error:`, err.message);\n }\n }\n \n return {\n valid: false,\n error: lastError || 'All facilitators failed',\n facilitator: 'none',\n };\n }\n \n /**\n * Settle payment using configured facilitators\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult & { facilitator: string }> {\n const network = paymentPayload.accepted?.network || paymentPayload.network || requirements.network;\n const facilitators = await this.getOrderedFacilitators(network);\n \n let lastError: string | undefined;\n \n for (const f of facilitators) {\n try {\n console.log(`[Registry] Trying ${f.name} for settle...`);\n const result = await f.settle(paymentPayload, requirements);\n \n if (result.success) {\n console.log(`[Registry] ${f.name} settle succeeded: ${result.transaction}`);\n return { ...result, facilitator: f.name };\n }\n \n lastError = result.error;\n console.log(`[Registry] ${f.name} settle failed: ${result.error}`);\n } catch (err: any) {\n lastError = err.message;\n console.error(`[Registry] ${f.name} error:`, err.message);\n }\n }\n \n return {\n success: false,\n error: lastError || 'All facilitators failed',\n facilitator: 'none',\n };\n }\n \n /**\n * Check health of all configured facilitators\n */\n async healthCheckAll(): Promise<Record<string, HealthCheckResult>> {\n const results: Record<string, HealthCheckResult> = {};\n \n for (const name of this.getConfiguredNames()) {\n try {\n const f = this.get(name);\n results[name] = await f.healthCheck();\n } catch (err: any) {\n results[name] = { healthy: false, error: err.message };\n }\n }\n \n return results;\n }\n \n /**\n * Check if an error is transient (network/server issue) vs permanent (bad request)\n */\n private isTransientError(error?: string): boolean {\n if (!error) return true;\n const transientPatterns = [\n /timeout/i,\n /network/i,\n /connection/i,\n /ECONNREFUSED/i,\n /ETIMEDOUT/i,\n /503/,\n /502/,\n /500/,\n ];\n return transientPatterns.some(p => p.test(error));\n }\n \n /**\n * Update selection configuration\n */\n setSelection(selection: FacilitatorSelection): void {\n this.selection = selection;\n // Clear cached instances to pick up new config\n this.instances.clear();\n }\n \n /**\n * Get current selection configuration\n */\n getSelection(): FacilitatorSelection {\n return { ...this.selection };\n }\n}\n\n// Default registry instance\nlet defaultRegistry: FacilitatorRegistry | null = null;\n\n/**\n * Get the default facilitator registry\n */\nexport function getDefaultRegistry(): FacilitatorRegistry {\n if (!defaultRegistry) {\n defaultRegistry = new FacilitatorRegistry();\n }\n return defaultRegistry;\n}\n\n/**\n * Create a new registry with custom selection\n */\nexport function createRegistry(selection?: FacilitatorSelection): FacilitatorRegistry {\n return new FacilitatorRegistry(selection);\n}\n"],"mappings":"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","names":["readFileSync","existsSync","path","X402_VERSION","loadEnvFile","existsSync","readFileSync","settlement"]}
@@ -1,15 +1,21 @@
1
+ import { T as TokenSymbol } from '../index-B3v8IWjM.mjs';
2
+
1
3
  /**
2
4
  * On-chain Payment Verification Module
3
5
  */
6
+
4
7
  interface VerifyPaymentParams {
5
8
  txHash: string;
6
9
  expectedAmount: number;
7
10
  expectedTo?: string;
8
11
  chain?: string | number;
12
+ /** Expected token (if not specified, accepts both USDC and USDT) */
13
+ expectedToken?: TokenSymbol;
9
14
  }
10
15
  interface VerifyPaymentResult {
11
16
  verified: boolean;
12
17
  amount?: number;
18
+ token?: TokenSymbol;
13
19
  from?: string;
14
20
  to?: string;
15
21
  txHash?: string;
@@ -18,6 +24,7 @@ interface VerifyPaymentResult {
18
24
  }
19
25
  /**
20
26
  * Verify on-chain payment
27
+ * Supports both USDC and USDT transfers
21
28
  */
22
29
  declare function verifyPayment(params: VerifyPaymentParams): Promise<VerifyPaymentResult>;
23
30
  /**
@@ -1,15 +1,21 @@
1
+ import { T as TokenSymbol } from '../index-B3v8IWjM.js';
2
+
1
3
  /**
2
4
  * On-chain Payment Verification Module
3
5
  */
6
+
4
7
  interface VerifyPaymentParams {
5
8
  txHash: string;
6
9
  expectedAmount: number;
7
10
  expectedTo?: string;
8
11
  chain?: string | number;
12
+ /** Expected token (if not specified, accepts both USDC and USDT) */
13
+ expectedToken?: TokenSymbol;
9
14
  }
10
15
  interface VerifyPaymentResult {
11
16
  verified: boolean;
12
17
  amount?: number;
18
+ token?: TokenSymbol;
13
19
  from?: string;
14
20
  to?: string;
15
21
  txHash?: string;
@@ -18,6 +24,7 @@ interface VerifyPaymentResult {
18
24
  }
19
25
  /**
20
26
  * Verify on-chain payment
27
+ * Supports both USDC and USDT transfers
21
28
  */
22
29
  declare function verifyPayment(params: VerifyPaymentParams): Promise<VerifyPaymentResult>;
23
30
  /**
@@ -34,7 +34,20 @@ var CHAINS = {
34
34
  name: "Base",
35
35
  chainId: 8453,
36
36
  rpc: "https://mainnet.base.org",
37
+ tokens: {
38
+ USDC: {
39
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
40
+ decimals: 6,
41
+ symbol: "USDC"
42
+ },
43
+ USDT: {
44
+ address: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
45
+ decimals: 6,
46
+ symbol: "USDT"
47
+ }
48
+ },
37
49
  usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
50
+ // deprecated, for backward compat
38
51
  explorer: "https://basescan.org/address/",
39
52
  explorerTx: "https://basescan.org/tx/",
40
53
  avgBlockTime: 2
@@ -43,6 +56,18 @@ var CHAINS = {
43
56
  name: "Polygon",
44
57
  chainId: 137,
45
58
  rpc: "https://polygon-rpc.com",
59
+ tokens: {
60
+ USDC: {
61
+ address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
62
+ decimals: 6,
63
+ symbol: "USDC"
64
+ },
65
+ USDT: {
66
+ address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
67
+ decimals: 6,
68
+ symbol: "USDT"
69
+ }
70
+ },
46
71
  usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
47
72
  explorer: "https://polygonscan.com/address/",
48
73
  explorerTx: "https://polygonscan.com/tx/",
@@ -52,6 +77,18 @@ var CHAINS = {
52
77
  name: "Ethereum",
53
78
  chainId: 1,
54
79
  rpc: "https://eth.llamarpc.com",
80
+ tokens: {
81
+ USDC: {
82
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
83
+ decimals: 6,
84
+ symbol: "USDC"
85
+ },
86
+ USDT: {
87
+ address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
88
+ decimals: 6,
89
+ symbol: "USDT"
90
+ }
91
+ },
55
92
  usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
56
93
  explorer: "https://etherscan.io/address/",
57
94
  explorerTx: "https://etherscan.io/tx/",
@@ -62,6 +99,19 @@ var CHAINS = {
62
99
  name: "Base Sepolia",
63
100
  chainId: 84532,
64
101
  rpc: "https://sepolia.base.org",
102
+ tokens: {
103
+ USDC: {
104
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
105
+ decimals: 6,
106
+ symbol: "USDC"
107
+ },
108
+ USDT: {
109
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
110
+ // Same as USDC on testnet (no official USDT)
111
+ decimals: 6,
112
+ symbol: "USDT"
113
+ }
114
+ },
65
115
  usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
66
116
  explorer: "https://sepolia.basescan.org/address/",
67
117
  explorerTx: "https://sepolia.basescan.org/tx/",
@@ -71,6 +121,19 @@ var CHAINS = {
71
121
  name: "Sepolia",
72
122
  chainId: 11155111,
73
123
  rpc: "https://rpc.sepolia.org",
124
+ tokens: {
125
+ USDC: {
126
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
127
+ decimals: 6,
128
+ symbol: "USDC"
129
+ },
130
+ USDT: {
131
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
132
+ // Same as USDC on testnet
133
+ decimals: 6,
134
+ symbol: "USDT"
135
+ }
136
+ },
74
137
  usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
75
138
  explorer: "https://sepolia.etherscan.io/address/",
76
139
  explorerTx: "https://sepolia.etherscan.io/tx/",
@@ -91,7 +154,7 @@ function getChainById(chainId) {
91
154
  // src/verify/index.ts
92
155
  var TRANSFER_EVENT_TOPIC = import_ethers.ethers.id("Transfer(address,address,uint256)");
93
156
  async function verifyPayment(params) {
94
- const { txHash, expectedAmount, expectedTo } = params;
157
+ const { txHash, expectedAmount, expectedTo, expectedToken } = params;
95
158
  let chain;
96
159
  try {
97
160
  if (typeof params.chain === "number") {
@@ -114,12 +177,20 @@ async function verifyPayment(params) {
114
177
  if (receipt.status !== 1) {
115
178
  return { verified: false, error: "Transaction failed" };
116
179
  }
117
- const usdcAddress = chain.usdc?.toLowerCase();
118
- if (!usdcAddress) {
119
- return { verified: false, error: `Chain ${chain.name} USDC address not configured` };
180
+ const tokenAddresses = {};
181
+ if (!expectedToken || expectedToken === "USDC") {
182
+ tokenAddresses[chain.tokens.USDC.address.toLowerCase()] = "USDC";
183
+ }
184
+ if (!expectedToken || expectedToken === "USDT") {
185
+ tokenAddresses[chain.tokens.USDT.address.toLowerCase()] = "USDT";
186
+ }
187
+ if (Object.keys(tokenAddresses).length === 0) {
188
+ return { verified: false, error: `No token addresses configured for ${chain.name}` };
120
189
  }
121
190
  for (const log of receipt.logs) {
122
- if (log.address.toLowerCase() !== usdcAddress) {
191
+ const logAddress = log.address.toLowerCase();
192
+ const detectedToken = tokenAddresses[logAddress];
193
+ if (!detectedToken) {
123
194
  continue;
124
195
  }
125
196
  if (log.topics.length < 3 || log.topics[0] !== TRANSFER_EVENT_TOPIC) {
@@ -128,15 +199,17 @@ async function verifyPayment(params) {
128
199
  const from = "0x" + log.topics[1].slice(-40);
129
200
  const to = "0x" + log.topics[2].slice(-40);
130
201
  const amountRaw = BigInt(log.data);
131
- const amount = Number(amountRaw) / 1e6;
202
+ const tokenConfig = chain.tokens[detectedToken];
203
+ const amount = Number(amountRaw) / 10 ** tokenConfig.decimals;
132
204
  if (expectedTo && to.toLowerCase() !== expectedTo.toLowerCase()) {
133
205
  continue;
134
206
  }
135
207
  if (amount < expectedAmount) {
136
208
  return {
137
209
  verified: false,
138
- error: `Insufficient amount: received ${amount} USDC, expected ${expectedAmount} USDC`,
210
+ error: `Insufficient amount: received ${amount} ${detectedToken}, expected ${expectedAmount}`,
139
211
  amount,
212
+ token: detectedToken,
140
213
  from,
141
214
  to,
142
215
  txHash,
@@ -146,13 +219,15 @@ async function verifyPayment(params) {
146
219
  return {
147
220
  verified: true,
148
221
  amount,
222
+ token: detectedToken,
149
223
  from,
150
224
  to,
151
225
  txHash,
152
226
  blockNumber: receipt.blockNumber
153
227
  };
154
228
  }
155
- return { verified: false, error: "No USDC transfer found" };
229
+ const tokenList = expectedToken ? expectedToken : "USDC/USDT";
230
+ return { verified: false, error: `No ${tokenList} transfer found` };
156
231
  } catch (e) {
157
232
  return { verified: false, error: e.message || String(e) };
158
233
  }