moltspay 2.0.0 → 2.4.0

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 (50) hide show
  1. package/.env.example +23 -0
  2. package/CHANGELOG.md +551 -0
  3. package/README.md +466 -8
  4. package/dist/cdp/index.js.map +1 -1
  5. package/dist/cdp/index.mjs.map +1 -1
  6. package/dist/chains/index.d.mts +69 -4
  7. package/dist/chains/index.d.ts +69 -4
  8. package/dist/chains/index.js +45 -1
  9. package/dist/chains/index.js.map +1 -1
  10. package/dist/chains/index.mjs +39 -1
  11. package/dist/chains/index.mjs.map +1 -1
  12. package/dist/cli/index.js +5444 -2126
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/cli/index.mjs +5457 -2133
  15. package/dist/cli/index.mjs.map +1 -1
  16. package/dist/client/index.d.mts +307 -1
  17. package/dist/client/index.d.ts +307 -1
  18. package/dist/client/index.js +639 -34
  19. package/dist/client/index.js.map +1 -1
  20. package/dist/client/index.mjs +656 -52
  21. package/dist/client/index.mjs.map +1 -1
  22. package/dist/client/web/index.mjs.map +1 -1
  23. package/dist/facilitators/index.d.mts +512 -10
  24. package/dist/facilitators/index.d.ts +512 -10
  25. package/dist/facilitators/index.js +925 -13
  26. package/dist/facilitators/index.js.map +1 -1
  27. package/dist/facilitators/index.mjs +906 -12
  28. package/dist/facilitators/index.mjs.map +1 -1
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +2843 -551
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +2849 -558
  34. package/dist/index.mjs.map +1 -1
  35. package/dist/mcp/index.js +635 -32
  36. package/dist/mcp/index.js.map +1 -1
  37. package/dist/mcp/index.mjs +660 -57
  38. package/dist/mcp/index.mjs.map +1 -1
  39. package/dist/server/index.d.mts +252 -11
  40. package/dist/server/index.d.ts +252 -11
  41. package/dist/server/index.js +2049 -261
  42. package/dist/server/index.js.map +1 -1
  43. package/dist/server/index.mjs +2049 -261
  44. package/dist/server/index.mjs.map +1 -1
  45. package/dist/verify/index.js.map +1 -1
  46. package/dist/verify/index.mjs.map +1 -1
  47. package/dist/wallet/index.js.map +1 -1
  48. package/dist/wallet/index.mjs.map +1 -1
  49. package/package.json +14 -2
  50. package/schemas/moltspay.services.schema.json +127 -16
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/index.ts","../../src/facilitators/interface.ts","../../src/facilitators/cdp.ts","../../src/facilitators/tempo.ts","../../src/chains/index.ts","../../src/facilitators/bnb.ts","../../src/facilitators/solana.ts","../../src/chains/solana.ts","../../src/facilitators/alipay.ts","../../src/facilitators/alipay/rsa2.ts","../../src/facilitators/alipay/encoding.ts","../../src/facilitators/alipay/openapi.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 FacilitatorConfig,\n X402PaymentPayload,\n X402PaymentRequirements,\n SettleResult,\n AlipayFacilitator,\n AlipayFacilitatorConfig,\n ALIPAY_NETWORK,\n ALIPAY_SCHEME,\n} from '../facilitators/index.js';\nimport { toPem } from '../facilitators/alipay/encoding.js';\nimport { isAlipayChainId } from '../chains/index.js';\nimport {\n ServicesManifest,\n ServiceConfig,\n SkillFunction,\n RegisteredSkill,\n MoltsPayServerOptions,\n CorsOptions,\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// MPP (Machine Payments Protocol) constants\nconst MPP_AUTH_HEADER = 'authorization';\nconst MPP_WWW_AUTH_HEADER = 'www-authenticate';\nconst MPP_RECEIPT_HEADER = 'payment-receipt';\n\n// Alipay AI 收 fiat rail constants (2.0.0)\n// Legacy `Payment-Needed` 402 challenge header, mirror of `X-Payment-Required`,\n// kept so `alipay-bot` (@alipay/agent-payment) skills work unchanged.\nconst ALIPAY_PAYMENT_NEEDED_HEADER = 'payment-needed';\n// Buyer's proof header: alipay-bot re-requests the resource carrying the\n// Base64URL `{protocol:{payment_proof,trade_no},method:{client_session}}`\n// blob here after the buyer pays. The server verifies it via the facilitator.\nconst ALIPAY_PAYMENT_PROOF_HEADER = 'payment-proof';\n\n/**\n * Make an arbitrary string safe to embed in an HTTP header value.\n *\n * HTTP header values are limited to Latin-1 (RFC 7230 §3.2.6); Node's\n * `res.writeHead` throws `Invalid character in header content` on any\n * code point outside that range. Provider/service names can contain\n * non-Latin-1 characters (e.g. CJK), so we percent-encode anything\n * outside printable ASCII and escape `\"` so it cannot terminate the\n * surrounding `Payment ... realm=\"…\"` quoted-string.\n */\nfunction headerSafe(value: string): string {\n return String(value ?? '')\n .replace(/[^\\x20-\\x7E]/g, ch => encodeURIComponent(ch))\n .replace(/\"/g, '%22');\n}\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 'eip155:137': {\n USDC: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n USDT: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n },\n 'eip155:42431': {\n // Tempo Moderato testnet - TIP-20 stablecoins\n USDC: '0x20c0000000000000000000000000000000000000', // pathUSD\n USDT: '0x20c0000000000000000000000000000000000001', // alphaUSD\n },\n // BNB Smart Chain mainnet\n 'eip155:56': {\n USDC: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n USDT: '0x55d398326f99059fF775485246999027B3197955',\n },\n // BNB Smart Chain testnet\n 'eip155:97': {\n USDC: '0x64544969ed7EBf5f083679233325356EbE738930',\n USDT: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd',\n },\n // Solana networks use mint addresses (SPL tokens)\n 'solana:mainnet': {\n USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // Circle USDC\n },\n 'solana:devnet': {\n USDC: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU', // Devnet USDC\n },\n};\n\n// Chain name to network ID mapping\nconst CHAIN_TO_NETWORK: Record<string, string> = {\n 'base': 'eip155:8453',\n 'base_sepolia': 'eip155:84532',\n 'polygon': 'eip155:137',\n 'tempo_moderato': 'eip155:42431',\n 'bnb': 'eip155:56',\n 'bnb_testnet': 'eip155:97',\n 'solana': 'solana:mainnet',\n 'solana_devnet': 'solana:devnet',\n};\n\n// Helper to check if a network is Solana\nfunction isSolanaNetwork(network: string): boolean {\n return network.startsWith('solana:');\n}\n\n// EIP-712 domain info for tokens (per network)\n// Different networks may have different domain names for the same token\nconst TOKEN_DOMAINS: Record<string, Record<string, { name: string; version: string }>> = {\n // Base mainnet\n 'eip155:8453': {\n USDC: { name: 'USD Coin', version: '2' },\n USDT: { name: 'Tether USD', version: '2' },\n },\n // Base Sepolia testnet - USDC uses 'USDC' not 'USD Coin'\n 'eip155:84532': {\n USDC: { name: 'USDC', version: '2' },\n USDT: { name: 'USDC', version: '2' }, // Same contract as USDC on testnet\n },\n // Polygon mainnet\n 'eip155:137': {\n USDC: { name: 'USD Coin', version: '2' },\n USDT: { name: '(PoS) Tether USD', version: '2' },\n },\n // Tempo Moderato testnet - TIP-20 stablecoins\n // Domain names verified against on-chain DOMAIN_SEPARATOR values on 2026-04-21.\n // See docs/TEMPO-WEB-SUPPORT.md Section 2 and test/server/tempo-domain.test.ts.\n // All 4 Tempo TIP-20 tokens (pathUSD / AlphaUSD / BetaUSD / ThetaUSD) use\n // the token symbol with first letter capitalized + version \"1\".\n 'eip155:42431': {\n USDC: { name: 'PathUSD', version: '1' },\n USDT: { name: 'AlphaUSD', version: '1' },\n },\n // BNB Smart Chain mainnet\n 'eip155:56': {\n USDC: { name: 'USD Coin', version: '1' },\n USDT: { name: 'Tether USD', version: '1' },\n },\n // BNB Smart Chain testnet\n 'eip155:97': {\n USDC: { name: 'USD Coin', version: '1' },\n USDT: { name: 'Tether USD', version: '1' },\n },\n};\n\n// Helper to get token domain for a network\nfunction getTokenDomain(network: string, token: string): { name: string; version: string } {\n const networkDomains = TOKEN_DOMAINS[network] || TOKEN_DOMAINS['eip155:8453']; // fallback to base mainnet\n return networkDomains[token] || { name: 'USD Coin', 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 /** Alipay AI 收 facilitator instance, set when `provider.alipay` is configured (2.0.0). */\n private alipayFacilitator: AlipayFacilitator | null = null;\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 default network from env (fallback only)\n // NOTE: Chain is auto-detected from client payment header (payment.network)\n // USE_MAINNET is only used as fallback when payment header omits network\n // Recommended: configure \"chains\" array in manifest instead\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 // Always include 'tempo', 'bnb', and 'solana' in fallback for multi-chain support\n const defaultFallback = ['tempo', 'bnb', 'solana'];\n const envFallback = process.env.FACILITATOR_FALLBACK?.split(',').filter(Boolean);\n const facilitatorConfig: FacilitatorSelection = options.facilitators || {\n primary: process.env.FACILITATOR_PRIMARY || 'cdp',\n fallback: envFallback || defaultFallback,\n strategy: (process.env.FACILITATOR_STRATEGY as any) || 'failover',\n config: {\n cdp: { useMainnet: this.useMainnet },\n },\n };\n\n // ── Alipay AI 收 fiat rail (2.0.0): opt-in via provider.alipay ──\n // When configured, resolve the PEM key files (the manifest stores PATHS,\n // the facilitator wants PEM STRINGS) and register the facilitator in the\n // selection so registry.verify/settle route `network: \"alipay\"` to it.\n // Key-load failure is fatal: a misconfigured alipay rail must not start\n // silently and then 500 on the first payment.\n const providerAlipay = this.manifest.provider.alipay;\n if (providerAlipay) {\n try {\n const baseDir = path.dirname(servicesPath);\n // Alipay hands out keys as bare Base64 (no PEM armor); toPem normalizes\n // both that and already-armored PEM into the PEM the facilitator needs.\n const resolvePem = (p: string, kind: 'PRIVATE' | 'PUBLIC') =>\n toPem(readFileSync(path.isAbsolute(p) ? p : path.resolve(baseDir, p), 'utf-8'), kind);\n const alipayFacilitatorConfig: AlipayFacilitatorConfig = {\n seller_id: providerAlipay.seller_id,\n app_id: providerAlipay.app_id,\n seller_name: providerAlipay.seller_name,\n service_id_default: providerAlipay.service_id_default,\n private_key_pem: resolvePem(providerAlipay.private_key_path, 'PRIVATE'),\n alipay_public_key_pem: resolvePem(providerAlipay.alipay_public_key_path, 'PUBLIC'),\n gateway_url: providerAlipay.gateway_url,\n sign_type: providerAlipay.sign_type,\n };\n facilitatorConfig.config = {\n ...facilitatorConfig.config,\n alipay: alipayFacilitatorConfig as unknown as FacilitatorConfig,\n };\n facilitatorConfig.fallback = facilitatorConfig.fallback || [];\n if (facilitatorConfig.primary !== 'alipay' && !facilitatorConfig.fallback.includes('alipay')) {\n facilitatorConfig.fallback.push('alipay');\n }\n } catch (err: any) {\n throw new Error(`[MoltsPay] Alipay rail configured but key load failed: ${err.message}`);\n }\n }\n\n this.registry = new FacilitatorRegistry(facilitatorConfig);\n\n if (providerAlipay) {\n this.alipayFacilitator = this.registry.get('alipay') as AlipayFacilitator;\n console.log(`[MoltsPay] Alipay AI 收 rail enabled (seller ${providerAlipay.seller_id})`);\n }\n\n // Get primary facilitator for logging\n const primaryFacilitator = this.registry.get(facilitatorConfig.primary);\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 \n // Log configured chains\n const chains = this.manifest.provider.chains;\n if (chains && chains.length > 0) {\n const chainNames = chains.map(c => c.chain || c.network).join(', ');\n console.log(`[MoltsPay] Chains: ${chainNames} (multi-chain enabled)`);\n } else {\n const networkName = this.useMainnet ? 'Base mainnet' : 'Base Sepolia (testnet)';\n console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);\n }\n \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 * Get all configured chains for this provider\n * Returns array of { network, wallet, tokens } for each chain\n */\n private getProviderChains(): Array<{ network: string; wallet: string; tokens: string[] }> {\n const provider = this.manifest.provider;\n \n // Helper to get the right wallet for a chain\n const getWalletForChain = (chainName: string, explicitWallet?: string): string => {\n // If explicit wallet provided (object format), use it\n if (explicitWallet) return explicitWallet;\n // For Solana chains, use solana_wallet if available\n if ((chainName === 'solana' || chainName === 'solana_devnet') && provider.solana_wallet) {\n return provider.solana_wallet;\n }\n // Default to EVM wallet\n return provider.wallet;\n };\n \n // If chains array is defined, use it\n // Supports both string array [\"base\", \"polygon\"] and object array [{chain, wallet, tokens}]\n if (provider.chains && provider.chains.length > 0) {\n return provider.chains.map(c => {\n const chainName = typeof c === 'string' ? c : c.chain;\n const explicitWallet = typeof c === 'object' ? c.wallet : null;\n return {\n network: CHAIN_TO_NETWORK[chainName] || 'eip155:8453',\n wallet: getWalletForChain(chainName, explicitWallet || undefined),\n tokens: (typeof c === 'object' ? c.tokens : null) || ['USDC'],\n };\n });\n }\n \n // Fallback to single chain (backward compat)\n const chain = provider.chain || 'base';\n const network = CHAIN_TO_NETWORK[chain] || this.networkId;\n return [{\n network,\n wallet: getWalletForChain(chain),\n tokens: ['USDC'],\n }];\n }\n\n /**\n * Get wallet address for a specific network\n */\n private getWalletForNetwork(network: string): string {\n const chains = this.getProviderChains();\n const chain = chains.find(c => c.network === network);\n return chain?.wallet || this.manifest.provider.wallet;\n }\n\n /**\n * Check if a network is accepted by this provider\n */\n private isNetworkAccepted(network: string): boolean {\n const chains = this.getProviderChains();\n return chains.some(c => c.network === network);\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 * Apply CORS response headers according to the `cors` option.\n *\n * Default (`cors` unset or `true`): `Access-Control-Allow-Origin: *`. Matches 1.5.x behavior\n * and works for every browser client whose origin does not need to send cookies.\n *\n * `cors: false`: emit no CORS headers. Same-origin only.\n * `cors: string[]`: origin allowlist — echo the origin back iff it matches.\n * `cors: CorsOptions`: full control (allowlist + credentials + maxAge).\n *\n * The required-for-Web response headers are always exposed when CORS is active:\n * `X-Payment-Required, X-Payment-Response, WWW-Authenticate, Payment-Receipt`.\n */\n private applyCorsHeaders(req: IncomingMessage, res: ServerResponse): void {\n const cors = (this.options as MoltsPayServerOptions).cors;\n\n // Explicitly disabled: no CORS headers at all (strict same-origin).\n if (cors === false) {\n return;\n }\n\n const requestOrigin = (req.headers.origin as string | undefined) ?? '*';\n\n // Default / explicit `true`: open to any origin (legacy 1.5.x behavior).\n if (cors === undefined || cors === true) {\n this.writeCorsHeaders(res, '*');\n return;\n }\n\n // Array shortcut: origins allowlist, no credentials, default maxAge.\n if (Array.isArray(cors)) {\n if (cors.includes(requestOrigin)) {\n this.writeCorsHeaders(res, requestOrigin);\n res.setHeader('Vary', 'Origin');\n }\n // Origin not on the allowlist → no CORS headers; browser will block.\n return;\n }\n\n // Full CorsOptions object.\n const opt = cors as CorsOptions;\n const isAllowed =\n typeof opt.origins === 'function'\n ? opt.origins(requestOrigin)\n : opt.origins.includes(requestOrigin);\n if (!isAllowed) {\n return;\n }\n this.writeCorsHeaders(res, requestOrigin);\n res.setHeader('Vary', 'Origin');\n if (opt.credentials) {\n res.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n const maxAge = opt.maxAge ?? 600;\n res.setHeader('Access-Control-Max-Age', String(maxAge));\n }\n\n private writeCorsHeaders(res: ServerResponse, origin: string): void {\n res.setHeader('Access-Control-Allow-Origin', origin);\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Payment, Authorization, Payment-Proof');\n res.setHeader(\n 'Access-Control-Expose-Headers',\n 'X-Payment-Required, X-Payment-Response, WWW-Authenticate, Payment-Receipt, Payment-Needed'\n );\n }\n\n /**\n * Handle incoming request\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // CORS — honors the `cors` option (default true = allow any origin, matches 1.5.x).\n this.applyCorsHeaders(req, res);\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 const proofHeader = req.headers[ALIPAY_PAYMENT_PROOF_HEADER] as string | undefined;\n return await this.handleExecute(body, paymentHeader, res, proofHeader);\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 const authHeader = req.headers[MPP_AUTH_HEADER] as string | undefined;\n return await this.handleProxy(body, paymentHeader, authHeader, res);\n }\n\n // MPP Protocol: Handle service-specific endpoints like /text-to-video, /ping\n // Check if URL matches a registered service ID\n const servicePath = url.pathname.replace(/^\\//, ''); // Remove leading slash\n const skill = this.skills.get(servicePath);\n if (skill && (req.method === 'POST' || req.method === 'GET')) {\n const body = req.method === 'POST' ? await this.readBody(req) : {};\n const authHeader = req.headers[MPP_AUTH_HEADER] as string | undefined;\n const x402Header = req.headers[PAYMENT_HEADER] as string | undefined;\n const proofHeader = req.headers[ALIPAY_PAYMENT_PROOF_HEADER] as string | undefined;\n return await this.handleMPPRequest(skill, body, authHeader, x402Header, res, proofHeader);\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 solana_wallet: this.manifest.provider.solana_wallet,\n chains: this.manifest.provider.chains,\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 proofHeader?: string\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 // Alipay fiat rail (2.0.0): a `Payment-Proof` header means the buyer paid\n // via alipay-bot and is re-requesting the resource with proof. Route to\n // the facilitator verify→fulfill path (the proof's Base64URL blob carries\n // payment_proof / trade_no / client_session).\n if (proofHeader) {\n const alipayPayment: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: ALIPAY_SCHEME,\n network: ALIPAY_NETWORK,\n payload: proofHeader,\n };\n return this.handleAlipayExecute(skill, params || {}, alipayPayment, res);\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 // Alipay fiat rail (2.0.0): route by scheme/network BEFORE the EVM path.\n // validatePayment() only accepts 'exact'/'permit' schemes + EVM/SVM\n // networks, so an alipay payment must branch off here or it'd be rejected.\n const payScheme = payment.accepted?.scheme || payment.scheme;\n const payNetwork = payment.accepted?.network || payment.network;\n if (payScheme === ALIPAY_SCHEME || (payNetwork ? isAlipayChainId(payNetwork) : false)) {\n return this.handleAlipayExecute(skill, params || {}, payment, res);\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 // Auto-detect chain from payment header (key insight: client specifies chain via --chain flag)\n // payment.network contains \"eip155:8453\" (base) or \"eip155:84532\" (base_sepolia) etc.\n // This allows provider to serve both mainnet and testnet without separate configuration\n const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;\n const paymentWallet = this.getWalletForNetwork(paymentNetwork);\n\n // Build requirements for facilitator using the detected token and network\n const requirements = this.buildPaymentRequirements(skill.config, paymentNetwork, paymentWallet, paymentToken);\n\n // Verify payment with facilitator (via registry)\n console.log(`[MoltsPay] Verifying payment on ${paymentNetwork}...`);\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 // For Solana: settle FIRST (blockhash expires quickly ~60s)\n // For EVM: pay-for-success (execute first, settle after)\n const isSolana = isSolanaNetwork(paymentNetwork);\n let settlement: any = null;\n\n if (isSolana) {\n console.log(`[MoltsPay] Solana detected - settling payment FIRST (blockhash expiry protection)`);\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] Solana settlement failed:', err.message);\n return this.sendJson(res, 402, {\n error: 'Payment settlement failed',\n message: err.message,\n });\n }\n }\n\n // Execute skill (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 // For Solana: payment already settled, skill failed - no refund (user accepted risk)\n // For EVM: payment not settled yet, user keeps their money\n return this.sendJson(res, 500, {\n error: 'Service execution failed',\n message: err.message,\n paymentSettled: isSolana ? true : false,\n note: isSolana ? 'Payment was settled before execution. Contact support for refund.' : undefined,\n });\n }\n\n // For EVM: settle payment now (pay-for-success)\n if (!isSolana) {\n console.log(`[MoltsPay] Skill succeeded, settling payment...`);\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 settlement = { success: false, error: err.message, facilitator: 'none' };\n }\n\n // Match Solana semantics: settle failure → 402, do NOT claim payment\n // succeeded. Skill was already executed; provider absorbs the cost.\n if (!settlement?.success) {\n return this.sendJson(res, 402, {\n error: 'Payment settlement failed',\n message: settlement?.error || 'Settlement returned no success state',\n facilitator: settlement?.facilitator,\n });\n }\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 * Execute a service paid via the Alipay AI 收 fiat rail (2.0.0).\n *\n * Differs from the EVM/SVM path: no token detection, no EIP-3009/permit\n * validation. Verify hits the Alipay Open API (`payment.verify`). Settlement\n * (`fulfillment.confirm`) is FIRE-AND-FORGET per ALIPAY-INTEGRATION-DESIGN\n * §5.1: a confirm failure is logged but does NOT fail the already-delivered\n * response (the buyer's payment proof was already verified).\n */\n private async handleAlipayExecute(\n skill: RegisteredSkill,\n params: Record<string, any>,\n payment: X402PaymentPayload,\n res: ServerResponse\n ): Promise<void> {\n if (!this.alipayFacilitator) {\n return this.sendJson(res, 402, { error: 'Alipay rail not configured on this server' });\n }\n\n // Verify/settle ignore `requirements` (the proof carries everything), but\n // requirements.network drives registry routing to the alipay facilitator.\n const requirements: X402PaymentRequirements = {\n scheme: ALIPAY_SCHEME,\n network: ALIPAY_NETWORK,\n asset: 'CNY',\n amount: skill.config.alipay?.price_cny || '0',\n payTo: this.manifest.provider.alipay?.seller_id || '',\n maxTimeoutSeconds: 1800,\n };\n\n console.log(`[MoltsPay] Verifying Alipay 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] Alipay payment verified by ${verifyResult.facilitator}`);\n\n // Execute skill (same timeout contract as the EVM path).\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n console.log(`[MoltsPay] Executing skill: ${skill.id} (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 // Fulfillment confirm — fire-and-forget: log failures, never roll back.\n let settlement: (SettleResult & { facilitator: string });\n try {\n settlement = await this.registry.settle(payment, requirements);\n if (settlement.success) {\n console.log(`[MoltsPay] Alipay fulfillment confirmed: ${settlement.transaction}`);\n } else {\n console.error(`[MoltsPay] Alipay fulfillment confirm failed (non-fatal): ${settlement.error}`);\n }\n } catch (err: any) {\n console.error(`[MoltsPay] Alipay fulfillment confirm threw (non-fatal): ${err.message}`);\n settlement = { success: false, error: err.message, facilitator: 'alipay' };\n }\n\n const responseHeaders: Record<string, string> = {};\n if (settlement.success) {\n responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(JSON.stringify({\n success: true,\n transaction: settlement.transaction,\n network: ALIPAY_NETWORK,\n facilitator: settlement.facilitator,\n })).toString('base64');\n }\n\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: settlement.success\n ? { transaction: settlement.transaction, status: 'fulfilled', facilitator: settlement.facilitator }\n : { status: 'delivered_unconfirmed', error: settlement.error },\n }, responseHeaders);\n }\n\n /**\n * Build the Alipay 402 challenge for a service, or null when the alipay rail\n * isn't configured for this server or this service. Returns the x402\n * `accepts[]` entry plus the Base64URL `Payment-Needed` header value so the\n * 402 responders can dual-emit both the x402 and legacy alipay-bot formats.\n */\n private async buildAlipayChallenge(\n config: ServiceConfig\n ): Promise<{ accepts: X402PaymentRequirements; paymentNeededHeader: string } | null> {\n if (!this.alipayFacilitator || !config.alipay) return null;\n try {\n const req = await this.alipayFacilitator.createPaymentRequirements({\n serviceId: config.alipay.service_id || this.manifest.provider.alipay!.service_id_default,\n priceCny: config.alipay.price_cny,\n goodsName: config.alipay.goods_name,\n resourceId: `/execute?service=${config.id}`,\n });\n return { accepts: req.x402Accepts, paymentNeededHeader: req.paymentNeededHeader };\n } catch (err: any) {\n console.error(`[MoltsPay] Alipay challenge build failed for ${config.id}: ${err.message}`);\n return null;\n }\n }\n\n /**\n * Handle MPP (Machine Payments Protocol) request\n * Supports both x402 and MPP protocols on service endpoints\n */\n private async handleMPPRequest(\n skill: RegisteredSkill,\n body: any,\n authHeader: string | undefined,\n x402Header: string | undefined,\n res: ServerResponse,\n proofHeader?: string\n ): Promise<void> {\n const config = skill.config;\n const params = body || {};\n\n // Alipay buyer re-request with a Payment-Proof header → verify + fulfill.\n if (proofHeader) {\n return await this.handleExecute({ service: config.id, params }, undefined, res, proofHeader);\n }\n\n // Check for x402 payment header first (backward compatibility)\n if (x402Header) {\n return await this.handleExecute({ service: config.id, params }, x402Header, res);\n }\n\n // Check for MPP payment credential\n if (authHeader && authHeader.toLowerCase().startsWith('payment ')) {\n return await this.handleMPPPayment(skill, params, authHeader, res);\n }\n\n // No payment provided - return 402 with both x402 and MPP headers\n return this.sendMPPPaymentRequired(config, res);\n }\n\n /**\n * Handle MPP payment verification and service execution\n */\n private async handleMPPPayment(\n skill: RegisteredSkill,\n params: any,\n authHeader: string,\n res: ServerResponse\n ): Promise<void> {\n const config = skill.config;\n\n // Parse MPP credential: \"Payment <base64>\"\n const credentialMatch = authHeader.match(/Payment\\s+(.+)/i);\n if (!credentialMatch) {\n return this.sendJson(res, 400, { error: 'Invalid Authorization header format' });\n }\n\n let mppCredential: {\n challenge: {\n id: string;\n realm: string;\n method: string;\n intent: string;\n request: any;\n };\n payload: {\n hash?: string;\n signature?: string;\n type: 'hash' | 'transaction';\n };\n source?: string;\n };\n \n try {\n // mppx uses base64url encoding without padding\n const base64 = credentialMatch[1].replace(/-/g, '+').replace(/_/g, '/');\n const decoded = Buffer.from(base64, 'base64').toString('utf-8');\n mppCredential = JSON.parse(decoded);\n } catch (err) {\n console.error('[MoltsPay] Failed to parse MPP credential:', err);\n return this.sendJson(res, 400, { error: 'Invalid payment credential encoding' });\n }\n\n // Extract transaction hash from payload\n let txHash: string | undefined;\n if (mppCredential.payload?.type === 'hash' && mppCredential.payload?.hash) {\n txHash = mppCredential.payload.hash;\n } else if (mppCredential.payload?.type === 'transaction') {\n // For 'transaction' type, server would need to submit the signed tx\n // For now, we only support 'hash' type (push mode)\n return this.sendJson(res, 400, { \n error: 'Transaction type not supported. Please use push mode (hash type).' \n });\n }\n\n if (!txHash) {\n return this.sendJson(res, 400, { error: 'Missing transaction hash in credential' });\n }\n\n // Extract chainId from challenge or source\n let chainId = mppCredential.challenge?.request?.methodDetails?.chainId;\n if (!chainId && mppCredential.source) {\n const chainMatch = mppCredential.source.match(/eip155:(\\d+)/);\n if (chainMatch) chainId = parseInt(chainMatch[1], 10);\n }\n chainId = chainId || 42431; // Default to Tempo Moderato\n\n // Determine network from chainId\n const network = `eip155:${chainId}`;\n\n if (!this.isNetworkAccepted(network)) {\n return this.sendJson(res, 402, { \n error: `Network not accepted: ${network}` \n });\n }\n\n // Build requirements for verification\n const requirements = this.buildPaymentRequirements(\n config,\n network,\n this.getWalletForNetwork(network),\n 'USDC'\n );\n\n // Create x402-compatible payload for facilitator\n const paymentPayload: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: 'exact',\n network,\n payload: {\n txHash,\n chainId,\n },\n };\n\n console.log(`[MoltsPay] Verifying MPP payment: txHash=${txHash}, chainId=${chainId}`);\n\n // Verify payment using facilitator registry\n const verification = await this.registry.verify(paymentPayload, requirements);\n \n if (!verification.valid) {\n return this.sendJson(res, 402, { \n error: `Payment verification failed: ${verification.error}` \n });\n }\n\n console.log(`[MoltsPay] Payment verified! Executing service: ${config.id}`);\n\n // Execute the skill\n let result: any;\n try {\n result = await skill.handler(params);\n } catch (err: any) {\n console.error(`[MoltsPay] Skill execution error:`, err);\n return this.sendJson(res, 500, { \n error: `Service execution failed: ${err.message}` \n });\n }\n\n // Build receipt\n const receipt = {\n success: true,\n txHash,\n network,\n facilitator: verification.facilitator,\n };\n const receiptEncoded = Buffer.from(JSON.stringify(receipt)).toString('base64');\n\n // Return success with MPP receipt header\n res.writeHead(200, {\n 'Content-Type': 'application/json',\n [MPP_RECEIPT_HEADER]: receiptEncoded,\n });\n res.end(JSON.stringify({\n success: true,\n result,\n payment: {\n txHash,\n status: 'verified',\n facilitator: verification.facilitator,\n },\n }, null, 2));\n }\n\n /**\n * Return 402 with both x402 and MPP payment requirements\n */\n private async sendMPPPaymentRequired(config: ServiceConfig, res: ServerResponse): Promise<void> {\n const acceptedTokens = getAcceptedCurrencies(config);\n const providerChains = this.getProviderChains();\n\n // === x402 format (existing) ===\n const accepts: X402PaymentRequirements[] = [];\n for (const chainConfig of providerChains) {\n for (const token of acceptedTokens) {\n if (chainConfig.tokens.includes(token)) {\n accepts.push(this.buildPaymentRequirements(config, chainConfig.network, chainConfig.wallet, token));\n }\n }\n }\n\n // Alipay fiat rail (2.0.0): append the alipay x402 entry when configured.\n const alipayChallenge = await this.buildAlipayChallenge(config);\n if (alipayChallenge) {\n accepts.push(alipayChallenge.accepts);\n }\n\n const x402PaymentRequired = {\n x402Version: X402_VERSION,\n accepts,\n acceptedCurrencies: acceptedTokens,\n resource: {\n url: `/${config.id}`,\n description: `${config.name} - $${config.price} ${config.currency}`,\n },\n };\n const x402Encoded = Buffer.from(JSON.stringify(x402PaymentRequired)).toString('base64');\n\n // === MPP format ===\n // Find Tempo chain if available\n const tempoChain = providerChains.find(c => c.network === 'eip155:42431');\n \n let mppWwwAuth = '';\n if (tempoChain) {\n const challengeId = this.generateChallengeId();\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const tokenAddress = TOKEN_ADDRESSES['eip155:42431']?.USDC || '0x20c0000000000000000000000000000000000000';\n \n const mppRequest = {\n amount: amountInUnits,\n currency: tokenAddress,\n methodDetails: {\n chainId: 42431,\n feePayer: true,\n },\n recipient: tempoChain.wallet,\n };\n const mppRequestEncoded = Buffer.from(JSON.stringify(mppRequest)).toString('base64');\n \n const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString();\n \n mppWwwAuth = `Payment id=\"${challengeId}\", realm=\"${headerSafe(this.manifest.provider.name)}\", method=\"tempo\", intent=\"charge\", request=\"${mppRequestEncoded}\", description=\"${headerSafe(config.name)}\", expires=\"${expiresAt}\"`;\n }\n\n // Build response headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/problem+json',\n [PAYMENT_REQUIRED_HEADER]: x402Encoded,\n };\n\n if (mppWwwAuth) {\n headers[MPP_WWW_AUTH_HEADER] = mppWwwAuth;\n }\n // Dual-emit the legacy `Payment-Needed` header for alipay-bot clients.\n if (alipayChallenge) {\n headers[ALIPAY_PAYMENT_NEEDED_HEADER] = alipayChallenge.paymentNeededHeader;\n }\n\n res.writeHead(402, headers);\n res.end(JSON.stringify({\n type: 'https://paymentauth.org/problems/payment-required',\n title: 'Payment Required',\n status: 402,\n detail: `Payment is required (${config.name}).`,\n service: config.id,\n price: config.price,\n currency: config.currency,\n acceptedCurrencies: acceptedTokens,\n }, null, 2));\n }\n\n /**\n * Generate a unique challenge ID for MPP\n */\n private generateChallengeId(): string {\n const bytes = new Uint8Array(24);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n return Buffer.from(bytes).toString('base64url');\n }\n\n /**\n * Return 402 with x402 payment requirements (v2 format)\n * Includes requirements for all chains and all accepted currencies\n */\n private async sendPaymentRequired(config: ServiceConfig, res: ServerResponse): Promise<void> {\n const acceptedTokens = getAcceptedCurrencies(config);\n const providerChains = this.getProviderChains();\n\n // Build requirements for each chain x token combination\n const accepts: X402PaymentRequirements[] = [];\n for (const chainConfig of providerChains) {\n for (const token of acceptedTokens) {\n // Only add if this chain supports this token\n if (chainConfig.tokens.includes(token)) {\n accepts.push(this.buildPaymentRequirements(config, chainConfig.network, chainConfig.wallet, token));\n }\n }\n }\n\n // Alipay fiat rail (2.0.0): append the alipay x402 entry when configured.\n const alipayChallenge = await this.buildAlipayChallenge(config);\n if (alipayChallenge) {\n accepts.push(alipayChallenge.accepts);\n }\n\n // Get list of accepted chains for response\n const acceptedChains = providerChains.map(c => {\n // Convert network ID to chain name for readability\n if (c.network === 'eip155:8453') return 'base';\n if (c.network === 'eip155:137') return 'polygon';\n return c.network;\n });\n\n const paymentRequired = {\n x402Version: X402_VERSION,\n accepts,\n acceptedCurrencies: acceptedTokens,\n acceptedChains,\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 const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n };\n // Dual-emit the legacy `Payment-Needed` header for alipay-bot clients\n // (@alipay/agent-payment), which only read this header and ignore the\n // x402 `accepts[]`. Mirrors sendMPPPaymentRequired so /execute is\n // byte-for-byte compatible with un-upgraded skills.\n if (alipayChallenge) {\n headers[ALIPAY_PAYMENT_NEEDED_HEADER] = alipayChallenge.paymentNeededHeader;\n }\n\n res.writeHead(402, headers);\n res.end(JSON.stringify({\n error: 'Payment required',\n message: `Service requires $${config.price} ${config.currency}`,\n acceptedCurrencies: acceptedTokens,\n acceptedChains,\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 || this.networkId;\n\n // Both schemes are supported: EIP-3009 `exact` (Base/Polygon/BNB/Solana) and\n // EIP-2612 `permit` (Tempo Moderato, added in 1.6.0). Facilitator routes\n // permit payloads to TempoFacilitator automatically.\n if (scheme !== 'exact' && scheme !== 'permit') {\n return { valid: false, error: `Unsupported scheme: ${scheme}` };\n }\n\n // Check if payment network is one of our accepted networks\n if (!this.isNetworkAccepted(network)) {\n const acceptedChains = this.getProviderChains().map(c => c.network).join(', ');\n return { valid: false, error: `Network not accepted: ${network}. Accepted: ${acceptedChains}` };\n }\n\n return { valid: true };\n }\n\n /**\n * Build payment requirements for facilitator\n * Now supports multi-chain: takes network and wallet as parameters\n */\n private buildPaymentRequirements(\n config: ServiceConfig, \n network?: string, \n wallet?: string,\n token?: string\n ): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const acceptedTokens = getAcceptedCurrencies(config);\n \n // Use specified values or defaults\n const selectedNetwork = network || this.networkId;\n const selectedWallet = wallet || this.manifest.provider.wallet;\n const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];\n \n const tokenAddresses = TOKEN_ADDRESSES[selectedNetwork] || {};\n const tokenAddress = tokenAddresses[selectedToken];\n const tokenDomain = getTokenDomain(selectedNetwork, selectedToken);\n\n // Tempo Moderato uses EIP-2612 permit (pathUSD / AlphaUSD don't implement EIP-3009).\n // Every other network uses the standard x402 \"exact\" (EIP-3009) scheme.\n const isTempo = selectedNetwork === 'eip155:42431';\n const scheme = isTempo ? 'permit' : 'exact';\n\n const requirements: X402PaymentRequirements = {\n scheme,\n network: selectedNetwork,\n asset: tokenAddress,\n amount: amountInUnits,\n payTo: selectedWallet,\n maxTimeoutSeconds: 300,\n extra: tokenDomain,\n };\n \n // For Solana: include fee payer pubkey if available (gasless mode)\n if (selectedNetwork === 'solana:mainnet' || selectedNetwork === 'solana:devnet') {\n const solanaFacilitator = this.registry.get('solana') as any;\n const feePayerPubkey = solanaFacilitator?.getFeePayerPubkey?.();\n if (feePayerPubkey) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n solanaFeePayer: feePayerPubkey,\n };\n }\n }\n \n // For BNB: include spender address for client approval\n if (selectedNetwork === 'eip155:56' || selectedNetwork === 'eip155:97') {\n const bnbFacilitator = this.registry.get('bnb') as any;\n const spenderAddress = bnbFacilitator?.getSpenderAddress?.();\n if (spenderAddress) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n bnbSpender: spenderAddress,\n };\n }\n }\n\n // For Tempo: include the settler EOA so the client can sign Permit(spender=settler).\n // If TEMPO_SETTLER_KEY is not configured, tempoSpender will be absent and Web Client\n // will surface a helpful error rather than sign a permit no one can fulfill.\n if (isTempo) {\n const tempoFacilitator = this.registry.get('tempo') as any;\n const tempoSpender = tempoFacilitator?.getSpenderAddress?.();\n if (tempoSpender) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n tempoSpender,\n };\n }\n }\n\n return requirements;\n }\n\n /**\n * Detect which token is being used in the payment\n * Checks across all supported networks\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 // Get payment network to check correct token addresses\n const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;\n const tokenAddresses = TOKEN_ADDRESSES[paymentNetwork] || {};\n \n for (const [symbol, address] of Object.entries(tokenAddresses)) {\n if (address && (address as string).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, allow all (for testing/open mode)\n if (allowedIPs.length === 0) {\n return true;\n }\n \n // If '*' is in the list, allow all\n if (allowedIPs.includes('*')) {\n return true;\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/MPP 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 * For x402 (base, polygon, base_sepolia):\n * Without X-Payment header: returns 402 with X-Payment-Required\n * With X-Payment header: verifies payment via CDP\n * \n * For MPP (tempo_moderato):\n * Without Authorization header: returns 402 with WWW-Authenticate\n * With Authorization: Payment header: verifies tx on Tempo chain\n */\n private async handleProxy(\n body: any,\n paymentHeader: string | undefined,\n authHeader: 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 chain if provided\n const supportedChains = ['base', 'polygon', 'base_sepolia', 'tempo_moderato', 'bnb', 'bnb_testnet', 'solana', 'solana_devnet'];\n if (chain && !supportedChains.includes(chain)) {\n return this.sendJson(res, 400, { error: `Unsupported chain: ${chain}. Supported: ${supportedChains.join(', ')}` });\n }\n\n // Validate wallet format based on chain\n const isSolanaChain = chain === 'solana' || chain === 'solana_devnet';\n const isValidEvmAddress = /^0x[a-fA-F0-9]{40}$/.test(wallet);\n const isValidSolanaAddress = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(wallet);\n \n if (isSolanaChain && !isValidSolanaAddress) {\n return this.sendJson(res, 400, { error: 'Invalid Solana wallet address format' });\n }\n if (!isSolanaChain && !isValidEvmAddress) {\n return this.sendJson(res, 400, { error: 'Invalid EVM 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 // ========== MPP Protocol for tempo_moderato ==========\n if (chain === 'tempo_moderato') {\n return await this.handleProxyMPP(body, proxyConfig, authHeader, res);\n }\n\n // ========== x402 Protocol for other chains ==========\n // Build payment requirements with the provided wallet and chain\n const requirements = this.buildProxyPaymentRequirements(proxyConfig, wallet, currency, chain);\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendProxyPaymentRequired(proxyConfig, wallet, memo, chain, 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' && scheme !== 'permit') {\n return this.sendJson(res, 402, { error: `Unsupported scheme: ${scheme}` });\n }\n\n // Validate network matches requested chain (or default to provider's network)\n const expectedNetwork = chain ? (CHAIN_TO_NETWORK[chain] || this.networkId) : this.networkId;\n if (network !== expectedNetwork) {\n return this.sendJson(res, 402, { error: `Network mismatch: expected ${expectedNetwork}, 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, handle skill + payment\n if (execute && 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 // For Solana: settle FIRST (blockhash expires quickly ~60s)\n // For EVM: pay-for-success (execute first, settle after)\n const isSolana = isSolanaNetwork(network);\n let settlement: any = null;\n\n if (isSolana) {\n console.log(`[MoltsPay] /proxy: Solana detected - settling payment FIRST`);\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] /proxy: Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n \n // Check if settlement actually succeeded (registry returns {success: false} on failure)\n if (!settlement.success) {\n console.error(`[MoltsPay] /proxy: Solana settlement failed: ${settlement.error}`);\n return this.sendJson(res, 402, {\n success: false,\n paymentSettled: false,\n error: `Payment settlement failed: ${settlement.error || 'Unknown error'}`,\n });\n }\n } catch (err: any) {\n console.error('[MoltsPay] /proxy: Solana settlement failed:', err.message);\n return this.sendJson(res, 402, {\n success: false,\n paymentSettled: false,\n error: `Payment settlement failed: ${err.message}`,\n });\n }\n } else {\n console.log(`[MoltsPay] /proxy: Executing skill first (pay on success): ${service}`);\n }\n\n // Execute skill (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`);\n } catch (err: any) {\n // Skill failed or timeout\n console.error(`[MoltsPay] /proxy: Skill failed: ${err.message}`);\n // For Solana: payment already settled, skill failed - no refund (user accepted risk)\n // For EVM: payment not settled yet, user keeps their money\n return this.sendJson(res, 500, {\n success: false,\n paymentSettled: isSolana ? true : false,\n error: `Service execution failed: ${err.message}`,\n note: isSolana ? 'Payment was settled before execution. Contact support for refund.' : undefined,\n });\n }\n\n // For EVM: settle payment now (pay-for-success)\n if (!isSolana) {\n console.log(`[MoltsPay] /proxy: Settling payment...`);\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,\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n memo,\n result,\n });\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,\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 * Handle MPP payment flow for /proxy endpoint (tempo_moderato chain)\n */\n private async handleProxyMPP(\n body: any,\n config: ServiceConfig,\n authHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { wallet, amount, memo, serviceId } = body;\n const amountNum = parseFloat(amount);\n const amountInUnits = Math.floor(amountNum * 1e6).toString();\n \n // If no Authorization header, return 402 with WWW-Authenticate\n if (!authHeader || !authHeader.toLowerCase().startsWith('payment ')) {\n const challengeId = this.generateChallengeId();\n const tokenAddress = TOKEN_ADDRESSES['eip155:42431']?.USDC || '0x20c0000000000000000000000000000000000000';\n \n const mppRequest = {\n amount: amountInUnits,\n currency: tokenAddress,\n methodDetails: {\n chainId: 42431,\n feePayer: true,\n },\n recipient: wallet,\n };\n const mppRequestEncoded = Buffer.from(JSON.stringify(mppRequest)).toString('base64');\n \n const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString();\n \n const wwwAuth = `Payment id=\"${challengeId}\", realm=\"MoltsPay Proxy\", method=\"tempo\", intent=\"charge\", request=\"${mppRequestEncoded}\", description=\"${headerSafe(config.name)}\", expires=\"${expiresAt}\"`;\n \n res.writeHead(402, {\n 'Content-Type': 'application/problem+json',\n [MPP_WWW_AUTH_HEADER]: wwwAuth,\n });\n res.end(JSON.stringify({\n type: 'https://paymentauth.org/problems/payment-required',\n title: 'Payment Required',\n status: 402,\n detail: `Payment is required (${config.name}).`,\n service: serviceId || 'proxy',\n price: amountNum,\n currency: 'USDC',\n }, null, 2));\n return;\n }\n\n // Parse MPP credential: \"Payment <base64>\"\n const credentialMatch = authHeader.match(/Payment\\s+(.+)/i);\n if (!credentialMatch) {\n return this.sendJson(res, 400, { error: 'Invalid Authorization header format' });\n }\n\n let mppCredential: {\n challenge: { id: string; realm: string; method: string; intent: string; request: any };\n payload: { hash?: string; type: 'hash' | 'transaction' };\n source?: string;\n };\n \n try {\n const base64 = credentialMatch[1].replace(/-/g, '+').replace(/_/g, '/');\n const decoded = Buffer.from(base64, 'base64').toString('utf-8');\n mppCredential = JSON.parse(decoded);\n } catch (err) {\n console.error('[MoltsPay] /proxy MPP: Failed to parse credential:', err);\n return this.sendJson(res, 400, { error: 'Invalid payment credential encoding' });\n }\n\n // Extract transaction hash\n let txHash: string | undefined;\n if (mppCredential.payload?.type === 'hash' && mppCredential.payload?.hash) {\n txHash = mppCredential.payload.hash;\n } else {\n return this.sendJson(res, 400, { error: 'Missing transaction hash in credential' });\n }\n\n console.log(`[MoltsPay] /proxy MPP: Verifying tx ${txHash} on Tempo...`);\n\n // Build requirements for verification\n const requirements = this.buildPaymentRequirements(config, 'eip155:42431', wallet, 'USDC');\n\n // Create x402-compatible payload for facilitator\n const paymentPayload: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: 'exact',\n network: 'eip155:42431',\n payload: { txHash, chainId: 42431 },\n };\n\n // Verify payment using facilitator registry\n const verification = await this.registry.verify(paymentPayload, requirements);\n \n if (!verification.valid) {\n return this.sendJson(res, 402, { \n error: `Payment verification failed: ${verification.error}` \n });\n }\n\n console.log(`[MoltsPay] /proxy MPP: Payment verified by ${verification.facilitator}`);\n\n // Check if execution requested\n const { execute, service, params } = body;\n \n if (execute && service) {\n console.log(`[MoltsPay] /proxy MPP: Executing skill: ${service}`);\n const skill = this.skills.get(service);\n if (!skill) {\n return this.sendJson(res, 404, {\n success: false,\n paymentSettled: true, // Payment already happened on Tempo\n error: `Service not found: ${service}`,\n });\n }\n\n // Execute skill\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 } catch (err: any) {\n console.error(`[MoltsPay] /proxy MPP: Skill failed: ${err.message}`);\n return this.sendJson(res, 500, {\n success: false,\n paymentSettled: true,\n error: `Service execution failed: ${err.message}`,\n });\n }\n\n return this.sendJson(res, 200, {\n success: true,\n verified: true,\n txHash,\n chain: 'tempo_moderato',\n paidTo: wallet,\n amount: amountNum,\n currency: 'USDC',\n facilitator: verification.facilitator,\n memo,\n result,\n });\n }\n\n // No execution requested - just return verification success\n this.sendJson(res, 200, {\n success: true,\n verified: true,\n txHash,\n chain: 'tempo_moderato',\n paidTo: wallet,\n amount: amountNum,\n currency: 'USDC',\n facilitator: verification.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, chain?: string): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const acceptedTokens = getAcceptedCurrencies(config);\n \n // Determine network from chain parameter or use default\n const networkId = chain ? (CHAIN_TO_NETWORK[chain] || this.networkId) : this.networkId;\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[networkId] || TOKEN_ADDRESSES[this.networkId] || {};\n const tokenAddress = tokenAddresses[selectedToken];\n const tokenDomain = getTokenDomain(networkId, selectedToken);\n\n const requirements: X402PaymentRequirements = {\n scheme: 'exact',\n network: networkId,\n asset: tokenAddress,\n amount: amountInUnits,\n payTo: wallet, // Use provided wallet, not manifest\n maxTimeoutSeconds: 300,\n extra: tokenDomain,\n };\n\n // For BNB: include spender address for client approval\n if (networkId === 'eip155:56' || networkId === 'eip155:97') {\n const bnbFacilitator = this.registry.get('bnb') as any;\n const spenderAddress = bnbFacilitator?.getSpenderAddress?.();\n if (spenderAddress) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n bnbSpender: spenderAddress,\n };\n }\n }\n\n return requirements;\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 chain: string | undefined,\n res: ServerResponse\n ): void {\n const requirements = this.buildProxyPaymentRequirements(config, wallet, config.currency, chain);\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 *\n * **Per-scheme `extra` conventions:**\n * - `alipay-aipay` (2.0.0+): `extra` carries the parallel `Payment-Needed`\n * contents so x402-aware clients don't need to read the separate HTTP\n * header. Server side, `AlipayFacilitator.createPaymentRequirements`\n * populates: `payment_needed_header` (Base64URL of nested\n * `{protocol, method}` JSON), `out_trade_no`, `pay_before`, `service_id`.\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 * Auto-detects mainnet vs testnet from chain ID in request.\n * \n * Supported networks:\n * - Base mainnet (eip155:8453)\n * - Polygon mainnet (eip155:137)\n * - Base Sepolia testnet (eip155:84532)\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 URL (handles both mainnet and testnet)\nconst CDP_URL = 'https://api.cdp.coinbase.com/platform/v2/x402';\n\n// Testnet chain IDs (for logging/info only - CDP auto-detects from network field)\nconst TESTNET_CHAIN_IDS = [84532]; // Base Sepolia\n\nexport interface CDPFacilitatorConfig extends FacilitatorConfig {\n /** CDP API Key ID (required) */\n apiKeyId?: string;\n /** CDP API Key Secret (required) */\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 apiKeyId?: string;\n private apiKeySecret?: string;\n \n constructor(config: CDPFacilitatorConfig = {}) {\n super();\n \n // Load env files for credentials\n loadEnvFile();\n \n // Get credentials (required for CDP)\n this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;\n this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;\n \n // Single endpoint handles both mainnet and testnet (auto-detected from chain ID in request)\n this.endpoint = CDP_URL;\n \n // All supported networks - CDP handles both mainnet and testnet\n this.supportedNetworks = [\n 'eip155:8453', // Base mainnet\n 'eip155:137', // Polygon mainnet\n 'eip155:84532', // Base Sepolia (testnet)\n ];\n \n // Warn if missing credentials\n if (!this.apiKeyId || !this.apiKeySecret) {\n console.warn('[CDPFacilitator] WARNING: Missing CDP credentials!');\n console.warn('[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env');\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.apiKeyId || !this.apiKeySecret) {\n throw new Error('CDP credentials required. Set CDP_API_KEY_ID and CDP_API_KEY_SECRET');\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 console.log('[CDP Verify] Payload:', JSON.stringify(paymentPayload, null, 2));\n \n const authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/verify',\n requestBody\n );\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...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 console.log('[CDP Verify] Response:', response.status, JSON.stringify(result));\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 authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/settle',\n requestBody\n );\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...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 * Check if a chain ID is testnet\n */\n static isTestnet(chainId: number): boolean {\n return TESTNET_CHAIN_IDS.includes(chainId);\n }\n \n /**\n * Get configuration summary (for logging)\n */\n getConfigSummary(): string {\n const hasCredentials = !!(this.apiKeyId && this.apiKeySecret);\n const networks = this.supportedNetworks.join(', ');\n return `CDP Facilitator (networks: ${networks}, credentials: ${hasCredentials ? 'yes' : 'no'})`;\n }\n}\n","/**\n * Tempo Testnet Facilitator\n * \n * Verifies payments on Tempo Moderato testnet by checking transaction receipts.\n * Unlike CDP facilitator, this directly verifies on-chain without a third-party service.\n */\n\nimport { ethers } from 'ethers';\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { CHAINS } from '../chains/index.js';\n\n// TIP-20 Transfer event signature\nconst TRANSFER_EVENT_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';\n\n// ===== Payload shapes (discriminated) =====\n\n/** Legacy MPP / tx-hash payload: client already submitted the TIP-20 transfer. */\ninterface TempoTxHashPayload {\n txHash: string;\n chainId: number;\n}\n\n/** EIP-2612 permit payload: server submits permit + transferFrom from the settler wallet. */\ninterface TempoPermitPayload {\n permit: {\n owner: string;\n spender: string;\n value: string;\n nonce: string;\n deadline: string;\n v: number;\n r: string;\n s: string;\n };\n}\n\n// Minimal ABI for permit + transferFrom calls on the TIP-20 precompile.\nconst TIP20_PERMIT_ABI = [\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'function transferFrom(address from, address to, uint256 value) returns (bool)',\n];\n\n/**\n * Tempo Testnet Facilitator\n * \n * Verifies TIP-20 token transfers on Tempo Moderato (chainId 42431).\n */\nexport class TempoFacilitator extends BaseFacilitator {\n readonly name = 'tempo';\n readonly displayName = 'Tempo Testnet';\n readonly supportedNetworks = ['eip155:42431']; // Tempo Moderato\n\n private rpcUrl: string;\n private settlerWallet: ethers.Wallet | null = null;\n\n constructor() {\n super();\n this.rpcUrl = CHAINS.tempo_moderato.rpc;\n\n // Optional: load settler key from env. If present, the facilitator can settle\n // EIP-2612 permit payments by submitting permit() + transferFrom() on behalf\n // of the user. If absent, only the legacy tx-hash verification path works.\n const settlerKey = process.env.TEMPO_SETTLER_KEY;\n if (settlerKey) {\n try {\n const provider = new ethers.JsonRpcProvider(this.rpcUrl);\n this.settlerWallet = new ethers.Wallet(settlerKey, provider);\n } catch (err) {\n console.warn('[TempoFacilitator] Invalid TEMPO_SETTLER_KEY, permit settlement disabled:', err);\n this.settlerWallet = null;\n }\n }\n }\n\n /**\n * Settler EOA address advertised to clients via `X-Payment-Required.extra.tempoSpender`.\n * Web Client uses this as the `spender` field in the signed EIP-2612 Permit.\n * Returns null if no TEMPO_SETTLER_KEY is configured — permit settlement unavailable.\n */\n getSpenderAddress(): string | null {\n return this.settlerWallet?.address ?? null;\n }\n\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n const response = await fetch(this.rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_chainId',\n params: [],\n id: 1,\n }),\n });\n \n const data = await response.json() as { result: string };\n const chainId = parseInt(data.result, 16);\n \n if (chainId !== 42431) {\n return { healthy: false, error: `Wrong chainId: ${chainId}` };\n }\n \n return { healthy: true, latencyMs: Date.now() - start };\n } catch (error) {\n return { healthy: false, error: String(error) };\n }\n }\n\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n // Dispatch on payload shape:\n // { permit: {...} } → new EIP-2612 permit path (Web Client, Phase 3c)\n // { txHash, chainId } → legacy MPP / Node CLI tx-hash verification\n const inner = paymentPayload.payload as Partial<TempoPermitPayload & TempoTxHashPayload>;\n if (inner && 'permit' in inner && inner.permit) {\n return this.verifyPermit(inner as TempoPermitPayload, requirements);\n }\n return this.verifyTxHash(paymentPayload, requirements);\n }\n\n /**\n * Structural validation of an EIP-2612 permit payload. Does NOT submit\n * anything on-chain — actual submission happens in settlePermit().\n */\n private async verifyPermit(\n payload: TempoPermitPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n if (!this.settlerWallet) {\n return { valid: false, error: 'Permit settlement not configured (TEMPO_SETTLER_KEY missing)' };\n }\n const p = payload.permit;\n if (!p || !p.owner || !p.spender || !p.value || !p.deadline) {\n return { valid: false, error: 'Invalid permit payload: missing fields' };\n }\n // Spender must match our settler — otherwise permit() would set allowance on a\n // different address and transferFrom() from our settler would fail.\n if (p.spender.toLowerCase() !== this.settlerWallet.address.toLowerCase()) {\n return {\n valid: false,\n error: `Permit spender ${p.spender} does not match configured settler ${this.settlerWallet.address}`,\n };\n }\n // Deadline not expired (evaluate at verify-time; settle runs shortly after).\n const deadline = BigInt(p.deadline);\n const now = BigInt(Math.floor(Date.now() / 1000));\n if (deadline <= now) {\n return { valid: false, error: 'Permit deadline has expired' };\n }\n // Amount must match what the requirement asked for.\n if (BigInt(p.value) < BigInt(requirements.amount || '0')) {\n return {\n valid: false,\n error: `Permit value ${p.value} is less than required ${requirements.amount}`,\n };\n }\n return { valid: true, details: { scheme: 'permit', owner: p.owner } };\n }\n\n private async verifyTxHash(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n // Extract Tempo-specific payload\n const tempoPayload = paymentPayload.payload as TempoTxHashPayload;\n\n if (!tempoPayload?.txHash) {\n return { valid: false, error: 'Missing txHash in payment payload' };\n }\n\n // Get transaction receipt\n const receipt = await this.getTransactionReceipt(tempoPayload.txHash);\n \n if (!receipt) {\n return { valid: false, error: 'Transaction not found' };\n }\n\n if (receipt.status !== '0x1') {\n return { valid: false, error: 'Transaction failed' };\n }\n\n // Find Transfer event\n const transferLog = receipt.logs.find((log: any) => \n log.topics[0] === TRANSFER_EVENT_TOPIC\n );\n\n if (!transferLog) {\n return { valid: false, error: 'No Transfer event found' };\n }\n\n // Verify recipient (topic[2] is 'to' address, padded to 32 bytes)\n const toAddress = '0x' + transferLog.topics[2].slice(26).toLowerCase();\n const expectedTo = requirements.payTo.toLowerCase();\n \n if (toAddress !== expectedTo) {\n return { \n valid: false, \n error: `Wrong recipient: ${toAddress}, expected ${expectedTo}` \n };\n }\n\n // Verify amount (data field contains the amount)\n const amount = BigInt(transferLog.data);\n const expectedAmount = BigInt(requirements.amount);\n \n if (amount < expectedAmount) {\n return { \n valid: false, \n error: `Insufficient amount: ${amount}, expected ${expectedAmount}` \n };\n }\n\n // Verify token address\n const tokenAddress = transferLog.address.toLowerCase();\n const expectedToken = requirements.asset.toLowerCase();\n \n if (tokenAddress !== expectedToken) {\n return { \n valid: false, \n error: `Wrong token: ${tokenAddress}, expected ${expectedToken}` \n };\n }\n\n return { \n valid: true, \n details: {\n txHash: tempoPayload.txHash,\n from: '0x' + transferLog.topics[1].slice(26),\n to: toAddress,\n amount: amount.toString(),\n token: tokenAddress,\n }\n };\n } catch (error) {\n return { valid: false, error: `Verification failed: ${error}` };\n }\n }\n\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n // Dispatch on payload shape, same rule as verify().\n const inner = paymentPayload.payload as Partial<TempoPermitPayload & TempoTxHashPayload>;\n if (inner && 'permit' in inner && inner.permit) {\n return this.settlePermit(inner as TempoPermitPayload, requirements);\n }\n\n // Legacy tx-hash path: client already submitted the transfer; we just re-verify.\n const verifyResult = await this.verifyTxHash(paymentPayload, requirements);\n if (!verifyResult.valid) {\n return { success: false, error: verifyResult.error };\n }\n const tempoPayload = paymentPayload.payload as TempoTxHashPayload;\n return {\n success: true,\n transaction: tempoPayload.txHash,\n status: 'settled',\n };\n }\n\n /**\n * EIP-2612 permit settlement path. Submits two transactions on Tempo:\n * 1. pathUSD.permit(owner, spender=settler, value, deadline, v, r, s)\n * 2. pathUSD.transferFrom(owner, payTo, value)\n *\n * The settler EOA pays Tempo gas (via the TIP-20 `feeToken` mechanism — no\n * native tTEMPO required; any held TIP-20 token balance covers fees).\n */\n private async settlePermit(\n payload: TempoPermitPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n if (!this.settlerWallet) {\n return { success: false, error: 'Permit settlement not configured (TEMPO_SETTLER_KEY missing)' };\n }\n if (!requirements.asset || !requirements.payTo) {\n return { success: false, error: 'Missing asset or payTo in requirements' };\n }\n\n const verifyResult = await this.verifyPermit(payload, requirements);\n if (!verifyResult.valid) {\n return { success: false, error: verifyResult.error };\n }\n\n const token = new ethers.Contract(requirements.asset, TIP20_PERMIT_ABI, this.settlerWallet);\n const p = payload.permit;\n\n try {\n const permitTx = await token.permit(\n p.owner,\n p.spender,\n p.value,\n p.deadline,\n p.v,\n p.r,\n p.s\n );\n await permitTx.wait();\n\n const transferTx = await token.transferFrom(p.owner, requirements.payTo, p.value);\n await transferTx.wait();\n\n return {\n success: true,\n transaction: transferTx.hash,\n status: 'settled',\n };\n } catch (err) {\n return {\n success: false,\n error: `Tempo permit settlement failed: ${(err as Error).message}`,\n };\n }\n }\n\n private async getTransactionReceipt(txHash: string): Promise<any> {\n const response = await fetch(this.rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_getTransactionReceipt',\n params: [txHash],\n id: 1,\n }),\n });\n\n const data = await response.json() as { result: any };\n return data.result;\n }\n}\n","/**\n * Blockchain Configuration\n */\n\nimport type { ChainConfig, ChainName, EvmChainName, TokenSymbol } from '../types/index.js';\n\nexport const CHAINS: Record<EvmChainName, ChainConfig> = {\n // ============ Mainnet ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n tokens: {\n USDC: {\n address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USD Coin', // EIP-712 domain name\n },\n USDT: {\n address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // deprecated, for backward compat\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-bor-rpc.publicnode.com',\n tokens: {\n USDC: {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: '(PoS) Tether USD', // Polygon uses this name\n },\n },\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n // ============ Testnet ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n tokens: {\n USDC: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USDC', // Testnet USDC uses 'USDC' not 'USD Coin'\n },\n USDT: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Same as USDC on testnet (no official USDT)\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'USDC', // Uses same contract as USDC\n },\n },\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n // ============ Tempo Testnet (Moderato) ============\n tempo_moderato: {\n name: 'Tempo Moderato',\n chainId: 42431,\n rpc: 'https://rpc.moderato.tempo.xyz',\n tokens: {\n // TIP-20 stablecoins on Tempo testnet (from mppx SDK)\n // Note: Tempo uses USD as native gas token, not ETH\n USDC: {\n address: '0x20c0000000000000000000000000000000000000', // pathUSD - primary testnet stablecoin\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'pathUSD',\n },\n USDT: {\n address: '0x20c0000000000000000000000000000000000001', // alphaUSD\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'alphaUSD',\n },\n },\n usdc: '0x20c0000000000000000000000000000000000000',\n explorer: 'https://explore.testnet.tempo.xyz/address/',\n explorerTx: 'https://explore.testnet.tempo.xyz/tx/',\n avgBlockTime: 0.5, // ~500ms finality\n },\n // ============ BNB Chain Testnet ============\n bnb_testnet: {\n name: 'BNB Testnet',\n chainId: 97,\n rpc: 'https://data-seed-prebsc-1-s1.binance.org:8545',\n tokens: {\n // Note: BNB uses 18 decimals for stablecoins (unlike Base/Polygon which use 6)\n // Using official Binance-Peg testnet tokens\n USDC: {\n address: '0x64544969ed7EBf5f083679233325356EbE738930', // Testnet USDC\n decimals: 18,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', // Testnet USDT\n decimals: 18,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x64544969ed7EBf5f083679233325356EbE738930',\n explorer: 'https://testnet.bscscan.com/address/',\n explorerTx: 'https://testnet.bscscan.com/tx/',\n avgBlockTime: 3,\n // BNB-specific: requires approval for pay-for-success flow\n requiresApproval: true,\n },\n // ============ BNB Chain Mainnet ============\n bnb: {\n name: 'BNB Smart Chain',\n chainId: 56,\n rpc: 'https://bsc-dataseed.binance.org',\n tokens: {\n // Note: BNB uses 18 decimals for stablecoins\n USDC: {\n address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n decimals: 18,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0x55d398326f99059fF775485246999027B3197955',\n decimals: 18,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n explorer: 'https://bscscan.com/address/',\n explorerTx: 'https://bscscan.com/tx/',\n avgBlockTime: 3,\n // BNB-specific: requires approval for pay-for-success flow\n requiresApproval: true,\n },\n};\n\n/**\n * Get token address for a chain\n */\nexport function getTokenAddress(chainName: EvmChainName, token: TokenSymbol): string {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n const tokenConfig = chain.tokens[token];\n if (!tokenConfig) {\n throw new Error(`Token ${token} not supported on ${chainName}`);\n }\n return tokenConfig.address;\n}\n\n/**\n * Get token config for a chain\n */\nexport function getTokenConfig(chainName: EvmChainName, token: TokenSymbol) {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n return chain.tokens[token];\n}\n\n/**\n * Get chain configuration\n */\nexport function getChain(name: EvmChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * List all supported EVM chains\n */\nexport function listChains(): EvmChainName[] {\n return Object.keys(CHAINS) as EvmChainName[];\n}\n\n/**\n * Get chain config by chainId\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n// ============ Alipay AI 收 Fiat Rail (2.0.0+) ============\n\n/**\n * Chain-id string for the Alipay AI 收 fiat rail.\n * Used in `provider.chains: [\"alipay\", ...]` to opt the provider into\n * accepting CNY payments alongside USDC.\n */\nexport const ALIPAY_CHAIN_ID = 'alipay' as const;\n\n/**\n * Rail metadata for the Alipay AI 收 fiat rail (2.0.0+).\n *\n * Intentionally kept **outside** the {@link CHAINS} Record because that\n * Record is `Record<EvmChainName, ChainConfig>` and an EVM `ChainConfig`\n * (rpc / tokens / chainId) is not meaningful for a fiat rail.\n *\n * The rail uses `type: \"fiat-rail\"`, distinct from `ChainFamily`'s\n * existing `\"evm\"` and `\"svm\"`. Server dispatch detects alipay via\n * {@link isAlipayChainId} rather than via the EVM/SVM type guards.\n */\nexport const ALIPAY_RAIL = {\n /** Chain-id string used in user manifests + routing. */\n id: ALIPAY_CHAIN_ID,\n /** Rail family — distinct from `ChainFamily` ('evm' | 'svm'). */\n type: 'fiat-rail' as const,\n /** Quote currency. */\n currency: 'CNY' as const,\n /** Decimal places for the `amount` field (元 with up to 2 decimals). */\n decimals: 2 as const,\n /** x402 `scheme` string — matches `ALIPAY_SCHEME` in src/facilitators/alipay.ts. */\n facilitator: 'alipay-aipay' as const,\n} as const;\n\n/**\n * Runtime type guard: is this chain-id string the Alipay fiat rail?\n *\n * Used by the server layer to route a `Payment-Proof` request to\n * {@link AlipayFacilitator} instead of an EVM/SVM verifier.\n */\nexport function isAlipayChainId(id: string): id is typeof ALIPAY_CHAIN_ID {\n return id === ALIPAY_CHAIN_ID;\n}\n\n/**\n * ERC20 ABI (minimal, only required methods)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName, EvmChainName, TokenSymbol };\n","/**\n * BNB Chain Facilitator\n * \n * Handles pay-for-success payments on BNB Smart Chain.\n * \n * Flow:\n * 1. Client pre-approves server wallet (one-time, via `moltspay init`)\n * 2. Client signs EIP-712 intent (no gas, just signature)\n * 3. Server verifies intent signature\n * 4. Server executes service\n * 5. Success → Server calls transferFrom (server pays gas)\n * 6. Failure → No transfer, client keeps money\n * \n * Key difference from Tempo:\n * - Tempo: Client pays first → service might fail → money lost\n * - BNB: Service runs first → success = payment (pay-for-success)\n */\n\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { CHAINS, ChainConfig } from '../chains/index.js';\nimport { privateKeyToAccount } from 'viem/accounts';\n\n// ERC20 Transfer event signature\nconst TRANSFER_EVENT_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';\n\n// EIP-712 Domain\nconst EIP712_DOMAIN = {\n name: 'MoltsPay',\n version: '1',\n};\n\n// EIP-712 Types for Payment Intent\nconst INTENT_TYPES = {\n PaymentIntent: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'amount', type: 'uint256' },\n { name: 'token', type: 'address' },\n { name: 'service', type: 'string' },\n { name: 'nonce', type: 'uint256' },\n { name: 'deadline', type: 'uint256' },\n ],\n};\n\n// ERC20 ABI (minimal)\nconst ERC20_ABI = {\n transfer: 'function transfer(address to, uint256 amount) returns (bool)',\n transferFrom: 'function transferFrom(address from, address to, uint256 amount) returns (bool)',\n allowance: 'function allowance(address owner, address spender) view returns (uint256)',\n balanceOf: 'function balanceOf(address account) view returns (uint256)',\n approve: 'function approve(address spender, uint256 amount) returns (bool)',\n};\n\n/**\n * BNB Payment Intent (signed by client)\n */\nexport interface BNBPaymentIntent {\n from: string;\n to: string;\n amount: string;\n token: string;\n service: string;\n nonce: number;\n deadline: number;\n signature: string;\n}\n\n/**\n * BNB Payment Payload (from client in x402 request)\n */\ninterface BNBPaymentPayload {\n intent: BNBPaymentIntent;\n chainId: number;\n}\n\n/**\n * BNB Chain Facilitator\n * \n * Handles pay-for-success payments on BNB mainnet (chainId 56) and testnet (chainId 97).\n * Server wallet executes transferFrom after successful service delivery.\n */\nexport class BNBFacilitator extends BaseFacilitator {\n readonly name = 'bnb';\n readonly displayName = 'BNB Smart Chain';\n readonly supportedNetworks = ['eip155:56', 'eip155:97']; // Mainnet + Testnet\n\n private serverPrivateKey: string;\n private spenderAddress: string | null = null;\n private chainConfigs: { [key: number]: { rpc: string; chain: ChainConfig } };\n\n constructor(serverPrivateKey?: string) {\n super();\n this.serverPrivateKey = serverPrivateKey || process.env.BNB_SERVER_PRIVATE_KEY || '';\n \n // Pre-compute spender address synchronously using viem\n if (this.serverPrivateKey) {\n const key = this.serverPrivateKey.startsWith('0x') \n ? this.serverPrivateKey as `0x${string}`\n : `0x${this.serverPrivateKey}` as `0x${string}`;\n const account = privateKeyToAccount(key);\n this.spenderAddress = account.address;\n }\n \n this.chainConfigs = {\n 56: { rpc: CHAINS.bnb.rpc, chain: CHAINS.bnb },\n 97: { rpc: CHAINS.bnb_testnet.rpc, chain: CHAINS.bnb_testnet },\n };\n }\n\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n // Check mainnet\n const response = await fetch(this.chainConfigs[56].rpc, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_chainId',\n params: [],\n id: 1,\n }),\n });\n \n const data = await response.json() as { result: string };\n const chainId = parseInt(data.result, 16);\n \n if (chainId !== 56) {\n return { healthy: false, error: `Wrong chainId: ${chainId}` };\n }\n \n return { healthy: true, latencyMs: Date.now() - start };\n } catch (error) {\n return { healthy: false, error: String(error) };\n }\n }\n\n /**\n * Verify a payment intent signature (before service execution)\n * \n * This verifies:\n * 1. Signature is valid for the intent\n * 2. Client has approved server wallet\n * 3. Client has sufficient balance\n * 4. Intent hasn't expired\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n const bnbPayload = paymentPayload.payload as BNBPaymentPayload;\n \n if (!bnbPayload?.intent) {\n return { valid: false, error: 'Missing intent in payment payload' };\n }\n\n const { intent, chainId } = bnbPayload;\n const config = this.chainConfigs[chainId];\n \n if (!config) {\n return { valid: false, error: `Unsupported chainId: ${chainId}` };\n }\n\n // Check deadline\n if (intent.deadline < Date.now()) {\n return { valid: false, error: 'Intent expired' };\n }\n\n // Verify signature\n const recoveredAddress = await this.recoverIntentSigner(intent, chainId);\n if (recoveredAddress.toLowerCase() !== intent.from.toLowerCase()) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n // Verify recipient matches\n if (intent.to.toLowerCase() !== requirements.payTo.toLowerCase()) {\n return { valid: false, error: `Wrong recipient: ${intent.to}` };\n }\n\n // Verify amount matches\n if (BigInt(intent.amount) < BigInt(requirements.amount)) {\n return { valid: false, error: `Insufficient amount: ${intent.amount}` };\n }\n\n // Verify token matches\n if (intent.token.toLowerCase() !== requirements.asset.toLowerCase()) {\n return { valid: false, error: `Wrong token: ${intent.token}` };\n }\n\n // Check allowance\n const serverAddress = await this.getServerAddress();\n const allowance = await this.getAllowance(intent.from, serverAddress, intent.token, config.rpc);\n \n if (BigInt(allowance) < BigInt(intent.amount)) {\n return { valid: false, error: 'Insufficient allowance. Run: npx moltspay init --chain bnb' };\n }\n\n // Check balance\n const balance = await this.getBalance(intent.from, intent.token, config.rpc);\n if (BigInt(balance) < BigInt(intent.amount)) {\n return { valid: false, error: 'Insufficient balance' };\n }\n\n return { \n valid: true, \n details: {\n from: intent.from,\n to: intent.to,\n amount: intent.amount,\n token: intent.token,\n service: intent.service,\n nonce: intent.nonce,\n deadline: intent.deadline,\n }\n };\n } catch (error) {\n return { valid: false, error: `Verification failed: ${error}` };\n }\n }\n\n /**\n * Settle a payment by executing transferFrom\n * \n * This is called AFTER the service has been successfully delivered.\n * Server pays gas, transfers tokens from client to provider.\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n if (!this.serverPrivateKey) {\n return { success: false, error: 'Server wallet not configured (BNB_SERVER_PRIVATE_KEY)' };\n }\n\n try {\n // First verify the intent\n const verifyResult = await this.verify(paymentPayload, requirements);\n if (!verifyResult.valid) {\n return { success: false, error: verifyResult.error };\n }\n\n const bnbPayload = paymentPayload.payload as BNBPaymentPayload;\n const { intent, chainId } = bnbPayload;\n const config = this.chainConfigs[chainId];\n\n // Execute transferFrom\n const txHash = await this.executeTransferFrom(\n intent.from,\n intent.to,\n intent.amount,\n intent.token,\n config.rpc\n );\n\n return { \n success: true, \n transaction: txHash,\n status: 'settled'\n };\n } catch (error) {\n return { success: false, error: `Settlement failed: ${error}` };\n }\n }\n\n /**\n * Check if client has approved the server wallet\n */\n async checkApproval(\n clientAddress: string, \n token: string, \n chainId: number\n ): Promise<{ approved: boolean; allowance: string }> {\n const config = this.chainConfigs[chainId];\n if (!config) {\n throw new Error(`Unsupported chainId: ${chainId}`);\n }\n\n const serverAddress = await this.getServerAddress();\n const allowance = await this.getAllowance(clientAddress, serverAddress, token, config.rpc);\n \n // Consider approved if allowance > 1000 USDC (with 18 decimals)\n const minAllowance = BigInt('1000000000000000000000'); // 1000 tokens\n \n return {\n approved: BigInt(allowance) >= minAllowance,\n allowance,\n };\n }\n\n /**\n * Verify a completed transaction (for checking past payments)\n */\n async verifyTransaction(\n txHash: string, \n expected: { to: string; amount: string; token: string },\n chainId: number\n ): Promise<VerifyResult> {\n const config = this.chainConfigs[chainId];\n if (!config) {\n return { valid: false, error: `Unsupported chainId: ${chainId}` };\n }\n\n try {\n const receipt = await this.getTransactionReceipt(txHash, config.rpc);\n \n if (!receipt) {\n return { valid: false, error: 'Transaction not found' };\n }\n\n if (receipt.status !== '0x1') {\n return { valid: false, error: 'Transaction failed' };\n }\n\n // Find Transfer event\n const transferLog = receipt.logs.find((log: any) => \n log.topics[0] === TRANSFER_EVENT_TOPIC &&\n log.address.toLowerCase() === expected.token.toLowerCase()\n );\n\n if (!transferLog) {\n return { valid: false, error: 'No Transfer event found' };\n }\n\n // Verify recipient\n const toAddress = '0x' + transferLog.topics[2].slice(26).toLowerCase();\n if (toAddress !== expected.to.toLowerCase()) {\n return { valid: false, error: `Wrong recipient: ${toAddress}` };\n }\n\n // Verify amount\n const amount = BigInt(transferLog.data);\n if (amount < BigInt(expected.amount)) {\n return { valid: false, error: `Insufficient amount: ${amount}` };\n }\n\n return { \n valid: true, \n details: {\n txHash,\n from: '0x' + transferLog.topics[1].slice(26),\n to: toAddress,\n amount: amount.toString(),\n token: transferLog.address,\n }\n };\n } catch (error) {\n return { valid: false, error: `Verification failed: ${error}` };\n }\n }\n\n // ==================== Private Methods ====================\n\n /**\n * Get the server's spender address (public, for 402 responses)\n * Returns cached value computed at construction time.\n */\n getSpenderAddress(): string | null {\n return this.spenderAddress;\n }\n\n private async getServerAddress(): Promise<string> {\n // Derive address from private key using ethers\n const { ethers } = await import('ethers');\n const wallet = new ethers.Wallet(this.serverPrivateKey);\n return wallet.address;\n }\n\n private async recoverIntentSigner(intent: BNBPaymentIntent, chainId: number): Promise<string> {\n // Use ethers for EIP-712 signature recovery\n const { ethers } = await import('ethers');\n \n const domain = {\n ...EIP712_DOMAIN,\n chainId,\n };\n\n const message = {\n from: intent.from,\n to: intent.to,\n amount: intent.amount,\n token: intent.token,\n service: intent.service,\n nonce: intent.nonce,\n deadline: intent.deadline,\n };\n\n const recoveredAddress = ethers.verifyTypedData(\n domain,\n INTENT_TYPES,\n message,\n intent.signature\n );\n\n return recoveredAddress;\n }\n\n private async getAllowance(owner: string, spender: string, token: string, rpcUrl: string): Promise<string> {\n // allowance(address,address) selector + params\n const selector = '0xdd62ed3e';\n const ownerPadded = owner.toLowerCase().replace('0x', '').padStart(64, '0');\n const spenderPadded = spender.toLowerCase().replace('0x', '').padStart(64, '0');\n const data = selector + ownerPadded + spenderPadded;\n\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_call',\n params: [{ to: token, data }, 'latest'],\n id: 1,\n }),\n });\n\n const result = await response.json() as { result: string };\n return result.result || '0x0';\n }\n\n private async getBalance(account: string, token: string, rpcUrl: string): Promise<string> {\n // balanceOf(address) selector + param\n const selector = '0x70a08231';\n const accountPadded = account.toLowerCase().replace('0x', '').padStart(64, '0');\n const data = selector + accountPadded;\n\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_call',\n params: [{ to: token, data }, 'latest'],\n id: 1,\n }),\n });\n\n const result = await response.json() as { result: string };\n return result.result || '0x0';\n }\n\n private async executeTransferFrom(\n from: string,\n to: string,\n amount: string,\n token: string,\n rpcUrl: string\n ): Promise<string> {\n const { ethers } = await import('ethers');\n \n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const wallet = new ethers.Wallet(this.serverPrivateKey, provider);\n \n const tokenContract = new ethers.Contract(token, [\n 'function transferFrom(address from, address to, uint256 amount) returns (bool)',\n ], wallet);\n\n const tx = await tokenContract.transferFrom(from, to, amount);\n const receipt = await tx.wait();\n \n return receipt.hash;\n }\n\n private async getTransactionReceipt(txHash: string, rpcUrl: string): Promise<any> {\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_getTransactionReceipt',\n params: [txHash],\n id: 1,\n }),\n });\n\n const data = await response.json() as { result: any };\n return data.result;\n }\n}\n\n/**\n * Create EIP-712 typed data for signing a payment intent\n * \n * Used by clients to sign their payment intent.\n */\nexport function createIntentTypedData(\n intent: Omit<BNBPaymentIntent, 'signature'>,\n chainId: number\n) {\n return {\n domain: {\n ...EIP712_DOMAIN,\n chainId,\n },\n types: INTENT_TYPES,\n primaryType: 'PaymentIntent' as const,\n message: {\n from: intent.from,\n to: intent.to,\n amount: intent.amount,\n token: intent.token,\n service: intent.service,\n nonce: intent.nonce,\n deadline: intent.deadline,\n },\n };\n}\n","/**\n * Solana Facilitator\n * \n * Pay-for-success payment settlement for Solana SPL token transfers.\n * Unlike EVM chains, Solana doesn't have a third-party facilitator - \n * we verify and settle directly on-chain.\n * \n * Flow:\n * 1. Client signs a SPL token transfer authorization\n * 2. Server receives the signed transaction\n * 3. Server verifies the signature and amount\n * 4. Server submits the transaction to settle payment\n */\n\nimport { \n Connection, \n PublicKey, \n Transaction,\n VersionedTransaction,\n sendAndConfirmTransaction,\n Keypair,\n} from '@solana/web3.js';\nimport {\n getAssociatedTokenAddress,\n createTransferCheckedInstruction,\n getAccount,\n createAssociatedTokenAccountInstruction,\n TOKEN_PROGRAM_ID,\n} from '@solana/spl-token';\nimport { \n BaseFacilitator, \n type X402PaymentPayload, \n type X402PaymentRequirements,\n type VerifyResult,\n type SettleResult,\n type HealthCheckResult,\n} from './interface.js';\nimport { SOLANA_CHAINS, type SolanaChainName } from '../chains/solana.js';\n\n/**\n * Solana payment payload structure\n */\nexport interface SolanaPaymentPayload {\n /** Base58 encoded signed transaction */\n signedTransaction: string;\n /** Sender's public key (Base58) */\n sender: string;\n /** Chain: solana or solana_devnet */\n chain: SolanaChainName;\n}\n\n/**\n * Solana Facilitator configuration\n */\nexport interface SolanaFacilitatorConfig {\n /** Optional fee payer keypair for gasless transactions */\n feePayerKeypair?: Keypair;\n}\n\n/**\n * Solana Facilitator for pay-for-success payments\n * \n * Supports gasless mode: if feePayerKeypair is provided, server pays tx fees\n */\nexport class SolanaFacilitator extends BaseFacilitator {\n readonly name = 'solana';\n readonly displayName = 'Solana Direct';\n readonly supportedNetworks = ['solana:mainnet', 'solana:devnet'];\n\n private connections: Map<SolanaChainName, Connection> = new Map();\n private feePayerKeypair?: Keypair;\n\n constructor(config?: SolanaFacilitatorConfig) {\n super();\n this.feePayerKeypair = config?.feePayerKeypair;\n \n // Initialize connections\n for (const [chain, config] of Object.entries(SOLANA_CHAINS)) {\n this.connections.set(\n chain as SolanaChainName, \n new Connection(config.rpc, 'confirmed')\n );\n }\n \n if (this.feePayerKeypair) {\n console.log(`[SolanaFacilitator] Gasless mode enabled. Fee payer: ${this.feePayerKeypair.publicKey.toBase58()}`);\n }\n }\n \n /**\n * Get fee payer public key (for gasless transactions)\n */\n getFeePayerPubkey(): string | null {\n return this.feePayerKeypair?.publicKey.toBase58() || null;\n }\n\n private getConnection(chain: SolanaChainName): Connection {\n const conn = this.connections.get(chain);\n if (!conn) {\n throw new Error(`No connection for chain: ${chain}`);\n }\n return conn;\n }\n\n /**\n * Convert our chain name to network identifier\n */\n static chainToNetwork(chain: SolanaChainName): string {\n return chain === 'solana' ? 'solana:mainnet' : 'solana:devnet';\n }\n\n /**\n * Convert network identifier to chain name\n */\n static networkToChain(network: string): SolanaChainName | null {\n if (network === 'solana:mainnet') return 'solana';\n if (network === 'solana:devnet') return 'solana_devnet';\n return null;\n }\n\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n // Check devnet connection\n const conn = this.getConnection('solana_devnet');\n await conn.getSlot();\n return {\n healthy: true,\n latencyMs: Date.now() - start,\n };\n } catch (error: any) {\n return {\n healthy: false,\n error: error.message,\n };\n }\n }\n\n /**\n * Verify a Solana payment\n * \n * Checks:\n * 1. Transaction is valid and properly signed\n * 2. Transfer instruction matches expected amount and recipient\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n const solanaPayload = paymentPayload.payload as SolanaPaymentPayload;\n if (!solanaPayload || !solanaPayload.signedTransaction) {\n return { valid: false, error: 'Missing signed transaction' };\n }\n\n const chain = solanaPayload.chain || 'solana_devnet';\n const chainConfig = SOLANA_CHAINS[chain];\n if (!chainConfig) {\n return { valid: false, error: `Invalid chain: ${chain}` };\n }\n\n // Decode the transaction\n const txBuffer = Buffer.from(solanaPayload.signedTransaction, 'base64');\n let tx: Transaction | VersionedTransaction;\n \n try {\n // Try legacy transaction first\n tx = Transaction.from(txBuffer);\n } catch {\n // Try versioned transaction\n tx = VersionedTransaction.deserialize(txBuffer);\n }\n\n // Verify at least one signature exists (may be partial in gasless mode)\n if (tx instanceof Transaction) {\n // In gasless mode, fee payer signature is added by server\n // Client only signs for token transfer authority\n const hasAnySignature = tx.signatures.some(sig => \n sig.signature && !sig.signature.every(b => b === 0)\n );\n if (!hasAnySignature) {\n return { valid: false, error: 'Transaction not signed' };\n }\n }\n\n // Parse expected values from requirements\n const expectedAmount = BigInt(requirements.amount);\n const expectedRecipient = new PublicKey(requirements.payTo);\n\n // For now, we trust the transaction structure\n // Full verification happens at settlement time\n return {\n valid: true,\n details: {\n chain,\n sender: solanaPayload.sender,\n recipient: requirements.payTo,\n amount: requirements.amount,\n },\n };\n } catch (error: any) {\n return { valid: false, error: error.message };\n }\n }\n\n /**\n * Settle a Solana payment\n * \n * Submits the signed transaction to the network.\n * In gasless mode, adds fee payer signature before submitting.\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n try {\n const solanaPayload = paymentPayload.payload as SolanaPaymentPayload;\n if (!solanaPayload || !solanaPayload.signedTransaction) {\n return { success: false, error: 'Missing signed transaction' };\n }\n\n const chain = solanaPayload.chain || 'solana_devnet';\n const connection = this.getConnection(chain);\n\n // Decode the transaction\n const txBuffer = Buffer.from(solanaPayload.signedTransaction, 'base64');\n \n let txToSend: Buffer;\n \n try {\n // Try legacy transaction\n const tx = Transaction.from(txBuffer);\n \n // Check if we need to add fee payer signature (gasless mode)\n if (this.feePayerKeypair && tx.feePayer) {\n const feePayerPubkey = this.feePayerKeypair.publicKey.toBase58();\n const txFeePayer = tx.feePayer.toBase58();\n \n if (txFeePayer === feePayerPubkey) {\n // Gasless mode: add fee payer signature\n console.log(`[SolanaFacilitator] Gasless mode: adding fee payer signature`);\n tx.partialSign(this.feePayerKeypair);\n }\n }\n \n txToSend = tx.serialize();\n } catch (e: any) {\n // Fall back to versioned transaction (no gasless support for versioned yet)\n txToSend = txBuffer;\n }\n\n // Send the transaction\n const signature = await connection.sendRawTransaction(txToSend, {\n skipPreflight: false,\n preflightCommitment: 'confirmed',\n });\n\n // Wait for confirmation\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n \n if (confirmation.value.err) {\n return {\n success: false,\n error: `Transaction failed: ${JSON.stringify(confirmation.value.err)}`,\n transaction: signature,\n };\n }\n\n return {\n success: true,\n transaction: signature,\n status: 'confirmed',\n };\n } catch (error: any) {\n return { success: false, error: error.message };\n }\n }\n\n supportsNetwork(network: string): boolean {\n return this.supportedNetworks.includes(network);\n }\n}\n\n/**\n * Create a Solana payment transaction for signing\n * \n * This is called by the client to create the transaction to sign.\n * \n * @param senderPubkey - The sender's public key (token owner)\n * @param recipientPubkey - The recipient's public key\n * @param amount - Amount in token base units\n * @param chain - Solana chain (solana or solana_devnet)\n * @param feePayerPubkey - Optional fee payer public key for gasless transactions\n */\nexport async function createSolanaPaymentTransaction(\n senderPubkey: PublicKey,\n recipientPubkey: PublicKey,\n amount: bigint,\n chain: SolanaChainName,\n feePayerPubkey?: PublicKey,\n connection?: Connection,\n): Promise<Transaction> {\n const chainConfig = SOLANA_CHAINS[chain];\n const conn = connection ?? new Connection(chainConfig.rpc, 'confirmed');\n const mint = new PublicKey(chainConfig.tokens.USDC.mint);\n\n // Determine who pays fees (gasless mode uses server's fee payer)\n const actualFeePayer = feePayerPubkey || senderPubkey;\n\n // Get ATAs\n const senderATA = await getAssociatedTokenAddress(mint, senderPubkey);\n const recipientATA = await getAssociatedTokenAddress(mint, recipientPubkey);\n\n const transaction = new Transaction();\n\n // Check if recipient ATA exists\n try {\n await getAccount(conn, recipientATA);\n } catch {\n // Create ATA for recipient (fee payer pays rent in gasless mode)\n transaction.add(\n createAssociatedTokenAccountInstruction(\n actualFeePayer, // payer (fee payer in gasless mode)\n recipientATA, // ata to create\n recipientPubkey, // owner\n mint // mint\n )\n );\n }\n\n // Add transfer instruction\n transaction.add(\n createTransferCheckedInstruction(\n senderATA, // source\n mint, // mint\n recipientATA, // destination\n senderPubkey, // owner (sender still authorizes the transfer)\n amount, // amount\n chainConfig.tokens.USDC.decimals // decimals\n )\n );\n\n // Get recent blockhash\n const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash();\n transaction.recentBlockhash = blockhash;\n transaction.feePayer = actualFeePayer;\n\n return transaction;\n}\n\nexport default SolanaFacilitator;\n","/**\n * Solana Chain Configuration\n * \n * Solana is NOT an EVM chain - uses different:\n * - Key format: ed25519 (EdDSA) vs secp256k1 (ECDSA)\n * - Address format: Base58 vs 0x hex\n * - Token standard: SPL vs ERC-20\n */\n\nimport { Connection, PublicKey } from '@solana/web3.js';\n\nexport interface SolanaChainConfig {\n name: string;\n cluster: 'mainnet-beta' | 'devnet' | 'testnet';\n rpc: string;\n explorer: string;\n explorerTx: string;\n tokens: {\n USDC: {\n mint: string;\n decimals: number;\n };\n };\n}\n\nexport type SolanaChainName = 'solana' | 'solana_devnet';\n\nexport const SOLANA_CHAINS: Record<SolanaChainName, SolanaChainConfig> = {\n solana: {\n name: 'Solana Mainnet',\n cluster: 'mainnet-beta',\n rpc: 'https://api.mainnet-beta.solana.com',\n explorer: 'https://solscan.io/account/',\n explorerTx: 'https://solscan.io/tx/',\n tokens: {\n USDC: {\n mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // Circle official USDC\n decimals: 6,\n },\n },\n },\n solana_devnet: {\n name: 'Solana Devnet',\n cluster: 'devnet',\n rpc: 'https://api.devnet.solana.com',\n explorer: 'https://solscan.io/account/',\n explorerTx: 'https://solscan.io/tx/',\n tokens: {\n USDC: {\n // Circle's devnet USDC (if not available, we'll deploy our own test token)\n mint: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',\n decimals: 6,\n },\n },\n },\n};\n\n/**\n * Get Solana RPC connection\n */\nexport function getSolanaConnection(chain: SolanaChainName): Connection {\n const config = SOLANA_CHAINS[chain];\n return new Connection(config.rpc, 'confirmed');\n}\n\n/**\n * Get USDC mint public key for a Solana chain\n */\nexport function getUSDCMint(chain: SolanaChainName): PublicKey {\n return new PublicKey(SOLANA_CHAINS[chain].tokens.USDC.mint);\n}\n\n/**\n * Get Solana chain config\n */\nexport function getSolanaChain(name: SolanaChainName): SolanaChainConfig {\n const config = SOLANA_CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported Solana chain: ${name}. Supported: ${Object.keys(SOLANA_CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * Check if a chain name is a Solana chain\n */\nexport function isSolanaChain(chain: string): chain is SolanaChainName {\n return chain === 'solana' || chain === 'solana_devnet';\n}\n\n/**\n * Get explorer URL for a Solana address\n */\nexport function getSolanaExplorerUrl(chain: SolanaChainName, address: string): string {\n const config = SOLANA_CHAINS[chain];\n const clusterParam = chain === 'solana_devnet' ? '?cluster=devnet' : '';\n return `${config.explorer}${address}${clusterParam}`;\n}\n\n/**\n * Get explorer URL for a Solana transaction\n */\nexport function getSolanaTxExplorerUrl(chain: SolanaChainName, signature: string): string {\n const config = SOLANA_CHAINS[chain];\n const clusterParam = chain === 'solana_devnet' ? '?cluster=devnet' : '';\n return `${config.explorerTx}${signature}${clusterParam}`;\n}\n","/**\n * Alipay AI 收 Facilitator (2.0.0)\n *\n * Implements the `Facilitator` interface for Alipay's 智能收 (AI Pay) 402\n * protocol. Adds a fiat rail (CNY) alongside the existing USDC/EVM/SVM\n * rails. Server-side only; clients shell out to the `alipay-bot` CLI\n * (see `AlipayClient` under `src/client/alipay/` in 1.7.0-rc.2).\n *\n * Key protocol differences from x402:\n * - Wire challenge is Base64URL-encoded `Payment-Needed` header with\n * nested `{protocol, method}` JSON (not flat `accepts[]`).\n * - Amount unit is **元** (CNY decimal string, not atomic units).\n * - Signature is RSA2 (SHA256WithRSA), not EIP-712 / EIP-3009.\n * - Verify/settle hit Alipay Open API HTTP endpoints, not chain RPC.\n *\n * The server emits **both** `X-Payment-Required` and `Payment-Needed`\n * headers so that legacy `alipay-bot` skills (`@alipay/agent-payment@1.0.9`)\n * keep working without changes.\n *\n * @see ../../docs/ALIPAY-RAIL.md — end-user integration guide\n * @see ../../docs/ALIPAY-INTEGRATION-DESIGN.md — architecture & decisions\n * @see ../../docs/ALIPAY-INTEGRATION-PLAN.md — implementation milestones\n *\n * Stub for 1.7.0-rc.1; bodies tracked in ALIPAY-INTEGRATION-PLAN.md §1.\n */\n\nimport crypto from 'node:crypto';\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { rsa2Sign } from './alipay/rsa2.js';\nimport { base64url, decodeBase64UrlWithPadFix } from './alipay/encoding.js';\nimport { alipayOpenApiCall, AlipayOpenApiConfig } from './alipay/openapi.js';\n\n/** Network identifier exposed via `Facilitator.supportedNetworks`. */\nexport const ALIPAY_NETWORK = 'alipay';\n\n/** x402 `scheme` string identifying the Alipay rail in `accepts[]`. */\nexport const ALIPAY_SCHEME = 'alipay-aipay';\n\n/** Default production gateway URL. */\nexport const ALIPAY_GATEWAY_PROD = 'https://openapi.alipay.com/gateway.do';\n\n/** Sandbox gateway URL (for testing without real CNY). */\nexport const ALIPAY_GATEWAY_SANDBOX = 'https://openapi.alipaydev.com/gateway.do';\n\n/** Validation regex for `price_cny` / `amount` (decimal string, unit 元, ≤ 2 decimal places). */\nexport const ALIPAY_AMOUNT_REGEX = /^\\d+(\\.\\d{1,2})?$/;\n\n/** Lifetime of a 402 challenge before `pay_before` expires (Alipay convention). */\nexport const ALIPAY_PAY_BEFORE_MS = 30 * 60 * 1000;\n\n/**\n * The 8 fields that get RSA2-signed in dictionary order for a 402 challenge.\n * Exposed for visibility; internal to {@link AlipayFacilitator}.\n */\nexport const ALIPAY_SIGNING_FIELDS = [\n 'amount',\n 'currency',\n 'goods_name',\n 'out_trade_no',\n 'pay_before',\n 'resource_id',\n 'seller_id',\n 'service_id',\n] as const;\n\n/**\n * Facilitator-level configuration sourced from `provider.alipay` in\n * `moltspay.services.json`. The server resolves `private_key_path` and\n * `alipay_public_key_path` to PEM strings before constructing the facilitator.\n */\nexport interface AlipayFacilitatorConfig {\n /** Merchant Alipay ID (16 digits, e.g. `\"2088641494699428\"`). */\n seller_id: string;\n /** Application ID from Alipay Open Platform. */\n app_id: string;\n /** Merchant legal name; appears in `method.seller_name` of the 402 challenge. */\n seller_name: string;\n /** Fallback `service_id` when a service doesn't override it. */\n service_id_default: string;\n /** RSA2 merchant private key (PEM). Loaded from `private_key_path` by the server. */\n private_key_pem: string;\n /** Alipay platform public key (PEM). Loaded from `alipay_public_key_path` by the server. */\n alipay_public_key_pem: string;\n /** Open API gateway URL. Defaults to {@link ALIPAY_GATEWAY_PROD}. */\n gateway_url?: string;\n /** Signature algorithm. Only `RSA2` is supported. */\n sign_type?: 'RSA2';\n}\n\n/**\n * Inputs required to construct a 402 `Payment-Needed` challenge for a service.\n */\nexport interface CreatePaymentRequirementsOpts {\n /** Per-service Alipay `service_id` (overrides `provider.alipay.service_id_default`). */\n serviceId: string;\n /** CNY price as decimal string in **元** (e.g. `\"1.00\"` = 1 CNY). */\n priceCny: string;\n /** Goods name shown to the user in the Alipay app. */\n goodsName: string;\n /** Resource identifier (typically the request URL or its hash). */\n resourceId: string;\n /** Client-supplied `out_trade_no`; if omitted the facilitator generates one. */\n outTradeNo?: string;\n}\n\n/**\n * Both headers the server emits in a 402 response:\n * - `x402Accepts` → `X-Payment-Required` (x402 standard, for new MoltsPay clients)\n * - `paymentNeededHeader` → `Payment-Needed` (Alipay standard, for legacy `alipay-bot`)\n *\n * The two headers are mirrors of each other; the single source of truth lives\n * in the server config.\n */\nexport interface AlipayPaymentRequirements {\n x402Accepts: X402PaymentRequirements;\n paymentNeededHeader: string;\n}\n\n/**\n * Decoded `Payment-Proof` header from the buyer's request.\n *\n * The proof is Base64URL of `{protocol: {...}, method: {...}}` where:\n * - `protocol.trade_no` is the 32-digit Alipay trade number\n * - `protocol.payment_proof` is the RSA2-signed payment proof\n * - `method.client_session` echoes the buyer's session for replay protection\n */\nexport interface AlipayPaymentProof {\n protocol: {\n payment_proof: string;\n trade_no: string;\n [k: string]: unknown;\n };\n method: {\n client_session: string;\n [k: string]: unknown;\n };\n}\n\n/**\n * Alipay AI 收 facilitator.\n *\n * Construction is cheap; expensive setup (key parsing, gateway probe) is\n * deferred to `healthCheck()`.\n */\nexport class AlipayFacilitator extends BaseFacilitator {\n readonly name = 'alipay';\n readonly displayName = 'Alipay AI 收';\n readonly supportedNetworks = [ALIPAY_NETWORK];\n\n private readonly config: AlipayFacilitatorConfig;\n\n constructor(config: AlipayFacilitatorConfig) {\n super();\n this.config = {\n gateway_url: ALIPAY_GATEWAY_PROD,\n sign_type: 'RSA2',\n ...config,\n };\n }\n\n /**\n * Build the 402 challenge for a service: signs the 8-field payload with\n * RSA2, packages the nested `{protocol, method}` JSON as Base64URL for\n * `Payment-Needed`, and emits the parallel x402 `accepts[]` entry.\n */\n async createPaymentRequirements(\n opts: CreatePaymentRequirementsOpts,\n ): Promise<AlipayPaymentRequirements> {\n if (!ALIPAY_AMOUNT_REGEX.test(opts.priceCny)) {\n throw new Error(\n `AlipayFacilitator.createPaymentRequirements: priceCny \"${opts.priceCny}\" ` +\n `does not match /^\\\\d+(\\\\.\\\\d{1,2})?$/ (unit is 元, not 分; e.g. \"1.00\" not \"100\")`,\n );\n }\n\n const now = new Date();\n const outTradeNo = opts.outTradeNo ?? generateOutTradeNo();\n const payBefore = formatPayBefore(now);\n\n // 8 fields signed (dictionary order enforced by `ALIPAY_SIGNING_FIELDS`)\n const signedFields = {\n amount: opts.priceCny,\n currency: 'CNY',\n goods_name: opts.goodsName,\n out_trade_no: outTradeNo,\n pay_before: payBefore,\n resource_id: opts.resourceId,\n seller_id: this.config.seller_id,\n service_id: opts.serviceId,\n } as const;\n\n const signingString = ALIPAY_SIGNING_FIELDS\n .map((k) => `${k}=${signedFields[k]}`)\n .join('&');\n const seller_signature = rsa2Sign(signingString, this.config.private_key_pem);\n\n const challenge = {\n protocol: {\n out_trade_no: outTradeNo,\n amount: signedFields.amount,\n currency: signedFields.currency,\n resource_id: signedFields.resource_id,\n pay_before: payBefore,\n seller_signature,\n seller_sign_type: this.config.sign_type ?? 'RSA2',\n seller_unique_id: this.config.seller_id,\n },\n method: {\n seller_name: this.config.seller_name,\n seller_id: this.config.seller_id,\n seller_app_id: this.config.app_id,\n goods_name: signedFields.goods_name,\n seller_unique_id_key: 'seller_id',\n service_id: signedFields.service_id,\n },\n };\n\n const paymentNeededHeader = base64url(JSON.stringify(challenge));\n\n const x402Accepts: X402PaymentRequirements = {\n scheme: ALIPAY_SCHEME,\n network: ALIPAY_NETWORK,\n asset: 'CNY',\n amount: opts.priceCny,\n payTo: this.config.seller_id,\n maxTimeoutSeconds: ALIPAY_PAY_BEFORE_MS / 1000,\n extra: {\n payment_needed_header: paymentNeededHeader,\n out_trade_no: outTradeNo,\n pay_before: payBefore,\n service_id: signedFields.service_id,\n },\n };\n\n return { x402Accepts, paymentNeededHeader };\n }\n\n /**\n * Verify a `Payment-Proof` by calling\n * `alipay.aipay.agent.payment.verify` against the Alipay Open API.\n *\n * The proof is conveyed via `paymentPayload.payload`, which may be:\n * - a raw Base64URL string (the `Payment-Proof` header value), or\n * - an object `{ paymentProof: string }` / `{ proofHeader: string }`.\n *\n * All failure modes (malformed payload, network errors, Alipay\n * `code != 10000`) return `{ valid: false, error }`. No exception\n * escapes, regardless of client-supplied input.\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n _requirements: X402PaymentRequirements,\n ): Promise<VerifyResult> {\n try {\n const proofHeader = extractProofHeader(paymentPayload.payload);\n const decoded = decodeProof(proofHeader);\n\n const response = await alipayOpenApiCall(\n 'alipay.aipay.agent.payment.verify',\n {\n payment_proof: decoded.protocol.payment_proof,\n trade_no: decoded.protocol.trade_no,\n client_session: decoded.method.client_session,\n },\n this.getOpenApiConfig(),\n );\n\n if (response.code !== '10000') {\n return {\n valid: false,\n error: `alipay verify ${response.code}: ${response.sub_msg ?? response.msg ?? 'unknown'}`,\n details: {\n code: response.code,\n sub_code: response.sub_code,\n sub_msg: response.sub_msg,\n },\n };\n }\n\n return {\n valid: true,\n details: {\n trade_no: (response.trade_no as string) ?? decoded.protocol.trade_no,\n amount: response.amount,\n out_trade_no: response.out_trade_no,\n resource_id: response.resource_id,\n active: response.active,\n },\n };\n } catch (e: unknown) {\n return {\n valid: false,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n }\n\n /**\n * Settle by calling `alipay.aipay.agent.fulfillment.confirm` after the\n * service resource has been returned to the buyer.\n *\n * Per the design (see ALIPAY-INTEGRATION-DESIGN.md §5.1, risk row\n * \"履约确认失败\"), this is **fire-and-forget**: the caller (registry /\n * server) is expected to log fulfillment failures but NOT roll back\n * the already-delivered resource.\n *\n * Re-decodes `paymentPayload.payload` to extract `trade_no` (verify\n * does the same; the redundant Base64URL decode is negligible).\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n _requirements: X402PaymentRequirements,\n ): Promise<SettleResult> {\n try {\n const proofHeader = extractProofHeader(paymentPayload.payload);\n const decoded = decodeProof(proofHeader);\n const tradeNo = decoded.protocol.trade_no;\n\n const response = await alipayOpenApiCall(\n 'alipay.aipay.agent.fulfillment.confirm',\n { trade_no: tradeNo },\n this.getOpenApiConfig(),\n );\n\n if (response.code !== '10000') {\n return {\n success: false,\n transaction: tradeNo,\n error: `alipay fulfillment ${response.code}: ${response.sub_msg ?? response.msg ?? 'unknown'}`,\n status: 'fulfillment_failed',\n };\n }\n\n return {\n success: true,\n transaction: tradeNo,\n status: 'fulfilled',\n };\n } catch (e: unknown) {\n return {\n success: false,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n }\n\n /**\n * Validate that the configured RSA keys parse and that the Open API\n * gateway is reachable. Does NOT make a real business API call (would\n * burn quota and could appear as a legitimate verify attempt in logs).\n */\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n\n try {\n crypto.createPrivateKey(this.config.private_key_pem);\n } catch (e: unknown) {\n return {\n healthy: false,\n error: `merchant private_key_pem parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n try {\n crypto.createPublicKey(this.config.alipay_public_key_pem);\n } catch (e: unknown) {\n return {\n healthy: false,\n error: `alipay_public_key_pem parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n\n const gatewayUrl = this.config.gateway_url ?? ALIPAY_GATEWAY_PROD;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const response = await fetch(gatewayUrl, {\n method: 'HEAD',\n signal: controller.signal,\n }).catch(() => null);\n clearTimeout(timeout);\n\n const latencyMs = Date.now() - start;\n\n if (!response) {\n return { healthy: false, error: `gateway unreachable: ${gatewayUrl}`, latencyMs };\n }\n return { healthy: true, latencyMs };\n }\n\n /** Bundle the facilitator config into the shape openapi.ts wants. */\n private getOpenApiConfig(): AlipayOpenApiConfig {\n return {\n gateway_url: this.config.gateway_url ?? ALIPAY_GATEWAY_PROD,\n app_id: this.config.app_id,\n private_key_pem: this.config.private_key_pem,\n alipay_public_key_pem: this.config.alipay_public_key_pem,\n sign_type: this.config.sign_type,\n };\n }\n}\n\n// ─── Internal helpers (exported for unit testing only) ────────────────────────\n\n/**\n * Generate a 32-char `out_trade_no` with `VID` prefix + 29 random base64url\n * chars. Cryptographically random; uniqueness is statistical.\n *\n * @internal\n */\nexport function generateOutTradeNo(): string {\n // 22 random bytes → 30 base64url chars; slice 29 + \"VID\" prefix = 32 chars.\n return 'VID' + crypto.randomBytes(22).toString('base64url').slice(0, 29);\n}\n\n/**\n * Format `pay_before` as ISO 8601 UTC, exactly\n * {@link ALIPAY_PAY_BEFORE_MS} after the provided instant.\n * Strips fractional seconds for cleaner querystring signing.\n *\n * @internal\n */\nexport function formatPayBefore(now: Date): string {\n const expiry = new Date(now.getTime() + ALIPAY_PAY_BEFORE_MS);\n // toISOString returns \"YYYY-MM-DDTHH:mm:ss.sssZ\"; strip the ms.\n return expiry.toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n\n/**\n * Extract the Base64URL Payment-Proof header from `paymentPayload.payload`.\n * Accepts a bare string or an object with `paymentProof` / `proofHeader` key.\n *\n * @internal\n * @throws If the payload shape doesn't match either contract\n */\nexport function extractProofHeader(payload: unknown): string {\n if (typeof payload === 'string') {\n if (payload.length === 0) {\n throw new Error('alipay Payment-Proof is empty');\n }\n return payload;\n }\n if (payload !== null && typeof payload === 'object') {\n const obj = payload as Record<string, unknown>;\n const candidate = obj.paymentProof ?? obj.proofHeader;\n if (typeof candidate === 'string' && candidate.length > 0) {\n return candidate;\n }\n }\n throw new Error(\n 'alipay payment payload must be a Base64URL string or ' +\n '{paymentProof: string} / {proofHeader: string}',\n );\n}\n\n/**\n * Decode a Base64URL Payment-Proof header into its `{protocol, method}`\n * JSON shape, validating the three fields used by verify\n * (`protocol.payment_proof`, `protocol.trade_no`, `method.client_session`).\n *\n * @internal\n * @throws If decoding fails or required fields are missing\n */\nexport function decodeProof(proofHeader: string): AlipayPaymentProof {\n let parsed: unknown;\n try {\n parsed = JSON.parse(decodeBase64UrlWithPadFix(proofHeader));\n } catch (e: unknown) {\n throw new Error(\n `failed to decode Payment-Proof: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n if (parsed === null || typeof parsed !== 'object') {\n throw new Error('decoded Payment-Proof is not an object');\n }\n const obj = parsed as Record<string, unknown>;\n const protocol = obj.protocol as Record<string, unknown> | undefined;\n const method = obj.method as Record<string, unknown> | undefined;\n if (!protocol || typeof protocol.payment_proof !== 'string') {\n throw new Error('decoded Payment-Proof missing protocol.payment_proof');\n }\n if (typeof protocol.trade_no !== 'string') {\n throw new Error('decoded Payment-Proof missing protocol.trade_no');\n }\n if (!method || typeof method.client_session !== 'string') {\n throw new Error('decoded Payment-Proof missing method.client_session');\n }\n return parsed as AlipayPaymentProof;\n}\n","/**\n * RSA2 (SHA256WithRSA) signing helpers for Alipay AI 收.\n *\n * Uses Node's built-in `crypto` module. On the merchant side, MoltsPay\n * signs the 8 fields of the 402 challenge in dictionary order\n * (`amount` / `currency` / `goods_name` / `out_trade_no` / `pay_before` /\n * `resource_id` / `seller_id` / `service_id`). On the verify side, the\n * Alipay platform public key is used against `Payment-Proof` headers.\n *\n * Padding: PKCS#1 v1.5 (Node default for `RSA-SHA256`), matching Alipay's\n * `SHA256WithRSA` algorithm identifier.\n */\n\nimport crypto from 'node:crypto';\n\n/**\n * Sign a string with RSA2 (SHA256WithRSA) using a PEM-encoded private key.\n *\n * @param data - The exact bytes to sign (already dictionary-sorted querystring)\n * @param privateKeyPem - PKCS#1 or PKCS#8 PEM-encoded RSA private key\n * @returns Base64-encoded signature suitable for the `seller_signature` field\n * @throws If the private key is malformed\n */\nexport function rsa2Sign(data: string, privateKeyPem: string): string {\n const signer = crypto.createSign('RSA-SHA256');\n signer.update(data, 'utf-8');\n signer.end();\n return signer.sign(privateKeyPem, 'base64');\n}\n\n/**\n * Verify an RSA2 signature against the Alipay platform public key.\n *\n * Returns `false` (never throws) for any failure — malformed input,\n * wrong key, tampered data, or invalid base64. Untrusted callers can\n * pass arbitrary `Payment-Proof` bytes safely.\n *\n * @param data - The exact bytes that were signed\n * @param signature - Base64-encoded signature from `Payment-Proof`\n * @param publicKeyPem - PEM-encoded Alipay platform public key\n * @returns `true` if and only if the signature is valid\n */\nexport function rsa2Verify(\n data: string,\n signature: string,\n publicKeyPem: string,\n): boolean {\n try {\n const verifier = crypto.createVerify('RSA-SHA256');\n verifier.update(data, 'utf-8');\n verifier.end();\n return verifier.verify(publicKeyPem, signature, 'base64');\n } catch {\n return false;\n }\n}\n","/**\n * Base64URL encoding helpers for Alipay AI 收 wire format.\n *\n * Alipay's `Payment-Needed` and `Payment-Proof` headers use Base64URL\n * (`-` replaces `+`, `_` replaces `/`, padding optional). Some proxies\n * strip the trailing `=` padding; `decodeBase64UrlWithPadFix` recovers it\n * and accepts either alphabet.\n */\n\n/**\n * Encode a UTF-8 string as Base64URL (no padding).\n *\n * @param input - UTF-8 string to encode\n * @returns Base64URL representation (no `=` padding)\n */\nexport function base64url(input: string): string {\n return Buffer.from(input, 'utf-8').toString('base64url');\n}\n\n/**\n * Decode a Base64URL (or standard Base64) string to a UTF-8 string.\n *\n * Tolerates either URL-safe (`-` `_`) or standard (`+` `/`) alphabets,\n * with or without trailing `=` padding. Used for `Payment-Needed` and\n * `Payment-Proof` headers where proxies may strip padding.\n *\n * @param input - Base64URL or Base64 string\n * @returns Decoded UTF-8 string\n */\nexport function decodeBase64UrlWithPadFix(input: string): string {\n const normalized = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);\n return Buffer.from(padded, 'base64').toString('utf-8');\n}\n\n/**\n * Normalize an RSA key into PEM form.\n *\n * Alipay Open Platform hands out keys as **bare Base64** (a single line of\n * Base64-encoded DER, no `-----BEGIN-----` armor), but Node's `crypto`\n * key loaders and {@link rsa2Sign} require PEM. This wraps bare Base64 in\n * the requested PEM armor (64-char lines per RFC 7468); input that already\n * carries a `-----BEGIN` header is returned unchanged (trimmed).\n *\n * @param key Bare Base64 (DER) or an already-armored PEM string.\n * @param kind `'PRIVATE'` → PKCS#8 `PRIVATE KEY`; `'PUBLIC'` → SPKI `PUBLIC KEY`.\n */\nexport function toPem(key: string, kind: 'PRIVATE' | 'PUBLIC'): string {\n const trimmed = key.trim();\n if (trimmed.includes('-----BEGIN')) return trimmed;\n const label = kind === 'PRIVATE' ? 'PRIVATE KEY' : 'PUBLIC KEY';\n const body = trimmed.replace(/\\s+/g, '').match(/.{1,64}/g)?.join('\\n') ?? '';\n return `-----BEGIN ${label}-----\\n${body}\\n-----END ${label}-----\\n`;\n}\n","/**\n * Alipay Open API caller for AI 收 verify and fulfillment.\n *\n * Wraps the `application/x-www-form-urlencoded` gateway protocol\n * (`https://openapi.alipay.com/gateway.do` for production,\n * `https://openapi.alipaydev.com/gateway.do` for sandbox). Handles\n * RSA2 request signing, response unwrapping, and gateway-level error\n * surfacing.\n *\n * Request envelope (8 public params + `sign`):\n * app_id — application ID\n * method — e.g. `alipay.aipay.agent.payment.verify`\n * format — `JSON`\n * charset — `utf-8`\n * sign_type — `RSA2`\n * timestamp — `YYYY-MM-DD HH:mm:ss`\n * version — `1.0`\n * biz_content — JSON-stringified business params\n * sign — RSA2 signature over the other 8 params sorted by key\n *\n * Response envelope:\n * { \"<method_with_underscores>_response\": { code, msg, ... } }\n *\n * NOTE: Response signature verification against the Alipay platform\n * public key is NOT implemented (relies on HTTPS transport integrity).\n * Adding it requires extracting raw bytes for the wrapped response key\n * from the response text; deferred to a future hardening pass.\n */\n\nimport { rsa2Sign } from './rsa2.js';\n\n/**\n * Configuration required to make a single Open API call.\n */\nexport interface AlipayOpenApiConfig {\n gateway_url: string;\n app_id: string;\n private_key_pem: string;\n alipay_public_key_pem: string;\n sign_type?: 'RSA2';\n}\n\n/**\n * Unwrapped response from an Alipay Open API call.\n *\n * `code` is the Alipay business code (`\"10000\"` = success).\n * `sub_code` / `sub_msg` carry the specific failure reason when `code != \"10000\"`.\n */\nexport interface AlipayOpenApiResponse {\n code: string;\n msg?: string;\n sub_code?: string;\n sub_msg?: string;\n [key: string]: unknown;\n}\n\n/**\n * Format a JS Date as Alipay's expected `YYYY-MM-DD HH:mm:ss` timestamp.\n * Uses local time (matches the convention of merchant-region Open API SDKs).\n *\n * Exported for unit testing only.\n */\nexport function formatAlipayTimestamp(d: Date = new Date()): string {\n const pad = (n: number): string => String(n).padStart(2, '0');\n return (\n `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +\n `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`\n );\n}\n\n/**\n * Build the signing string for a set of Alipay Open API parameters:\n * keys sorted alphabetically, joined as `key=value&key=value`. Values\n * are NOT URL-encoded at this stage.\n *\n * Exported for unit testing only.\n */\nexport function buildSigningString(params: Record<string, string>): string {\n return Object.keys(params)\n .sort()\n .map((k) => `${k}=${params[k]}`)\n .join('&');\n}\n\n/**\n * Derive the response wrapper key for a given method name.\n *\n * \"alipay.aipay.agent.payment.verify\"\n * → \"alipay_aipay_agent_payment_verify_response\"\n *\n * Exported for unit testing only.\n */\nexport function responseWrapperKey(method: string): string {\n return `${method.replace(/\\./g, '_')}_response`;\n}\n\n/**\n * Call an Alipay Open API method.\n *\n * Common methods used by MoltsPay:\n * - `alipay.aipay.agent.payment.verify` — verify a `Payment-Proof`\n * - `alipay.aipay.agent.fulfillment.confirm` — confirm fulfillment\n *\n * @param method - Alipay Open API method name\n * @param bizContent - Method-specific business parameters\n * @param config - Gateway URL + credentials\n * @returns Unwrapped business response; check `code === \"10000\"` for success\n * @throws On HTTP-level failure, malformed JSON, or missing response wrapper\n */\nexport async function alipayOpenApiCall(\n method: string,\n bizContent: Record<string, unknown>,\n config: AlipayOpenApiConfig,\n): Promise<AlipayOpenApiResponse> {\n const publicParams: Record<string, string> = {\n app_id: config.app_id,\n method,\n format: 'JSON',\n charset: 'utf-8',\n sign_type: config.sign_type ?? 'RSA2',\n timestamp: formatAlipayTimestamp(),\n version: '1.0',\n biz_content: JSON.stringify(bizContent),\n };\n\n const signingString = buildSigningString(publicParams);\n const sign = rsa2Sign(signingString, config.private_key_pem);\n\n const body = new URLSearchParams({ ...publicParams, sign }).toString();\n\n const response = await fetch(config.gateway_url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',\n },\n body,\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '<unreadable>');\n throw new Error(\n `Alipay Open API HTTP ${response.status} for ${method}: ${text.slice(0, 500)}`,\n );\n }\n\n const json = (await response.json()) as Record<string, unknown>;\n const wrapperKey = responseWrapperKey(method);\n const business = json[wrapperKey];\n\n if (business === undefined || business === null || typeof business !== 'object') {\n throw new Error(\n `Alipay Open API response missing \"${wrapperKey}\" wrapper for ${method}: ` +\n `${JSON.stringify(json).slice(0, 500)}`,\n );\n }\n\n return business as AlipayOpenApiResponse;\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';\nimport { TempoFacilitator } from './tempo.js';\nimport { BNBFacilitator } from './bnb.js';\nimport { SolanaFacilitator, SolanaFacilitatorConfig } from './solana.js';\nimport { AlipayFacilitator, AlipayFacilitatorConfig } from './alipay.js';\nimport { Keypair } from '@solana/web3.js';\nimport bs58 from 'bs58';\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 this.registerFactory('tempo', () => new TempoFacilitator());\n this.registerFactory('bnb', (config) => new BNBFacilitator(config?.serverPrivateKey as string));\n this.registerFactory('solana', (config) => {\n // Load fee payer keypair from config or env\n let feePayerKeypair: Keypair | undefined;\n const feePayerKey = (config as any)?.feePayerPrivateKey || process.env.SOLANA_FEE_PAYER_KEY;\n \n if (feePayerKey) {\n try {\n feePayerKeypair = Keypair.fromSecretKey(bs58.decode(feePayerKey));\n } catch (e: any) {\n console.warn(`[SolanaFacilitator] Invalid fee payer key: ${e.message}`);\n }\n }\n \n return new SolanaFacilitator({ feePayerKeypair } as SolanaFacilitatorConfig);\n });\n this.registerFactory('alipay', (config) => new AlipayFacilitator(config as unknown as AlipayFacilitatorConfig));\n\n // Default selection — alipay is opt-in (requires provider.alipay config), kept out of fallback list\n this.selection = selection || { primary: 'cdp', fallback: ['tempo', 'bnb', 'solana'], 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":["import_fs","path","TRANSFER_EVENT_TOPIC","TRANSFER_EVENT_TOPIC","ethers","import_web3","config","import_node_crypto","crypto","crypto","import_web3","bs58","X402_VERSION","loadEnvFile","resolve","settlement"]}
1
+ {"version":3,"sources":["../../src/server/index.ts","../../src/facilitators/interface.ts","../../src/facilitators/cdp.ts","../../src/facilitators/tempo.ts","../../src/chains/index.ts","../../src/facilitators/bnb.ts","../../src/facilitators/solana.ts","../../src/chains/solana.ts","../../src/facilitators/alipay.ts","../../src/facilitators/alipay/rsa2.ts","../../src/facilitators/alipay/encoding.ts","../../src/facilitators/alipay/openapi.ts","../../src/facilitators/wechat.ts","../../src/facilitators/wechat/sign.ts","../../src/facilitators/wechat/api.ts","../../src/facilitators/balance/ledger.ts","../../src/facilitators/balance/auth.ts","../../src/facilitators/balance.ts","../../src/facilitators/registry.ts","../../src/server/balance-endpoints.ts","../../src/verify/index.ts","../../src/server/internal.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 } from 'fs';\nimport { createServer, IncomingMessage, ServerResponse } from 'http';\nimport * as path from 'path';\nimport crypto from 'node:crypto';\nimport {\n FacilitatorRegistry,\n FacilitatorSelection,\n FacilitatorConfig,\n X402PaymentPayload,\n X402PaymentRequirements,\n SettleResult,\n AlipayFacilitator,\n AlipayFacilitatorConfig,\n ALIPAY_NETWORK,\n ALIPAY_SCHEME,\n WechatFacilitator,\n WechatFacilitatorConfig,\n WECHAT_NETWORK,\n WECHAT_SCHEME,\n WECHAT_TIME_EXPIRE_MS,\n BalanceFacilitator,\n BalanceFacilitatorConfig,\n BALANCE_SCHEME,\n extractBalancePayload,\n verifyDeductAuth,\n} from '../facilitators/index.js';\nimport { toPem } from '../facilitators/alipay/encoding.js';\nimport { BalanceEndpoints } from './balance-endpoints.js';\nimport { isAlipayChainId, isWechatChainId, isBalanceChainId } from '../chains/index.js';\nimport {\n ServicesManifest,\n ServiceConfig,\n SkillFunction,\n RegisteredSkill,\n MoltsPayServerOptions,\n CorsOptions,\n} from './types.js';\n\nexport * from './types.js';\n\n// Server-internal constants and pure helpers (extracted to ./internal.ts).\nimport {\n X402_VERSION, PAYMENT_REQUIRED_HEADER, PAYMENT_HEADER, PAYMENT_RESPONSE_HEADER,\n MPP_AUTH_HEADER, MPP_WWW_AUTH_HEADER, MPP_RECEIPT_HEADER,\n ALIPAY_PAYMENT_NEEDED_HEADER, ALIPAY_PAYMENT_PROOF_HEADER,\n headerSafe, canonicalJson, TOKEN_ADDRESSES, CHAIN_TO_NETWORK, isSolanaNetwork,\n getTokenDomain, getAcceptedCurrencies, loadEnvFile,\n} from './internal.js';\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 /** Alipay AI Pay facilitator instance, set when `provider.alipay` is configured (2.0.0). */\n private alipayFacilitator: AlipayFacilitator | null = null;\n /** WeChat Pay Native facilitator instance, set when `provider.wechat` is configured (2.1.0). */\n private wechatFacilitator: WechatFacilitator | null = null;\n /** Custodial balance facilitator instance, set when `provider.balance` is configured (2.2.0). */\n private balanceFacilitator: BalanceFacilitator | null = null;\n private balanceEndpoints: BalanceEndpoints | null = null;\n /**\n * Pending WeChat Native order cache — the double-charge fix.\n *\n * Every `buildWechatChallenge` used to place a NEW Native order, so a client\n * that received two 402s (e.g. initial challenge + one poll re-request that\n * raced ahead of payment) could surface two live QRs and a buyer could pay\n * both (confirmed ¥0.07×2 on 2026-07-02). Now the unpaid order is cached\n * under a content-derived key — sha256(service id | canonical params |\n * price_cny) — and reused until it is paid or its `time_expire` window\n * nears expiry, so any number of 402 emits for the same purchase intent\n * share ONE order, even across separate client processes.\n * Storing the in-flight promise also dedupes concurrent 402 builds.\n * In-memory by design: on restart the worst case is one extra unpaid order,\n * which expires server-side per `time_expire` — never a double charge.\n */\n private wechatPendingChallenges: Map<string, {\n promise: Promise<{ accepts: X402PaymentRequirements; codeUrl: string; outTradeNo: string } | null>;\n expiresAtMs: number;\n outTradeNo?: string;\n }> = new Map();\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 default network from env (fallback only)\n // NOTE: Chain is auto-detected from client payment header (payment.network)\n // USE_MAINNET is only used as fallback when payment header omits network\n // Recommended: configure \"chains\" array in manifest instead\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 // Always include 'tempo', 'bnb', and 'solana' in fallback for multi-chain support\n const defaultFallback = ['tempo', 'bnb', 'solana'];\n const envFallback = process.env.FACILITATOR_FALLBACK?.split(',').filter(Boolean);\n const facilitatorConfig: FacilitatorSelection = options.facilitators || {\n primary: process.env.FACILITATOR_PRIMARY || 'cdp',\n fallback: envFallback || defaultFallback,\n strategy: (process.env.FACILITATOR_STRATEGY as any) || 'failover',\n config: {\n cdp: { useMainnet: this.useMainnet },\n },\n };\n\n // ── Alipay AI Pay fiat rail (2.0.0): opt-in via provider.alipay ──\n // When configured, resolve the PEM key files (the manifest stores PATHS,\n // the facilitator wants PEM STRINGS) and register the facilitator in the\n // selection so registry.verify/settle route `network: \"alipay\"` to it.\n // Key-load failure is fatal: a misconfigured alipay rail must not start\n // silently and then 500 on the first payment.\n const providerAlipay = this.manifest.provider.alipay;\n if (providerAlipay) {\n try {\n const baseDir = path.dirname(servicesPath);\n // Alipay hands out keys as bare Base64 (no PEM armor); toPem normalizes\n // both that and already-armored PEM into the PEM the facilitator needs.\n const resolvePem = (p: string, kind: 'PRIVATE' | 'PUBLIC') =>\n toPem(readFileSync(path.isAbsolute(p) ? p : path.resolve(baseDir, p), 'utf-8'), kind);\n const alipayFacilitatorConfig: AlipayFacilitatorConfig = {\n seller_id: providerAlipay.seller_id,\n app_id: providerAlipay.app_id,\n seller_name: providerAlipay.seller_name,\n service_id_default: providerAlipay.service_id_default,\n private_key_pem: resolvePem(providerAlipay.private_key_path, 'PRIVATE'),\n alipay_public_key_pem: resolvePem(providerAlipay.alipay_public_key_path, 'PUBLIC'),\n gateway_url: providerAlipay.gateway_url,\n sign_type: providerAlipay.sign_type,\n };\n facilitatorConfig.config = {\n ...facilitatorConfig.config,\n alipay: alipayFacilitatorConfig as unknown as FacilitatorConfig,\n };\n facilitatorConfig.fallback = facilitatorConfig.fallback || [];\n if (facilitatorConfig.primary !== 'alipay' && !facilitatorConfig.fallback.includes('alipay')) {\n facilitatorConfig.fallback.push('alipay');\n }\n } catch (err: any) {\n throw new Error(`[MoltsPay] Alipay rail configured but key load failed: ${err.message}`);\n }\n }\n\n // ── WeChat Pay v3 Native fiat rail (2.1.0): opt-in via provider.wechat ──\n // Same model as Alipay: resolve the PEM key files (manifest stores PATHS,\n // the facilitator wants PEM STRINGS) and register the facilitator so\n // registry.verify/settle route `network: \"wechat\"` to it. The platform\n // public key may be a public-key PEM OR an X.509 certificate PEM; the\n // latter is normalized to a public-key PEM via X509Certificate. Key-load\n // failure is fatal — a misconfigured rail must not start silently.\n const providerWechat = this.manifest.provider.wechat;\n if (providerWechat) {\n try {\n const baseDir = path.dirname(servicesPath);\n const readPem = (p: string) =>\n readFileSync(path.isAbsolute(p) ? p : path.resolve(baseDir, p), 'utf-8');\n const toPublicKeyPem = (pem: string): string =>\n pem.includes('BEGIN CERTIFICATE')\n ? new crypto.X509Certificate(pem).publicKey.export({ type: 'spki', format: 'pem' }).toString()\n : pem;\n const wechatFacilitatorConfig: WechatFacilitatorConfig = {\n mchid: providerWechat.mchid,\n appid: providerWechat.appid,\n serial_no: providerWechat.serial_no,\n private_key_pem: readPem(providerWechat.private_key_path),\n platform_public_key_pem: providerWechat.platform_public_key_path\n ? toPublicKeyPem(readPem(providerWechat.platform_public_key_path))\n : undefined,\n apiv3_key: providerWechat.apiv3_key,\n notify_url: providerWechat.notify_url,\n api_base: providerWechat.api_base,\n };\n facilitatorConfig.config = {\n ...facilitatorConfig.config,\n wechat: wechatFacilitatorConfig as unknown as FacilitatorConfig,\n };\n facilitatorConfig.fallback = facilitatorConfig.fallback || [];\n if (facilitatorConfig.primary !== 'wechat' && !facilitatorConfig.fallback.includes('wechat')) {\n facilitatorConfig.fallback.push('wechat');\n }\n } catch (err: any) {\n throw new Error(`[MoltsPay] WeChat rail configured but key load failed: ${err.message}`);\n }\n }\n\n // ── Custodial balance rail (2.2.0): opt-in via provider.balance ──\n // No key material — just resolve the ledger db path relative to the\n // manifest. Ledger construction (and the Node >= 22.5 check inside it)\n // happens when the registry instantiates the facilitator below; a\n // failure there is fatal, same as a fiat-rail key-load failure.\n const providerBalance = this.manifest.provider.balance;\n if (providerBalance) {\n const baseDir = path.dirname(servicesPath);\n const balanceFacilitatorConfig: BalanceFacilitatorConfig = {\n db_path: providerBalance.db_path === ':memory:'\n ? providerBalance.db_path\n : path.isAbsolute(providerBalance.db_path)\n ? providerBalance.db_path\n : path.resolve(baseDir, providerBalance.db_path),\n currency: providerBalance.currency,\n single_limit: providerBalance.single_limit,\n daily_limit: providerBalance.daily_limit,\n auth_mode: providerBalance.auth_mode,\n };\n facilitatorConfig.config = {\n ...facilitatorConfig.config,\n balance: balanceFacilitatorConfig as unknown as FacilitatorConfig,\n };\n facilitatorConfig.fallback = facilitatorConfig.fallback || [];\n if (facilitatorConfig.primary !== 'balance' && !facilitatorConfig.fallback.includes('balance')) {\n facilitatorConfig.fallback.push('balance');\n }\n }\n\n this.registry = new FacilitatorRegistry(facilitatorConfig);\n\n if (providerAlipay) {\n this.alipayFacilitator = this.registry.get('alipay') as AlipayFacilitator;\n console.log(`[MoltsPay] Alipay AI Pay rail enabled (seller ${providerAlipay.seller_id})`);\n }\n\n if (providerWechat) {\n this.wechatFacilitator = this.registry.get('wechat') as WechatFacilitator;\n console.log(`[MoltsPay] WeChat Pay rail enabled (mchid ${providerWechat.mchid})`);\n }\n\n if (providerBalance) {\n this.balanceFacilitator = this.registry.get('balance') as BalanceFacilitator;\n // WeChat is set up before balance, so wechatFacilitator is final here.\n this.balanceEndpoints = new BalanceEndpoints({\n manifest: this.manifest,\n balance: this.balanceFacilitator,\n wechat: this.wechatFacilitator,\n sendJson: (res, status, data) => this.sendJson(res, status, data),\n getOrCreatePendingWechatOrder: (cacheKey, logLabel, create) =>\n this.getOrCreatePendingWechatOrder(cacheKey, logLabel, create),\n invalidateWechatChallenge: (outTradeNo) => this.invalidateWechatChallenge(outTradeNo),\n });\n console.log(`[MoltsPay] Custodial balance rail enabled (ledger ${providerBalance.db_path})`);\n }\n\n // Get primary facilitator for logging\n const primaryFacilitator = this.registry.get(facilitatorConfig.primary);\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 \n // Log configured chains\n const chains = this.manifest.provider.chains;\n if (chains && chains.length > 0) {\n const chainNames = chains.map(c => c.chain || c.network).join(', ');\n console.log(`[MoltsPay] Chains: ${chainNames} (multi-chain enabled)`);\n } else {\n const networkName = this.useMainnet ? 'Base mainnet' : 'Base Sepolia (testnet)';\n console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);\n }\n \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 * Get all configured chains for this provider\n * Returns array of { network, wallet, tokens } for each chain\n */\n private getProviderChains(): Array<{ network: string; wallet: string; tokens: string[] }> {\n const provider = this.manifest.provider;\n \n // Helper to get the right wallet for a chain\n const getWalletForChain = (chainName: string, explicitWallet?: string): string => {\n // If explicit wallet provided (object format), use it\n if (explicitWallet) return explicitWallet;\n // For Solana chains, use solana_wallet if available\n if ((chainName === 'solana' || chainName === 'solana_devnet') && provider.solana_wallet) {\n return provider.solana_wallet;\n }\n // Default to EVM wallet\n return provider.wallet;\n };\n \n // If chains array is defined, use it\n // Supports both string array [\"base\", \"polygon\"] and object array [{chain, wallet, tokens}]\n if (provider.chains && provider.chains.length > 0) {\n return provider.chains\n // Fiat rails (alipay/wechat) and the balance rail carry no EVM\n // network/token; they are emitted separately via\n // buildAlipayChallenge/buildWechatChallenge/buildBalanceChallenge.\n // Excluding them here prevents a spurious base/USDC accepts[] entry.\n .filter(c => {\n const chainName = typeof c === 'string' ? c : c.chain;\n return !isAlipayChainId(chainName) && !isWechatChainId(chainName) && !isBalanceChainId(chainName);\n })\n .map(c => {\n const chainName = typeof c === 'string' ? c : c.chain;\n const explicitWallet = typeof c === 'object' ? c.wallet : null;\n return {\n network: CHAIN_TO_NETWORK[chainName] || 'eip155:8453',\n wallet: getWalletForChain(chainName, explicitWallet || undefined),\n tokens: (typeof c === 'object' ? c.tokens : null) || ['USDC'],\n };\n });\n }\n \n // Fallback to single chain (backward compat)\n const chain = provider.chain || 'base';\n const network = CHAIN_TO_NETWORK[chain] || this.networkId;\n return [{\n network,\n wallet: getWalletForChain(chain),\n tokens: ['USDC'],\n }];\n }\n\n /**\n * Get wallet address for a specific network\n */\n private getWalletForNetwork(network: string): string {\n const chains = this.getProviderChains();\n const chain = chains.find(c => c.network === network);\n return chain?.wallet || this.manifest.provider.wallet;\n }\n\n /**\n * Check if a network is accepted by this provider\n */\n private isNetworkAccepted(network: string): boolean {\n const chains = this.getProviderChains();\n return chains.some(c => c.network === network);\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 * Apply CORS response headers according to the `cors` option.\n *\n * Default (`cors` unset or `true`): `Access-Control-Allow-Origin: *`. Matches 1.5.x behavior\n * and works for every browser client whose origin does not need to send cookies.\n *\n * `cors: false`: emit no CORS headers. Same-origin only.\n * `cors: string[]`: origin allowlist — echo the origin back iff it matches.\n * `cors: CorsOptions`: full control (allowlist + credentials + maxAge).\n *\n * The required-for-Web response headers are always exposed when CORS is active:\n * `X-Payment-Required, X-Payment-Response, WWW-Authenticate, Payment-Receipt`.\n */\n private applyCorsHeaders(req: IncomingMessage, res: ServerResponse): void {\n const cors = (this.options as MoltsPayServerOptions).cors;\n\n // Explicitly disabled: no CORS headers at all (strict same-origin).\n if (cors === false) {\n return;\n }\n\n const requestOrigin = (req.headers.origin as string | undefined) ?? '*';\n\n // Default / explicit `true`: open to any origin (legacy 1.5.x behavior).\n if (cors === undefined || cors === true) {\n this.writeCorsHeaders(res, '*');\n return;\n }\n\n // Array shortcut: origins allowlist, no credentials, default maxAge.\n if (Array.isArray(cors)) {\n if (cors.includes(requestOrigin)) {\n this.writeCorsHeaders(res, requestOrigin);\n res.setHeader('Vary', 'Origin');\n }\n // Origin not on the allowlist → no CORS headers; browser will block.\n return;\n }\n\n // Full CorsOptions object.\n const opt = cors as CorsOptions;\n const isAllowed =\n typeof opt.origins === 'function'\n ? opt.origins(requestOrigin)\n : opt.origins.includes(requestOrigin);\n if (!isAllowed) {\n return;\n }\n this.writeCorsHeaders(res, requestOrigin);\n res.setHeader('Vary', 'Origin');\n if (opt.credentials) {\n res.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n const maxAge = opt.maxAge ?? 600;\n res.setHeader('Access-Control-Max-Age', String(maxAge));\n }\n\n private writeCorsHeaders(res: ServerResponse, origin: string): void {\n res.setHeader('Access-Control-Allow-Origin', origin);\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Payment, Authorization, Payment-Proof');\n res.setHeader(\n 'Access-Control-Expose-Headers',\n 'X-Payment-Required, X-Payment-Response, WWW-Authenticate, Payment-Receipt, Payment-Needed'\n );\n }\n\n /**\n * Handle incoming request\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // CORS — honors the `cors` option (default true = allow any origin, matches 1.5.x).\n this.applyCorsHeaders(req, res);\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 // Root path — a caller (human or agent) landing on the base URL should be\n // guided into service discovery, not met with a bare 404. Serve the same\n // discovery payload as the well-known endpoint.\n if (url.pathname === '/' && 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 // Custodial balance rail management endpoints (2.2.0).\n if (url.pathname.startsWith('/balance') && this.balanceEndpoints) {\n if (url.pathname === '/balance' && req.method === 'GET') {\n return this.balanceEndpoints.handleQuery(url, res);\n }\n if (url.pathname === '/balance/topup/order' && req.method === 'POST') {\n const body = await this.readBody(req);\n return await this.balanceEndpoints.handleTopupOrder(body, res);\n }\n if (url.pathname === '/balance/topup/confirm' && req.method === 'POST') {\n const body = await this.readBody(req);\n return await this.balanceEndpoints.handleTopupConfirm(body, res);\n }\n if (url.pathname === '/balance/topup' && req.method === 'POST') {\n const body = await this.readBody(req);\n return await this.balanceEndpoints.handleTopup(body, res);\n }\n if (url.pathname === '/balance/refund' && req.method === 'POST') {\n const body = await this.readBody(req);\n return this.balanceEndpoints.handleRefund(body, res);\n }\n if (url.pathname === '/balance/transactions' && req.method === 'GET') {\n return this.balanceEndpoints.handleTransactions(url, res);\n }\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 const proofHeader = req.headers[ALIPAY_PAYMENT_PROOF_HEADER] as string | undefined;\n return await this.handleExecute(body, paymentHeader, res, proofHeader);\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 const authHeader = req.headers[MPP_AUTH_HEADER] as string | undefined;\n return await this.handleProxy(body, paymentHeader, authHeader, res);\n }\n\n // MPP Protocol: Handle service-specific endpoints like /text-to-video, /ping\n // Check if URL matches a registered service ID\n const servicePath = url.pathname.replace(/^\\//, ''); // Remove leading slash\n const skill = this.skills.get(servicePath);\n if (skill && (req.method === 'POST' || req.method === 'GET')) {\n const body = req.method === 'POST' ? await this.readBody(req) : {};\n const authHeader = req.headers[MPP_AUTH_HEADER] as string | undefined;\n const x402Header = req.headers[PAYMENT_HEADER] as string | undefined;\n const proofHeader = req.headers[ALIPAY_PAYMENT_PROOF_HEADER] as string | undefined;\n return await this.handleMPPRequest(skill, body, authHeader, x402Header, res, proofHeader);\n }\n\n // Not found — include discovery hints so a mistyped or unknown path still\n // points the caller at service discovery instead of a dead end.\n this.sendJson(res, 404, {\n error: 'Not found',\n discovery: `${this.publicBase}/.well-known/agent-services.json`,\n endpoints: [`${this.publicBase}/health`, `${this.publicBase}/services`, `${this.publicBase}/execute`],\n });\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 * Public base URL prefix for self-describing links, from PUBLIC_BASE_URL\n * (trailing slash stripped). Empty when unset, so emitted paths stay\n * root-relative — behavior is unchanged for local / no-prefix deploys.\n *\n * Needed because nginx rewrites the deployment prefix (e.g.\n * `/t/moltspay-server`) away before proxying, so the process cannot infer\n * its own public prefix; a root-relative `/services` would otherwise\n * resolve against the domain root and hit the wrong backend.\n */\n private get publicBase(): string {\n return (process.env.PUBLIC_BASE_URL || '').replace(/\\/+$/, '');\n }\n\n /**\n * Per-service pricing across every configured rail, for the discovery\n * payloads. The top-level `price`/`currency` (crypto/USDC) stay unchanged\n * for back-compat; this surfaces the fiat + balance rails (CNY) that were\n * previously invisible in discovery even though the manifest defines them\n * and the 402 challenge already quotes them. `acceptedCurrencies` becomes\n * the union across rails so a client can see CNY is accepted without\n * first triggering a 402.\n */\n private describeServicePricing(s: ServiceConfig): {\n acceptedCurrencies: string[];\n pricing: Array<{ rail: string; currency: string; amount: string }>;\n } {\n const pricing: Array<{ rail: string; currency: string; amount: string }> = [];\n // Only advertise the crypto rail when the provider actually has crypto\n // chains configured. Otherwise discovery would promise a rail that the 402\n // challenge never offers (getProviderChains drives those accepts[]), and a\n // client would waste an attempt on a payment path that cannot succeed.\n if (this.getProviderChains().length > 0) {\n for (const currency of getAcceptedCurrencies(s)) {\n pricing.push({ rail: 'crypto', currency, amount: String(s.price) });\n }\n }\n if (s.alipay) pricing.push({ rail: 'alipay', currency: 'CNY', amount: s.alipay.price_cny });\n if (s.wechat) pricing.push({ rail: 'wechat', currency: 'CNY', amount: s.wechat.price_cny });\n if (s.balance) {\n pricing.push({\n rail: 'balance',\n currency: this.manifest.provider.balance?.currency ?? 'CNY',\n amount: s.balance.price ?? s.price.toFixed(2),\n });\n }\n return { acceptedCurrencies: [...new Set(pricing.map(p => p.currency))], pricing };\n }\n\n /** Shared service-list entry for the discovery and /services endpoints. */\n private buildDiscoveryService(s: ServiceConfig) {\n const { acceptedCurrencies, pricing } = this.describeServicePricing(s);\n // The legacy top-level price/currency are the USDC list price. On a server\n // that no longer accepts crypto they are a lie that reads as an offer --\n // an agent quotes \"$0.10 USDC\" and tries to pay a rail with no accepts[]\n // entry. When crypto is not on offer, headline the first rail that is.\n const headline = pricing.find(p => p.rail === 'crypto') ?? pricing[0];\n return {\n id: s.id,\n name: s.name,\n description: s.description,\n price: headline ? Number(headline.amount) : s.price,\n currency: headline ? headline.currency : s.currency,\n acceptedCurrencies,\n pricing,\n input: s.input,\n output: s.output,\n available: this.skills.has(s.id),\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 => this.buildDiscoveryService(s));\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 solana_wallet: this.manifest.provider.solana_wallet,\n chains: this.manifest.provider.chains,\n },\n services,\n endpoints: {\n services: `${this.publicBase}/services`,\n execute: `${this.publicBase}/execute`,\n health: `${this.publicBase}/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 => this.buildDiscoveryService(s));\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 proofHeader?: string\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 // Alipay fiat rail (2.0.0): a `Payment-Proof` header means the buyer paid\n // via alipay-bot and is re-requesting the resource with proof. Route to\n // the facilitator verify→fulfill path (the proof's Base64URL blob carries\n // payment_proof / trade_no / client_session).\n if (proofHeader) {\n const alipayPayment: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: ALIPAY_SCHEME,\n network: ALIPAY_NETWORK,\n payload: proofHeader,\n };\n return this.handleAlipayExecute(skill, params || {}, alipayPayment, res);\n }\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendPaymentRequired(skill.config, res, params || {});\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 // Alipay fiat rail (2.0.0): route by scheme/network BEFORE the EVM path.\n // validatePayment() only accepts 'exact'/'permit' schemes + EVM/SVM\n // networks, so an alipay payment must branch off here or it'd be rejected.\n const payScheme = payment.accepted?.scheme || payment.scheme;\n const payNetwork = payment.accepted?.network || payment.network;\n if (payScheme === ALIPAY_SCHEME || (payNetwork ? isAlipayChainId(payNetwork) : false)) {\n return this.handleAlipayExecute(skill, params || {}, payment, res);\n }\n if (payScheme === WECHAT_SCHEME || (payNetwork ? isWechatChainId(payNetwork) : false)) {\n return this.handleWechatExecute(skill, params || {}, payment, res);\n }\n if (payScheme === BALANCE_SCHEME || (payNetwork ? isBalanceChainId(payNetwork) : false)) {\n return this.handleBalanceExecute(skill, params || {}, payment, res);\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 // Auto-detect chain from payment header (key insight: client specifies chain via --chain flag)\n // payment.network contains \"eip155:8453\" (base) or \"eip155:84532\" (base_sepolia) etc.\n // This allows provider to serve both mainnet and testnet without separate configuration\n const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;\n const paymentWallet = this.getWalletForNetwork(paymentNetwork);\n\n // Build requirements for facilitator using the detected token and network\n const requirements = this.buildPaymentRequirements(skill.config, paymentNetwork, paymentWallet, paymentToken);\n\n // Verify payment with facilitator (via registry)\n console.log(`[MoltsPay] Verifying payment on ${paymentNetwork}...`);\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 // For Solana: settle FIRST (blockhash expires quickly ~60s)\n // For EVM: pay-for-success (execute first, settle after)\n const isSolana = isSolanaNetwork(paymentNetwork);\n let settlement: any = null;\n\n if (isSolana) {\n console.log(`[MoltsPay] Solana detected - settling payment FIRST (blockhash expiry protection)`);\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] Solana settlement failed:', err.message);\n return this.sendJson(res, 402, {\n error: 'Payment settlement failed',\n message: err.message,\n });\n }\n }\n\n // Execute skill (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 // For Solana: payment already settled, skill failed - no refund (user accepted risk)\n // For EVM: payment not settled yet, user keeps their money\n return this.sendJson(res, 500, {\n error: 'Service execution failed',\n message: err.message,\n paymentSettled: isSolana ? true : false,\n note: isSolana ? 'Payment was settled before execution. Contact support for refund.' : undefined,\n });\n }\n\n // For EVM: settle payment now (pay-for-success)\n if (!isSolana) {\n console.log(`[MoltsPay] Skill succeeded, settling payment...`);\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 settlement = { success: false, error: err.message, facilitator: 'none' };\n }\n\n // Match Solana semantics: settle failure → 402, do NOT claim payment\n // succeeded. Skill was already executed; provider absorbs the cost.\n if (!settlement?.success) {\n return this.sendJson(res, 402, {\n error: 'Payment settlement failed',\n message: settlement?.error || 'Settlement returned no success state',\n facilitator: settlement?.facilitator,\n });\n }\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 * Execute a service paid via the Alipay AI Pay fiat rail (2.0.0).\n *\n * Differs from the EVM/SVM path: no token detection, no EIP-3009/permit\n * validation. Verify hits the Alipay Open API (`payment.verify`). Settlement\n * (`fulfillment.confirm`) is FIRE-AND-FORGET per ALIPAY-INTEGRATION-DESIGN\n * §5.1: a confirm failure is logged but does NOT fail the already-delivered\n * response (the buyer's payment proof was already verified).\n */\n private async handleAlipayExecute(\n skill: RegisteredSkill,\n params: Record<string, any>,\n payment: X402PaymentPayload,\n res: ServerResponse\n ): Promise<void> {\n if (!this.alipayFacilitator) {\n return this.sendJson(res, 402, { error: 'Alipay rail not configured on this server' });\n }\n\n // Verify/settle ignore `requirements` (the proof carries everything), but\n // requirements.network drives registry routing to the alipay facilitator.\n const requirements: X402PaymentRequirements = {\n scheme: ALIPAY_SCHEME,\n network: ALIPAY_NETWORK,\n asset: 'CNY',\n amount: skill.config.alipay?.price_cny || '0',\n payTo: this.manifest.provider.alipay?.seller_id || '',\n maxTimeoutSeconds: 1800,\n };\n\n console.log(`[MoltsPay] Verifying Alipay 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] Alipay payment verified by ${verifyResult.facilitator}`);\n\n // Execute skill (same timeout contract as the EVM path).\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n console.log(`[MoltsPay] Executing skill: ${skill.id} (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 // Fulfillment confirm — fire-and-forget: log failures, never roll back.\n let settlement: (SettleResult & { facilitator: string });\n try {\n settlement = await this.registry.settle(payment, requirements);\n if (settlement.success) {\n console.log(`[MoltsPay] Alipay fulfillment confirmed: ${settlement.transaction}`);\n } else {\n console.error(`[MoltsPay] Alipay fulfillment confirm failed (non-fatal): ${settlement.error}`);\n }\n } catch (err: any) {\n console.error(`[MoltsPay] Alipay fulfillment confirm threw (non-fatal): ${err.message}`);\n settlement = { success: false, error: err.message, facilitator: 'alipay' };\n }\n\n const responseHeaders: Record<string, string> = {};\n if (settlement.success) {\n responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(JSON.stringify({\n success: true,\n transaction: settlement.transaction,\n network: ALIPAY_NETWORK,\n facilitator: settlement.facilitator,\n })).toString('base64');\n }\n\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: settlement.success\n ? { transaction: settlement.transaction, status: 'fulfilled', facilitator: settlement.facilitator }\n : { status: 'delivered_unconfirmed', error: settlement.error },\n }, responseHeaders);\n }\n\n /**\n * Build the Alipay 402 challenge for a service, or null when the alipay rail\n * isn't configured for this server or this service. Returns the x402\n * `accepts[]` entry plus the Base64URL `Payment-Needed` header value so the\n * 402 responders can dual-emit both the x402 and legacy alipay-bot formats.\n */\n private async buildAlipayChallenge(\n config: ServiceConfig\n ): Promise<{ accepts: X402PaymentRequirements; paymentNeededHeader: string } | null> {\n if (!this.alipayFacilitator || !config.alipay) return null;\n try {\n const req = await this.alipayFacilitator.createPaymentRequirements({\n serviceId: config.alipay.service_id || this.manifest.provider.alipay!.service_id_default,\n priceCny: config.alipay.price_cny,\n goodsName: config.alipay.goods_name,\n resourceId: `/execute?service=${config.id}`,\n });\n return { accepts: req.x402Accepts, paymentNeededHeader: req.paymentNeededHeader };\n } catch (err: any) {\n console.error(`[MoltsPay] Alipay challenge build failed for ${config.id}: ${err.message}`);\n return null;\n }\n }\n\n /**\n * Execute a service paid via the WeChat Pay v3 Native fiat rail (2.1.0).\n *\n * Differs from the EVM/SVM path: no token detection, no EIP-3009/permit\n * validation. The buyer (a human) scanned the Native QR and paid; the\n * client re-requests carrying `out_trade_no` in the X-Payment payload.\n * Verify queries the order (`trade_state === SUCCESS`). Settlement is an\n * idempotent re-confirm and is FIRE-AND-FORGET (mirrors the Alipay path):\n * a confirm failure is logged but does NOT fail the delivered response —\n * the order was already verified SUCCESS.\n */\n private async handleWechatExecute(\n skill: RegisteredSkill,\n params: Record<string, any>,\n payment: X402PaymentPayload,\n res: ServerResponse\n ): Promise<void> {\n if (!this.wechatFacilitator) {\n return this.sendJson(res, 402, { error: 'WeChat rail not configured on this server' });\n }\n\n // Verify/settle extract out_trade_no from the payload; requirements.network\n // drives registry routing to the wechat facilitator. Pass the client's\n // out_trade_no through requirements.extra as a fallback for verify().\n const outTradeNo =\n typeof payment.accepted?.extra?.out_trade_no === 'string'\n ? payment.accepted.extra.out_trade_no\n : undefined;\n const requirements: X402PaymentRequirements = {\n scheme: WECHAT_SCHEME,\n network: WECHAT_NETWORK,\n asset: 'CNY',\n amount: skill.config.wechat?.price_cny || '0',\n payTo: this.manifest.provider.wechat?.mchid || '',\n maxTimeoutSeconds: 300,\n extra: outTradeNo ? { out_trade_no: outTradeNo } : undefined,\n };\n\n console.log(`[MoltsPay] Verifying WeChat 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] WeChat payment verified by ${verifyResult.facilitator}`);\n\n // The order is consumed (Native: one code, one payment) — drop it from the\n // pending-challenge cache so the next 402 mints a fresh order.\n if (outTradeNo) {\n this.invalidateWechatChallenge(outTradeNo);\n }\n\n // Execute skill (same timeout contract as the EVM path).\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n console.log(`[MoltsPay] Executing skill: ${skill.id} (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 // Settlement confirm — fire-and-forget: log failures, never roll back.\n let settlement: (SettleResult & { facilitator: string });\n try {\n settlement = await this.registry.settle(payment, requirements);\n if (settlement.success) {\n console.log(`[MoltsPay] WeChat settlement confirmed: ${settlement.transaction}`);\n } else {\n console.error(`[MoltsPay] WeChat settlement confirm failed (non-fatal): ${settlement.error}`);\n }\n } catch (err: any) {\n console.error(`[MoltsPay] WeChat settlement confirm threw (non-fatal): ${err.message}`);\n settlement = { success: false, error: err.message, facilitator: 'wechat' };\n }\n\n const responseHeaders: Record<string, string> = {};\n if (settlement.success) {\n responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(JSON.stringify({\n success: true,\n transaction: settlement.transaction,\n network: WECHAT_NETWORK,\n facilitator: settlement.facilitator,\n })).toString('base64');\n }\n\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: settlement.success\n ? { transaction: settlement.transaction, status: 'fulfilled', facilitator: settlement.facilitator }\n : { status: 'delivered_unconfirmed', error: settlement.error },\n }, responseHeaders);\n }\n\n /**\n * Build the WeChat 402 challenge for a service, or null when the wechat rail\n * isn't configured for this server or this service. Placing a Native order\n * is a network call that returns a fresh `code_url` + `out_trade_no`; the\n * x402 `accepts[]` entry carries both in `extra` so the client can render\n * the QR and later echo `out_trade_no` back for verification.\n *\n * DOUBLE-CHARGE FIX: the unpaid order is cached per service id (see\n * `wechatPendingChallenges`), so repeated 402 emits within the order's\n * `time_expire` window return the SAME `code_url`/`out_trade_no` instead of\n * minting a new payable order each time. The entry is dropped once the\n * order is paid (`invalidateWechatChallenge`) or shortly before it expires\n * (refresh margin, so clients never receive a nearly-dead QR). A build\n * failure is not cached and degrades gracefully (the other rails'\n * accepts[] still ship).\n */\n private async buildWechatChallenge(\n config: ServiceConfig,\n params?: Record<string, any>\n ): Promise<{ accepts: X402PaymentRequirements } | null> {\n if (!this.wechatFacilitator || !config.wechat) return null;\n\n // Content-derived idempotency key: same service + same params + same\n // price ⇒ same pending order, even across separate client processes (a\n // client-random key could not dedupe two independent `pay` retries).\n // Distinct params get distinct orders, so one buyer's payment can never\n // cover another buyer's different work product. Documented limitation:\n // two buyers requesting the IDENTICAL service+params within the TTL share\n // one order (no buyer identity exists at 402 time — accepted).\n const cacheKey = crypto\n .createHash('sha256')\n .update(`${config.id}|${canonicalJson(params ?? {})}|${config.wechat.price_cny}`)\n .digest('hex');\n\n const result = await this.getOrCreatePendingWechatOrder(cacheKey, config.id, () =>\n this.wechatFacilitator!.createPaymentRequirements({\n priceCny: config.wechat!.price_cny,\n description: config.wechat!.description,\n }),\n );\n return result ? { accepts: result.accepts } : null;\n }\n\n /**\n * Get-or-create a pending WeChat Native order under `cacheKey`, deduping\n * concurrent builds and reusing an unpaid order until it nears expiry.\n * Shared by the 402 challenge path ({@link buildWechatChallenge}) and the\n * balance top-up order path ({@link handleBalanceTopupOrder}). See the\n * `wechatPendingChallenges` doc for the double-charge rationale.\n */\n private async getOrCreatePendingWechatOrder(\n cacheKey: string,\n logLabel: string,\n create: () => Promise<{ x402Accepts: X402PaymentRequirements; codeUrl: string; outTradeNo: string }>,\n ): Promise<{ accepts: X402PaymentRequirements; codeUrl: string; outTradeNo: string } | null> {\n const now = Date.now();\n const cached = this.wechatPendingChallenges.get(cacheKey);\n if (cached) {\n if (now < cached.expiresAtMs) {\n const hit = await cached.promise;\n if (hit) {\n console.log(`[MoltsPay] Reusing pending WeChat order ${hit.outTradeNo} for ${logLabel}`);\n return hit;\n }\n // Build failed after we joined it -- fall through to a fresh attempt.\n }\n this.wechatPendingChallenges.delete(cacheKey);\n }\n\n // Refresh 30s before the real order expiry so a just-served QR always has\n // usable life left (never less than half the window, for tiny expiries).\n const orderTtlMs = WECHAT_TIME_EXPIRE_MS;\n const cacheTtlMs = Math.max(orderTtlMs - 30_000, Math.floor(orderTtlMs / 2));\n\n const entry: {\n promise: Promise<{ accepts: X402PaymentRequirements; codeUrl: string; outTradeNo: string } | null>;\n expiresAtMs: number;\n outTradeNo?: string;\n } = {\n expiresAtMs: now + cacheTtlMs,\n promise: Promise.resolve(null),\n };\n entry.promise = (async () => {\n try {\n const req = await create();\n entry.outTradeNo = req.outTradeNo;\n return { accepts: req.x402Accepts, codeUrl: req.codeUrl, outTradeNo: req.outTradeNo };\n } catch (err: any) {\n console.error(`[MoltsPay] WeChat order build failed for ${logLabel}: ${err.message}`);\n // Never cache a failure -- the next attempt retries.\n this.wechatPendingChallenges.delete(cacheKey);\n return null;\n }\n })();\n this.wechatPendingChallenges.set(cacheKey, entry);\n\n return entry.promise;\n }\n\n /**\n * Drop the cached pending WeChat order that matches a paid `out_trade_no`,\n * so the next 402 mints a fresh order instead of re-serving a consumed one\n * (Native is one-code-one-payment).\n */\n private invalidateWechatChallenge(outTradeNo: string): void {\n for (const [cacheKey, entry] of this.wechatPendingChallenges) {\n if (entry.outTradeNo === outTradeNo) {\n this.wechatPendingChallenges.delete(cacheKey);\n }\n }\n }\n\n /**\n * Handle /execute for the custodial balance rail (2.2.0).\n *\n * Execution order is INVERTED relative to the QR rails: the deduction IS\n * the settlement, so it must land before the skill runs, and a skill\n * failure refunds it. `settle()` is idempotent on the client's\n * `request_id`, so a retried request never double-charges.\n *\n * QR rails: verify(paid?) → run skill → settle (confirm, fire-and-forget)\n * balance: verify implicit in settle (atomic deduct) → run skill → [fail → refund]\n */\n private async handleBalanceExecute(\n skill: RegisteredSkill,\n params: Record<string, any>,\n payment: X402PaymentPayload,\n res: ServerResponse\n ): Promise<void> {\n if (!this.balanceFacilitator) {\n return this.sendJson(res, 402, { error: 'Balance rail not configured on this server' });\n }\n\n const requirements = this.balanceRequirementsFor(skill.config);\n\n // User auth (1b): verify the originator signature and TOFU-bind the\n // account's signer. `off` skips entirely; `shadow` records but never\n // blocks; `enforce` rejects unsigned / wrong-signer deductions before any\n // charge. See docs/2026-07-13-wechat-fiat-auth-design.md.\n const authMode = this.balanceFacilitator.authMode;\n if (authMode !== 'off') {\n const bp = extractBalancePayload(payment);\n const buyerId = bp?.buyer_id ?? '';\n const requestId = bp?.request_id ?? '';\n const av = verifyDeductAuth({\n auth: bp?.auth ?? null,\n buyerId,\n requestId,\n service: skill.id,\n nowMs: Date.now(),\n });\n const ledger = this.balanceFacilitator.getLedger();\n let denyReason: string | undefined;\n if (av.ok && av.recovered) {\n const bind = ledger.bindSigner(buyerId, av.recovered);\n if (bind.conflict) denyReason = `wrong signer (account bound to ${bind.existing}, got ${av.recovered})`;\n } else {\n denyReason = `signature ${av.reason}`;\n }\n if (denyReason) {\n if (authMode === 'enforce') {\n console.warn(`[MoltsPay] Balance auth DENY (enforce) buyer=${buyerId} svc=${skill.id}: ${denyReason}`);\n return this.sendJson(res, 401, { error: `Balance auth failed: ${denyReason}`, facilitator: 'balance' });\n }\n console.warn(`[MoltsPay] Balance auth would-deny (shadow) buyer=${buyerId} svc=${skill.id}: ${denyReason}`);\n } else {\n console.log(`[MoltsPay] Balance auth ok (${authMode}) buyer=${buyerId} signer=${av.recovered}`);\n }\n }\n\n // Atomic deduct (settle). checkDeduct runs inside the same transaction,\n // so a separate verify() call here would only add a TOCTOU window.\n console.log(`[MoltsPay] Deducting balance for ${skill.id}...`);\n const settlement = await this.balanceFacilitator.settle(payment, requirements);\n if (!settlement.success) {\n return this.sendJson(res, 402, {\n error: `Balance deduction failed: ${settlement.error}`,\n code: settlement.status,\n facilitator: 'balance',\n });\n }\n console.log(`[MoltsPay] Balance deducted (tx ${settlement.transaction}${settlement.status === 'replayed' ? ', replayed' : ''})`);\n\n // Execute skill (same timeout contract as the other rails).\n const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || '1200');\n console.log(`[MoltsPay] Executing skill: ${skill.id} (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 // The buyer was already charged — reverse it. refund() is idempotent\n // per deduct, so a crash-retry of this path cannot double-credit.\n const refund = this.balanceFacilitator.refund(settlement.transaction!, `skill_failed: ${err.message}`.slice(0, 200));\n if (!refund.success) {\n console.error(`[MoltsPay] Balance refund FAILED for ${settlement.transaction}: ${refund.error} — manual reconciliation needed`);\n } else {\n console.log(`[MoltsPay] Balance refunded (tx ${refund.txId})`);\n }\n return this.sendJson(res, 500, {\n error: 'Service execution failed',\n message: err.message,\n refunded: refund.success,\n });\n }\n\n const responseHeaders: Record<string, string> = {\n [PAYMENT_RESPONSE_HEADER]: Buffer.from(JSON.stringify({\n success: true,\n transaction: settlement.transaction,\n network: 'balance',\n facilitator: 'balance',\n })).toString('base64'),\n };\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: { transaction: settlement.transaction, status: 'fulfilled', facilitator: 'balance' },\n }, responseHeaders);\n }\n\n /** The balance rail's requirements for a service (price defaults to `config.price`). */\n private balanceRequirementsFor(config: ServiceConfig): X402PaymentRequirements {\n const price = config.balance?.price ?? config.price.toFixed(2);\n return {\n scheme: BALANCE_SCHEME,\n network: 'balance',\n asset: this.balanceFacilitator?.currency ?? 'USD',\n amount: price,\n payTo: 'custodial',\n maxTimeoutSeconds: 30,\n extra: { service_id: config.id },\n };\n }\n\n /**\n * Build the balance 402 challenge for a service, or null when the rail\n * isn't configured for this server or this service. Pure — nothing is\n * minted, so unlike the QR rails a 402 emit has no side effects.\n */\n private buildBalanceChallenge(config: ServiceConfig): { accepts: X402PaymentRequirements } | null {\n if (!this.balanceFacilitator || !config.balance) return null;\n try {\n return { accepts: this.balanceRequirementsFor(config) };\n } catch (err: any) {\n console.error(`[MoltsPay] Balance challenge build failed for ${config.id}: ${err.message}`);\n return null;\n }\n }\n\n /** GET /balance?buyer_id= — balance, limits, and today's spend. */\n /**\n * Handle MPP (Machine Payments Protocol) request\n * Supports both x402 and MPP protocols on service endpoints\n */\n private async handleMPPRequest(\n skill: RegisteredSkill,\n body: any,\n authHeader: string | undefined,\n x402Header: string | undefined,\n res: ServerResponse,\n proofHeader?: string\n ): Promise<void> {\n const config = skill.config;\n const params = body || {};\n\n // Alipay buyer re-request with a Payment-Proof header → verify + fulfill.\n if (proofHeader) {\n return await this.handleExecute({ service: config.id, params }, undefined, res, proofHeader);\n }\n\n // Check for x402 payment header first (backward compatibility)\n if (x402Header) {\n return await this.handleExecute({ service: config.id, params }, x402Header, res);\n }\n\n // Check for MPP payment credential\n if (authHeader && authHeader.toLowerCase().startsWith('payment ')) {\n return await this.handleMPPPayment(skill, params, authHeader, res);\n }\n\n // No payment provided - return 402 with both x402 and MPP headers\n return this.sendMPPPaymentRequired(config, res, params);\n }\n\n /**\n * Handle MPP payment verification and service execution\n */\n private async handleMPPPayment(\n skill: RegisteredSkill,\n params: any,\n authHeader: string,\n res: ServerResponse\n ): Promise<void> {\n const config = skill.config;\n\n // Parse MPP credential: \"Payment <base64>\"\n const credentialMatch = authHeader.match(/Payment\\s+(.+)/i);\n if (!credentialMatch) {\n return this.sendJson(res, 400, { error: 'Invalid Authorization header format' });\n }\n\n let mppCredential: {\n challenge: {\n id: string;\n realm: string;\n method: string;\n intent: string;\n request: any;\n };\n payload: {\n hash?: string;\n signature?: string;\n type: 'hash' | 'transaction';\n };\n source?: string;\n };\n \n try {\n // mppx uses base64url encoding without padding\n const base64 = credentialMatch[1].replace(/-/g, '+').replace(/_/g, '/');\n const decoded = Buffer.from(base64, 'base64').toString('utf-8');\n mppCredential = JSON.parse(decoded);\n } catch (err) {\n console.error('[MoltsPay] Failed to parse MPP credential:', err);\n return this.sendJson(res, 400, { error: 'Invalid payment credential encoding' });\n }\n\n // Extract transaction hash from payload\n let txHash: string | undefined;\n if (mppCredential.payload?.type === 'hash' && mppCredential.payload?.hash) {\n txHash = mppCredential.payload.hash;\n } else if (mppCredential.payload?.type === 'transaction') {\n // For 'transaction' type, server would need to submit the signed tx\n // For now, we only support 'hash' type (push mode)\n return this.sendJson(res, 400, { \n error: 'Transaction type not supported. Please use push mode (hash type).' \n });\n }\n\n if (!txHash) {\n return this.sendJson(res, 400, { error: 'Missing transaction hash in credential' });\n }\n\n // Extract chainId from challenge or source\n let chainId = mppCredential.challenge?.request?.methodDetails?.chainId;\n if (!chainId && mppCredential.source) {\n const chainMatch = mppCredential.source.match(/eip155:(\\d+)/);\n if (chainMatch) chainId = parseInt(chainMatch[1], 10);\n }\n chainId = chainId || 42431; // Default to Tempo Moderato\n\n // Determine network from chainId\n const network = `eip155:${chainId}`;\n\n if (!this.isNetworkAccepted(network)) {\n return this.sendJson(res, 402, { \n error: `Network not accepted: ${network}` \n });\n }\n\n // Build requirements for verification\n const requirements = this.buildPaymentRequirements(\n config,\n network,\n this.getWalletForNetwork(network),\n 'USDC'\n );\n\n // Create x402-compatible payload for facilitator\n const paymentPayload: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: 'exact',\n network,\n payload: {\n txHash,\n chainId,\n },\n };\n\n console.log(`[MoltsPay] Verifying MPP payment: txHash=${txHash}, chainId=${chainId}`);\n\n // Verify payment using facilitator registry\n const verification = await this.registry.verify(paymentPayload, requirements);\n \n if (!verification.valid) {\n return this.sendJson(res, 402, { \n error: `Payment verification failed: ${verification.error}` \n });\n }\n\n console.log(`[MoltsPay] Payment verified! Executing service: ${config.id}`);\n\n // Execute the skill\n let result: any;\n try {\n result = await skill.handler(params);\n } catch (err: any) {\n console.error(`[MoltsPay] Skill execution error:`, err);\n return this.sendJson(res, 500, { \n error: `Service execution failed: ${err.message}` \n });\n }\n\n // Build receipt\n const receipt = {\n success: true,\n txHash,\n network,\n facilitator: verification.facilitator,\n };\n const receiptEncoded = Buffer.from(JSON.stringify(receipt)).toString('base64');\n\n // Return success with MPP receipt header\n res.writeHead(200, {\n 'Content-Type': 'application/json',\n [MPP_RECEIPT_HEADER]: receiptEncoded,\n });\n res.end(JSON.stringify({\n success: true,\n result,\n payment: {\n txHash,\n status: 'verified',\n facilitator: verification.facilitator,\n },\n }, null, 2));\n }\n\n /**\n * Return 402 with both x402 and MPP payment requirements\n */\n private async sendMPPPaymentRequired(config: ServiceConfig, res: ServerResponse, params?: Record<string, any>): Promise<void> {\n const acceptedTokens = getAcceptedCurrencies(config);\n const providerChains = this.getProviderChains();\n\n // === x402 format (existing) ===\n const accepts: X402PaymentRequirements[] = [];\n for (const chainConfig of providerChains) {\n for (const token of acceptedTokens) {\n if (chainConfig.tokens.includes(token)) {\n accepts.push(this.buildPaymentRequirements(config, chainConfig.network, chainConfig.wallet, token));\n }\n }\n }\n\n // Alipay fiat rail (2.0.0): append the alipay x402 entry when configured.\n const alipayChallenge = await this.buildAlipayChallenge(config);\n if (alipayChallenge) {\n accepts.push(alipayChallenge.accepts);\n }\n\n // WeChat fiat rail (2.1.0): append the wechat x402 entry when configured.\n const wechatChallenge = await this.buildWechatChallenge(config, params);\n if (wechatChallenge) {\n accepts.push(wechatChallenge.accepts);\n }\n\n // Custodial balance rail (2.2.0): append the balance x402 entry when configured.\n const balanceChallenge = this.buildBalanceChallenge(config);\n if (balanceChallenge) {\n accepts.push(balanceChallenge.accepts);\n }\n\n const x402PaymentRequired = {\n x402Version: X402_VERSION,\n accepts,\n acceptedCurrencies: acceptedTokens,\n resource: {\n url: `/${config.id}`,\n description: `${config.name} - $${config.price} ${config.currency}`,\n },\n };\n const x402Encoded = Buffer.from(JSON.stringify(x402PaymentRequired)).toString('base64');\n\n // === MPP format ===\n // Find Tempo chain if available\n const tempoChain = providerChains.find(c => c.network === 'eip155:42431');\n \n let mppWwwAuth = '';\n if (tempoChain) {\n const challengeId = this.generateChallengeId();\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const tokenAddress = TOKEN_ADDRESSES['eip155:42431']?.USDC || '0x20c0000000000000000000000000000000000000';\n \n const mppRequest = {\n amount: amountInUnits,\n currency: tokenAddress,\n methodDetails: {\n chainId: 42431,\n feePayer: true,\n },\n recipient: tempoChain.wallet,\n };\n const mppRequestEncoded = Buffer.from(JSON.stringify(mppRequest)).toString('base64');\n \n const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString();\n \n mppWwwAuth = `Payment id=\"${challengeId}\", realm=\"${headerSafe(this.manifest.provider.name)}\", method=\"tempo\", intent=\"charge\", request=\"${mppRequestEncoded}\", description=\"${headerSafe(config.name)}\", expires=\"${expiresAt}\"`;\n }\n\n // Build response headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/problem+json',\n [PAYMENT_REQUIRED_HEADER]: x402Encoded,\n };\n\n if (mppWwwAuth) {\n headers[MPP_WWW_AUTH_HEADER] = mppWwwAuth;\n }\n // Dual-emit the legacy `Payment-Needed` header for alipay-bot clients.\n if (alipayChallenge) {\n headers[ALIPAY_PAYMENT_NEEDED_HEADER] = alipayChallenge.paymentNeededHeader;\n }\n\n res.writeHead(402, headers);\n res.end(JSON.stringify({\n type: 'https://paymentauth.org/problems/payment-required',\n title: 'Payment Required',\n status: 402,\n detail: `Payment is required (${config.name}).`,\n service: config.id,\n price: config.price,\n currency: config.currency,\n acceptedCurrencies: acceptedTokens,\n }, null, 2));\n }\n\n /**\n * Generate a unique challenge ID for MPP\n */\n private generateChallengeId(): string {\n const bytes = new Uint8Array(24);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n return Buffer.from(bytes).toString('base64url');\n }\n\n /**\n * Return 402 with x402 payment requirements (v2 format)\n * Includes requirements for all chains and all accepted currencies\n */\n private async sendPaymentRequired(config: ServiceConfig, res: ServerResponse, params?: Record<string, any>): Promise<void> {\n const acceptedTokens = getAcceptedCurrencies(config);\n const providerChains = this.getProviderChains();\n\n // Build requirements for each chain x token combination\n const accepts: X402PaymentRequirements[] = [];\n for (const chainConfig of providerChains) {\n for (const token of acceptedTokens) {\n // Only add if this chain supports this token\n if (chainConfig.tokens.includes(token)) {\n accepts.push(this.buildPaymentRequirements(config, chainConfig.network, chainConfig.wallet, token));\n }\n }\n }\n\n // Alipay fiat rail (2.0.0): append the alipay x402 entry when configured.\n const alipayChallenge = await this.buildAlipayChallenge(config);\n if (alipayChallenge) {\n accepts.push(alipayChallenge.accepts);\n }\n\n // WeChat fiat rail (2.1.0): append the wechat x402 entry when configured.\n const wechatChallenge = await this.buildWechatChallenge(config, params);\n if (wechatChallenge) {\n accepts.push(wechatChallenge.accepts);\n }\n\n // Custodial balance rail (2.2.0): append the balance x402 entry when configured.\n const balanceChallenge = this.buildBalanceChallenge(config);\n if (balanceChallenge) {\n accepts.push(balanceChallenge.accepts);\n }\n\n // Get list of accepted chains for response\n const acceptedChains = providerChains.map(c => {\n // Convert network ID to chain name for readability\n if (c.network === 'eip155:8453') return 'base';\n if (c.network === 'eip155:137') return 'polygon';\n return c.network;\n });\n\n const paymentRequired = {\n x402Version: X402_VERSION,\n accepts,\n acceptedCurrencies: acceptedTokens,\n acceptedChains,\n resource: {\n url: `${this.publicBase}/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 const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n };\n // Dual-emit the legacy `Payment-Needed` header for alipay-bot clients\n // (@alipay/agent-payment), which only read this header and ignore the\n // x402 `accepts[]`. Mirrors sendMPPPaymentRequired so /execute is\n // byte-for-byte compatible with un-upgraded skills.\n if (alipayChallenge) {\n headers[ALIPAY_PAYMENT_NEEDED_HEADER] = alipayChallenge.paymentNeededHeader;\n }\n\n // The human-readable body must describe the rails actually on offer. It\n // used to hardcode the USDC list price, which told an LLM agent to pay in\n // crypto even on a server that no longer accepts it -- the agent then\n // burned its first attempt on a rail with no accepts[] entry.\n const offered = this.describeServicePricing(config);\n const message = offered.pricing.length\n ? `Payment required — ${offered.pricing.map(p => `${p.rail}: ${p.amount} ${p.currency}`).join(' | ')}`\n : `Service requires $${config.price} ${config.currency}`;\n\n res.writeHead(402, headers);\n res.end(JSON.stringify({\n error: 'Payment required',\n message,\n acceptedCurrencies: offered.acceptedCurrencies,\n acceptedChains,\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 || this.networkId;\n\n // Both schemes are supported: EIP-3009 `exact` (Base/Polygon/BNB/Solana) and\n // EIP-2612 `permit` (Tempo Moderato, added in 1.6.0). Facilitator routes\n // permit payloads to TempoFacilitator automatically.\n if (scheme !== 'exact' && scheme !== 'permit') {\n return { valid: false, error: `Unsupported scheme: ${scheme}` };\n }\n\n // Check if payment network is one of our accepted networks\n if (!this.isNetworkAccepted(network)) {\n const acceptedChains = this.getProviderChains().map(c => c.network).join(', ');\n return { valid: false, error: `Network not accepted: ${network}. Accepted: ${acceptedChains}` };\n }\n\n return { valid: true };\n }\n\n /**\n * Build payment requirements for facilitator\n * Now supports multi-chain: takes network and wallet as parameters\n */\n private buildPaymentRequirements(\n config: ServiceConfig, \n network?: string, \n wallet?: string,\n token?: string\n ): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const acceptedTokens = getAcceptedCurrencies(config);\n \n // Use specified values or defaults\n const selectedNetwork = network || this.networkId;\n const selectedWallet = wallet || this.manifest.provider.wallet;\n const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];\n \n const tokenAddresses = TOKEN_ADDRESSES[selectedNetwork] || {};\n const tokenAddress = tokenAddresses[selectedToken];\n const tokenDomain = getTokenDomain(selectedNetwork, selectedToken);\n\n // Tempo Moderato uses EIP-2612 permit (pathUSD / AlphaUSD don't implement EIP-3009).\n // Every other network uses the standard x402 \"exact\" (EIP-3009) scheme.\n const isTempo = selectedNetwork === 'eip155:42431';\n const scheme = isTempo ? 'permit' : 'exact';\n\n const requirements: X402PaymentRequirements = {\n scheme,\n network: selectedNetwork,\n asset: tokenAddress,\n amount: amountInUnits,\n payTo: selectedWallet,\n maxTimeoutSeconds: 300,\n extra: tokenDomain,\n };\n \n // For Solana: include fee payer pubkey if available (gasless mode)\n if (selectedNetwork === 'solana:mainnet' || selectedNetwork === 'solana:devnet') {\n const solanaFacilitator = this.registry.get('solana') as any;\n const feePayerPubkey = solanaFacilitator?.getFeePayerPubkey?.();\n if (feePayerPubkey) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n solanaFeePayer: feePayerPubkey,\n };\n }\n }\n \n // For BNB: include spender address for client approval\n if (selectedNetwork === 'eip155:56' || selectedNetwork === 'eip155:97') {\n const bnbFacilitator = this.registry.get('bnb') as any;\n const spenderAddress = bnbFacilitator?.getSpenderAddress?.();\n if (spenderAddress) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n bnbSpender: spenderAddress,\n };\n }\n }\n\n // For Tempo: include the settler EOA so the client can sign Permit(spender=settler).\n // If TEMPO_SETTLER_KEY is not configured, tempoSpender will be absent and Web Client\n // will surface a helpful error rather than sign a permit no one can fulfill.\n if (isTempo) {\n const tempoFacilitator = this.registry.get('tempo') as any;\n const tempoSpender = tempoFacilitator?.getSpenderAddress?.();\n if (tempoSpender) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n tempoSpender,\n };\n }\n }\n\n return requirements;\n }\n\n /**\n * Detect which token is being used in the payment\n * Checks across all supported networks\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 // Get payment network to check correct token addresses\n const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;\n const tokenAddresses = TOKEN_ADDRESSES[paymentNetwork] || {};\n \n for (const [symbol, address] of Object.entries(tokenAddresses)) {\n if (address && (address as string).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, allow all (for testing/open mode)\n if (allowedIPs.length === 0) {\n return true;\n }\n \n // If '*' is in the list, allow all\n if (allowedIPs.includes('*')) {\n return true;\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/MPP 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 * For x402 (base, polygon, base_sepolia):\n * Without X-Payment header: returns 402 with X-Payment-Required\n * With X-Payment header: verifies payment via CDP\n * \n * For MPP (tempo_moderato):\n * Without Authorization header: returns 402 with WWW-Authenticate\n * With Authorization: Payment header: verifies tx on Tempo chain\n */\n private async handleProxy(\n body: any,\n paymentHeader: string | undefined,\n authHeader: 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 chain if provided\n const supportedChains = ['base', 'polygon', 'base_sepolia', 'tempo_moderato', 'bnb', 'bnb_testnet', 'solana', 'solana_devnet'];\n if (chain && !supportedChains.includes(chain)) {\n return this.sendJson(res, 400, { error: `Unsupported chain: ${chain}. Supported: ${supportedChains.join(', ')}` });\n }\n\n // Validate wallet format based on chain\n const isSolanaChain = chain === 'solana' || chain === 'solana_devnet';\n const isValidEvmAddress = /^0x[a-fA-F0-9]{40}$/.test(wallet);\n const isValidSolanaAddress = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(wallet);\n \n if (isSolanaChain && !isValidSolanaAddress) {\n return this.sendJson(res, 400, { error: 'Invalid Solana wallet address format' });\n }\n if (!isSolanaChain && !isValidEvmAddress) {\n return this.sendJson(res, 400, { error: 'Invalid EVM 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 // ========== MPP Protocol for tempo_moderato ==========\n if (chain === 'tempo_moderato') {\n return await this.handleProxyMPP(body, proxyConfig, authHeader, res);\n }\n\n // ========== x402 Protocol for other chains ==========\n // Build payment requirements with the provided wallet and chain\n const requirements = this.buildProxyPaymentRequirements(proxyConfig, wallet, currency, chain);\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendProxyPaymentRequired(proxyConfig, wallet, memo, chain, 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' && scheme !== 'permit') {\n return this.sendJson(res, 402, { error: `Unsupported scheme: ${scheme}` });\n }\n\n // Validate network matches requested chain (or default to provider's network)\n const expectedNetwork = chain ? (CHAIN_TO_NETWORK[chain] || this.networkId) : this.networkId;\n if (network !== expectedNetwork) {\n return this.sendJson(res, 402, { error: `Network mismatch: expected ${expectedNetwork}, 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, handle skill + payment\n if (execute && 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 // For Solana: settle FIRST (blockhash expires quickly ~60s)\n // For EVM: pay-for-success (execute first, settle after)\n const isSolana = isSolanaNetwork(network);\n let settlement: any = null;\n\n if (isSolana) {\n console.log(`[MoltsPay] /proxy: Solana detected - settling payment FIRST`);\n try {\n settlement = await this.registry.settle(payment, requirements);\n console.log(`[MoltsPay] /proxy: Payment settled by ${settlement.facilitator}: ${settlement.transaction || 'pending'}`);\n \n // Check if settlement actually succeeded (registry returns {success: false} on failure)\n if (!settlement.success) {\n console.error(`[MoltsPay] /proxy: Solana settlement failed: ${settlement.error}`);\n return this.sendJson(res, 402, {\n success: false,\n paymentSettled: false,\n error: `Payment settlement failed: ${settlement.error || 'Unknown error'}`,\n });\n }\n } catch (err: any) {\n console.error('[MoltsPay] /proxy: Solana settlement failed:', err.message);\n return this.sendJson(res, 402, {\n success: false,\n paymentSettled: false,\n error: `Payment settlement failed: ${err.message}`,\n });\n }\n } else {\n console.log(`[MoltsPay] /proxy: Executing skill first (pay on success): ${service}`);\n }\n\n // Execute skill (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`);\n } catch (err: any) {\n // Skill failed or timeout\n console.error(`[MoltsPay] /proxy: Skill failed: ${err.message}`);\n // For Solana: payment already settled, skill failed - no refund (user accepted risk)\n // For EVM: payment not settled yet, user keeps their money\n return this.sendJson(res, 500, {\n success: false,\n paymentSettled: isSolana ? true : false,\n error: `Service execution failed: ${err.message}`,\n note: isSolana ? 'Payment was settled before execution. Contact support for refund.' : undefined,\n });\n }\n\n // For EVM: settle payment now (pay-for-success)\n if (!isSolana) {\n console.log(`[MoltsPay] /proxy: Settling payment...`);\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,\n paidTo: wallet,\n amount: amountNum,\n currency: currency || 'USDC',\n memo,\n result,\n });\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,\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 * Handle MPP payment flow for /proxy endpoint (tempo_moderato chain)\n */\n private async handleProxyMPP(\n body: any,\n config: ServiceConfig,\n authHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { wallet, amount, memo, serviceId } = body;\n const amountNum = parseFloat(amount);\n const amountInUnits = Math.floor(amountNum * 1e6).toString();\n \n // If no Authorization header, return 402 with WWW-Authenticate\n if (!authHeader || !authHeader.toLowerCase().startsWith('payment ')) {\n const challengeId = this.generateChallengeId();\n const tokenAddress = TOKEN_ADDRESSES['eip155:42431']?.USDC || '0x20c0000000000000000000000000000000000000';\n \n const mppRequest = {\n amount: amountInUnits,\n currency: tokenAddress,\n methodDetails: {\n chainId: 42431,\n feePayer: true,\n },\n recipient: wallet,\n };\n const mppRequestEncoded = Buffer.from(JSON.stringify(mppRequest)).toString('base64');\n \n const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString();\n \n const wwwAuth = `Payment id=\"${challengeId}\", realm=\"MoltsPay Proxy\", method=\"tempo\", intent=\"charge\", request=\"${mppRequestEncoded}\", description=\"${headerSafe(config.name)}\", expires=\"${expiresAt}\"`;\n \n res.writeHead(402, {\n 'Content-Type': 'application/problem+json',\n [MPP_WWW_AUTH_HEADER]: wwwAuth,\n });\n res.end(JSON.stringify({\n type: 'https://paymentauth.org/problems/payment-required',\n title: 'Payment Required',\n status: 402,\n detail: `Payment is required (${config.name}).`,\n service: serviceId || 'proxy',\n price: amountNum,\n currency: 'USDC',\n }, null, 2));\n return;\n }\n\n // Parse MPP credential: \"Payment <base64>\"\n const credentialMatch = authHeader.match(/Payment\\s+(.+)/i);\n if (!credentialMatch) {\n return this.sendJson(res, 400, { error: 'Invalid Authorization header format' });\n }\n\n let mppCredential: {\n challenge: { id: string; realm: string; method: string; intent: string; request: any };\n payload: { hash?: string; type: 'hash' | 'transaction' };\n source?: string;\n };\n \n try {\n const base64 = credentialMatch[1].replace(/-/g, '+').replace(/_/g, '/');\n const decoded = Buffer.from(base64, 'base64').toString('utf-8');\n mppCredential = JSON.parse(decoded);\n } catch (err) {\n console.error('[MoltsPay] /proxy MPP: Failed to parse credential:', err);\n return this.sendJson(res, 400, { error: 'Invalid payment credential encoding' });\n }\n\n // Extract transaction hash\n let txHash: string | undefined;\n if (mppCredential.payload?.type === 'hash' && mppCredential.payload?.hash) {\n txHash = mppCredential.payload.hash;\n } else {\n return this.sendJson(res, 400, { error: 'Missing transaction hash in credential' });\n }\n\n console.log(`[MoltsPay] /proxy MPP: Verifying tx ${txHash} on Tempo...`);\n\n // Build requirements for verification\n const requirements = this.buildPaymentRequirements(config, 'eip155:42431', wallet, 'USDC');\n\n // Create x402-compatible payload for facilitator\n const paymentPayload: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: 'exact',\n network: 'eip155:42431',\n payload: { txHash, chainId: 42431 },\n };\n\n // Verify payment using facilitator registry\n const verification = await this.registry.verify(paymentPayload, requirements);\n \n if (!verification.valid) {\n return this.sendJson(res, 402, { \n error: `Payment verification failed: ${verification.error}` \n });\n }\n\n console.log(`[MoltsPay] /proxy MPP: Payment verified by ${verification.facilitator}`);\n\n // Check if execution requested\n const { execute, service, params } = body;\n \n if (execute && service) {\n console.log(`[MoltsPay] /proxy MPP: Executing skill: ${service}`);\n const skill = this.skills.get(service);\n if (!skill) {\n return this.sendJson(res, 404, {\n success: false,\n paymentSettled: true, // Payment already happened on Tempo\n error: `Service not found: ${service}`,\n });\n }\n\n // Execute skill\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 } catch (err: any) {\n console.error(`[MoltsPay] /proxy MPP: Skill failed: ${err.message}`);\n return this.sendJson(res, 500, {\n success: false,\n paymentSettled: true,\n error: `Service execution failed: ${err.message}`,\n });\n }\n\n return this.sendJson(res, 200, {\n success: true,\n verified: true,\n txHash,\n chain: 'tempo_moderato',\n paidTo: wallet,\n amount: amountNum,\n currency: 'USDC',\n facilitator: verification.facilitator,\n memo,\n result,\n });\n }\n\n // No execution requested - just return verification success\n this.sendJson(res, 200, {\n success: true,\n verified: true,\n txHash,\n chain: 'tempo_moderato',\n paidTo: wallet,\n amount: amountNum,\n currency: 'USDC',\n facilitator: verification.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, chain?: string): X402PaymentRequirements {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const acceptedTokens = getAcceptedCurrencies(config);\n \n // Determine network from chain parameter or use default\n const networkId = chain ? (CHAIN_TO_NETWORK[chain] || this.networkId) : this.networkId;\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[networkId] || TOKEN_ADDRESSES[this.networkId] || {};\n const tokenAddress = tokenAddresses[selectedToken];\n const tokenDomain = getTokenDomain(networkId, selectedToken);\n\n const requirements: X402PaymentRequirements = {\n scheme: 'exact',\n network: networkId,\n asset: tokenAddress,\n amount: amountInUnits,\n payTo: wallet, // Use provided wallet, not manifest\n maxTimeoutSeconds: 300,\n extra: tokenDomain,\n };\n\n // For BNB: include spender address for client approval\n if (networkId === 'eip155:56' || networkId === 'eip155:97') {\n const bnbFacilitator = this.registry.get('bnb') as any;\n const spenderAddress = bnbFacilitator?.getSpenderAddress?.();\n if (spenderAddress) {\n (requirements.extra as any) = {\n ...(requirements.extra || {}),\n bnbSpender: spenderAddress,\n };\n }\n }\n\n return requirements;\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 chain: string | undefined,\n res: ServerResponse\n ): void {\n const requirements = this.buildProxyPaymentRequirements(config, wallet, config.currency, chain);\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 *\n * **Per-scheme `extra` conventions:**\n * - `alipay-aipay` (2.0.0+): `extra` carries the parallel `Payment-Needed`\n * contents so x402-aware clients don't need to read the separate HTTP\n * header. Server side, `AlipayFacilitator.createPaymentRequirements`\n * populates: `payment_needed_header` (Base64URL of nested\n * `{protocol, method}` JSON), `out_trade_no`, `pay_before`, `service_id`.\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 * Auto-detects mainnet vs testnet from chain ID in request.\n * \n * Supported networks:\n * - Base mainnet (eip155:8453)\n * - Polygon mainnet (eip155:137)\n * - Base Sepolia testnet (eip155:84532)\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 URL (handles both mainnet and testnet)\nconst CDP_URL = 'https://api.cdp.coinbase.com/platform/v2/x402';\n\n// Testnet chain IDs (for logging/info only - CDP auto-detects from network field)\nconst TESTNET_CHAIN_IDS = [84532]; // Base Sepolia\n\nexport interface CDPFacilitatorConfig extends FacilitatorConfig {\n /** CDP API Key ID (required) */\n apiKeyId?: string;\n /** CDP API Key Secret (required) */\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 apiKeyId?: string;\n private apiKeySecret?: string;\n \n constructor(config: CDPFacilitatorConfig = {}) {\n super();\n \n // Load env files for credentials\n loadEnvFile();\n \n // Get credentials (required for CDP)\n this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;\n this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;\n \n // Single endpoint handles both mainnet and testnet (auto-detected from chain ID in request)\n this.endpoint = CDP_URL;\n \n // All supported networks - CDP handles both mainnet and testnet\n this.supportedNetworks = [\n 'eip155:8453', // Base mainnet\n 'eip155:137', // Polygon mainnet\n 'eip155:84532', // Base Sepolia (testnet)\n ];\n \n // Warn if missing credentials\n if (!this.apiKeyId || !this.apiKeySecret) {\n console.warn('[CDPFacilitator] WARNING: Missing CDP credentials!');\n console.warn('[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env');\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.apiKeyId || !this.apiKeySecret) {\n throw new Error('CDP credentials required. Set CDP_API_KEY_ID and CDP_API_KEY_SECRET');\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 console.log('[CDP Verify] Payload:', JSON.stringify(paymentPayload, null, 2));\n \n const authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/verify',\n requestBody\n );\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...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 console.log('[CDP Verify] Response:', response.status, JSON.stringify(result));\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 authHeaders = await this.getAuthHeaders(\n 'POST',\n '/platform/v2/x402/settle',\n requestBody\n );\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...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 * Check if a chain ID is testnet\n */\n static isTestnet(chainId: number): boolean {\n return TESTNET_CHAIN_IDS.includes(chainId);\n }\n \n /**\n * Get configuration summary (for logging)\n */\n getConfigSummary(): string {\n const hasCredentials = !!(this.apiKeyId && this.apiKeySecret);\n const networks = this.supportedNetworks.join(', ');\n return `CDP Facilitator (networks: ${networks}, credentials: ${hasCredentials ? 'yes' : 'no'})`;\n }\n}\n","/**\n * Tempo Testnet Facilitator\n * \n * Verifies payments on Tempo Moderato testnet by checking transaction receipts.\n * Unlike CDP facilitator, this directly verifies on-chain without a third-party service.\n */\n\nimport { ethers } from 'ethers';\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { CHAINS } from '../chains/index.js';\n\n// TIP-20 Transfer event signature\nconst TRANSFER_EVENT_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';\n\n// ===== Payload shapes (discriminated) =====\n\n/** Legacy MPP / tx-hash payload: client already submitted the TIP-20 transfer. */\ninterface TempoTxHashPayload {\n txHash: string;\n chainId: number;\n}\n\n/** EIP-2612 permit payload: server submits permit + transferFrom from the settler wallet. */\ninterface TempoPermitPayload {\n permit: {\n owner: string;\n spender: string;\n value: string;\n nonce: string;\n deadline: string;\n v: number;\n r: string;\n s: string;\n };\n}\n\n// Minimal ABI for permit + transferFrom calls on the TIP-20 precompile.\nconst TIP20_PERMIT_ABI = [\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'function transferFrom(address from, address to, uint256 value) returns (bool)',\n];\n\n/**\n * Tempo Testnet Facilitator\n * \n * Verifies TIP-20 token transfers on Tempo Moderato (chainId 42431).\n */\nexport class TempoFacilitator extends BaseFacilitator {\n readonly name = 'tempo';\n readonly displayName = 'Tempo Testnet';\n readonly supportedNetworks = ['eip155:42431']; // Tempo Moderato\n\n private rpcUrl: string;\n private settlerWallet: ethers.Wallet | null = null;\n\n constructor() {\n super();\n this.rpcUrl = CHAINS.tempo_moderato.rpc;\n\n // Optional: load settler key from env. If present, the facilitator can settle\n // EIP-2612 permit payments by submitting permit() + transferFrom() on behalf\n // of the user. If absent, only the legacy tx-hash verification path works.\n const settlerKey = process.env.TEMPO_SETTLER_KEY;\n if (settlerKey) {\n try {\n const provider = new ethers.JsonRpcProvider(this.rpcUrl);\n this.settlerWallet = new ethers.Wallet(settlerKey, provider);\n } catch (err) {\n console.warn('[TempoFacilitator] Invalid TEMPO_SETTLER_KEY, permit settlement disabled:', err);\n this.settlerWallet = null;\n }\n }\n }\n\n /**\n * Settler EOA address advertised to clients via `X-Payment-Required.extra.tempoSpender`.\n * Web Client uses this as the `spender` field in the signed EIP-2612 Permit.\n * Returns null if no TEMPO_SETTLER_KEY is configured — permit settlement unavailable.\n */\n getSpenderAddress(): string | null {\n return this.settlerWallet?.address ?? null;\n }\n\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n const response = await fetch(this.rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_chainId',\n params: [],\n id: 1,\n }),\n });\n \n const data = await response.json() as { result: string };\n const chainId = parseInt(data.result, 16);\n \n if (chainId !== 42431) {\n return { healthy: false, error: `Wrong chainId: ${chainId}` };\n }\n \n return { healthy: true, latencyMs: Date.now() - start };\n } catch (error) {\n return { healthy: false, error: String(error) };\n }\n }\n\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n // Dispatch on payload shape:\n // { permit: {...} } → new EIP-2612 permit path (Web Client, Phase 3c)\n // { txHash, chainId } → legacy MPP / Node CLI tx-hash verification\n const inner = paymentPayload.payload as Partial<TempoPermitPayload & TempoTxHashPayload>;\n if (inner && 'permit' in inner && inner.permit) {\n return this.verifyPermit(inner as TempoPermitPayload, requirements);\n }\n return this.verifyTxHash(paymentPayload, requirements);\n }\n\n /**\n * Structural validation of an EIP-2612 permit payload. Does NOT submit\n * anything on-chain — actual submission happens in settlePermit().\n */\n private async verifyPermit(\n payload: TempoPermitPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n if (!this.settlerWallet) {\n return { valid: false, error: 'Permit settlement not configured (TEMPO_SETTLER_KEY missing)' };\n }\n const p = payload.permit;\n if (!p || !p.owner || !p.spender || !p.value || !p.deadline) {\n return { valid: false, error: 'Invalid permit payload: missing fields' };\n }\n // Spender must match our settler — otherwise permit() would set allowance on a\n // different address and transferFrom() from our settler would fail.\n if (p.spender.toLowerCase() !== this.settlerWallet.address.toLowerCase()) {\n return {\n valid: false,\n error: `Permit spender ${p.spender} does not match configured settler ${this.settlerWallet.address}`,\n };\n }\n // Deadline not expired (evaluate at verify-time; settle runs shortly after).\n const deadline = BigInt(p.deadline);\n const now = BigInt(Math.floor(Date.now() / 1000));\n if (deadline <= now) {\n return { valid: false, error: 'Permit deadline has expired' };\n }\n // Amount must match what the requirement asked for.\n if (BigInt(p.value) < BigInt(requirements.amount || '0')) {\n return {\n valid: false,\n error: `Permit value ${p.value} is less than required ${requirements.amount}`,\n };\n }\n return { valid: true, details: { scheme: 'permit', owner: p.owner } };\n }\n\n private async verifyTxHash(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n // Extract Tempo-specific payload\n const tempoPayload = paymentPayload.payload as TempoTxHashPayload;\n\n if (!tempoPayload?.txHash) {\n return { valid: false, error: 'Missing txHash in payment payload' };\n }\n\n // Get transaction receipt\n const receipt = await this.getTransactionReceipt(tempoPayload.txHash);\n \n if (!receipt) {\n return { valid: false, error: 'Transaction not found' };\n }\n\n if (receipt.status !== '0x1') {\n return { valid: false, error: 'Transaction failed' };\n }\n\n // Find Transfer event\n const transferLog = receipt.logs.find((log: any) => \n log.topics[0] === TRANSFER_EVENT_TOPIC\n );\n\n if (!transferLog) {\n return { valid: false, error: 'No Transfer event found' };\n }\n\n // Verify recipient (topic[2] is 'to' address, padded to 32 bytes)\n const toAddress = '0x' + transferLog.topics[2].slice(26).toLowerCase();\n const expectedTo = requirements.payTo.toLowerCase();\n \n if (toAddress !== expectedTo) {\n return { \n valid: false, \n error: `Wrong recipient: ${toAddress}, expected ${expectedTo}` \n };\n }\n\n // Verify amount (data field contains the amount)\n const amount = BigInt(transferLog.data);\n const expectedAmount = BigInt(requirements.amount);\n \n if (amount < expectedAmount) {\n return { \n valid: false, \n error: `Insufficient amount: ${amount}, expected ${expectedAmount}` \n };\n }\n\n // Verify token address\n const tokenAddress = transferLog.address.toLowerCase();\n const expectedToken = requirements.asset.toLowerCase();\n \n if (tokenAddress !== expectedToken) {\n return { \n valid: false, \n error: `Wrong token: ${tokenAddress}, expected ${expectedToken}` \n };\n }\n\n return { \n valid: true, \n details: {\n txHash: tempoPayload.txHash,\n from: '0x' + transferLog.topics[1].slice(26),\n to: toAddress,\n amount: amount.toString(),\n token: tokenAddress,\n }\n };\n } catch (error) {\n return { valid: false, error: `Verification failed: ${error}` };\n }\n }\n\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n // Dispatch on payload shape, same rule as verify().\n const inner = paymentPayload.payload as Partial<TempoPermitPayload & TempoTxHashPayload>;\n if (inner && 'permit' in inner && inner.permit) {\n return this.settlePermit(inner as TempoPermitPayload, requirements);\n }\n\n // Legacy tx-hash path: client already submitted the transfer; we just re-verify.\n const verifyResult = await this.verifyTxHash(paymentPayload, requirements);\n if (!verifyResult.valid) {\n return { success: false, error: verifyResult.error };\n }\n const tempoPayload = paymentPayload.payload as TempoTxHashPayload;\n return {\n success: true,\n transaction: tempoPayload.txHash,\n status: 'settled',\n };\n }\n\n /**\n * EIP-2612 permit settlement path. Submits two transactions on Tempo:\n * 1. pathUSD.permit(owner, spender=settler, value, deadline, v, r, s)\n * 2. pathUSD.transferFrom(owner, payTo, value)\n *\n * The settler EOA pays Tempo gas (via the TIP-20 `feeToken` mechanism — no\n * native tTEMPO required; any held TIP-20 token balance covers fees).\n */\n private async settlePermit(\n payload: TempoPermitPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n if (!this.settlerWallet) {\n return { success: false, error: 'Permit settlement not configured (TEMPO_SETTLER_KEY missing)' };\n }\n if (!requirements.asset || !requirements.payTo) {\n return { success: false, error: 'Missing asset or payTo in requirements' };\n }\n\n const verifyResult = await this.verifyPermit(payload, requirements);\n if (!verifyResult.valid) {\n return { success: false, error: verifyResult.error };\n }\n\n const token = new ethers.Contract(requirements.asset, TIP20_PERMIT_ABI, this.settlerWallet);\n const p = payload.permit;\n\n try {\n const permitTx = await token.permit(\n p.owner,\n p.spender,\n p.value,\n p.deadline,\n p.v,\n p.r,\n p.s\n );\n await permitTx.wait();\n\n const transferTx = await token.transferFrom(p.owner, requirements.payTo, p.value);\n await transferTx.wait();\n\n return {\n success: true,\n transaction: transferTx.hash,\n status: 'settled',\n };\n } catch (err) {\n return {\n success: false,\n error: `Tempo permit settlement failed: ${(err as Error).message}`,\n };\n }\n }\n\n private async getTransactionReceipt(txHash: string): Promise<any> {\n const response = await fetch(this.rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_getTransactionReceipt',\n params: [txHash],\n id: 1,\n }),\n });\n\n const data = await response.json() as { result: any };\n return data.result;\n }\n}\n","/**\n * Blockchain Configuration\n */\n\nimport type { ChainConfig, ChainName, EvmChainName, TokenSymbol } from '../types/index.js';\n\nexport const CHAINS: Record<EvmChainName, ChainConfig> = {\n // ============ Mainnet ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n tokens: {\n USDC: {\n address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USD Coin', // EIP-712 domain name\n },\n USDT: {\n address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // deprecated, for backward compat\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-bor-rpc.publicnode.com',\n tokens: {\n USDC: {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: '(PoS) Tether USD', // Polygon uses this name\n },\n },\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n // ============ Testnet ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n tokens: {\n USDC: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USDC', // Testnet USDC uses 'USDC' not 'USD Coin'\n },\n USDT: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Same as USDC on testnet (no official USDT)\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'USDC', // Uses same contract as USDC\n },\n },\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n // ============ Tempo Testnet (Moderato) ============\n tempo_moderato: {\n name: 'Tempo Moderato',\n chainId: 42431,\n rpc: 'https://rpc.moderato.tempo.xyz',\n tokens: {\n // TIP-20 stablecoins on Tempo testnet (from mppx SDK)\n // Note: Tempo uses USD as native gas token, not ETH\n USDC: {\n address: '0x20c0000000000000000000000000000000000000', // pathUSD - primary testnet stablecoin\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'pathUSD',\n },\n USDT: {\n address: '0x20c0000000000000000000000000000000000001', // alphaUSD\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'alphaUSD',\n },\n },\n usdc: '0x20c0000000000000000000000000000000000000',\n explorer: 'https://explore.testnet.tempo.xyz/address/',\n explorerTx: 'https://explore.testnet.tempo.xyz/tx/',\n avgBlockTime: 0.5, // ~500ms finality\n },\n // ============ BNB Chain Testnet ============\n bnb_testnet: {\n name: 'BNB Testnet',\n chainId: 97,\n rpc: 'https://data-seed-prebsc-1-s1.binance.org:8545',\n tokens: {\n // Note: BNB uses 18 decimals for stablecoins (unlike Base/Polygon which use 6)\n // Using official Binance-Peg testnet tokens\n USDC: {\n address: '0x64544969ed7EBf5f083679233325356EbE738930', // Testnet USDC\n decimals: 18,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', // Testnet USDT\n decimals: 18,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x64544969ed7EBf5f083679233325356EbE738930',\n explorer: 'https://testnet.bscscan.com/address/',\n explorerTx: 'https://testnet.bscscan.com/tx/',\n avgBlockTime: 3,\n // BNB-specific: requires approval for pay-for-success flow\n requiresApproval: true,\n },\n // ============ BNB Chain Mainnet ============\n bnb: {\n name: 'BNB Smart Chain',\n chainId: 56,\n rpc: 'https://bsc-dataseed.binance.org',\n tokens: {\n // Note: BNB uses 18 decimals for stablecoins\n USDC: {\n address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n decimals: 18,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0x55d398326f99059fF775485246999027B3197955',\n decimals: 18,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n explorer: 'https://bscscan.com/address/',\n explorerTx: 'https://bscscan.com/tx/',\n avgBlockTime: 3,\n // BNB-specific: requires approval for pay-for-success flow\n requiresApproval: true,\n },\n};\n\n/**\n * Get token address for a chain\n */\nexport function getTokenAddress(chainName: EvmChainName, token: TokenSymbol): string {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n const tokenConfig = chain.tokens[token];\n if (!tokenConfig) {\n throw new Error(`Token ${token} not supported on ${chainName}`);\n }\n return tokenConfig.address;\n}\n\n/**\n * Get token config for a chain\n */\nexport function getTokenConfig(chainName: EvmChainName, token: TokenSymbol) {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n return chain.tokens[token];\n}\n\n/**\n * Get chain configuration\n */\nexport function getChain(name: EvmChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * List all supported EVM chains\n */\nexport function listChains(): EvmChainName[] {\n return Object.keys(CHAINS) as EvmChainName[];\n}\n\n/**\n * Get chain config by chainId\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n// ============ Alipay AI Pay Fiat Rail (2.0.0+) ============\n\n/**\n * Chain-id string for the Alipay AI Pay fiat rail.\n * Used in `provider.chains: [\"alipay\", ...]` to opt the provider into\n * accepting CNY payments alongside USDC.\n */\nexport const ALIPAY_CHAIN_ID = 'alipay' as const;\n\n/**\n * Rail metadata for the Alipay AI Pay fiat rail (2.0.0+).\n *\n * Intentionally kept **outside** the {@link CHAINS} Record because that\n * Record is `Record<EvmChainName, ChainConfig>` and an EVM `ChainConfig`\n * (rpc / tokens / chainId) is not meaningful for a fiat rail.\n *\n * The rail uses `type: \"fiat-rail\"`, distinct from `ChainFamily`'s\n * existing `\"evm\"` and `\"svm\"`. Server dispatch detects alipay via\n * {@link isAlipayChainId} rather than via the EVM/SVM type guards.\n */\nexport const ALIPAY_RAIL = {\n /** Chain-id string used in user manifests + routing. */\n id: ALIPAY_CHAIN_ID,\n /** Rail family — distinct from `ChainFamily` ('evm' | 'svm'). */\n type: 'fiat-rail' as const,\n /** Quote currency. */\n currency: 'CNY' as const,\n /** Decimal places for the `amount` field (yuan with up to 2 decimals). */\n decimals: 2 as const,\n /** x402 `scheme` string — matches `ALIPAY_SCHEME` in src/facilitators/alipay.ts. */\n facilitator: 'alipay-aipay' as const,\n} as const;\n\n/**\n * Runtime type guard: is this chain-id string the Alipay fiat rail?\n *\n * Used by the server layer to route a `Payment-Proof` request to\n * {@link AlipayFacilitator} instead of an EVM/SVM verifier.\n */\nexport function isAlipayChainId(id: string): id is typeof ALIPAY_CHAIN_ID {\n return id === ALIPAY_CHAIN_ID;\n}\n\n// ============ WeChat Pay Fiat Rail (2.1.0+) ============\n\n/**\n * Chain-id string for the WeChat Pay v3 Native fiat rail.\n * Used in `provider.chains: [\"wechat\", ...]` to opt the provider into\n * accepting CNY payments via WeChat scan-to-pay.\n */\nexport const WECHAT_CHAIN_ID = 'wechat' as const;\n\n/**\n * Rail metadata for the WeChat Pay Native fiat rail (2.1.0+).\n *\n * Like {@link ALIPAY_RAIL}, kept outside the EVM-only {@link CHAINS} Record;\n * a fiat rail has no rpc / tokens / chainId. Server dispatch detects it via\n * {@link isWechatChainId} rather than the EVM/SVM type guards.\n */\nexport const WECHAT_RAIL = {\n /** Chain-id string used in user manifests + routing. */\n id: WECHAT_CHAIN_ID,\n /** Rail family — distinct from `ChainFamily` ('evm' | 'svm'). */\n type: 'fiat-rail' as const,\n /** Quote currency. */\n currency: 'CNY' as const,\n /** Decimal places for the `amount` field (yuan with up to 2 decimals). */\n decimals: 2 as const,\n /** x402 `scheme` string — matches `WECHAT_SCHEME` in src/facilitators/wechat.ts. */\n facilitator: 'wechatpay-native' as const,\n} as const;\n\n/**\n * Runtime type guard: is this chain-id string the WeChat Pay fiat rail?\n *\n * Used by the server layer to route a payment to {@link WechatFacilitator}\n * instead of an EVM/SVM verifier.\n */\nexport function isWechatChainId(id: string): id is typeof WECHAT_CHAIN_ID {\n return id === WECHAT_CHAIN_ID;\n}\n\n// ============ Custodial Balance Rail (2.2.0+) ============\n\n/**\n * Chain-id string for the custodial balance (\"password-free\" / password-free) rail.\n * Used in `provider.chains: [\"balance\", ...]` to opt the provider into\n * deducting from server-custodied buyer balances instead of a per-transaction\n * signature or scan-to-pay.\n */\nexport const BALANCE_CHAIN_ID = 'balance' as const;\n\n/**\n * Rail metadata for the custodial balance rail (2.2.0+).\n *\n * Like {@link ALIPAY_RAIL} / {@link WECHAT_RAIL}, kept outside the EVM-only\n * {@link CHAINS} Record; the ledger is local SQLite, so there is no rpc /\n * tokens / chainId. Server dispatch detects it via {@link isBalanceChainId}.\n */\nexport const BALANCE_RAIL = {\n /** Chain-id string used in user manifests + routing. */\n id: BALANCE_CHAIN_ID,\n /** Rail family — a server-side ledger, neither 'evm' | 'svm' nor a fiat gateway. */\n type: 'balance-rail' as const,\n /** Quote currency of the ledger. */\n currency: 'USD' as const,\n /** Decimal places for the `amount` field (dollars with up to 2 decimals). */\n decimals: 2 as const,\n /** x402 `scheme` string — matches `BALANCE_SCHEME` in src/facilitators/balance.ts. */\n facilitator: 'balance' as const,\n} as const;\n\n/**\n * Runtime type guard: is this chain-id string the custodial balance rail?\n *\n * Used by the server layer to route a payment to {@link BalanceFacilitator}\n * instead of an EVM/SVM verifier or a fiat gateway.\n */\nexport function isBalanceChainId(id: string): id is typeof BALANCE_CHAIN_ID {\n return id === BALANCE_CHAIN_ID;\n}\n\n/**\n * ERC20 ABI (minimal, only required methods)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName, EvmChainName, TokenSymbol };\n","/**\n * BNB Chain Facilitator\n * \n * Handles pay-for-success payments on BNB Smart Chain.\n * \n * Flow:\n * 1. Client pre-approves server wallet (one-time, via `moltspay init`)\n * 2. Client signs EIP-712 intent (no gas, just signature)\n * 3. Server verifies intent signature\n * 4. Server executes service\n * 5. Success → Server calls transferFrom (server pays gas)\n * 6. Failure → No transfer, client keeps money\n * \n * Key difference from Tempo:\n * - Tempo: Client pays first → service might fail → money lost\n * - BNB: Service runs first → success = payment (pay-for-success)\n */\n\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { CHAINS, ChainConfig } from '../chains/index.js';\nimport { privateKeyToAccount } from 'viem/accounts';\n\n// ERC20 Transfer event signature\nconst TRANSFER_EVENT_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';\n\n// EIP-712 Domain\nconst EIP712_DOMAIN = {\n name: 'MoltsPay',\n version: '1',\n};\n\n// EIP-712 Types for Payment Intent\nconst INTENT_TYPES = {\n PaymentIntent: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'amount', type: 'uint256' },\n { name: 'token', type: 'address' },\n { name: 'service', type: 'string' },\n { name: 'nonce', type: 'uint256' },\n { name: 'deadline', type: 'uint256' },\n ],\n};\n\n// ERC20 ABI (minimal)\nconst ERC20_ABI = {\n transfer: 'function transfer(address to, uint256 amount) returns (bool)',\n transferFrom: 'function transferFrom(address from, address to, uint256 amount) returns (bool)',\n allowance: 'function allowance(address owner, address spender) view returns (uint256)',\n balanceOf: 'function balanceOf(address account) view returns (uint256)',\n approve: 'function approve(address spender, uint256 amount) returns (bool)',\n};\n\n/**\n * BNB Payment Intent (signed by client)\n */\nexport interface BNBPaymentIntent {\n from: string;\n to: string;\n amount: string;\n token: string;\n service: string;\n nonce: number;\n deadline: number;\n signature: string;\n}\n\n/**\n * BNB Payment Payload (from client in x402 request)\n */\ninterface BNBPaymentPayload {\n intent: BNBPaymentIntent;\n chainId: number;\n}\n\n/**\n * BNB Chain Facilitator\n * \n * Handles pay-for-success payments on BNB mainnet (chainId 56) and testnet (chainId 97).\n * Server wallet executes transferFrom after successful service delivery.\n */\nexport class BNBFacilitator extends BaseFacilitator {\n readonly name = 'bnb';\n readonly displayName = 'BNB Smart Chain';\n readonly supportedNetworks = ['eip155:56', 'eip155:97']; // Mainnet + Testnet\n\n private serverPrivateKey: string;\n private spenderAddress: string | null = null;\n private chainConfigs: { [key: number]: { rpc: string; chain: ChainConfig } };\n\n constructor(serverPrivateKey?: string) {\n super();\n this.serverPrivateKey = serverPrivateKey || process.env.BNB_SERVER_PRIVATE_KEY || '';\n \n // Pre-compute spender address synchronously using viem\n if (this.serverPrivateKey) {\n const key = this.serverPrivateKey.startsWith('0x') \n ? this.serverPrivateKey as `0x${string}`\n : `0x${this.serverPrivateKey}` as `0x${string}`;\n const account = privateKeyToAccount(key);\n this.spenderAddress = account.address;\n }\n \n this.chainConfigs = {\n 56: { rpc: CHAINS.bnb.rpc, chain: CHAINS.bnb },\n 97: { rpc: CHAINS.bnb_testnet.rpc, chain: CHAINS.bnb_testnet },\n };\n }\n\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n // Check mainnet\n const response = await fetch(this.chainConfigs[56].rpc, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_chainId',\n params: [],\n id: 1,\n }),\n });\n \n const data = await response.json() as { result: string };\n const chainId = parseInt(data.result, 16);\n \n if (chainId !== 56) {\n return { healthy: false, error: `Wrong chainId: ${chainId}` };\n }\n \n return { healthy: true, latencyMs: Date.now() - start };\n } catch (error) {\n return { healthy: false, error: String(error) };\n }\n }\n\n /**\n * Verify a payment intent signature (before service execution)\n * \n * This verifies:\n * 1. Signature is valid for the intent\n * 2. Client has approved server wallet\n * 3. Client has sufficient balance\n * 4. Intent hasn't expired\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n const bnbPayload = paymentPayload.payload as BNBPaymentPayload;\n \n if (!bnbPayload?.intent) {\n return { valid: false, error: 'Missing intent in payment payload' };\n }\n\n const { intent, chainId } = bnbPayload;\n const config = this.chainConfigs[chainId];\n \n if (!config) {\n return { valid: false, error: `Unsupported chainId: ${chainId}` };\n }\n\n // Check deadline\n if (intent.deadline < Date.now()) {\n return { valid: false, error: 'Intent expired' };\n }\n\n // Verify signature\n const recoveredAddress = await this.recoverIntentSigner(intent, chainId);\n if (recoveredAddress.toLowerCase() !== intent.from.toLowerCase()) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n // Verify recipient matches\n if (intent.to.toLowerCase() !== requirements.payTo.toLowerCase()) {\n return { valid: false, error: `Wrong recipient: ${intent.to}` };\n }\n\n // Verify amount matches\n if (BigInt(intent.amount) < BigInt(requirements.amount)) {\n return { valid: false, error: `Insufficient amount: ${intent.amount}` };\n }\n\n // Verify token matches\n if (intent.token.toLowerCase() !== requirements.asset.toLowerCase()) {\n return { valid: false, error: `Wrong token: ${intent.token}` };\n }\n\n // Check allowance\n const serverAddress = await this.getServerAddress();\n const allowance = await this.getAllowance(intent.from, serverAddress, intent.token, config.rpc);\n \n if (BigInt(allowance) < BigInt(intent.amount)) {\n return { valid: false, error: 'Insufficient allowance. Run: npx moltspay init --chain bnb' };\n }\n\n // Check balance\n const balance = await this.getBalance(intent.from, intent.token, config.rpc);\n if (BigInt(balance) < BigInt(intent.amount)) {\n return { valid: false, error: 'Insufficient balance' };\n }\n\n return { \n valid: true, \n details: {\n from: intent.from,\n to: intent.to,\n amount: intent.amount,\n token: intent.token,\n service: intent.service,\n nonce: intent.nonce,\n deadline: intent.deadline,\n }\n };\n } catch (error) {\n return { valid: false, error: `Verification failed: ${error}` };\n }\n }\n\n /**\n * Settle a payment by executing transferFrom\n * \n * This is called AFTER the service has been successfully delivered.\n * Server pays gas, transfers tokens from client to provider.\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n if (!this.serverPrivateKey) {\n return { success: false, error: 'Server wallet not configured (BNB_SERVER_PRIVATE_KEY)' };\n }\n\n try {\n // First verify the intent\n const verifyResult = await this.verify(paymentPayload, requirements);\n if (!verifyResult.valid) {\n return { success: false, error: verifyResult.error };\n }\n\n const bnbPayload = paymentPayload.payload as BNBPaymentPayload;\n const { intent, chainId } = bnbPayload;\n const config = this.chainConfigs[chainId];\n\n // Execute transferFrom\n const txHash = await this.executeTransferFrom(\n intent.from,\n intent.to,\n intent.amount,\n intent.token,\n config.rpc\n );\n\n return { \n success: true, \n transaction: txHash,\n status: 'settled'\n };\n } catch (error) {\n return { success: false, error: `Settlement failed: ${error}` };\n }\n }\n\n /**\n * Check if client has approved the server wallet\n */\n async checkApproval(\n clientAddress: string, \n token: string, \n chainId: number\n ): Promise<{ approved: boolean; allowance: string }> {\n const config = this.chainConfigs[chainId];\n if (!config) {\n throw new Error(`Unsupported chainId: ${chainId}`);\n }\n\n const serverAddress = await this.getServerAddress();\n const allowance = await this.getAllowance(clientAddress, serverAddress, token, config.rpc);\n \n // Consider approved if allowance > 1000 USDC (with 18 decimals)\n const minAllowance = BigInt('1000000000000000000000'); // 1000 tokens\n \n return {\n approved: BigInt(allowance) >= minAllowance,\n allowance,\n };\n }\n\n /**\n * Verify a completed transaction (for checking past payments)\n */\n async verifyTransaction(\n txHash: string, \n expected: { to: string; amount: string; token: string },\n chainId: number\n ): Promise<VerifyResult> {\n const config = this.chainConfigs[chainId];\n if (!config) {\n return { valid: false, error: `Unsupported chainId: ${chainId}` };\n }\n\n try {\n const receipt = await this.getTransactionReceipt(txHash, config.rpc);\n \n if (!receipt) {\n return { valid: false, error: 'Transaction not found' };\n }\n\n if (receipt.status !== '0x1') {\n return { valid: false, error: 'Transaction failed' };\n }\n\n // Find Transfer event\n const transferLog = receipt.logs.find((log: any) => \n log.topics[0] === TRANSFER_EVENT_TOPIC &&\n log.address.toLowerCase() === expected.token.toLowerCase()\n );\n\n if (!transferLog) {\n return { valid: false, error: 'No Transfer event found' };\n }\n\n // Verify recipient\n const toAddress = '0x' + transferLog.topics[2].slice(26).toLowerCase();\n if (toAddress !== expected.to.toLowerCase()) {\n return { valid: false, error: `Wrong recipient: ${toAddress}` };\n }\n\n // Verify amount\n const amount = BigInt(transferLog.data);\n if (amount < BigInt(expected.amount)) {\n return { valid: false, error: `Insufficient amount: ${amount}` };\n }\n\n return { \n valid: true, \n details: {\n txHash,\n from: '0x' + transferLog.topics[1].slice(26),\n to: toAddress,\n amount: amount.toString(),\n token: transferLog.address,\n }\n };\n } catch (error) {\n return { valid: false, error: `Verification failed: ${error}` };\n }\n }\n\n // ==================== Private Methods ====================\n\n /**\n * Get the server's spender address (public, for 402 responses)\n * Returns cached value computed at construction time.\n */\n getSpenderAddress(): string | null {\n return this.spenderAddress;\n }\n\n private async getServerAddress(): Promise<string> {\n // Derive address from private key using ethers\n const { ethers } = await import('ethers');\n const wallet = new ethers.Wallet(this.serverPrivateKey);\n return wallet.address;\n }\n\n private async recoverIntentSigner(intent: BNBPaymentIntent, chainId: number): Promise<string> {\n // Use ethers for EIP-712 signature recovery\n const { ethers } = await import('ethers');\n \n const domain = {\n ...EIP712_DOMAIN,\n chainId,\n };\n\n const message = {\n from: intent.from,\n to: intent.to,\n amount: intent.amount,\n token: intent.token,\n service: intent.service,\n nonce: intent.nonce,\n deadline: intent.deadline,\n };\n\n const recoveredAddress = ethers.verifyTypedData(\n domain,\n INTENT_TYPES,\n message,\n intent.signature\n );\n\n return recoveredAddress;\n }\n\n private async getAllowance(owner: string, spender: string, token: string, rpcUrl: string): Promise<string> {\n // allowance(address,address) selector + params\n const selector = '0xdd62ed3e';\n const ownerPadded = owner.toLowerCase().replace('0x', '').padStart(64, '0');\n const spenderPadded = spender.toLowerCase().replace('0x', '').padStart(64, '0');\n const data = selector + ownerPadded + spenderPadded;\n\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_call',\n params: [{ to: token, data }, 'latest'],\n id: 1,\n }),\n });\n\n const result = await response.json() as { result: string };\n return result.result || '0x0';\n }\n\n private async getBalance(account: string, token: string, rpcUrl: string): Promise<string> {\n // balanceOf(address) selector + param\n const selector = '0x70a08231';\n const accountPadded = account.toLowerCase().replace('0x', '').padStart(64, '0');\n const data = selector + accountPadded;\n\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_call',\n params: [{ to: token, data }, 'latest'],\n id: 1,\n }),\n });\n\n const result = await response.json() as { result: string };\n return result.result || '0x0';\n }\n\n private async executeTransferFrom(\n from: string,\n to: string,\n amount: string,\n token: string,\n rpcUrl: string\n ): Promise<string> {\n const { ethers } = await import('ethers');\n \n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const wallet = new ethers.Wallet(this.serverPrivateKey, provider);\n \n const tokenContract = new ethers.Contract(token, [\n 'function transferFrom(address from, address to, uint256 amount) returns (bool)',\n ], wallet);\n\n const tx = await tokenContract.transferFrom(from, to, amount);\n const receipt = await tx.wait();\n \n return receipt.hash;\n }\n\n private async getTransactionReceipt(txHash: string, rpcUrl: string): Promise<any> {\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_getTransactionReceipt',\n params: [txHash],\n id: 1,\n }),\n });\n\n const data = await response.json() as { result: any };\n return data.result;\n }\n}\n\n/**\n * Create EIP-712 typed data for signing a payment intent\n * \n * Used by clients to sign their payment intent.\n */\nexport function createIntentTypedData(\n intent: Omit<BNBPaymentIntent, 'signature'>,\n chainId: number\n) {\n return {\n domain: {\n ...EIP712_DOMAIN,\n chainId,\n },\n types: INTENT_TYPES,\n primaryType: 'PaymentIntent' as const,\n message: {\n from: intent.from,\n to: intent.to,\n amount: intent.amount,\n token: intent.token,\n service: intent.service,\n nonce: intent.nonce,\n deadline: intent.deadline,\n },\n };\n}\n","/**\n * Solana Facilitator\n * \n * Pay-for-success payment settlement for Solana SPL token transfers.\n * Unlike EVM chains, Solana doesn't have a third-party facilitator - \n * we verify and settle directly on-chain.\n * \n * Flow:\n * 1. Client signs a SPL token transfer authorization\n * 2. Server receives the signed transaction\n * 3. Server verifies the signature and amount\n * 4. Server submits the transaction to settle payment\n */\n\nimport { \n Connection, \n PublicKey, \n Transaction,\n VersionedTransaction,\n sendAndConfirmTransaction,\n Keypair,\n} from '@solana/web3.js';\nimport {\n getAssociatedTokenAddress,\n createTransferCheckedInstruction,\n getAccount,\n createAssociatedTokenAccountInstruction,\n TOKEN_PROGRAM_ID,\n} from '@solana/spl-token';\nimport { \n BaseFacilitator, \n type X402PaymentPayload, \n type X402PaymentRequirements,\n type VerifyResult,\n type SettleResult,\n type HealthCheckResult,\n} from './interface.js';\nimport { SOLANA_CHAINS, type SolanaChainName } from '../chains/solana.js';\n\n/**\n * Solana payment payload structure\n */\nexport interface SolanaPaymentPayload {\n /** Base58 encoded signed transaction */\n signedTransaction: string;\n /** Sender's public key (Base58) */\n sender: string;\n /** Chain: solana or solana_devnet */\n chain: SolanaChainName;\n}\n\n/**\n * Solana Facilitator configuration\n */\nexport interface SolanaFacilitatorConfig {\n /** Optional fee payer keypair for gasless transactions */\n feePayerKeypair?: Keypair;\n}\n\n/**\n * Solana Facilitator for pay-for-success payments\n * \n * Supports gasless mode: if feePayerKeypair is provided, server pays tx fees\n */\nexport class SolanaFacilitator extends BaseFacilitator {\n readonly name = 'solana';\n readonly displayName = 'Solana Direct';\n readonly supportedNetworks = ['solana:mainnet', 'solana:devnet'];\n\n private connections: Map<SolanaChainName, Connection> = new Map();\n private feePayerKeypair?: Keypair;\n\n constructor(config?: SolanaFacilitatorConfig) {\n super();\n this.feePayerKeypair = config?.feePayerKeypair;\n \n // Initialize connections\n for (const [chain, config] of Object.entries(SOLANA_CHAINS)) {\n this.connections.set(\n chain as SolanaChainName, \n new Connection(config.rpc, 'confirmed')\n );\n }\n \n if (this.feePayerKeypair) {\n console.log(`[SolanaFacilitator] Gasless mode enabled. Fee payer: ${this.feePayerKeypair.publicKey.toBase58()}`);\n }\n }\n \n /**\n * Get fee payer public key (for gasless transactions)\n */\n getFeePayerPubkey(): string | null {\n return this.feePayerKeypair?.publicKey.toBase58() || null;\n }\n\n private getConnection(chain: SolanaChainName): Connection {\n const conn = this.connections.get(chain);\n if (!conn) {\n throw new Error(`No connection for chain: ${chain}`);\n }\n return conn;\n }\n\n /**\n * Convert our chain name to network identifier\n */\n static chainToNetwork(chain: SolanaChainName): string {\n return chain === 'solana' ? 'solana:mainnet' : 'solana:devnet';\n }\n\n /**\n * Convert network identifier to chain name\n */\n static networkToChain(network: string): SolanaChainName | null {\n if (network === 'solana:mainnet') return 'solana';\n if (network === 'solana:devnet') return 'solana_devnet';\n return null;\n }\n\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n // Check devnet connection\n const conn = this.getConnection('solana_devnet');\n await conn.getSlot();\n return {\n healthy: true,\n latencyMs: Date.now() - start,\n };\n } catch (error: any) {\n return {\n healthy: false,\n error: error.message,\n };\n }\n }\n\n /**\n * Verify a Solana payment\n * \n * Checks:\n * 1. Transaction is valid and properly signed\n * 2. Transfer instruction matches expected amount and recipient\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n try {\n const solanaPayload = paymentPayload.payload as SolanaPaymentPayload;\n if (!solanaPayload || !solanaPayload.signedTransaction) {\n return { valid: false, error: 'Missing signed transaction' };\n }\n\n const chain = solanaPayload.chain || 'solana_devnet';\n const chainConfig = SOLANA_CHAINS[chain];\n if (!chainConfig) {\n return { valid: false, error: `Invalid chain: ${chain}` };\n }\n\n // Decode the transaction\n const txBuffer = Buffer.from(solanaPayload.signedTransaction, 'base64');\n let tx: Transaction | VersionedTransaction;\n \n try {\n // Try legacy transaction first\n tx = Transaction.from(txBuffer);\n } catch {\n // Try versioned transaction\n tx = VersionedTransaction.deserialize(txBuffer);\n }\n\n // Verify at least one signature exists (may be partial in gasless mode)\n if (tx instanceof Transaction) {\n // In gasless mode, fee payer signature is added by server\n // Client only signs for token transfer authority\n const hasAnySignature = tx.signatures.some(sig => \n sig.signature && !sig.signature.every(b => b === 0)\n );\n if (!hasAnySignature) {\n return { valid: false, error: 'Transaction not signed' };\n }\n }\n\n // Parse expected values from requirements\n const expectedAmount = BigInt(requirements.amount);\n const expectedRecipient = new PublicKey(requirements.payTo);\n\n // For now, we trust the transaction structure\n // Full verification happens at settlement time\n return {\n valid: true,\n details: {\n chain,\n sender: solanaPayload.sender,\n recipient: requirements.payTo,\n amount: requirements.amount,\n },\n };\n } catch (error: any) {\n return { valid: false, error: error.message };\n }\n }\n\n /**\n * Settle a Solana payment\n * \n * Submits the signed transaction to the network.\n * In gasless mode, adds fee payer signature before submitting.\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n try {\n const solanaPayload = paymentPayload.payload as SolanaPaymentPayload;\n if (!solanaPayload || !solanaPayload.signedTransaction) {\n return { success: false, error: 'Missing signed transaction' };\n }\n\n const chain = solanaPayload.chain || 'solana_devnet';\n const connection = this.getConnection(chain);\n\n // Decode the transaction\n const txBuffer = Buffer.from(solanaPayload.signedTransaction, 'base64');\n \n let txToSend: Buffer;\n \n try {\n // Try legacy transaction\n const tx = Transaction.from(txBuffer);\n \n // Check if we need to add fee payer signature (gasless mode)\n if (this.feePayerKeypair && tx.feePayer) {\n const feePayerPubkey = this.feePayerKeypair.publicKey.toBase58();\n const txFeePayer = tx.feePayer.toBase58();\n \n if (txFeePayer === feePayerPubkey) {\n // Gasless mode: add fee payer signature\n console.log(`[SolanaFacilitator] Gasless mode: adding fee payer signature`);\n tx.partialSign(this.feePayerKeypair);\n }\n }\n \n txToSend = tx.serialize();\n } catch (e: any) {\n // Fall back to versioned transaction (no gasless support for versioned yet)\n txToSend = txBuffer;\n }\n\n // Send the transaction\n const signature = await connection.sendRawTransaction(txToSend, {\n skipPreflight: false,\n preflightCommitment: 'confirmed',\n });\n\n // Wait for confirmation\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n \n if (confirmation.value.err) {\n return {\n success: false,\n error: `Transaction failed: ${JSON.stringify(confirmation.value.err)}`,\n transaction: signature,\n };\n }\n\n return {\n success: true,\n transaction: signature,\n status: 'confirmed',\n };\n } catch (error: any) {\n return { success: false, error: error.message };\n }\n }\n\n supportsNetwork(network: string): boolean {\n return this.supportedNetworks.includes(network);\n }\n}\n\n/**\n * Create a Solana payment transaction for signing\n * \n * This is called by the client to create the transaction to sign.\n * \n * @param senderPubkey - The sender's public key (token owner)\n * @param recipientPubkey - The recipient's public key\n * @param amount - Amount in token base units\n * @param chain - Solana chain (solana or solana_devnet)\n * @param feePayerPubkey - Optional fee payer public key for gasless transactions\n */\nexport async function createSolanaPaymentTransaction(\n senderPubkey: PublicKey,\n recipientPubkey: PublicKey,\n amount: bigint,\n chain: SolanaChainName,\n feePayerPubkey?: PublicKey,\n connection?: Connection,\n): Promise<Transaction> {\n const chainConfig = SOLANA_CHAINS[chain];\n const conn = connection ?? new Connection(chainConfig.rpc, 'confirmed');\n const mint = new PublicKey(chainConfig.tokens.USDC.mint);\n\n // Determine who pays fees (gasless mode uses server's fee payer)\n const actualFeePayer = feePayerPubkey || senderPubkey;\n\n // Get ATAs\n const senderATA = await getAssociatedTokenAddress(mint, senderPubkey);\n const recipientATA = await getAssociatedTokenAddress(mint, recipientPubkey);\n\n const transaction = new Transaction();\n\n // Check if recipient ATA exists\n try {\n await getAccount(conn, recipientATA);\n } catch {\n // Create ATA for recipient (fee payer pays rent in gasless mode)\n transaction.add(\n createAssociatedTokenAccountInstruction(\n actualFeePayer, // payer (fee payer in gasless mode)\n recipientATA, // ata to create\n recipientPubkey, // owner\n mint // mint\n )\n );\n }\n\n // Add transfer instruction\n transaction.add(\n createTransferCheckedInstruction(\n senderATA, // source\n mint, // mint\n recipientATA, // destination\n senderPubkey, // owner (sender still authorizes the transfer)\n amount, // amount\n chainConfig.tokens.USDC.decimals // decimals\n )\n );\n\n // Get recent blockhash\n const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash();\n transaction.recentBlockhash = blockhash;\n transaction.feePayer = actualFeePayer;\n\n return transaction;\n}\n\nexport default SolanaFacilitator;\n","/**\n * Solana Chain Configuration\n * \n * Solana is NOT an EVM chain - uses different:\n * - Key format: ed25519 (EdDSA) vs secp256k1 (ECDSA)\n * - Address format: Base58 vs 0x hex\n * - Token standard: SPL vs ERC-20\n */\n\nimport { Connection, PublicKey } from '@solana/web3.js';\n\nexport interface SolanaChainConfig {\n name: string;\n cluster: 'mainnet-beta' | 'devnet' | 'testnet';\n rpc: string;\n explorer: string;\n explorerTx: string;\n tokens: {\n USDC: {\n mint: string;\n decimals: number;\n };\n };\n}\n\nexport type SolanaChainName = 'solana' | 'solana_devnet';\n\nexport const SOLANA_CHAINS: Record<SolanaChainName, SolanaChainConfig> = {\n solana: {\n name: 'Solana Mainnet',\n cluster: 'mainnet-beta',\n rpc: 'https://api.mainnet-beta.solana.com',\n explorer: 'https://solscan.io/account/',\n explorerTx: 'https://solscan.io/tx/',\n tokens: {\n USDC: {\n mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // Circle official USDC\n decimals: 6,\n },\n },\n },\n solana_devnet: {\n name: 'Solana Devnet',\n cluster: 'devnet',\n rpc: 'https://api.devnet.solana.com',\n explorer: 'https://solscan.io/account/',\n explorerTx: 'https://solscan.io/tx/',\n tokens: {\n USDC: {\n // Circle's devnet USDC (if not available, we'll deploy our own test token)\n mint: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',\n decimals: 6,\n },\n },\n },\n};\n\n/**\n * Get Solana RPC connection\n */\nexport function getSolanaConnection(chain: SolanaChainName): Connection {\n const config = SOLANA_CHAINS[chain];\n return new Connection(config.rpc, 'confirmed');\n}\n\n/**\n * Get USDC mint public key for a Solana chain\n */\nexport function getUSDCMint(chain: SolanaChainName): PublicKey {\n return new PublicKey(SOLANA_CHAINS[chain].tokens.USDC.mint);\n}\n\n/**\n * Get Solana chain config\n */\nexport function getSolanaChain(name: SolanaChainName): SolanaChainConfig {\n const config = SOLANA_CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported Solana chain: ${name}. Supported: ${Object.keys(SOLANA_CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * Check if a chain name is a Solana chain\n */\nexport function isSolanaChain(chain: string): chain is SolanaChainName {\n return chain === 'solana' || chain === 'solana_devnet';\n}\n\n/**\n * Get explorer URL for a Solana address\n */\nexport function getSolanaExplorerUrl(chain: SolanaChainName, address: string): string {\n const config = SOLANA_CHAINS[chain];\n const clusterParam = chain === 'solana_devnet' ? '?cluster=devnet' : '';\n return `${config.explorer}${address}${clusterParam}`;\n}\n\n/**\n * Get explorer URL for a Solana transaction\n */\nexport function getSolanaTxExplorerUrl(chain: SolanaChainName, signature: string): string {\n const config = SOLANA_CHAINS[chain];\n const clusterParam = chain === 'solana_devnet' ? '?cluster=devnet' : '';\n return `${config.explorerTx}${signature}${clusterParam}`;\n}\n","/**\n * Alipay AI Pay Facilitator (2.0.0)\n *\n * Implements the `Facilitator` interface for Alipay's AI Pay 402\n * protocol. Adds a fiat rail (CNY) alongside the existing USDC/EVM/SVM\n * rails. Server-side only; clients shell out to the `alipay-bot` CLI\n * (see `AlipayClient` under `src/client/alipay/` in 1.7.0-rc.2).\n *\n * Key protocol differences from x402:\n * - Wire challenge is Base64URL-encoded `Payment-Needed` header with\n * nested `{protocol, method}` JSON (not flat `accepts[]`).\n * - Amount unit is **yuan** (CNY decimal string, not atomic units).\n * - Signature is RSA2 (SHA256WithRSA), not EIP-712 / EIP-3009.\n * - Verify/settle hit Alipay Open API HTTP endpoints, not chain RPC.\n *\n * The server emits **both** `X-Payment-Required` and `Payment-Needed`\n * headers so that legacy `alipay-bot` skills (`@alipay/agent-payment@1.0.9`)\n * keep working without changes.\n *\n * @see ../../docs/ALIPAY-RAIL.md — end-user integration guide\n * @see ../../docs/ALIPAY-INTEGRATION-DESIGN.md — architecture & decisions\n * @see ../../docs/ALIPAY-INTEGRATION-PLAN.md — implementation milestones\n *\n * Stub for 1.7.0-rc.1; bodies tracked in ALIPAY-INTEGRATION-PLAN.md §1.\n */\n\nimport crypto from 'node:crypto';\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { rsa2Sign } from './alipay/rsa2.js';\nimport { base64url, decodeBase64UrlWithPadFix } from './alipay/encoding.js';\nimport { alipayOpenApiCall, AlipayOpenApiConfig } from './alipay/openapi.js';\n\n/** Network identifier exposed via `Facilitator.supportedNetworks`. */\nexport const ALIPAY_NETWORK = 'alipay';\n\n/** x402 `scheme` string identifying the Alipay rail in `accepts[]`. */\nexport const ALIPAY_SCHEME = 'alipay-aipay';\n\n/** Default production gateway URL. */\nexport const ALIPAY_GATEWAY_PROD = 'https://openapi.alipay.com/gateway.do';\n\n/** Sandbox gateway URL (for testing without real CNY). */\nexport const ALIPAY_GATEWAY_SANDBOX = 'https://openapi.alipaydev.com/gateway.do';\n\n/** Validation regex for `price_cny` / `amount` (decimal string, unit yuan, ≤ 2 decimal places). */\nexport const ALIPAY_AMOUNT_REGEX = /^\\d+(\\.\\d{1,2})?$/;\n\n/** Lifetime of a 402 challenge before `pay_before` expires (Alipay convention). */\nexport const ALIPAY_PAY_BEFORE_MS = 30 * 60 * 1000;\n\n/**\n * The 8 fields that get RSA2-signed in dictionary order for a 402 challenge.\n * Exposed for visibility; internal to {@link AlipayFacilitator}.\n */\nexport const ALIPAY_SIGNING_FIELDS = [\n 'amount',\n 'currency',\n 'goods_name',\n 'out_trade_no',\n 'pay_before',\n 'resource_id',\n 'seller_id',\n 'service_id',\n] as const;\n\n/**\n * Facilitator-level configuration sourced from `provider.alipay` in\n * `moltspay.services.json`. The server resolves `private_key_path` and\n * `alipay_public_key_path` to PEM strings before constructing the facilitator.\n */\nexport interface AlipayFacilitatorConfig {\n /** Merchant Alipay ID (16 digits, e.g. `\"2088641494699428\"`). */\n seller_id: string;\n /** Application ID from Alipay Open Platform. */\n app_id: string;\n /** Merchant legal name; appears in `method.seller_name` of the 402 challenge. */\n seller_name: string;\n /** Fallback `service_id` when a service doesn't override it. */\n service_id_default: string;\n /** RSA2 merchant private key (PEM). Loaded from `private_key_path` by the server. */\n private_key_pem: string;\n /** Alipay platform public key (PEM). Loaded from `alipay_public_key_path` by the server. */\n alipay_public_key_pem: string;\n /** Open API gateway URL. Defaults to {@link ALIPAY_GATEWAY_PROD}. */\n gateway_url?: string;\n /** Signature algorithm. Only `RSA2` is supported. */\n sign_type?: 'RSA2';\n}\n\n/**\n * Inputs required to construct a 402 `Payment-Needed` challenge for a service.\n */\nexport interface CreatePaymentRequirementsOpts {\n /** Per-service Alipay `service_id` (overrides `provider.alipay.service_id_default`). */\n serviceId: string;\n /** CNY price as decimal string in **yuan** (e.g. `\"1.00\"` = 1 CNY). */\n priceCny: string;\n /** Goods name shown to the user in the Alipay app. */\n goodsName: string;\n /** Resource identifier (typically the request URL or its hash). */\n resourceId: string;\n /** Client-supplied `out_trade_no`; if omitted the facilitator generates one. */\n outTradeNo?: string;\n}\n\n/**\n * Both headers the server emits in a 402 response:\n * - `x402Accepts` → `X-Payment-Required` (x402 standard, for new MoltsPay clients)\n * - `paymentNeededHeader` → `Payment-Needed` (Alipay standard, for legacy `alipay-bot`)\n *\n * The two headers are mirrors of each other; the single source of truth lives\n * in the server config.\n */\nexport interface AlipayPaymentRequirements {\n x402Accepts: X402PaymentRequirements;\n paymentNeededHeader: string;\n}\n\n/**\n * Decoded `Payment-Proof` header from the buyer's request.\n *\n * The proof is Base64URL of `{protocol: {...}, method: {...}}` where:\n * - `protocol.trade_no` is the 32-digit Alipay trade number\n * - `protocol.payment_proof` is the RSA2-signed payment proof\n * - `method.client_session` echoes the buyer's session for replay protection\n */\nexport interface AlipayPaymentProof {\n protocol: {\n payment_proof: string;\n trade_no: string;\n [k: string]: unknown;\n };\n method: {\n client_session: string;\n [k: string]: unknown;\n };\n}\n\n/**\n * Alipay AI Pay facilitator.\n *\n * Construction is cheap; expensive setup (key parsing, gateway probe) is\n * deferred to `healthCheck()`.\n */\nexport class AlipayFacilitator extends BaseFacilitator {\n readonly name = 'alipay';\n readonly displayName = 'Alipay AI Pay';\n readonly supportedNetworks = [ALIPAY_NETWORK];\n\n private readonly config: AlipayFacilitatorConfig;\n\n constructor(config: AlipayFacilitatorConfig) {\n super();\n this.config = {\n gateway_url: ALIPAY_GATEWAY_PROD,\n sign_type: 'RSA2',\n ...config,\n };\n }\n\n /**\n * Build the 402 challenge for a service: signs the 8-field payload with\n * RSA2, packages the nested `{protocol, method}` JSON as Base64URL for\n * `Payment-Needed`, and emits the parallel x402 `accepts[]` entry.\n */\n async createPaymentRequirements(\n opts: CreatePaymentRequirementsOpts,\n ): Promise<AlipayPaymentRequirements> {\n if (!ALIPAY_AMOUNT_REGEX.test(opts.priceCny)) {\n throw new Error(\n `AlipayFacilitator.createPaymentRequirements: priceCny \"${opts.priceCny}\" ` +\n `does not match /^\\\\d+(\\\\.\\\\d{1,2})?$/ (unit is yuan, not fen; e.g. \"1.00\" not \"100\")`,\n );\n }\n\n const now = new Date();\n const outTradeNo = opts.outTradeNo ?? generateOutTradeNo();\n const payBefore = formatPayBefore(now);\n\n // 8 fields signed (dictionary order enforced by `ALIPAY_SIGNING_FIELDS`)\n const signedFields = {\n amount: opts.priceCny,\n currency: 'CNY',\n goods_name: opts.goodsName,\n out_trade_no: outTradeNo,\n pay_before: payBefore,\n resource_id: opts.resourceId,\n seller_id: this.config.seller_id,\n service_id: opts.serviceId,\n } as const;\n\n const signingString = ALIPAY_SIGNING_FIELDS\n .map((k) => `${k}=${signedFields[k]}`)\n .join('&');\n const seller_signature = rsa2Sign(signingString, this.config.private_key_pem);\n\n const challenge = {\n protocol: {\n out_trade_no: outTradeNo,\n amount: signedFields.amount,\n currency: signedFields.currency,\n resource_id: signedFields.resource_id,\n pay_before: payBefore,\n seller_signature,\n seller_sign_type: this.config.sign_type ?? 'RSA2',\n seller_unique_id: this.config.seller_id,\n },\n method: {\n seller_name: this.config.seller_name,\n seller_id: this.config.seller_id,\n seller_app_id: this.config.app_id,\n goods_name: signedFields.goods_name,\n seller_unique_id_key: 'seller_id',\n service_id: signedFields.service_id,\n },\n };\n\n const paymentNeededHeader = base64url(JSON.stringify(challenge));\n\n const x402Accepts: X402PaymentRequirements = {\n scheme: ALIPAY_SCHEME,\n network: ALIPAY_NETWORK,\n asset: 'CNY',\n amount: opts.priceCny,\n payTo: this.config.seller_id,\n maxTimeoutSeconds: ALIPAY_PAY_BEFORE_MS / 1000,\n extra: {\n payment_needed_header: paymentNeededHeader,\n out_trade_no: outTradeNo,\n pay_before: payBefore,\n service_id: signedFields.service_id,\n },\n };\n\n return { x402Accepts, paymentNeededHeader };\n }\n\n /**\n * Verify a `Payment-Proof` by calling\n * `alipay.aipay.agent.payment.verify` against the Alipay Open API.\n *\n * The proof is conveyed via `paymentPayload.payload`, which may be:\n * - a raw Base64URL string (the `Payment-Proof` header value), or\n * - an object `{ paymentProof: string }` / `{ proofHeader: string }`.\n *\n * All failure modes (malformed payload, network errors, Alipay\n * `code != 10000`) return `{ valid: false, error }`. No exception\n * escapes, regardless of client-supplied input.\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n _requirements: X402PaymentRequirements,\n ): Promise<VerifyResult> {\n try {\n const proofHeader = extractProofHeader(paymentPayload.payload);\n const decoded = decodeProof(proofHeader);\n\n const response = await alipayOpenApiCall(\n 'alipay.aipay.agent.payment.verify',\n {\n payment_proof: decoded.protocol.payment_proof,\n trade_no: decoded.protocol.trade_no,\n client_session: decoded.method.client_session,\n },\n this.getOpenApiConfig(),\n );\n\n if (response.code !== '10000') {\n return {\n valid: false,\n error: `alipay verify ${response.code}: ${response.sub_msg ?? response.msg ?? 'unknown'}`,\n details: {\n code: response.code,\n sub_code: response.sub_code,\n sub_msg: response.sub_msg,\n },\n };\n }\n\n return {\n valid: true,\n details: {\n trade_no: (response.trade_no as string) ?? decoded.protocol.trade_no,\n amount: response.amount,\n out_trade_no: response.out_trade_no,\n resource_id: response.resource_id,\n active: response.active,\n },\n };\n } catch (e: unknown) {\n return {\n valid: false,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n }\n\n /**\n * Settle by calling `alipay.aipay.agent.fulfillment.confirm` after the\n * service resource has been returned to the buyer.\n *\n * Per the design (see ALIPAY-INTEGRATION-DESIGN.md §5.1, risk row\n * (a fulfillment-confirm failure), this is **fire-and-forget**: the caller (registry /\n * server) is expected to log fulfillment failures but NOT roll back\n * the already-delivered resource.\n *\n * Re-decodes `paymentPayload.payload` to extract `trade_no` (verify\n * does the same; the redundant Base64URL decode is negligible).\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n _requirements: X402PaymentRequirements,\n ): Promise<SettleResult> {\n try {\n const proofHeader = extractProofHeader(paymentPayload.payload);\n const decoded = decodeProof(proofHeader);\n const tradeNo = decoded.protocol.trade_no;\n\n const response = await alipayOpenApiCall(\n 'alipay.aipay.agent.fulfillment.confirm',\n { trade_no: tradeNo },\n this.getOpenApiConfig(),\n );\n\n if (response.code !== '10000') {\n return {\n success: false,\n transaction: tradeNo,\n error: `alipay fulfillment ${response.code}: ${response.sub_msg ?? response.msg ?? 'unknown'}`,\n status: 'fulfillment_failed',\n };\n }\n\n return {\n success: true,\n transaction: tradeNo,\n status: 'fulfilled',\n };\n } catch (e: unknown) {\n return {\n success: false,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n }\n\n /**\n * Validate that the configured RSA keys parse and that the Open API\n * gateway is reachable. Does NOT make a real business API call (would\n * burn quota and could appear as a legitimate verify attempt in logs).\n */\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n\n try {\n crypto.createPrivateKey(this.config.private_key_pem);\n } catch (e: unknown) {\n return {\n healthy: false,\n error: `merchant private_key_pem parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n try {\n crypto.createPublicKey(this.config.alipay_public_key_pem);\n } catch (e: unknown) {\n return {\n healthy: false,\n error: `alipay_public_key_pem parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n\n const gatewayUrl = this.config.gateway_url ?? ALIPAY_GATEWAY_PROD;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const response = await fetch(gatewayUrl, {\n method: 'HEAD',\n signal: controller.signal,\n }).catch(() => null);\n clearTimeout(timeout);\n\n const latencyMs = Date.now() - start;\n\n if (!response) {\n return { healthy: false, error: `gateway unreachable: ${gatewayUrl}`, latencyMs };\n }\n return { healthy: true, latencyMs };\n }\n\n /** Bundle the facilitator config into the shape openapi.ts wants. */\n private getOpenApiConfig(): AlipayOpenApiConfig {\n return {\n gateway_url: this.config.gateway_url ?? ALIPAY_GATEWAY_PROD,\n app_id: this.config.app_id,\n private_key_pem: this.config.private_key_pem,\n alipay_public_key_pem: this.config.alipay_public_key_pem,\n sign_type: this.config.sign_type,\n };\n }\n}\n\n// ─── Internal helpers (exported for unit testing only) ────────────────────────\n\n/**\n * Generate a 32-char `out_trade_no` with `VID` prefix + 29 random base64url\n * chars. Cryptographically random; uniqueness is statistical.\n *\n * @internal\n */\nexport function generateOutTradeNo(): string {\n // 22 random bytes → 30 base64url chars; slice 29 + \"VID\" prefix = 32 chars.\n return 'VID' + crypto.randomBytes(22).toString('base64url').slice(0, 29);\n}\n\n/**\n * Format `pay_before` as ISO 8601 UTC, exactly\n * {@link ALIPAY_PAY_BEFORE_MS} after the provided instant.\n * Strips fractional seconds for cleaner querystring signing.\n *\n * @internal\n */\nexport function formatPayBefore(now: Date): string {\n const expiry = new Date(now.getTime() + ALIPAY_PAY_BEFORE_MS);\n // toISOString returns \"YYYY-MM-DDTHH:mm:ss.sssZ\"; strip the ms.\n return expiry.toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n\n/**\n * Extract the Base64URL Payment-Proof header from `paymentPayload.payload`.\n * Accepts a bare string or an object with `paymentProof` / `proofHeader` key.\n *\n * @internal\n * @throws If the payload shape doesn't match either contract\n */\nexport function extractProofHeader(payload: unknown): string {\n if (typeof payload === 'string') {\n if (payload.length === 0) {\n throw new Error('alipay Payment-Proof is empty');\n }\n return payload;\n }\n if (payload !== null && typeof payload === 'object') {\n const obj = payload as Record<string, unknown>;\n const candidate = obj.paymentProof ?? obj.proofHeader;\n if (typeof candidate === 'string' && candidate.length > 0) {\n return candidate;\n }\n }\n throw new Error(\n 'alipay payment payload must be a Base64URL string or ' +\n '{paymentProof: string} / {proofHeader: string}',\n );\n}\n\n/**\n * Decode a Base64URL Payment-Proof header into its `{protocol, method}`\n * JSON shape, validating the three fields used by verify\n * (`protocol.payment_proof`, `protocol.trade_no`, `method.client_session`).\n *\n * @internal\n * @throws If decoding fails or required fields are missing\n */\nexport function decodeProof(proofHeader: string): AlipayPaymentProof {\n let parsed: unknown;\n try {\n parsed = JSON.parse(decodeBase64UrlWithPadFix(proofHeader));\n } catch (e: unknown) {\n throw new Error(\n `failed to decode Payment-Proof: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n if (parsed === null || typeof parsed !== 'object') {\n throw new Error('decoded Payment-Proof is not an object');\n }\n const obj = parsed as Record<string, unknown>;\n const protocol = obj.protocol as Record<string, unknown> | undefined;\n const method = obj.method as Record<string, unknown> | undefined;\n if (!protocol || typeof protocol.payment_proof !== 'string') {\n throw new Error('decoded Payment-Proof missing protocol.payment_proof');\n }\n if (typeof protocol.trade_no !== 'string') {\n throw new Error('decoded Payment-Proof missing protocol.trade_no');\n }\n if (!method || typeof method.client_session !== 'string') {\n throw new Error('decoded Payment-Proof missing method.client_session');\n }\n return parsed as AlipayPaymentProof;\n}\n","/**\n * RSA2 (SHA256WithRSA) signing helpers for Alipay AI Pay.\n *\n * Uses Node's built-in `crypto` module. On the merchant side, MoltsPay\n * signs the 8 fields of the 402 challenge in dictionary order\n * (`amount` / `currency` / `goods_name` / `out_trade_no` / `pay_before` /\n * `resource_id` / `seller_id` / `service_id`). On the verify side, the\n * Alipay platform public key is used against `Payment-Proof` headers.\n *\n * Padding: PKCS#1 v1.5 (Node default for `RSA-SHA256`), matching Alipay's\n * `SHA256WithRSA` algorithm identifier.\n */\n\nimport crypto from 'node:crypto';\n\n/**\n * Sign a string with RSA2 (SHA256WithRSA) using a PEM-encoded private key.\n *\n * @param data - The exact bytes to sign (already dictionary-sorted querystring)\n * @param privateKeyPem - PKCS#1 or PKCS#8 PEM-encoded RSA private key\n * @returns Base64-encoded signature suitable for the `seller_signature` field\n * @throws If the private key is malformed\n */\nexport function rsa2Sign(data: string, privateKeyPem: string): string {\n const signer = crypto.createSign('RSA-SHA256');\n signer.update(data, 'utf-8');\n signer.end();\n return signer.sign(privateKeyPem, 'base64');\n}\n\n/**\n * Verify an RSA2 signature against the Alipay platform public key.\n *\n * Returns `false` (never throws) for any failure — malformed input,\n * wrong key, tampered data, or invalid base64. Untrusted callers can\n * pass arbitrary `Payment-Proof` bytes safely.\n *\n * @param data - The exact bytes that were signed\n * @param signature - Base64-encoded signature from `Payment-Proof`\n * @param publicKeyPem - PEM-encoded Alipay platform public key\n * @returns `true` if and only if the signature is valid\n */\nexport function rsa2Verify(\n data: string,\n signature: string,\n publicKeyPem: string,\n): boolean {\n try {\n const verifier = crypto.createVerify('RSA-SHA256');\n verifier.update(data, 'utf-8');\n verifier.end();\n return verifier.verify(publicKeyPem, signature, 'base64');\n } catch {\n return false;\n }\n}\n","/**\n * Base64URL encoding helpers for Alipay AI Pay wire format.\n *\n * Alipay's `Payment-Needed` and `Payment-Proof` headers use Base64URL\n * (`-` replaces `+`, `_` replaces `/`, padding optional). Some proxies\n * strip the trailing `=` padding; `decodeBase64UrlWithPadFix` recovers it\n * and accepts either alphabet.\n */\n\n/**\n * Encode a UTF-8 string as Base64URL (no padding).\n *\n * @param input - UTF-8 string to encode\n * @returns Base64URL representation (no `=` padding)\n */\nexport function base64url(input: string): string {\n return Buffer.from(input, 'utf-8').toString('base64url');\n}\n\n/**\n * Decode a Base64URL (or standard Base64) string to a UTF-8 string.\n *\n * Tolerates either URL-safe (`-` `_`) or standard (`+` `/`) alphabets,\n * with or without trailing `=` padding. Used for `Payment-Needed` and\n * `Payment-Proof` headers where proxies may strip padding.\n *\n * @param input - Base64URL or Base64 string\n * @returns Decoded UTF-8 string\n */\nexport function decodeBase64UrlWithPadFix(input: string): string {\n const normalized = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);\n return Buffer.from(padded, 'base64').toString('utf-8');\n}\n\n/**\n * Normalize an RSA key into PEM form.\n *\n * Alipay Open Platform hands out keys as **bare Base64** (a single line of\n * Base64-encoded DER, no `-----BEGIN-----` armor), but Node's `crypto`\n * key loaders and {@link rsa2Sign} require PEM. This wraps bare Base64 in\n * the requested PEM armor (64-char lines per RFC 7468); input that already\n * carries a `-----BEGIN` header is returned unchanged (trimmed).\n *\n * @param key Bare Base64 (DER) or an already-armored PEM string.\n * @param kind `'PRIVATE'` → PKCS#8 `PRIVATE KEY`; `'PUBLIC'` → SPKI `PUBLIC KEY`.\n */\nexport function toPem(key: string, kind: 'PRIVATE' | 'PUBLIC'): string {\n const trimmed = key.trim();\n if (trimmed.includes('-----BEGIN')) return trimmed;\n const label = kind === 'PRIVATE' ? 'PRIVATE KEY' : 'PUBLIC KEY';\n const body = trimmed.replace(/\\s+/g, '').match(/.{1,64}/g)?.join('\\n') ?? '';\n return `-----BEGIN ${label}-----\\n${body}\\n-----END ${label}-----\\n`;\n}\n","/**\n * Alipay Open API caller for AI Pay verify and fulfillment.\n *\n * Wraps the `application/x-www-form-urlencoded` gateway protocol\n * (`https://openapi.alipay.com/gateway.do` for production,\n * `https://openapi.alipaydev.com/gateway.do` for sandbox). Handles\n * RSA2 request signing, response unwrapping, and gateway-level error\n * surfacing.\n *\n * Request envelope (8 public params + `sign`):\n * app_id — application ID\n * method — e.g. `alipay.aipay.agent.payment.verify`\n * format — `JSON`\n * charset — `utf-8`\n * sign_type — `RSA2`\n * timestamp — `YYYY-MM-DD HH:mm:ss`\n * version — `1.0`\n * biz_content — JSON-stringified business params\n * sign — RSA2 signature over the other 8 params sorted by key\n *\n * Response envelope:\n * { \"<method_with_underscores>_response\": { code, msg, ... } }\n *\n * NOTE: Response signature verification against the Alipay platform\n * public key is NOT implemented (relies on HTTPS transport integrity).\n * Adding it requires extracting raw bytes for the wrapped response key\n * from the response text; deferred to a future hardening pass.\n */\n\nimport { rsa2Sign } from './rsa2.js';\n\n/**\n * Configuration required to make a single Open API call.\n */\nexport interface AlipayOpenApiConfig {\n gateway_url: string;\n app_id: string;\n private_key_pem: string;\n alipay_public_key_pem: string;\n sign_type?: 'RSA2';\n}\n\n/**\n * Unwrapped response from an Alipay Open API call.\n *\n * `code` is the Alipay business code (`\"10000\"` = success).\n * `sub_code` / `sub_msg` carry the specific failure reason when `code != \"10000\"`.\n */\nexport interface AlipayOpenApiResponse {\n code: string;\n msg?: string;\n sub_code?: string;\n sub_msg?: string;\n [key: string]: unknown;\n}\n\n/**\n * Format a JS Date as Alipay's expected `YYYY-MM-DD HH:mm:ss` timestamp.\n * Uses local time (matches the convention of merchant-region Open API SDKs).\n *\n * Exported for unit testing only.\n */\nexport function formatAlipayTimestamp(d: Date = new Date()): string {\n const pad = (n: number): string => String(n).padStart(2, '0');\n return (\n `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +\n `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`\n );\n}\n\n/**\n * Build the signing string for a set of Alipay Open API parameters:\n * keys sorted alphabetically, joined as `key=value&key=value`. Values\n * are NOT URL-encoded at this stage.\n *\n * Exported for unit testing only.\n */\nexport function buildSigningString(params: Record<string, string>): string {\n return Object.keys(params)\n .sort()\n .map((k) => `${k}=${params[k]}`)\n .join('&');\n}\n\n/**\n * Derive the response wrapper key for a given method name.\n *\n * \"alipay.aipay.agent.payment.verify\"\n * → \"alipay_aipay_agent_payment_verify_response\"\n *\n * Exported for unit testing only.\n */\nexport function responseWrapperKey(method: string): string {\n return `${method.replace(/\\./g, '_')}_response`;\n}\n\n/**\n * Call an Alipay Open API method.\n *\n * Common methods used by MoltsPay:\n * - `alipay.aipay.agent.payment.verify` — verify a `Payment-Proof`\n * - `alipay.aipay.agent.fulfillment.confirm` — confirm fulfillment\n *\n * @param method - Alipay Open API method name\n * @param bizContent - Method-specific business parameters\n * @param config - Gateway URL + credentials\n * @returns Unwrapped business response; check `code === \"10000\"` for success\n * @throws On HTTP-level failure, malformed JSON, or missing response wrapper\n */\nexport async function alipayOpenApiCall(\n method: string,\n bizContent: Record<string, unknown>,\n config: AlipayOpenApiConfig,\n): Promise<AlipayOpenApiResponse> {\n const publicParams: Record<string, string> = {\n app_id: config.app_id,\n method,\n format: 'JSON',\n charset: 'utf-8',\n sign_type: config.sign_type ?? 'RSA2',\n timestamp: formatAlipayTimestamp(),\n version: '1.0',\n biz_content: JSON.stringify(bizContent),\n };\n\n const signingString = buildSigningString(publicParams);\n const sign = rsa2Sign(signingString, config.private_key_pem);\n\n const body = new URLSearchParams({ ...publicParams, sign }).toString();\n\n const response = await fetch(config.gateway_url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',\n },\n body,\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '<unreadable>');\n throw new Error(\n `Alipay Open API HTTP ${response.status} for ${method}: ${text.slice(0, 500)}`,\n );\n }\n\n const json = (await response.json()) as Record<string, unknown>;\n const wrapperKey = responseWrapperKey(method);\n const business = json[wrapperKey];\n\n if (business === undefined || business === null || typeof business !== 'object') {\n throw new Error(\n `Alipay Open API response missing \"${wrapperKey}\" wrapper for ${method}: ` +\n `${JSON.stringify(json).slice(0, 500)}`,\n );\n }\n\n return business as AlipayOpenApiResponse;\n}\n","/**\n * WeChat Pay v3 Facilitator (Native, scenario A).\n *\n * Implements the `Facilitator` interface for WeChat Pay's v3 **Native**\n * (scan-to-pay) flow. Adds a CNY fiat rail alongside the USDC/EVM/SVM and\n * Alipay rails. Server-side only.\n *\n * Scenario A — \"agent issues a code, payer is not pre-bound\":\n * - `createPaymentRequirements` places a Native order and returns its\n * `code_url`. The code is **payer-agnostic** (no openid, unlike JSAPI):\n * any WeChat user can scan it. It is **one-code-one-payment** — the first\n * payer settles the order; collect again by issuing a new code.\n * - `verify` polls the order (`trade_state === 'SUCCESS'`).\n * - `settle` re-confirms SUCCESS and returns the `transaction_id` (Native\n * captures funds at SUCCESS; there is no separate capture step).\n *\n * Key protocol differences from Alipay AI Pay (see docs/WECHAT-RAIL-DESIGN.md §3):\n * - REST/JSON gateway, not a form-urlencoded `gateway.do`.\n * - SHA256-RSA over `METHOD\\nURL\\nTS\\nNONCE\\nBODY\\n`, packed into the\n * `Authorization` header (handled by ./wechat/api.ts + ./wechat/sign.ts).\n * - Amount unit is **fen** (integer cents), not yuan — `cnyToFen` converts.\n *\n * Async callback decryption (AES-256-GCM) and the notify webhook are NOT in\n * this milestone; scenario A confirms via polling. They land in Phase 2.\n *\n * @see ./wechat/sign.ts — signing primitives\n * @see ./wechat/api.ts — v3 JSON caller\n * @see ../../docs/WECHAT-RAIL-DESIGN.md — design & scenario\n */\n\nimport crypto from 'node:crypto';\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport { WechatV3Config, wechatV3Call, WechatApiError, WECHAT_API_BASE } from './wechat/api.js';\n\n/** Network identifier exposed via `Facilitator.supportedNetworks`. */\nexport const WECHAT_NETWORK = 'wechat';\n\n/** x402 `scheme` string identifying the WeChat Native rail in `accepts[]`. */\nexport const WECHAT_SCHEME = 'wechatpay-native';\n\n/** Validation regex for `price_cny` (decimal string, unit yuan, <= 2 decimals). */\nexport const WECHAT_AMOUNT_REGEX = /^\\d+(\\.\\d{1,2})?$/;\n\n/** Default order lifetime if the caller doesn't pass one (Native convention). */\nexport const WECHAT_TIME_EXPIRE_MS = 5 * 60 * 1000;\n\nexport { WECHAT_API_BASE };\n\n/**\n * Facilitator-level config sourced from `provider.wechat` in\n * `moltspay.services.json`. The server resolves `private_key_path` /\n * `platform_public_key_path` to PEM strings before constructing this.\n */\nexport interface WechatFacilitatorConfig {\n /** Merchant id (mchid). */\n mchid: string;\n /** App id (official account / mini-program / app). */\n appid: string;\n /** Merchant API certificate serial number. */\n serial_no: string;\n /** Merchant RSA private key (PEM). */\n private_key_pem: string;\n /** WeChat platform certificate public key (PEM). Enables response verify. */\n platform_public_key_pem?: string;\n /** APIv3 key (32 bytes). Only needed for callback decryption (Phase 2). */\n apiv3_key?: string;\n /** Async result notify URL. **Required by Native order create** even when polling. */\n notify_url: string;\n /** Base URL; defaults to {@link WECHAT_API_BASE}. */\n api_base?: string;\n}\n\n/** Inputs to place a Native order (402 challenge) for a service. */\nexport interface CreatePaymentRequirementsOpts {\n /** CNY price as a decimal string in **yuan** (e.g. `\"10.00\"`). */\n priceCny: string;\n /** Order description shown to the payer in the WeChat app. */\n description: string;\n /** Client-supplied `out_trade_no`; generated when omitted. */\n outTradeNo?: string;\n /** Order lifetime; defaults to {@link WECHAT_TIME_EXPIRE_MS}. */\n expiresInMs?: number;\n /**\n * Passthrough metadata WeChat echoes back on order-query and callback\n * (v3 `attach`, max 128 bytes once JSON-serialized). Used to bind an\n * otherwise payer-agnostic Native order to a `buyer_id` for balance\n * top-ups. Read it back with {@link parseWechatAttach}.\n */\n attach?: Record<string, string>;\n}\n\n/** Result of placing a Native order. */\nexport interface WechatPaymentRequirements {\n /** x402 `accepts[]` entry (carries `extra.code_url` + `extra.out_trade_no`). */\n x402Accepts: X402PaymentRequirements;\n /** `weixin://wxpay/bizpayurl?pr=...` — render verbatim as a QR. */\n codeUrl: string;\n /** The order's merchant trade number, used to poll `verify`/`settle`. */\n outTradeNo: string;\n}\n\n/**\n * WeChat Pay v3 Native facilitator.\n *\n * Construction is cheap; key parsing / gateway probe is deferred to\n * `healthCheck()`.\n */\nexport class WechatFacilitator extends BaseFacilitator {\n readonly name = 'wechat';\n readonly displayName = 'WeChat Pay';\n readonly supportedNetworks = [WECHAT_NETWORK];\n\n private readonly config: WechatFacilitatorConfig;\n\n constructor(config: WechatFacilitatorConfig) {\n super();\n this.config = { api_base: WECHAT_API_BASE, ...config };\n }\n\n /**\n * Place a Native order and build the 402 challenge. The returned\n * `code_url` is payer-agnostic — any WeChat user may scan it.\n */\n async createPaymentRequirements(\n opts: CreatePaymentRequirementsOpts,\n ): Promise<WechatPaymentRequirements> {\n if (!WECHAT_AMOUNT_REGEX.test(opts.priceCny)) {\n throw new Error(\n `WechatFacilitator.createPaymentRequirements: priceCny \"${opts.priceCny}\" ` +\n `does not match /^\\\\d+(\\\\.\\\\d{1,2})?$/ (unit is yuan; e.g. \"10.00\")`,\n );\n }\n const total = cnyToFen(opts.priceCny);\n if (total < 1) {\n throw new Error(\n `WechatFacilitator.createPaymentRequirements: amount ${total} fen is below the 1 fen minimum`,\n );\n }\n\n const outTradeNo = opts.outTradeNo ?? generateOutTradeNo();\n const expiresInMs = opts.expiresInMs ?? WECHAT_TIME_EXPIRE_MS;\n\n const body: Record<string, unknown> = {\n appid: this.config.appid,\n mchid: this.config.mchid,\n description: opts.description,\n out_trade_no: outTradeNo,\n notify_url: this.config.notify_url,\n time_expire: formatTimeExpire(new Date(Date.now() + expiresInMs)),\n amount: { total, currency: 'CNY' },\n };\n\n if (opts.attach) {\n const attachStr = JSON.stringify(opts.attach);\n if (Buffer.byteLength(attachStr, 'utf8') > 128) {\n throw new Error(\n `WechatFacilitator.createPaymentRequirements: attach exceeds WeChat's 128-byte limit (${Buffer.byteLength(attachStr, 'utf8')} bytes)`,\n );\n }\n body.attach = attachStr;\n }\n\n const { body: resp } = await wechatV3Call(\n 'POST',\n '/v3/pay/transactions/native',\n body,\n this.getApiConfig(),\n );\n\n const codeUrl = resp.code_url;\n if (typeof codeUrl !== 'string' || codeUrl.length === 0) {\n throw new Error(\n `WeChat Native order returned no code_url: ${JSON.stringify(resp).slice(0, 300)}`,\n );\n }\n\n const x402Accepts: X402PaymentRequirements = {\n scheme: WECHAT_SCHEME,\n network: WECHAT_NETWORK,\n asset: 'CNY',\n amount: opts.priceCny,\n payTo: this.config.mchid,\n maxTimeoutSeconds: Math.floor(expiresInMs / 1000),\n extra: {\n code_url: codeUrl,\n out_trade_no: outTradeNo,\n },\n };\n\n return { x402Accepts, codeUrl, outTradeNo };\n }\n\n /**\n * Poll an order: `trade_state === 'SUCCESS'` ⇒ paid. All failure modes\n * (missing out_trade_no, gateway error, not-yet-paid) return\n * `{ valid: false, error }`; no exception escapes.\n */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements,\n ): Promise<VerifyResult> {\n try {\n const outTradeNo = extractOutTradeNo(paymentPayload, requirements);\n const resp = await this.queryOrder(outTradeNo);\n const tradeState = resp.trade_state as string | undefined;\n\n if (tradeState !== 'SUCCESS') {\n return {\n valid: false,\n error: `wechat trade_state ${tradeState ?? 'UNKNOWN'}`,\n details: { trade_state: tradeState, out_trade_no: outTradeNo },\n };\n }\n\n return {\n valid: true,\n details: {\n trade_state: tradeState,\n transaction_id: resp.transaction_id,\n out_trade_no: resp.out_trade_no ?? outTradeNo,\n amount: resp.amount,\n attach: resp.attach,\n // Payer identity, gateway-attested. Present on a SUCCESS Native\n // order even though order creation was payer-agnostic; anchors the\n // custodial balance to a real WeChat user. @see WECHAT fiat auth design.\n openid: (resp.payer as { openid?: string } | undefined)?.openid,\n },\n };\n } catch (e: unknown) {\n return { valid: false, error: e instanceof Error ? e.message : String(e) };\n }\n }\n\n /**\n * Confirm settlement. Native captures funds at SUCCESS, so this is an\n * idempotent re-confirm that returns the `transaction_id`. Like Alipay's\n * fulfillment confirm, failures are surfaced but non-fatal to an\n * already-delivered resource (caller logs, does not roll back).\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements,\n ): Promise<SettleResult> {\n try {\n const outTradeNo = extractOutTradeNo(paymentPayload, requirements);\n const resp = await this.queryOrder(outTradeNo);\n const tradeState = resp.trade_state as string | undefined;\n const transactionId = resp.transaction_id as string | undefined;\n\n if (tradeState !== 'SUCCESS') {\n return {\n success: false,\n transaction: transactionId,\n error: `wechat trade_state ${tradeState ?? 'UNKNOWN'} (expected SUCCESS)`,\n status: tradeState,\n };\n }\n\n return { success: true, transaction: transactionId, status: 'fulfilled' };\n } catch (e: unknown) {\n return { success: false, error: e instanceof Error ? e.message : String(e) };\n }\n }\n\n /**\n * Validate keys parse, apiv3 key length, and gateway reachability. Does\n * NOT make a business API call.\n */\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n\n try {\n crypto.createPrivateKey(this.config.private_key_pem);\n } catch (e: unknown) {\n return {\n healthy: false,\n error: `merchant private_key_pem parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n if (this.config.platform_public_key_pem) {\n try {\n crypto.createPublicKey(this.config.platform_public_key_pem);\n } catch (e: unknown) {\n return {\n healthy: false,\n error: `platform_public_key_pem parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n }\n if (this.config.apiv3_key !== undefined && Buffer.byteLength(this.config.apiv3_key, 'utf-8') !== 32) {\n return { healthy: false, error: 'apiv3_key must be exactly 32 bytes' };\n }\n\n const base = this.config.api_base ?? WECHAT_API_BASE;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const response = await fetch(base, { method: 'HEAD', signal: controller.signal }).catch(() => null);\n clearTimeout(timeout);\n\n const latencyMs = Date.now() - start;\n if (!response) {\n return { healthy: false, error: `gateway unreachable: ${base}`, latencyMs };\n }\n return { healthy: true, latencyMs };\n }\n\n /** Query a Native order by out_trade_no. The query string is part of the signed path. */\n private async queryOrder(outTradeNo: string): Promise<Record<string, unknown>> {\n const path =\n `/v3/pay/transactions/out-trade-no/${encodeURIComponent(outTradeNo)}` +\n `?mchid=${encodeURIComponent(this.config.mchid)}`;\n const { body } = await wechatV3Call('GET', path, null, this.getApiConfig());\n return body;\n }\n\n /** Project the facilitator config down to what api.ts needs. */\n private getApiConfig(): WechatV3Config {\n return {\n mchid: this.config.mchid,\n serial_no: this.config.serial_no,\n private_key_pem: this.config.private_key_pem,\n platform_public_key_pem: this.config.platform_public_key_pem,\n api_base: this.config.api_base,\n };\n }\n}\n\n// ─── Internal helpers (exported for unit testing only) ────────────────────────\n\n/**\n * Convert a CNY yuan decimal string to integer fen.\n * Uses rounding to avoid binary float drift (`0.10 * 100 = 10.000000000000002`).\n *\n * @internal\n */\nexport function cnyToFen(cny: string): number {\n return Math.round(parseFloat(cny) * 100);\n}\n\n/**\n * Generate a 32-char `out_trade_no`: `WX` prefix + 30 hex chars.\n * Within WeChat's allowed charset (`[a-zA-Z0-9_-|*@]`) and 6–32 length.\n *\n * @internal\n */\nexport function generateOutTradeNo(): string {\n return 'WX' + crypto.randomBytes(15).toString('hex');\n}\n\n/**\n * Safely parse the `attach` string echoed back on order-query / callback into\n * the object passed to {@link CreatePaymentRequirementsOpts.attach}. Returns\n * null for a missing, non-string, or malformed value (a per-transaction order\n * that carried no attach, or tampered input) so callers never throw on it.\n */\nexport function parseWechatAttach(attach: unknown): Record<string, string> | null {\n if (typeof attach !== 'string' || attach.length === 0) return null;\n try {\n const parsed = JSON.parse(attach);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, string>)\n : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Format a Date as WeChat's RFC 3339 `time_expire` with timezone offset\n * (e.g. `2026-06-27T12:30:00+08:00`). Uses the host timezone offset.\n *\n * @internal\n */\nexport function formatTimeExpire(d: Date): string {\n const pad = (n: number): string => String(n).padStart(2, '0');\n const offMin = -d.getTimezoneOffset();\n const sign = offMin >= 0 ? '+' : '-';\n const abs = Math.abs(offMin);\n return (\n `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +\n `T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}` +\n `${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`\n );\n}\n\n/**\n * Extract `out_trade_no` from the payment payload or, failing that, the\n * requirements `extra`. Accepts the payload as a bare string or an object\n * with `out_trade_no` / `outTradeNo`.\n *\n * @internal\n * @throws If no out_trade_no can be found\n */\nexport function extractOutTradeNo(\n paymentPayload: X402PaymentPayload,\n requirements?: X402PaymentRequirements,\n): string {\n const p = paymentPayload?.payload;\n if (typeof p === 'string' && p.length > 0) return p;\n if (p !== null && typeof p === 'object') {\n const obj = p as Record<string, unknown>;\n const cand = obj.out_trade_no ?? obj.outTradeNo;\n if (typeof cand === 'string' && cand.length > 0) return cand;\n }\n const fromReq = requirements?.extra?.out_trade_no;\n if (typeof fromReq === 'string' && fromReq.length > 0) return fromReq;\n\n throw new Error(\n 'wechat payment payload must carry out_trade_no (string, ' +\n '{out_trade_no}/{outTradeNo}, or requirements.extra.out_trade_no)',\n );\n}\n\nexport { WechatApiError };\n","/**\n * WeChat Pay v3 signing / verification helpers (SHA256-RSA).\n *\n * Direction of trust:\n * - **Request** (merchant → WeChat): sign the canonical\n * `METHOD\\nURL\\nTIMESTAMP\\nNONCE\\nBODY\\n` string with the merchant RSA\n * private key, then pack it into the `Authorization` header.\n * - **Response / callback** (WeChat → merchant): verify the\n * `Wechatpay-Signature` header over `TIMESTAMP\\nNONCE\\nBODY\\n` using the\n * WeChat **platform certificate** public key.\n *\n * Padding is PKCS#1 v1.5 (Node default for `RSA-SHA256`), which is what\n * WeChat Pay v3 uses (`WECHATPAY2-SHA256-RSA2048`).\n *\n * @see https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-generation.html\n */\n\nimport crypto from 'node:crypto';\n\n/** The auth scheme token WeChat Pay v3 mandates in the Authorization header. */\nexport const WECHAT_AUTH_SCHEMA = 'WECHATPAY2-SHA256-RSA2048';\n\n/**\n * Build the canonical message that v3 signs for an outbound request.\n *\n * `urlPath` is the path **plus query string** (e.g.\n * `/v3/pay/transactions/out-trade-no/X?mchid=Y`), NOT the full URL.\n * `body` is the exact request body bytes (`\"\"` for GET / no-body requests).\n *\n * Exported for unit testing only.\n */\nexport function buildRequestMessage(\n method: string,\n urlPath: string,\n timestamp: string,\n nonce: string,\n body: string,\n): string {\n return `${method.toUpperCase()}\\n${urlPath}\\n${timestamp}\\n${nonce}\\n${body}\\n`;\n}\n\n/**\n * Sign an outbound v3 request with the merchant private key.\n *\n * @returns Base64 signature for the `signature=\"...\"` field\n * @throws If the private key is malformed\n */\nexport function wechatV3Sign(\n method: string,\n urlPath: string,\n timestamp: string,\n nonce: string,\n body: string,\n privateKeyPem: string,\n): string {\n const message = buildRequestMessage(method, urlPath, timestamp, nonce, body);\n const signer = crypto.createSign('RSA-SHA256');\n signer.update(message, 'utf-8');\n signer.end();\n return signer.sign(privateKeyPem, 'base64');\n}\n\n/**\n * Assemble the `Authorization` header value for a v3 request.\n *\n * WECHATPAY2-SHA256-RSA2048 mchid=\"..\",nonce_str=\"..\",signature=\"..\",timestamp=\"..\",serial_no=\"..\"\n */\nexport function buildAuthorizationToken(args: {\n mchid: string;\n serialNo: string;\n nonce: string;\n timestamp: string;\n signature: string;\n}): string {\n const fields = [\n `mchid=\"${args.mchid}\"`,\n `nonce_str=\"${args.nonce}\"`,\n `signature=\"${args.signature}\"`,\n `timestamp=\"${args.timestamp}\"`,\n `serial_no=\"${args.serialNo}\"`,\n ].join(',');\n return `${WECHAT_AUTH_SCHEMA} ${fields}`;\n}\n\n/**\n * Verify a `Wechatpay-Signature` over a response or async callback.\n *\n * Returns `false` (never throws) for any failure — malformed key, bad\n * base64, tampered body, wrong key. Untrusted callback bytes are safe to\n * pass in.\n *\n * @param platformPublicKeyPem PEM public key extracted from the WeChat\n * platform certificate (the cert WeChat issues, NOT the merchant key).\n */\nexport function wechatV3VerifyResponse(\n timestamp: string,\n nonce: string,\n body: string,\n signature: string,\n platformPublicKeyPem: string,\n): boolean {\n try {\n const message = `${timestamp}\\n${nonce}\\n${body}\\n`;\n const verifier = crypto.createVerify('RSA-SHA256');\n verifier.update(message, 'utf-8');\n verifier.end();\n return verifier.verify(platformPublicKeyPem, signature, 'base64');\n } catch {\n return false;\n }\n}\n\n/**\n * Generate a v3 `nonce_str` (32 hex chars). Cryptographically random.\n */\nexport function generateNonce(): string {\n return crypto.randomBytes(16).toString('hex');\n}\n","/**\n * WeChat Pay v3 JSON API caller.\n *\n * Wraps the REST/JSON gateway (`https://api.mch.weixin.qq.com`). Handles:\n * - SHA256-RSA request signing + the `Authorization` header (see ./sign.ts)\n * - JSON body / response marshalling\n * - optional response signature verification against the WeChat platform\n * public key (enabled when `platform_public_key_pem` is configured)\n * - uniform error surfacing: non-2xx throws a {@link WechatApiError} carrying\n * the gateway `code`/`message`\n *\n * Unlike Alipay's form-urlencoded gateway, v3 is plain REST: the method +\n * path + body are signed, and the business payload IS the HTTP body (no\n * `biz_content` wrapper).\n *\n * @see https://pay.weixin.qq.com/docs/merchant/development/interface-rules/\n */\n\nimport {\n wechatV3Sign,\n buildAuthorizationToken,\n wechatV3VerifyResponse,\n generateNonce,\n} from './sign.js';\n\n/** Default production base URL for the v3 REST gateway. */\nexport const WECHAT_API_BASE = 'https://api.mch.weixin.qq.com';\n\n/**\n * Credentials + endpoint for a single v3 call. Sourced from\n * `provider.wechat` in `moltspay.services.json` (PEMs resolved by the server).\n */\nexport interface WechatV3Config {\n /** Merchant id (mchid). */\n mchid: string;\n /** Merchant API certificate serial number. */\n serial_no: string;\n /** Merchant RSA private key (PEM). */\n private_key_pem: string;\n /**\n * WeChat platform certificate public key (PEM). When present, every\n * response signature is verified; when absent, verification is skipped\n * (relies on HTTPS transport integrity — first-version fallback).\n */\n platform_public_key_pem?: string;\n /** Base URL; defaults to {@link WECHAT_API_BASE}. */\n api_base?: string;\n}\n\n/**\n * Error thrown for any non-2xx v3 response.\n *\n * `code` is the WeChat business error code (e.g. `ORDERNOTEXIST`,\n * `PARAM_ERROR`); `status` is the HTTP status.\n */\nexport class WechatApiError extends Error {\n readonly status: number;\n readonly code?: string;\n\n constructor(message: string, status: number, code?: string) {\n super(message);\n this.name = 'WechatApiError';\n this.status = status;\n this.code = code;\n }\n}\n\n/** Successful v3 call result: HTTP status + parsed JSON body (empty object for 204). */\nexport interface WechatV3Response {\n status: number;\n body: Record<string, unknown>;\n}\n\n/**\n * Call a WeChat Pay v3 endpoint.\n *\n * @param method HTTP verb (`GET` / `POST`)\n * @param urlPath Path **plus query string** (e.g.\n * `/v3/pay/transactions/out-trade-no/X?mchid=Y`). This exact\n * string is what gets signed.\n * @param body Business object for POST; `null` for GET / no-body.\n * @param config Credentials + endpoint.\n * @returns `{ status, body }` for 2xx responses.\n * @throws {WechatApiError} on non-2xx, or {@link Error} on transport/parse\n * failure or a failed response-signature check.\n */\nexport async function wechatV3Call(\n method: 'GET' | 'POST',\n urlPath: string,\n body: Record<string, unknown> | null,\n config: WechatV3Config,\n): Promise<WechatV3Response> {\n const base = config.api_base ?? WECHAT_API_BASE;\n const bodyStr = body === null ? '' : JSON.stringify(body);\n const timestamp = String(Math.floor(Date.now() / 1000));\n const nonce = generateNonce();\n\n const signature = wechatV3Sign(\n method,\n urlPath,\n timestamp,\n nonce,\n bodyStr,\n config.private_key_pem,\n );\n const authorization = buildAuthorizationToken({\n mchid: config.mchid,\n serialNo: config.serial_no,\n nonce,\n timestamp,\n signature,\n });\n\n const response = await fetch(`${base}${urlPath}`, {\n method,\n headers: {\n Authorization: authorization,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n // WeChat requires a non-empty UA; some edge nodes 403 a blank one.\n 'User-Agent': 'moltspay-wechat/1.0',\n },\n body: method === 'GET' ? undefined : bodyStr,\n });\n\n const text = await response.text();\n\n // Optional response-signature verification (resp headers + raw body).\n if (config.platform_public_key_pem && text.length > 0) {\n const ts = response.headers.get('Wechatpay-Timestamp');\n const nc = response.headers.get('Wechatpay-Nonce');\n const sig = response.headers.get('Wechatpay-Signature');\n if (!ts || !nc || !sig) {\n throw new Error(\n `WeChat v3 ${method} ${urlPath}: response missing Wechatpay-Signature headers`,\n );\n }\n if (!wechatV3VerifyResponse(ts, nc, text, sig, config.platform_public_key_pem)) {\n throw new Error(\n `WeChat v3 ${method} ${urlPath}: response signature verification failed`,\n );\n }\n }\n\n let json: Record<string, unknown> = {};\n if (text.length > 0) {\n try {\n json = JSON.parse(text) as Record<string, unknown>;\n } catch {\n throw new Error(\n `WeChat v3 ${method} ${urlPath}: non-JSON response (HTTP ${response.status}): ${text.slice(0, 300)}`,\n );\n }\n }\n\n if (!response.ok) {\n const code = typeof json.code === 'string' ? json.code : undefined;\n const message = typeof json.message === 'string' ? json.message : text.slice(0, 300);\n throw new WechatApiError(\n `WeChat v3 ${method} ${urlPath} failed: HTTP ${response.status}${code ? ` ${code}` : ''}: ${message}`,\n response.status,\n code,\n );\n }\n\n return { status: response.status, body: json };\n}\n","/**\n * Custodial balance ledger (SQLite).\n *\n * Backs the balance (\"password-free\" / password-free) rail: buyers top up once and\n * subsequent purchases are deducted server-side — no signature or scan per\n * transaction. All amounts are **integer cents** (`*_sat`, 1 USD = 100) to\n * avoid floating-point drift; the dollar<->cent boundary is `toSat`/`fromSat`.\n *\n * Uses the Node built-in `node:sqlite` (zero new dependencies). That module\n * is only available on Node >= 22.5, so it is loaded lazily inside the\n * constructor: servers that don't enable the balance rail keep the package's\n * `node >= 18` floor.\n *\n * Concurrency: `DatabaseSync` is synchronous and single-connection, so every\n * ledger call is naturally serialized within the process — the\n * check-and-deduct UPDATE (`... WHERE balance_sat >= ?`) is atomic without\n * explicit transactions. WAL mode keeps concurrent readers cheap.\n *\n * @see ../../../docs/BALANCE-RAIL-DESIGN.md — data model & semantics\n */\n\nimport { randomUUID } from 'node:crypto';\n\n/** Buyer account row (amounts in integer cents). */\nexport interface BuyerRow {\n buyer_id: string;\n display_name: string | null;\n balance_sat: number;\n total_topup_sat: number;\n total_spent_sat: number;\n daily_limit_sat: number;\n single_limit_sat: number;\n status: 'active' | 'frozen' | 'banned';\n /**\n * TOFU-bound originator signer address (EVM, lowercase 0x…) for the\n * WeChat fiat auth flow. Null for legacy accounts never seen with a\n * signature; bound on first signed request. @see ./auth.ts\n */\n signer_address: string | null;\n /**\n * Gateway-attested WeChat payer openid that funded this account, recorded\n * on top-up confirm. Anchors the custodial balance to a real WeChat user.\n * Null for accounts never funded via WeChat (crypto/alipay/operator).\n */\n wechat_openid: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/** Ledger transaction row (amounts in integer cents, always positive). */\nexport interface LedgerTxRow {\n id: string;\n buyer_id: string;\n type: 'topup' | 'deduct' | 'refund';\n amount_sat: number;\n service: string | null;\n description: string | null;\n /** Client-supplied idempotency key (deducts). Unique when present. */\n request_id: string | null;\n /** External settlement reference: on-chain tx hash / Alipay or WeChat trade no. */\n external_ref: string | null;\n /** For refunds: the deduct row being reversed. */\n refunds_tx_id: string | null;\n status: 'completed' | 'refunded';\n created_at: string;\n}\n\nexport type DeductErrorCode =\n | 'buyer_not_found'\n | 'buyer_not_active'\n | 'insufficient_balance'\n | 'exceeds_single_limit'\n | 'exceeds_daily_limit';\n\nexport interface DeductResult {\n success: boolean;\n /** Ledger transaction id (also returned on an idempotent replay). */\n txId?: string;\n /** True when `request_id` matched an existing deduct — nothing was charged. */\n replayed?: boolean;\n balanceSat?: number;\n error?: DeductErrorCode;\n /** Populated for limit errors. */\n limitSat?: number;\n}\n\nexport interface DeductOpts {\n buyerId: string;\n amountSat: number;\n /** Idempotency key; a replay returns the original tx without deducting. */\n requestId?: string;\n service?: string;\n description?: string;\n}\n\nexport interface TopupOpts {\n buyerId: string;\n amountSat: number;\n /** On-chain tx hash / Alipay trade_no / WeChat out_trade_no. Unique — a\n * replayed reference credits nothing and returns the original row. */\n externalRef: string;\n description?: string;\n}\n\nexport interface RefundResult {\n success: boolean;\n txId?: string;\n balanceSat?: number;\n /** True when the deduct was already refunded — nothing was credited. */\n replayed?: boolean;\n error?: 'tx_not_found' | 'not_a_deduct';\n}\n\nexport interface LedgerConfig {\n /** SQLite file path, or ':memory:' for tests. */\n dbPath: string;\n /** Default per-transaction limit for new buyers, integer cents. */\n defaultSingleLimitSat?: number;\n /** Default daily limit for new buyers, integer cents. */\n defaultDailyLimitSat?: number;\n /**\n * Ledger quote currency (e.g. 'USD', 'CNY'). Recorded once in `ledger_meta`\n * on first init and enforced on every subsequent open: the minor unit\n * (`*_sat`) is 1/100 of this currency, so reopening a USD ledger as CNY would\n * silently reinterpret every balance. Defaults to \"USD\".\n */\n currency?: string;\n}\n\nexport const DEFAULT_SINGLE_LIMIT_SAT = 500; // 5.00\nexport const DEFAULT_DAILY_LIMIT_SAT = 1000; // 10.00\n\n/** Convert a decimal string/number of dollars to integer cents. Throws on >2dp. */\nexport function toSat(amount: string | number): number {\n const s = typeof amount === 'number' ? amount.toFixed(2) : amount.trim();\n if (!/^\\d+(\\.\\d{1,2})?$/.test(s)) {\n throw new Error(`Invalid amount \"${amount}\": expected a non-negative decimal with <= 2 places`);\n }\n const [whole, frac = ''] = s.split('.');\n return parseInt(whole, 10) * 100 + parseInt(frac.padEnd(2, '0') || '0', 10);\n}\n\n/** Convert integer cents back to a 2-decimal string. */\nexport function fromSat(sat: number): string {\n return (sat / 100).toFixed(2);\n}\n\nexport class BalanceLedger {\n private readonly db: any;\n private readonly defaultSingleLimitSat: number;\n private readonly defaultDailyLimitSat: number;\n\n constructor(config: LedgerConfig) {\n // process.getBuiltinModule (Node >= 22.3) works under both the cjs and\n // esm builds; node:sqlite itself needs Node >= 22.5. Loaded lazily so\n // servers that don't enable the balance rail keep the node >= 18 floor.\n const getBuiltin = (process as any).getBuiltinModule as\n | ((id: string) => any)\n | undefined;\n const sqlite = getBuiltin?.('node:sqlite');\n if (!sqlite?.DatabaseSync) {\n throw new Error(\n 'The balance rail requires the node:sqlite module (Node.js >= 22.5). ' +\n `Current version: ${process.version}. Upgrade Node or disable provider.balance.`\n );\n }\n const { DatabaseSync } = sqlite;\n this.db = new DatabaseSync(config.dbPath);\n this.defaultSingleLimitSat = config.defaultSingleLimitSat ?? DEFAULT_SINGLE_LIMIT_SAT;\n this.defaultDailyLimitSat = config.defaultDailyLimitSat ?? DEFAULT_DAILY_LIMIT_SAT;\n this.db.exec('PRAGMA journal_mode = WAL');\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS buyers (\n buyer_id TEXT PRIMARY KEY,\n display_name TEXT,\n balance_sat INTEGER NOT NULL DEFAULT 0,\n total_topup_sat INTEGER NOT NULL DEFAULT 0,\n total_spent_sat INTEGER NOT NULL DEFAULT 0,\n daily_limit_sat INTEGER NOT NULL,\n single_limit_sat INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE TABLE IF NOT EXISTS ledger_transactions (\n id TEXT PRIMARY KEY,\n buyer_id TEXT NOT NULL REFERENCES buyers(buyer_id),\n type TEXT NOT NULL,\n amount_sat INTEGER NOT NULL,\n service TEXT,\n description TEXT,\n request_id TEXT,\n external_ref TEXT,\n refunds_tx_id TEXT,\n status TEXT NOT NULL DEFAULT 'completed',\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE UNIQUE INDEX IF NOT EXISTS idx_ledger_request_id\n ON ledger_transactions(request_id) WHERE request_id IS NOT NULL;\n CREATE UNIQUE INDEX IF NOT EXISTS idx_ledger_external_ref\n ON ledger_transactions(external_ref) WHERE external_ref IS NOT NULL;\n CREATE UNIQUE INDEX IF NOT EXISTS idx_ledger_refunds_tx\n ON ledger_transactions(refunds_tx_id) WHERE refunds_tx_id IS NOT NULL;\n CREATE INDEX IF NOT EXISTS idx_ledger_buyer_time\n ON ledger_transactions(buyer_id, created_at);\n CREATE TABLE IF NOT EXISTS ledger_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n\n // Migration: add auth columns to pre-existing ledgers. ALTER ... ADD\n // COLUMN is not idempotent, so guard on the current column set.\n const cols = (this.db.prepare('PRAGMA table_info(buyers)').all() as { name: string }[])\n .map(c => c.name);\n if (!cols.includes('signer_address')) {\n this.db.exec('ALTER TABLE buyers ADD COLUMN signer_address TEXT');\n }\n if (!cols.includes('wechat_openid')) {\n this.db.exec('ALTER TABLE buyers ADD COLUMN wechat_openid TEXT');\n }\n\n // Record and enforce the ledger's quote currency. The minor unit (`*_sat`)\n // is 1/100 of this currency -- cents for USD, fen for CNY -- so reopening a\n // USD-funded ledger under a CNY config would silently reinterpret every\n // balance (7 sat = 0.07 USD vs 0.07 CNY). Refuse the mismatch; a different\n // currency requires a separate db_path.\n const currency = config.currency ?? 'USD';\n const existingCurrency = this.db\n .prepare(`SELECT value FROM ledger_meta WHERE key = 'currency'`)\n .get() as { value: string } | undefined;\n if (existingCurrency) {\n if (existingCurrency.value !== currency) {\n throw new Error(\n `Balance ledger currency mismatch: db=${existingCurrency.value} config=${currency}. ` +\n `Use a separate db_path for a different currency; do not reinterpret an existing ledger.`\n );\n }\n } else {\n this.db\n .prepare(`INSERT INTO ledger_meta (key, value) VALUES ('currency', ?)`)\n .run(currency);\n }\n }\n\n /** Fetch a buyer, or null. */\n getBuyer(buyerId: string): BuyerRow | null {\n const row = this.db\n .prepare('SELECT * FROM buyers WHERE buyer_id = ?')\n .get(buyerId);\n return (row as BuyerRow) ?? null;\n }\n\n /** Fetch a buyer, creating an empty active account on first sight. */\n getOrCreateBuyer(buyerId: string, displayName?: string): BuyerRow {\n const existing = this.getBuyer(buyerId);\n if (existing) return existing;\n this.db\n .prepare(\n `INSERT INTO buyers (buyer_id, display_name, daily_limit_sat, single_limit_sat)\n VALUES (?, ?, ?, ?)`\n )\n .run(buyerId, displayName ?? null, this.defaultDailyLimitSat, this.defaultSingleLimitSat);\n return this.getBuyer(buyerId)!;\n }\n\n /**\n * Record the gateway-attested WeChat payer openid that funded a buyer, on\n * top-up confirm. Idempotent and observational (stage 1a): it never\n * overwrites an existing binding with a *different* openid — a conflict is\n * reported to the caller (possible account sharing / spoof) but not\n * enforced here. Creates the buyer if absent.\n */\n bindOpenid(buyerId: string, openid: string): { bound: boolean; conflict: boolean; existing: string | null } {\n const buyer = this.getOrCreateBuyer(buyerId);\n if (buyer.wechat_openid === openid) {\n return { bound: true, conflict: false, existing: openid };\n }\n if (buyer.wechat_openid && buyer.wechat_openid !== openid) {\n return { bound: false, conflict: true, existing: buyer.wechat_openid };\n }\n this.db\n .prepare(`UPDATE buyers SET wechat_openid = ?, updated_at = datetime('now') WHERE buyer_id = ?`)\n .run(openid, buyerId);\n return { bound: true, conflict: false, existing: null };\n }\n\n /**\n * TOFU-bind the account's spending signer address (EVM, lowercase). First\n * signed request records it; later requests must match. A mismatch is\n * reported (`conflict`) so the caller can reject under `enforce` — it is\n * never silently overwritten. Creates the buyer if absent.\n */\n bindSigner(buyerId: string, address: string): { bound: boolean; conflict: boolean; existing: string | null } {\n const a = address.toLowerCase();\n const buyer = this.getOrCreateBuyer(buyerId);\n if (buyer.signer_address === a) return { bound: true, conflict: false, existing: a };\n if (buyer.signer_address && buyer.signer_address !== a) {\n return { bound: false, conflict: true, existing: buyer.signer_address };\n }\n this.db\n .prepare(`UPDATE buyers SET signer_address = ?, updated_at = datetime('now') WHERE buyer_id = ?`)\n .run(a, buyerId);\n return { bound: true, conflict: false, existing: null };\n }\n\n /** Sum of today's (UTC) completed deducts minus refunds issued against them. */\n spentTodaySat(buyerId: string): number {\n const row = this.db\n .prepare(\n `SELECT COALESCE(SUM(CASE type WHEN 'deduct' THEN amount_sat ELSE -amount_sat END), 0) AS spent\n FROM ledger_transactions\n WHERE buyer_id = ? AND type IN ('deduct','refund') AND date(created_at) = date('now')`\n )\n .get(buyerId) as { spent: number };\n return Math.max(0, row.spent);\n }\n\n /**\n * Read-only deduction precheck (the rail's `verify`). Never mutates.\n * Returns the same error codes `deduct` would.\n */\n checkDeduct(buyerId: string, amountSat: number): DeductResult {\n const buyer = this.getBuyer(buyerId);\n if (!buyer) return { success: false, error: 'buyer_not_found' };\n if (buyer.status !== 'active') return { success: false, error: 'buyer_not_active' };\n if (amountSat > buyer.single_limit_sat) {\n return { success: false, error: 'exceeds_single_limit', limitSat: buyer.single_limit_sat };\n }\n const spent = this.spentTodaySat(buyerId);\n if (spent + amountSat > buyer.daily_limit_sat) {\n return { success: false, error: 'exceeds_daily_limit', limitSat: buyer.daily_limit_sat };\n }\n if (buyer.balance_sat < amountSat) {\n return { success: false, error: 'insufficient_balance', balanceSat: buyer.balance_sat };\n }\n return { success: true, balanceSat: buyer.balance_sat };\n }\n\n /**\n * Atomic deduction (the rail's `settle`). Check + UPDATE run inside one\n * SQLite transaction; a `request_id` replay returns the original tx\n * without charging again.\n */\n deduct(opts: DeductOpts): DeductResult {\n if (!Number.isInteger(opts.amountSat) || opts.amountSat <= 0) {\n throw new Error(`deduct amountSat must be a positive integer, got ${opts.amountSat}`);\n }\n if (opts.requestId) {\n const prior = this.db\n .prepare(`SELECT * FROM ledger_transactions WHERE request_id = ?`)\n .get(opts.requestId) as LedgerTxRow | undefined;\n if (prior) {\n const buyer = this.getBuyer(prior.buyer_id)!;\n return { success: true, txId: prior.id, replayed: true, balanceSat: buyer.balance_sat };\n }\n }\n\n this.db.exec('BEGIN IMMEDIATE');\n try {\n const check = this.checkDeduct(opts.buyerId, opts.amountSat);\n if (!check.success) {\n this.db.exec('ROLLBACK');\n return check;\n }\n const updated = this.db\n .prepare(\n `UPDATE buyers SET\n balance_sat = balance_sat - ?,\n total_spent_sat = total_spent_sat + ?,\n updated_at = datetime('now')\n WHERE buyer_id = ? AND balance_sat >= ? AND status = 'active'`\n )\n .run(opts.amountSat, opts.amountSat, opts.buyerId, opts.amountSat);\n if (Number(updated.changes) !== 1) {\n this.db.exec('ROLLBACK');\n return { success: false, error: 'insufficient_balance' };\n }\n const txId = `btx_${randomUUID()}`;\n this.db\n .prepare(\n `INSERT INTO ledger_transactions (id, buyer_id, type, amount_sat, service, description, request_id)\n VALUES (?, ?, 'deduct', ?, ?, ?, ?)`\n )\n .run(txId, opts.buyerId, opts.amountSat, opts.service ?? null, opts.description ?? null, opts.requestId ?? null);\n this.db.exec('COMMIT');\n const buyer = this.getBuyer(opts.buyerId)!;\n return { success: true, txId, balanceSat: buyer.balance_sat };\n } catch (err) {\n try { this.db.exec('ROLLBACK'); } catch { /* already rolled back */ }\n throw err;\n }\n }\n\n /**\n * Credit a top-up. `externalRef` is the settlement proof reference\n * (on-chain tx hash / fiat trade number) and is unique: replaying the same\n * reference returns the original row without crediting twice.\n */\n topup(opts: TopupOpts): { txId: string; balanceSat: number; replayed?: boolean } {\n if (!Number.isInteger(opts.amountSat) || opts.amountSat <= 0) {\n throw new Error(`topup amountSat must be a positive integer, got ${opts.amountSat}`);\n }\n const prior = this.db\n .prepare(`SELECT * FROM ledger_transactions WHERE external_ref = ?`)\n .get(opts.externalRef) as LedgerTxRow | undefined;\n if (prior) {\n const buyer = this.getBuyer(prior.buyer_id)!;\n return { txId: prior.id, balanceSat: buyer.balance_sat, replayed: true };\n }\n this.getOrCreateBuyer(opts.buyerId);\n const txId = `btx_${randomUUID()}`;\n this.db.exec('BEGIN IMMEDIATE');\n try {\n this.db\n .prepare(\n `UPDATE buyers SET\n balance_sat = balance_sat + ?,\n total_topup_sat = total_topup_sat + ?,\n updated_at = datetime('now')\n WHERE buyer_id = ?`\n )\n .run(opts.amountSat, opts.amountSat, opts.buyerId);\n this.db\n .prepare(\n `INSERT INTO ledger_transactions (id, buyer_id, type, amount_sat, description, external_ref)\n VALUES (?, ?, 'topup', ?, ?, ?)`\n )\n .run(txId, opts.buyerId, opts.amountSat, opts.description ?? null, opts.externalRef);\n this.db.exec('COMMIT');\n } catch (err) {\n try { this.db.exec('ROLLBACK'); } catch { /* already rolled back */ }\n throw err;\n }\n const buyer = this.getBuyer(opts.buyerId)!;\n return { txId, balanceSat: buyer.balance_sat };\n }\n\n /**\n * Reverse a deduct (service failed after the charge). Idempotent: the\n * unique index on `refunds_tx_id` means a second refund of the same deduct\n * returns the original refund row.\n */\n refund(deductTxId: string, reason?: string): RefundResult {\n const deductRow = this.db\n .prepare(`SELECT * FROM ledger_transactions WHERE id = ?`)\n .get(deductTxId) as LedgerTxRow | undefined;\n if (!deductRow) return { success: false, error: 'tx_not_found' };\n if (deductRow.type !== 'deduct') return { success: false, error: 'not_a_deduct' };\n const priorRefund = this.db\n .prepare(`SELECT * FROM ledger_transactions WHERE refunds_tx_id = ?`)\n .get(deductTxId) as LedgerTxRow | undefined;\n if (priorRefund) {\n const buyer = this.getBuyer(deductRow.buyer_id)!;\n return { success: true, txId: priorRefund.id, balanceSat: buyer.balance_sat, replayed: true };\n }\n this.db.exec('BEGIN IMMEDIATE');\n try {\n this.db\n .prepare(\n `UPDATE buyers SET\n balance_sat = balance_sat + ?,\n total_spent_sat = total_spent_sat - ?,\n updated_at = datetime('now')\n WHERE buyer_id = ?`\n )\n .run(deductRow.amount_sat, deductRow.amount_sat, deductRow.buyer_id);\n this.db\n .prepare(`UPDATE ledger_transactions SET status = 'refunded' WHERE id = ?`)\n .run(deductTxId);\n const txId = `btx_${randomUUID()}`;\n this.db\n .prepare(\n `INSERT INTO ledger_transactions (id, buyer_id, type, amount_sat, description, refunds_tx_id)\n VALUES (?, ?, 'refund', ?, ?, ?)`\n )\n .run(txId, deductRow.buyer_id, deductRow.amount_sat, reason ?? null, deductTxId);\n this.db.exec('COMMIT');\n const buyer = this.getBuyer(deductRow.buyer_id)!;\n return { success: true, txId, balanceSat: buyer.balance_sat };\n } catch (err) {\n try { this.db.exec('ROLLBACK'); } catch { /* already rolled back */ }\n throw err;\n }\n }\n\n /** Paged transaction history, newest first (rowid breaks same-second ties). */\n listTransactions(buyerId: string, limit = 20, offset = 0): LedgerTxRow[] {\n return this.db\n .prepare(\n `SELECT * FROM ledger_transactions WHERE buyer_id = ?\n ORDER BY created_at DESC, rowid DESC LIMIT ? OFFSET ?`\n )\n .all(buyerId, limit, offset) as LedgerTxRow[];\n }\n\n /** Quick integrity probe for healthCheck(). */\n integrityOk(): boolean {\n const row = this.db.prepare(`PRAGMA quick_check`).get() as { quick_check: string };\n return row.quick_check === 'ok';\n }\n\n close(): void {\n this.db.close();\n }\n}\n","/**\n * Custodial balance rail — user authentication (originator signature).\n *\n * The balance rail is password-free by design (a bare `buyer_id` deducts).\n * This adds a per-request signature so only the holder of the account's\n * bound key can spend it. The signer is an EVM key (reuses the client's\n * ethers wallet); the server recovers the address from the signature via\n * EIP-191 `personal_sign` — no public key is transmitted or stored beyond\n * the recovered address.\n *\n * TOFU binding + rollout live at the call site (see handleBalanceExecute):\n * `auth_mode` = off | shadow | enforce.\n *\n * @see ../../../docs/2026-07-13-wechat-fiat-auth-design.md\n */\nimport { ethers } from 'ethers';\n\n/** Domain tag — separates these signatures from any other message a key signs. */\nexport const BALANCE_AUTH_DOMAIN = 'moltspay-balance-auth:v1';\n\n/** Accepted clock skew between client timestamp and server (replay window). */\nexport const BALANCE_AUTH_MAX_SKEW_MS = 5 * 60 * 1000;\n\n/** Rollout gate for balance-rail user auth. */\nexport type BalanceAuthMode = 'off' | 'shadow' | 'enforce';\n\n/** Signature material carried in the balance X-Payment payload. */\nexport interface BalanceAuthFields {\n /** Unix seconds when the client signed. */\n timestamp: number;\n /** EIP-191 signature over {@link buildDeductMessage}. */\n signature: string;\n}\n\n/** Extract auth fields from an untrusted payload object, or null. */\nexport function extractBalanceAuth(raw: unknown): BalanceAuthFields | null {\n if (!raw || typeof raw !== 'object') return null;\n const a = raw as Record<string, unknown>;\n if (typeof a.signature === 'string' && a.signature && typeof a.timestamp === 'number' && Number.isFinite(a.timestamp)) {\n return { timestamp: a.timestamp, signature: a.signature };\n }\n return null;\n}\n\n/**\n * Canonical message a client signs to authorize one deduction. Both sides\n * MUST build this identically. `amount` is intentionally omitted — the\n * service id determines the price server-side, and `request_id` (unique per\n * charge) + `timestamp` (windowed) already bound replay.\n */\nexport function buildDeductMessage(f: {\n buyerId: string;\n requestId: string;\n service: string;\n timestamp: number;\n}): string {\n return [BALANCE_AUTH_DOMAIN, 'balance-deduct', f.buyerId, f.requestId, f.service, String(f.timestamp)].join('\\n');\n}\n\nexport interface AuthVerifyResult {\n ok: boolean;\n /** Recovered signer address (lowercase 0x…), present when the signature parsed. */\n recovered?: string;\n /** Failure code when `ok` is false: no_signature | malformed | timestamp_skew | bad_signature. */\n reason?: string;\n}\n\n/**\n * Verify a deduction signature and recover the signer address. Never throws.\n * Does NOT decide binding/enforcement — the caller compares `recovered`\n * against the account's bound signer and applies `auth_mode`.\n */\nexport function verifyDeductAuth(opts: {\n auth: BalanceAuthFields | null;\n buyerId: string;\n requestId: string;\n service: string;\n nowMs: number;\n}): AuthVerifyResult {\n const { auth } = opts;\n if (!auth) return { ok: false, reason: 'no_signature' };\n if (!auth.signature || !Number.isFinite(auth.timestamp)) return { ok: false, reason: 'malformed' };\n if (Math.abs(opts.nowMs - auth.timestamp * 1000) > BALANCE_AUTH_MAX_SKEW_MS) {\n return { ok: false, reason: 'timestamp_skew' };\n }\n const message = buildDeductMessage({\n buyerId: opts.buyerId,\n requestId: opts.requestId,\n service: opts.service,\n timestamp: auth.timestamp,\n });\n try {\n const recovered = ethers.verifyMessage(message, auth.signature).toLowerCase();\n return { ok: true, recovered };\n } catch {\n return { ok: false, reason: 'bad_signature' };\n }\n}\n","/**\n * Custodial Balance Facilitator (password-free rail).\n *\n * Third payment mode beside per-transaction crypto signing and fiat QR\n * (Alipay/WeChat): buyers top up once into a server-custodied SQLite ledger\n * and subsequent purchases are deducted directly — no signature, no scan.\n *\n * Interface mapping (differs from the QR rails — see BALANCE-RAIL-DESIGN.md):\n * - `createPaymentRequirements` is **pure**: it formats the `accepts[]` entry\n * without any I/O. Nothing is minted per 402, so the WeChat rail's\n * order-per-challenge double-charge class of bug cannot occur here.\n * - `verify` is a read-only funds/limits precheck.\n * - `settle` is **the atomic deduction** (single SQLite transaction),\n * idempotent on the client-supplied `request_id`.\n * - `refund` (rail-specific, not on the Facilitator interface) reverses a\n * deduct when the skill fails after the charge.\n *\n * Execution order at the server is therefore inverted relative to QR rails:\n * QR: verify(paid?) → run skill → settle (confirm, fire-and-forget)\n * balance: verify(funds?) → settle (deduct) → run skill → [fail → refund]\n *\n * @see ./balance/ledger.ts — SQLite ledger (atomicity, idempotency, limits)\n * @see ../../docs/BALANCE-RAIL-DESIGN.md — design\n */\n\nimport {\n BaseFacilitator,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n} from './interface.js';\nimport {\n BalanceLedger,\n LedgerConfig,\n DeductResult,\n RefundResult,\n toSat,\n fromSat,\n DEFAULT_SINGLE_LIMIT_SAT,\n DEFAULT_DAILY_LIMIT_SAT,\n} from './balance/ledger.js';\nimport { BalanceAuthMode, BalanceAuthFields, extractBalanceAuth } from './balance/auth.js';\n\nexport * from './balance/auth.js';\n\n/** Network identifier exposed via `Facilitator.supportedNetworks`. */\nexport const BALANCE_NETWORK = 'balance';\n\n/** x402 `scheme` string identifying the custodial balance rail in `accepts[]`. */\nexport const BALANCE_SCHEME = 'balance';\n\nexport { toSat, fromSat };\n\n/**\n * Facilitator-level config sourced from `provider.balance` in\n * `moltspay.services.json`.\n */\nexport interface BalanceFacilitatorConfig {\n /** SQLite ledger file path (created on first init). ':memory:' for tests. */\n db_path: string;\n /** Ledger quote currency. Default 'USD'. */\n currency?: string;\n /** Default per-transaction limit for new buyers, decimal string. Default \"5.00\". */\n single_limit?: string;\n /** Default daily limit for new buyers, decimal string. Default \"10.00\". */\n daily_limit?: string;\n /**\n * User-auth rollout gate for deductions. Default 'off' (bare buyer_id, as\n * before). 'shadow' verifies + TOFU-binds the signer but never blocks;\n * 'enforce' rejects unsigned/mismatched deductions.\n */\n auth_mode?: BalanceAuthMode;\n}\n\n/** The buyer-identifying payload carried in X-Payment for this rail. */\nexport interface BalancePaymentPayload {\n buyer_id: string;\n /** Client-generated idempotency key: replays never double-deduct. */\n request_id?: string;\n /** Originator signature (present when the client signs). @see ./balance/auth.ts */\n auth?: BalanceAuthFields;\n}\n\n/** Extract {buyer_id, request_id, auth} from an x402 payload, or null. */\nexport function extractBalancePayload(payment: X402PaymentPayload): BalancePaymentPayload | null {\n const p = payment.payload as Record<string, unknown> | undefined;\n if (p && typeof p.buyer_id === 'string' && p.buyer_id.length > 0) {\n return {\n buyer_id: p.buyer_id,\n request_id: typeof p.request_id === 'string' ? p.request_id : undefined,\n auth: extractBalanceAuth(p.auth) ?? undefined,\n };\n }\n return null;\n}\n\n/**\n * Custodial balance facilitator. Construction opens (or creates) the SQLite\n * ledger; on Node < 22.5 it throws with an actionable message.\n */\nexport class BalanceFacilitator extends BaseFacilitator {\n readonly name = 'balance';\n readonly displayName = 'Custodial Balance';\n readonly supportedNetworks = [BALANCE_NETWORK];\n\n readonly currency: string;\n /** User-auth rollout gate for deductions (off | shadow | enforce). */\n readonly authMode: BalanceAuthMode;\n private readonly ledger: BalanceLedger;\n\n constructor(config: BalanceFacilitatorConfig) {\n super();\n this.currency = config.currency ?? 'USD';\n this.authMode = config.auth_mode ?? 'off';\n const ledgerConfig: LedgerConfig = {\n dbPath: config.db_path,\n defaultSingleLimitSat: config.single_limit ? toSat(config.single_limit) : DEFAULT_SINGLE_LIMIT_SAT,\n defaultDailyLimitSat: config.daily_limit ? toSat(config.daily_limit) : DEFAULT_DAILY_LIMIT_SAT,\n currency: this.currency,\n };\n this.ledger = new BalanceLedger(ledgerConfig);\n }\n\n /** Direct ledger access for the server's balance-management endpoints. */\n getLedger(): BalanceLedger {\n return this.ledger;\n }\n\n /**\n * Build the `accepts[]` entry for a service. Pure — no I/O, nothing minted.\n */\n createPaymentRequirements(opts: { price: string; serviceId?: string }): X402PaymentRequirements {\n toSat(opts.price); // validate format early\n return {\n scheme: BALANCE_SCHEME,\n network: BALANCE_NETWORK,\n asset: this.currency,\n amount: opts.price,\n payTo: 'custodial',\n maxTimeoutSeconds: 30,\n extra: opts.serviceId ? { service_id: opts.serviceId } : undefined,\n };\n }\n\n /** Read-only funds/limits precheck. Never mutates the ledger. */\n async verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult> {\n const payload = extractBalancePayload(paymentPayload);\n if (!payload) {\n return { valid: false, error: 'Missing buyer_id in balance payment payload' };\n }\n let amountSat: number;\n try {\n amountSat = toSat(requirements.amount);\n } catch (err: any) {\n return { valid: false, error: err.message };\n }\n const check = this.ledger.checkDeduct(payload.buyer_id, amountSat);\n if (!check.success) {\n return {\n valid: false,\n error: this.describeDeductError(check),\n details: { code: check.error, balance: check.balanceSat !== undefined ? fromSat(check.balanceSat) : undefined },\n };\n }\n return { valid: true, details: { balance: fromSat(check.balanceSat!) } };\n }\n\n /**\n * The atomic deduction. Idempotent on `request_id`; the returned\n * `transaction` is the ledger tx id (usable for `refund`).\n */\n async settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult> {\n const payload = extractBalancePayload(paymentPayload);\n if (!payload) {\n return { success: false, error: 'Missing buyer_id in balance payment payload' };\n }\n let amountSat: number;\n try {\n amountSat = toSat(requirements.amount);\n } catch (err: any) {\n return { success: false, error: err.message };\n }\n const serviceId =\n typeof requirements.extra?.service_id === 'string' ? requirements.extra.service_id : undefined;\n let result: DeductResult;\n try {\n result = this.ledger.deduct({\n buyerId: payload.buyer_id,\n amountSat,\n requestId: payload.request_id,\n service: serviceId,\n });\n } catch (err: any) {\n return { success: false, error: `Ledger deduct failed: ${err.message}` };\n }\n if (!result.success) {\n return { success: false, error: this.describeDeductError(result), status: result.error };\n }\n return {\n success: true,\n transaction: result.txId,\n status: result.replayed ? 'replayed' : 'deducted',\n };\n }\n\n /** Reverse a deduct after a downstream failure. Idempotent per deduct. */\n refund(deductTxId: string, reason?: string): RefundResult {\n return this.ledger.refund(deductTxId, reason);\n }\n\n /**\n * Credit a gateway-verified external settlement to a buyer's balance. The\n * single entry point for every funding path -- WeChat callback, WeChat\n * polling, and the operator `/balance/topup` endpoint -- so they share one\n * idempotency boundary: `externalRef` is unique in the ledger, so a replay\n * credits nothing and returns the original transaction (`replayed: true`).\n * Callers must pass a gateway-verified `amountSat`, never a client-declared\n * amount.\n */\n credit(opts: {\n buyerId: string;\n amountSat: number;\n externalRef: string;\n description?: string;\n }): { txId: string; balance: string; balanceSat: number; replayed: boolean } {\n const result = this.ledger.topup({\n buyerId: opts.buyerId,\n amountSat: opts.amountSat,\n externalRef: opts.externalRef,\n description: opts.description,\n });\n return {\n txId: result.txId,\n balance: fromSat(result.balanceSat),\n balanceSat: result.balanceSat,\n replayed: result.replayed ?? false,\n };\n }\n\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n const ok = this.ledger.integrityOk();\n return ok\n ? { healthy: true, latencyMs: Date.now() - start }\n : { healthy: false, error: 'SQLite quick_check failed' };\n } catch (err: any) {\n return { healthy: false, error: err.message };\n }\n }\n\n private describeDeductError(result: DeductResult): string {\n switch (result.error) {\n case 'buyer_not_found':\n return 'Unknown buyer: top up first to create an account';\n case 'buyer_not_active':\n return 'Buyer account is frozen or banned';\n case 'insufficient_balance':\n return `Insufficient balance${result.balanceSat !== undefined ? ` (have ${fromSat(result.balanceSat)})` : ''}`;\n case 'exceeds_single_limit':\n return `Amount exceeds the per-transaction limit${result.limitSat !== undefined ? ` of ${fromSat(result.limitSat)}` : ''}`;\n case 'exceeds_daily_limit':\n return `Amount exceeds the daily spending limit${result.limitSat !== undefined ? ` of ${fromSat(result.limitSat)}` : ''}`;\n default:\n return 'Deduction failed';\n }\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';\nimport { TempoFacilitator } from './tempo.js';\nimport { BNBFacilitator } from './bnb.js';\nimport { SolanaFacilitator, SolanaFacilitatorConfig } from './solana.js';\nimport { AlipayFacilitator, AlipayFacilitatorConfig } from './alipay.js';\nimport { WechatFacilitator, WechatFacilitatorConfig } from './wechat.js';\nimport { BalanceFacilitator, BalanceFacilitatorConfig } from './balance.js';\nimport { Keypair } from '@solana/web3.js';\nimport bs58 from 'bs58';\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 this.registerFactory('tempo', () => new TempoFacilitator());\n this.registerFactory('bnb', (config) => new BNBFacilitator(config?.serverPrivateKey as string));\n this.registerFactory('solana', (config) => {\n // Load fee payer keypair from config or env\n let feePayerKeypair: Keypair | undefined;\n const feePayerKey = (config as any)?.feePayerPrivateKey || process.env.SOLANA_FEE_PAYER_KEY;\n \n if (feePayerKey) {\n try {\n feePayerKeypair = Keypair.fromSecretKey(bs58.decode(feePayerKey));\n } catch (e: any) {\n console.warn(`[SolanaFacilitator] Invalid fee payer key: ${e.message}`);\n }\n }\n \n return new SolanaFacilitator({ feePayerKeypair } as SolanaFacilitatorConfig);\n });\n this.registerFactory('alipay', (config) => new AlipayFacilitator(config as unknown as AlipayFacilitatorConfig));\n this.registerFactory('wechat', (config) => new WechatFacilitator(config as unknown as WechatFacilitatorConfig));\n this.registerFactory('balance', (config) => new BalanceFacilitator(config as unknown as BalanceFacilitatorConfig));\n\n // Default selection — alipay/wechat/balance are opt-in (require provider config), kept out of fallback list\n this.selection = selection || { primary: 'cdp', fallback: ['tempo', 'bnb', 'solana'], 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","/**\n * Custodial balance rail HTTP management endpoints (`/balance/*`), extracted\n * from index.ts to keep the server class focused. A thin collaborator injected\n * with the pieces it needs (facilitators, manifest, sendJson, and the WeChat\n * pending-order helpers) so it can be unit-driven and keeps index.ts small.\n *\n * Behavior is unchanged from the in-class handlers; see\n * WECHAT-BALANCE-PASSWORDLESS-DESIGN.md and BALANCE-RAIL-DESIGN.md.\n */\nimport { ServerResponse } from 'http';\nimport crypto from 'node:crypto';\nimport {\n WechatFacilitator,\n BalanceFacilitator,\n WECHAT_NETWORK,\n WECHAT_SCHEME,\n parseWechatAttach,\n toSat,\n fromSat,\n} from '../facilitators/index.js';\nimport { X402PaymentPayload, X402PaymentRequirements } from '../facilitators/interface.js';\nimport { verifyPayment as verifyOnChainPayment } from '../verify/index.js';\nimport { ServicesManifest } from './types.js';\nimport { X402_VERSION } from './internal.js';\n\n/** A pending WeChat order as returned by the shared get-or-create helper. */\ntype PendingWechatOrder = {\n accepts: X402PaymentRequirements;\n codeUrl: string;\n outTradeNo: string;\n};\n\n/** Dependencies injected from MoltsPayServer. */\nexport interface BalanceEndpointsDeps {\n manifest: ServicesManifest;\n balance: BalanceFacilitator;\n wechat: WechatFacilitator | null;\n sendJson: (res: ServerResponse, status: number, data: any) => void;\n getOrCreatePendingWechatOrder: (\n cacheKey: string,\n logLabel: string,\n create: () => Promise<{ x402Accepts: X402PaymentRequirements; codeUrl: string; outTradeNo: string }>,\n ) => Promise<PendingWechatOrder | null>;\n invalidateWechatChallenge: (outTradeNo: string) => void;\n}\n\nexport class BalanceEndpoints {\n constructor(private readonly deps: BalanceEndpointsDeps) {}\n\n /** GET /balance?buyer_id= -- balance, limits, and today's spend. */\n handleQuery(url: URL, res: ServerResponse): void {\n const { balance, sendJson } = this.deps;\n const buyerId = url.searchParams.get('buyer_id');\n if (!buyerId) {\n return sendJson(res, 400, { error: 'buyer_id query parameter is required' });\n }\n const ledger = balance.getLedger();\n const buyer = ledger.getBuyer(buyerId);\n if (!buyer) {\n // A never-seen buyer is a valid empty account, not an error.\n return sendJson(res, 200, {\n buyer_id: buyerId,\n balance: '0.00',\n currency: balance.currency,\n exists: false,\n });\n }\n sendJson(res, 200, {\n buyer_id: buyerId,\n balance: fromSat(buyer.balance_sat),\n currency: balance.currency,\n single_limit: fromSat(buyer.single_limit_sat),\n daily_limit: fromSat(buyer.daily_limit_sat),\n today_spent: fromSat(ledger.spentTodaySat(buyerId)),\n status: buyer.status,\n wechat_openid: buyer.wechat_openid ?? null,\n signer_address: buyer.signer_address ?? null,\n exists: true,\n });\n }\n\n /**\n * Extract the gateway-confirmed paid amount (fen) from a WeChat verify\n * result. `payer_total` is what the buyer actually paid; falls back to\n * `total`. Returns null if no usable positive integer is present, so the\n * client-declared amount can never be trusted for crediting.\n */\n private wechatPaidFen(check: { details?: { amount?: unknown } }): number | null {\n const amount = check.details?.amount as { payer_total?: unknown; total?: unknown } | undefined;\n const paid = amount?.payer_total ?? amount?.total;\n return typeof paid === 'number' && Number.isFinite(paid) && paid > 0 ? paid : null;\n }\n\n /**\n * POST /balance/topup/order -- mint a buyer-bound WeChat Native order for a\n * configured top-up pack. The buyer_id rides in the WeChat `attach` so the\n * later confirm/callback credits the correct balance. Reuses the pending\n * order cache (keyed by buyer_id + pack) so concurrent requests share one\n * order. Body: `{ buyer_id, pack? }`. Returns `{ code_url, out_trade_no,\n * pack, max_timeout_seconds }`.\n */\n async handleTopupOrder(body: any, res: ServerResponse): Promise<void> {\n const { manifest, wechat, sendJson, getOrCreatePendingWechatOrder } = this.deps;\n const { buyer_id, pack } = body || {};\n if (typeof buyer_id !== 'string' || !buyer_id) {\n return sendJson(res, 400, { error: 'buyer_id is required' });\n }\n // Optional: bind the client's spending signer at top-up time (stage 3).\n // Rides in the WeChat attach so confirm can TOFU-bind it to the account\n // alongside the payer openid.\n const signerAddress =\n typeof body?.signer_address === 'string' && /^0x[0-9a-fA-F]{40}$/.test(body.signer_address)\n ? body.signer_address.toLowerCase()\n : undefined;\n if (!wechat) {\n return sendJson(res, 400, { error: 'WeChat rail not configured on this server' });\n }\n const balCfg = manifest.provider.balance;\n const packs = balCfg?.topup_packs ?? [];\n const chosen: string | undefined =\n typeof pack === 'string' && pack ? pack : balCfg?.default_pack;\n if (!chosen) {\n return sendJson(res, 400, { error: 'no pack specified and no default_pack configured' });\n }\n // Accept a pack that is either offered or within the auto-topup ceiling.\n let chosenSat: number;\n try {\n chosenSat = toSat(chosen);\n if (chosenSat <= 0) throw new Error('pack must be positive');\n } catch (err: any) {\n return sendJson(res, 400, { error: `Invalid pack: ${err.message}` });\n }\n const withinMax = balCfg?.auto_topup_max ? chosenSat <= toSat(balCfg.auto_topup_max) : false;\n if (!packs.includes(chosen) && !withinMax) {\n return sendJson(res, 400, {\n error: `pack \"${chosen}\" is not an offered top-up pack and exceeds auto_topup_max`,\n });\n }\n\n const nonce = crypto.randomBytes(8).toString('hex');\n // attach rides to confirm via the gateway. buyer_id is required; signer\n // (when present) lets confirm bind the account's spender. Kept compact —\n // WeChat caps attach at 128 bytes (createPaymentRequirements enforces).\n const attach: Record<string, string> = signerAddress\n ? { buyer_id, signer: signerAddress }\n : { buyer_id, nonce };\n const cacheKey = crypto\n .createHash('sha256')\n .update(`topup|${buyer_id}|${chosen}|${signerAddress ?? ''}`)\n .digest('hex');\n const result = await getOrCreatePendingWechatOrder(cacheKey, `topup:${buyer_id}`, () =>\n wechat.createPaymentRequirements({\n priceCny: chosen,\n description: `Balance top-up ${chosen}`,\n attach,\n }),\n );\n if (!result) {\n return sendJson(res, 502, { error: 'failed to create WeChat top-up order' });\n }\n return sendJson(res, 200, {\n code_url: result.codeUrl,\n out_trade_no: result.outTradeNo,\n pack: chosen,\n max_timeout_seconds: result.accepts.maxTimeoutSeconds,\n });\n }\n\n /**\n * POST /balance/topup/confirm -- the polling-fallback credit path. The client\n * polls this after a scan; the server verifies the order with the WeChat\n * gateway and, on SUCCESS, credits the buyer bound in `attach` with the\n * gateway-confirmed `payer_total` (never a client-declared amount).\n * Idempotent on `wechat:<out_trade_no>`. Body: `{ out_trade_no }`.\n */\n async handleTopupConfirm(body: any, res: ServerResponse): Promise<void> {\n const { manifest, balance, wechat, sendJson, invalidateWechatChallenge } = this.deps;\n const outTradeNo = body?.out_trade_no;\n if (typeof outTradeNo !== 'string' || !outTradeNo) {\n return sendJson(res, 400, { error: 'out_trade_no is required' });\n }\n if (!wechat) {\n return sendJson(res, 400, { error: 'WeChat rail not configured on this server' });\n }\n const wxPayload: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: WECHAT_SCHEME,\n network: WECHAT_NETWORK,\n payload: { out_trade_no: outTradeNo },\n };\n const wxReqs: X402PaymentRequirements = {\n scheme: WECHAT_SCHEME, network: WECHAT_NETWORK, asset: 'CNY', amount: '0',\n payTo: manifest.provider.wechat?.mchid || '', maxTimeoutSeconds: 30,\n extra: { out_trade_no: outTradeNo },\n };\n const check = await wechat.verify(wxPayload, wxReqs);\n if (!check.valid) {\n // Not yet paid (or a transient gateway error): tell the client to keep\n // polling rather than surfacing an error.\n return sendJson(res, 200, { credited: false, pending: true, reason: check.error });\n }\n const paidFen = this.wechatPaidFen(check);\n if (paidFen === null) {\n return sendJson(res, 502, { error: 'WeChat order verification did not return a usable paid amount' });\n }\n const attach = parseWechatAttach((check.details as { attach?: unknown } | undefined)?.attach);\n const buyerId = attach?.buyer_id;\n if (!buyerId) {\n return sendJson(res, 422, {\n error: 'top-up order has no buyer binding (attach.buyer_id missing)',\n });\n }\n const credited = balance.credit({\n buyerId,\n amountSat: paidFen,\n externalRef: `wechat:${outTradeNo}`,\n description: `wechat topup out_trade_no=${outTradeNo} fiat=${JSON.stringify(check.details?.amount ?? null)}`,\n });\n // Paid orders can leave the pending cache immediately (one code, one payment).\n invalidateWechatChallenge(outTradeNo);\n // Stage 1a: record the gateway-attested payer openid that funded this\n // account (observational — anchors the balance to a real WeChat user).\n const openid = (check.details as { openid?: unknown } | undefined)?.openid;\n let openidBinding: { bound: boolean; conflict: boolean; existing: string | null } | undefined;\n if (typeof openid === 'string' && openid) {\n openidBinding = balance.getLedger().bindOpenid(buyerId, openid);\n if (openidBinding.conflict) {\n console.warn(\n `[MoltsPay] Balance top-up openid conflict for buyer=${buyerId}: ` +\n `already bound to ${openidBinding.existing}, this payment from ${openid} — recorded, not enforced`,\n );\n }\n }\n // Stage 3: bind the spending signer carried in attach (topup-time binding,\n // complements consumption-time TOFU). Conflicts are recorded, not enforced.\n const signer = (attach as { signer?: unknown } | null)?.signer;\n if (typeof signer === 'string' && /^0x[0-9a-fA-F]{40}$/.test(signer)) {\n const sb = balance.getLedger().bindSigner(buyerId, signer);\n if (sb.conflict) {\n console.warn(\n `[MoltsPay] Balance top-up signer conflict for buyer=${buyerId}: ` +\n `already bound to ${sb.existing}, this order signed for ${signer.toLowerCase()} — recorded, not enforced`,\n );\n }\n }\n console.log(\n `[MoltsPay] Balance top-up credited buyer=${buyerId} +${fromSat(paidFen)} ` +\n `(${outTradeNo})${credited.replayed ? ' [replayed]' : ''}` +\n `${typeof openid === 'string' && openid ? ` openid=${openid}${openidBinding?.conflict ? ' [CONFLICT]' : ''}` : ''}`,\n );\n return sendJson(res, 200, {\n credited: true,\n buyer_id: buyerId,\n tx_id: credited.txId,\n balance: credited.balance,\n replayed: credited.replayed,\n openid_bound: openidBinding?.bound ?? false,\n openid_conflict: openidBinding?.conflict ?? false,\n });\n }\n\n /**\n * POST /balance/topup -- verify an externally settled payment and credit the\n * buyer's ledger balance (operator/recovery path). Per rail: `crypto`\n * verifies the tx on-chain; `wechat` queries the order and credits the\n * gateway-confirmed payer_total (never the client-declared amount);\n * `alipay` is operator-trusted in this MVP. Idempotent on the external ref.\n */\n async handleTopup(body: any, res: ServerResponse): Promise<void> {\n const { manifest, balance, wechat, sendJson } = this.deps;\n const { buyer_id, rail, amount } = body || {};\n if (typeof buyer_id !== 'string' || !buyer_id) {\n return sendJson(res, 400, { error: 'buyer_id is required' });\n }\n let amountSat: number;\n try {\n amountSat = toSat(String(amount));\n if (amountSat <= 0) throw new Error('amount must be positive');\n } catch (err: any) {\n return sendJson(res, 400, { error: `Invalid amount: ${err.message}` });\n }\n\n let externalRef: string;\n let description: string;\n if (rail === 'crypto') {\n const txHash = body.tx_hash;\n if (typeof txHash !== 'string' || !txHash) {\n return sendJson(res, 400, { error: 'tx_hash is required for rail \"crypto\"' });\n }\n const check = await verifyOnChainPayment({\n txHash,\n expectedAmount: amountSat / 100,\n expectedTo: manifest.provider.wallet,\n chain: body.chain || 'base',\n });\n if (!check.verified) {\n return sendJson(res, 402, { error: `On-chain verification failed: ${check.error}` });\n }\n externalRef = txHash.toLowerCase();\n description = `crypto topup ${check.amount} ${check.token} on ${body.chain || 'base'}`;\n } else if (rail === 'wechat') {\n const outTradeNo = body.out_trade_no;\n if (typeof outTradeNo !== 'string' || !outTradeNo) {\n return sendJson(res, 400, { error: 'out_trade_no is required for rail \"wechat\"' });\n }\n if (!wechat) {\n return sendJson(res, 400, { error: 'WeChat rail not configured on this server' });\n }\n const wxPayload: X402PaymentPayload = {\n x402Version: X402_VERSION,\n scheme: WECHAT_SCHEME,\n network: WECHAT_NETWORK,\n payload: { out_trade_no: outTradeNo },\n };\n const wxReqs: X402PaymentRequirements = {\n scheme: WECHAT_SCHEME, network: WECHAT_NETWORK, asset: 'CNY', amount: '0',\n payTo: manifest.provider.wechat?.mchid || '', maxTimeoutSeconds: 30,\n extra: { out_trade_no: outTradeNo },\n };\n const check = await wechat.verify(wxPayload, wxReqs);\n if (!check.valid) {\n return sendJson(res, 402, { error: `WeChat order verification failed: ${check.error}` });\n }\n // Credit what WeChat actually confirms was paid on this order, not the\n // client-declared `amount` -- otherwise a buyer can pay 0.01 CNY and claim\n // any amount. `payer_total` is fen, which is 1:1 with ledger cents.\n const paidFen = this.wechatPaidFen(check);\n if (paidFen === null) {\n return sendJson(res, 502, { error: 'WeChat order verification did not return a usable paid amount' });\n }\n if (paidFen !== amountSat) {\n console.warn(\n `[MoltsPay] WeChat topup amount mismatch for ${outTradeNo}: client declared ${fromSat(amountSat)}, ` +\n `gateway confirms ${fromSat(paidFen)} paid -- crediting the verified amount`\n );\n }\n amountSat = paidFen;\n externalRef = `wechat:${outTradeNo}`;\n description = `wechat topup out_trade_no=${outTradeNo} fiat=${JSON.stringify(check.details?.amount ?? null)}`;\n console.log(`[MoltsPay] WeChat topup verified: ${description}`);\n } else if (rail === 'alipay') {\n const tradeNo = body.trade_no;\n if (typeof tradeNo !== 'string' || !tradeNo) {\n return sendJson(res, 400, { error: 'trade_no is required for rail \"alipay\"' });\n }\n // MVP: no gateway verification possible without the buyer's\n // payment_proof -- operator-trusted credit, idempotent on trade_no.\n externalRef = `alipay:${tradeNo}`;\n description = `alipay topup trade_no=${tradeNo} (operator-confirmed, unverified)`;\n console.warn(`[MoltsPay] Alipay topup credited without gateway verification: ${tradeNo}`);\n } else {\n return sendJson(res, 400, { error: 'rail must be one of \"crypto\" | \"alipay\" | \"wechat\"' });\n }\n\n const result = balance.getLedger().topup({ buyerId: buyer_id, amountSat, externalRef, description });\n sendJson(res, 200, {\n success: true,\n tx_id: result.txId,\n balance: fromSat(result.balanceSat),\n replayed: result.replayed ?? false,\n });\n }\n\n /** POST /balance/refund -- reverse a deduct (operator/agent use). */\n handleRefund(body: any, res: ServerResponse): void {\n const { balance, sendJson } = this.deps;\n const { tx_id, reason } = body || {};\n if (typeof tx_id !== 'string' || !tx_id) {\n return sendJson(res, 400, { error: 'tx_id is required' });\n }\n const result = balance.refund(tx_id, typeof reason === 'string' ? reason : undefined);\n if (!result.success) {\n return sendJson(res, result.error === 'tx_not_found' ? 404 : 400, { error: result.error });\n }\n sendJson(res, 200, {\n success: true,\n tx_id: result.txId,\n balance: fromSat(result.balanceSat!),\n replayed: result.replayed ?? false,\n });\n }\n\n /** GET /balance/transactions?buyer_id=&limit=&offset= -- history, newest first. */\n handleTransactions(url: URL, res: ServerResponse): void {\n const { balance, sendJson } = this.deps;\n const buyerId = url.searchParams.get('buyer_id');\n if (!buyerId) {\n return sendJson(res, 400, { error: 'buyer_id query parameter is required' });\n }\n const limit = Math.min(parseInt(url.searchParams.get('limit') || '20', 10) || 20, 100);\n const offset = parseInt(url.searchParams.get('offset') || '0', 10) || 0;\n const rows = balance.getLedger().listTransactions(buyerId, limit, offset);\n sendJson(res, 200, {\n buyer_id: buyerId,\n transactions: rows.map(r => ({\n tx_id: r.id,\n type: r.type,\n amount: fromSat(r.amount_sat),\n service: r.service,\n description: r.description,\n external_ref: r.external_ref,\n status: r.status,\n created_at: r.created_at,\n })),\n });\n }\n}\n","/**\n * On-chain Payment Verification Module\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, getChainById, type ChainConfig, type EvmChainName, type TokenSymbol } from '../chains';\n\n// ERC20 Transfer event signature\nconst TRANSFER_EVENT_TOPIC = ethers.id('Transfer(address,address,uint256)');\n\nexport interface VerifyPaymentParams {\n txHash: string;\n expectedAmount: number;\n expectedTo?: string;\n chain?: string | number;\n /** Expected token (if not specified, accepts both USDC and USDT) */\n expectedToken?: TokenSymbol;\n}\n\nexport interface VerifyPaymentResult {\n verified: boolean;\n amount?: number;\n token?: TokenSymbol;\n from?: string;\n to?: string;\n txHash?: string;\n blockNumber?: number;\n error?: string;\n}\n\n/**\n * Verify on-chain payment\n * Supports both USDC and USDT transfers\n */\nexport async function verifyPayment(params: VerifyPaymentParams): Promise<VerifyPaymentResult> {\n const { txHash, expectedAmount, expectedTo, expectedToken } = params;\n \n // Get chain config\n let chain: ChainConfig | undefined;\n try {\n if (typeof params.chain === 'number') {\n chain = getChainById(params.chain);\n } else {\n chain = getChain((params.chain || 'base') as EvmChainName);\n }\n if (!chain) {\n return { verified: false, error: `Unsupported chain: ${params.chain}` };\n }\n } catch (e) {\n return { verified: false, error: `Unsupported chain: ${params.chain}` };\n }\n\n try {\n const provider = new ethers.JsonRpcProvider(chain.rpc);\n \n // Get transaction receipt\n const receipt = await provider.getTransactionReceipt(txHash);\n \n if (!receipt) {\n return { verified: false, error: 'Transaction not found or not confirmed' };\n }\n\n if (receipt.status !== 1) {\n return { verified: false, error: 'Transaction failed' };\n }\n\n // Build map of accepted token addresses\n const tokenAddresses: Record<string, TokenSymbol> = {};\n \n if (!expectedToken || expectedToken === 'USDC') {\n tokenAddresses[chain.tokens.USDC.address.toLowerCase()] = 'USDC';\n }\n if (!expectedToken || expectedToken === 'USDT') {\n tokenAddresses[chain.tokens.USDT.address.toLowerCase()] = 'USDT';\n }\n\n if (Object.keys(tokenAddresses).length === 0) {\n return { verified: false, error: `No token addresses configured for ${chain.name}` };\n }\n\n for (const log of receipt.logs) {\n const logAddress = log.address.toLowerCase();\n \n // Check if this is one of our accepted tokens\n const detectedToken = tokenAddresses[logAddress];\n if (!detectedToken) {\n continue;\n }\n\n // Check if Transfer event\n if (log.topics.length < 3 || log.topics[0] !== TRANSFER_EVENT_TOPIC) {\n continue;\n }\n\n // Parse Transfer event params\n const from = '0x' + log.topics[1].slice(-40);\n const to = '0x' + log.topics[2].slice(-40);\n const amountRaw = BigInt(log.data);\n const tokenConfig = chain.tokens[detectedToken];\n const amount = Number(amountRaw) / (10 ** tokenConfig.decimals);\n\n // Verify recipient address\n if (expectedTo && to.toLowerCase() !== expectedTo.toLowerCase()) {\n continue;\n }\n\n // Verify amount\n if (amount < expectedAmount) {\n return {\n verified: false,\n error: `Insufficient amount: received ${amount} ${detectedToken}, expected ${expectedAmount}`,\n amount,\n token: detectedToken,\n from,\n to,\n txHash,\n blockNumber: receipt.blockNumber,\n };\n }\n\n // Verification successful\n return {\n verified: true,\n amount,\n token: detectedToken,\n from,\n to,\n txHash,\n blockNumber: receipt.blockNumber,\n };\n }\n\n const tokenList = expectedToken ? expectedToken : 'USDC/USDT';\n return { verified: false, error: `No ${tokenList} transfer found` };\n\n } catch (e: any) {\n return { verified: false, error: e.message || String(e) };\n }\n}\n\n/**\n * Get transaction status\n */\nexport async function getTransactionStatus(\n txHash: string,\n chain: string | number = 'base'\n): Promise<{\n status: 'pending' | 'confirmed' | 'failed' | 'not_found';\n blockNumber?: number;\n confirmations?: number;\n}> {\n let chainConfig: ChainConfig | undefined;\n try {\n chainConfig = typeof chain === 'number' ? getChainById(chain) : getChain(chain as EvmChainName);\n if (!chainConfig) return { status: 'not_found' };\n } catch {\n return { status: 'not_found' };\n }\n\n try {\n const provider = new ethers.JsonRpcProvider(chainConfig.rpc);\n const receipt = await provider.getTransactionReceipt(txHash);\n\n if (!receipt) {\n // Check if in pending pool\n const tx = await provider.getTransaction(txHash);\n if (tx) {\n return { status: 'pending' };\n }\n return { status: 'not_found' };\n }\n\n const currentBlock = await provider.getBlockNumber();\n const confirmations = currentBlock - receipt.blockNumber;\n\n if (receipt.status === 1) {\n return {\n status: 'confirmed',\n blockNumber: receipt.blockNumber,\n confirmations,\n };\n } else {\n return {\n status: 'failed',\n blockNumber: receipt.blockNumber,\n };\n }\n } catch {\n return { status: 'not_found' };\n }\n}\n\n/**\n * Wait for transaction confirmation\n */\nexport async function waitForTransaction(\n txHash: string,\n chain: string | number = 'base',\n confirmations = 1,\n timeoutMs = 60000\n): Promise<VerifyPaymentResult & { confirmed: boolean }> {\n let chainConfig: ChainConfig | undefined;\n try {\n chainConfig = typeof chain === 'number' ? getChainById(chain) : getChain(chain as EvmChainName);\n if (!chainConfig) {\n return { verified: false, confirmed: false, error: `Unsupported chain: ${chain}` };\n }\n } catch (e) {\n return { verified: false, confirmed: false, error: `Unsupported chain: ${chain}` };\n }\n\n const provider = new ethers.JsonRpcProvider(chainConfig.rpc);\n \n try {\n const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);\n \n if (!receipt) {\n return { verified: false, confirmed: false, error: 'Timeout waiting' };\n }\n\n if (receipt.status !== 1) {\n return { verified: false, confirmed: true, error: 'Transaction failed' };\n }\n\n return {\n verified: true,\n confirmed: true,\n txHash,\n blockNumber: receipt.blockNumber,\n };\n } catch (e: any) {\n return { verified: false, confirmed: false, error: e.message || String(e) };\n }\n}\n","/**\n * Server-internal constants and pure helpers extracted from index.ts to keep\n * the server class focused on request handling. No `this`, no I/O beyond\n * loadEnvFile's file reads. Imported back into index.ts.\n */\nimport { readFileSync, existsSync } from 'fs';\nimport * as path from 'path';\nimport { ServiceConfig } from './types.js';\n\n// x402 constants\nexport const X402_VERSION = 2;\nexport const PAYMENT_REQUIRED_HEADER = 'x-payment-required';\nexport const PAYMENT_HEADER = 'x-payment';\nexport const PAYMENT_RESPONSE_HEADER = 'x-payment-response';\n\n// MPP (Machine Payments Protocol) constants\nexport const MPP_AUTH_HEADER = 'authorization';\nexport const MPP_WWW_AUTH_HEADER = 'www-authenticate';\nexport const MPP_RECEIPT_HEADER = 'payment-receipt';\n\n// Alipay AI fiat rail constants (2.0.0)\n// Legacy `Payment-Needed` 402 challenge header, mirror of `X-Payment-Required`,\n// kept so `alipay-bot` (@alipay/agent-payment) skills work unchanged.\nexport const ALIPAY_PAYMENT_NEEDED_HEADER = 'payment-needed';\n// Buyer's proof header: alipay-bot re-requests the resource carrying the\n// Base64URL `{protocol:{payment_proof,trade_no},method:{client_session}}`\n// blob here after the buyer pays. The server verifies it via the facilitator.\nexport const ALIPAY_PAYMENT_PROOF_HEADER = 'payment-proof';\n\n/**\n * Make an arbitrary string safe to embed in an HTTP header value.\n *\n * HTTP header values are limited to Latin-1 (RFC 7230 3.2.6); Node's\n * `res.writeHead` throws `Invalid character in header content` on any\n * code point outside that range. Provider/service names can contain\n * non-Latin-1 characters (e.g. CJK), so we percent-encode anything\n * outside printable ASCII and escape `\"` so it cannot terminate the\n * surrounding `Payment ... realm=\"...\"` quoted-string.\n */\nexport function headerSafe(value: string): string {\n return String(value ?? '')\n .replace(/[^\\x20-\\x7E]/g, ch => encodeURIComponent(ch))\n .replace(/\"/g, '%22');\n}\n\n/**\n * Deterministic JSON: object keys sorted recursively, so semantically equal\n * params hash identically regardless of key order. Used for the WeChat\n * pending-order idempotency key.\n */\nexport function canonicalJson(value: any): string {\n if (value === null || typeof value !== 'object') {\n return JSON.stringify(value) ?? 'null';\n }\n if (Array.isArray(value)) {\n return '[' + value.map(canonicalJson).join(',') + ']';\n }\n return '{' + Object.keys(value).sort()\n .map(k => JSON.stringify(k) + ':' + canonicalJson(value[k]))\n .join(',') + '}';\n}\n\n// Token contract addresses by network\nexport const 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 'eip155:137': {\n USDC: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n USDT: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n },\n 'eip155:42431': {\n // Tempo Moderato testnet - TIP-20 stablecoins\n USDC: '0x20c0000000000000000000000000000000000000', // pathUSD\n USDT: '0x20c0000000000000000000000000000000000001', // alphaUSD\n },\n // BNB Smart Chain mainnet\n 'eip155:56': {\n USDC: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n USDT: '0x55d398326f99059fF775485246999027B3197955',\n },\n // BNB Smart Chain testnet\n 'eip155:97': {\n USDC: '0x64544969ed7EBf5f083679233325356EbE738930',\n USDT: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd',\n },\n // Solana networks use mint addresses (SPL tokens)\n 'solana:mainnet': {\n USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // Circle USDC\n },\n 'solana:devnet': {\n USDC: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU', // Devnet USDC\n },\n};\n\n// Chain name to network ID mapping\nexport const CHAIN_TO_NETWORK: Record<string, string> = {\n 'base': 'eip155:8453',\n 'base_sepolia': 'eip155:84532',\n 'polygon': 'eip155:137',\n 'tempo_moderato': 'eip155:42431',\n 'bnb': 'eip155:56',\n 'bnb_testnet': 'eip155:97',\n 'solana': 'solana:mainnet',\n 'solana_devnet': 'solana:devnet',\n};\n\n// Helper to check if a network is Solana\nexport function isSolanaNetwork(network: string): boolean {\n return network.startsWith('solana:');\n}\n\n// EIP-712 domain info for tokens (per network)\n// Different networks may have different domain names for the same token\nexport const TOKEN_DOMAINS: Record<string, Record<string, { name: string; version: string }>> = {\n // Base mainnet\n 'eip155:8453': {\n USDC: { name: 'USD Coin', version: '2' },\n USDT: { name: 'Tether USD', version: '2' },\n },\n // Base Sepolia testnet - USDC uses 'USDC' not 'USD Coin'\n 'eip155:84532': {\n USDC: { name: 'USDC', version: '2' },\n USDT: { name: 'USDC', version: '2' }, // Same contract as USDC on testnet\n },\n // Polygon mainnet\n 'eip155:137': {\n USDC: { name: 'USD Coin', version: '2' },\n USDT: { name: '(PoS) Tether USD', version: '2' },\n },\n // Tempo Moderato testnet - TIP-20 stablecoins\n // Domain names verified against on-chain DOMAIN_SEPARATOR values on 2026-04-21.\n // See docs/TEMPO-WEB-SUPPORT.md Section 2 and test/server/tempo-domain.test.ts.\n // All 4 Tempo TIP-20 tokens (pathUSD / AlphaUSD / BetaUSD / ThetaUSD) use\n // the token symbol with first letter capitalized + version \"1\".\n 'eip155:42431': {\n USDC: { name: 'PathUSD', version: '1' },\n USDT: { name: 'AlphaUSD', version: '1' },\n },\n // BNB Smart Chain mainnet\n 'eip155:56': {\n USDC: { name: 'USD Coin', version: '1' },\n USDT: { name: 'Tether USD', version: '1' },\n },\n // BNB Smart Chain testnet\n 'eip155:97': {\n USDC: { name: 'USD Coin', version: '1' },\n USDT: { name: 'Tether USD', version: '1' },\n },\n};\n\n// Helper to get token domain for a network\nexport function getTokenDomain(network: string, token: string): { name: string; version: string } {\n const networkDomains = TOKEN_DOMAINS[network] || TOKEN_DOMAINS['eip155:8453']; // fallback to base mainnet\n return networkDomains[token] || { name: 'USD Coin', version: '2' };\n}\n\n// Helper to get accepted currencies with backward compatibility\nexport function getAcceptedCurrencies(config: ServiceConfig): string[] {\n return config.acceptedCurrencies ?? [config.currency];\n}\n\n/**\n * Load environment from .env files.\n */\nexport function 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"],"mappings":"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","names":["import_fs","path","import_node_crypto","TRANSFER_EVENT_TOPIC","TRANSFER_EVENT_TOPIC","ethers","import_web3","config","import_node_crypto","crypto","crypto","import_node_crypto","import_node_crypto","crypto","generateOutTradeNo","crypto","path","import_node_crypto","buyer","import_ethers","import_web3","bs58","import_node_crypto","import_ethers","TRANSFER_EVENT_TOPIC","import_fs","path","X402_VERSION","loadEnvFile","crypto","X402_VERSION","loadEnvFile","crypto","X402_VERSION","resolve","settlement"]}