moltspay 1.6.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.
- package/.env.example +23 -0
- package/CHANGELOG.md +551 -0
- package/README.md +466 -7
- package/dist/cdp/index.js.map +1 -1
- package/dist/cdp/index.mjs.map +1 -1
- package/dist/{cdp-DeohBe1o.d.ts → cdp-B5PhDUTC.d.ts} +1 -1
- package/dist/{cdp-p_eHuQpb.d.mts → cdp-D-5Hg3y_.d.mts} +1 -1
- package/dist/chains/index.d.mts +102 -1
- package/dist/chains/index.d.ts +102 -1
- package/dist/chains/index.js +66 -0
- package/dist/chains/index.js.map +1 -1
- package/dist/chains/index.mjs +57 -0
- package/dist/chains/index.mjs.map +1 -1
- package/dist/cli/index.js +6850 -2127
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +6857 -2128
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +348 -1
- package/dist/client/index.d.ts +348 -1
- package/dist/client/index.js +1462 -43
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +1469 -51
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/web/index.d.mts +17 -1
- package/dist/client/web/index.mjs +11 -0
- package/dist/client/web/index.mjs.map +1 -1
- package/dist/facilitators/index.d.mts +663 -4
- package/dist/facilitators/index.d.ts +663 -4
- package/dist/facilitators/index.js +1292 -10
- package/dist/facilitators/index.js.map +1 -1
- package/dist/facilitators/index.mjs +1268 -9
- package/dist/facilitators/index.mjs.map +1 -1
- package/dist/index.d.mts +78 -3
- package/dist/index.d.ts +78 -3
- package/dist/index.js +4229 -556
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4214 -548
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/index.js +1462 -45
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/index.mjs +1473 -56
- package/dist/mcp/index.mjs.map +1 -1
- package/dist/{registry-OsEO2dOu.d.mts → registry-DIo0WNoO.d.mts} +8 -1
- package/dist/{registry-OsEO2dOu.d.ts → registry-DIo0WNoO.d.ts} +8 -1
- package/dist/server/index.d.mts +336 -2
- package/dist/server/index.d.ts +336 -2
- package/dist/server/index.js +2516 -188
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +2516 -188
- package/dist/server/index.mjs.map +1 -1
- package/dist/verify/index.js.map +1 -1
- package/dist/verify/index.mjs.map +1 -1
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +20 -2
- package/schemas/moltspay.services.schema.json +211 -6
- package/scripts/postinstall.js +91 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/facilitators/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/registry.ts"],"sourcesContent":["/**\n * Facilitator Module\n * \n * Provides pluggable payment facilitator support for MoltsPay.\n * \n * @example\n * ```typescript\n * import { FacilitatorRegistry, CDPFacilitator } from 'moltspay/facilitators';\n * \n * // Use default CDP facilitator\n * const registry = new FacilitatorRegistry();\n * const result = await registry.verify(paymentPayload, requirements);\n * \n * // Or with custom config\n * const registry = new FacilitatorRegistry({\n * primary: 'cdp',\n * fallback: ['chaoschain'], // Coming in v0.9.0\n * strategy: 'failover',\n * config: {\n * cdp: { useMainnet: true }\n * }\n * });\n * ```\n */\n\n// Interface & types\nexport {\n Facilitator,\n BaseFacilitator,\n FacilitatorConfig,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n FacilitatorFee,\n} from './interface.js';\n\n// CDP Facilitator\nexport {\n CDPFacilitator,\n CDPFacilitatorConfig,\n} from './cdp.js';\n\n// Tempo Facilitator\nexport {\n TempoFacilitator,\n} from './tempo.js';\n\n// BNB Facilitator\nexport {\n BNBFacilitator,\n BNBPaymentIntent,\n createIntentTypedData,\n} from './bnb.js';\n\n// Solana Facilitator\nexport {\n SolanaFacilitator,\n createSolanaPaymentTransaction,\n type SolanaPaymentPayload,\n} from './solana.js';\n\n// Registry\nexport {\n FacilitatorRegistry,\n FacilitatorSelection,\n SelectionStrategy,\n getDefaultRegistry,\n createRegistry,\n} from './registry.js';\n","/**\n * Facilitator Interface\n * \n * A facilitator is a service that handles x402 payment verification and settlement.\n * This abstraction allows MoltsPay to support multiple facilitators.\n * \n * @see https://www.x402.org/ecosystem?category=facilitators\n */\n\n/**\n * x402 Payment Payload (from client)\n */\nexport interface X402PaymentPayload {\n x402Version: number;\n scheme?: string;\n network?: string;\n accepted?: {\n scheme: string;\n network: string;\n asset: string;\n amount: string;\n payTo: string;\n maxTimeoutSeconds: number;\n extra?: Record<string, unknown>;\n };\n payload: unknown;\n}\n\n/**\n * x402 Payment Requirements (server specifies what it accepts)\n */\nexport interface X402PaymentRequirements {\n scheme: string;\n network: string;\n asset: string;\n amount: string;\n payTo: string;\n maxTimeoutSeconds: number;\n extra?: Record<string, unknown>;\n}\n\n/**\n * Result of payment verification\n */\nexport interface VerifyResult {\n valid: boolean;\n error?: string;\n details?: Record<string, unknown>;\n}\n\n/**\n * Result of payment settlement\n */\nexport interface SettleResult {\n success: boolean;\n transaction?: string;\n error?: string;\n status?: string;\n}\n\n/**\n * Facilitator health check result\n */\nexport interface HealthCheckResult {\n healthy: boolean;\n latencyMs?: number;\n error?: string;\n}\n\n/**\n * Facilitator fee information (for selection strategies)\n */\nexport interface FacilitatorFee {\n perTx: number;\n currency: string;\n freeQuota?: number;\n}\n\n/**\n * Facilitator configuration\n */\nexport interface FacilitatorConfig {\n /** Facilitator endpoint URL */\n endpoint?: string;\n /** API key (if required) */\n apiKey?: string;\n /** API secret (if required) */\n apiSecret?: string;\n /** Additional config specific to facilitator */\n [key: string]: unknown;\n}\n\n/**\n * Facilitator Interface\n * \n * All facilitators must implement this interface.\n */\nexport interface Facilitator {\n /** Unique identifier for this facilitator */\n readonly name: string;\n \n /** Human-readable display name */\n readonly displayName: string;\n \n /** Supported networks (e.g., [\"eip155:8453\", \"eip155:84532\"]) */\n readonly supportedNetworks: string[];\n \n /**\n * Check if facilitator is available and responsive\n */\n healthCheck(): Promise<HealthCheckResult>;\n \n /**\n * Verify a payment signature without executing it\n * \n * @param paymentPayload - The x402 payment payload from client\n * @param requirements - The payment requirements from server\n */\n verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult>;\n \n /**\n * Settle a payment on-chain\n * \n * @param paymentPayload - The x402 payment payload from client\n * @param requirements - The payment requirements from server\n */\n settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult>;\n \n /**\n * Get current fee information (optional, for selection strategies)\n */\n getFee?(): Promise<FacilitatorFee>;\n \n /**\n * Check if this facilitator supports a given network\n */\n supportsNetwork(network: string): boolean;\n}\n\n/**\n * Base class with common functionality\n */\nexport abstract class BaseFacilitator implements Facilitator {\n abstract readonly name: string;\n abstract readonly displayName: string;\n abstract readonly supportedNetworks: string[];\n \n abstract healthCheck(): Promise<HealthCheckResult>;\n abstract verify(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<VerifyResult>;\n abstract settle(\n paymentPayload: X402PaymentPayload,\n requirements: X402PaymentRequirements\n ): Promise<SettleResult>;\n \n supportsNetwork(network: string): boolean {\n return this.supportedNetworks.includes(network);\n }\n}\n","/**\n * CDP Facilitator\n * \n * Coinbase Developer Platform x402 facilitator implementation.\n * 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/**\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 * 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 { 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 \n // Default selection\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":["TRANSFER_EVENT_TOPIC","TRANSFER_EVENT_TOPIC","ethers","import_web3","config","import_web3","bs58"]}
|
|
1
|
+
{"version":3,"sources":["../../src/facilitators/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"],"sourcesContent":["/**\n * Facilitator Module\n * \n * Provides pluggable payment facilitator support for MoltsPay.\n * \n * @example\n * ```typescript\n * import { FacilitatorRegistry, CDPFacilitator } from 'moltspay/facilitators';\n * \n * // Use default CDP facilitator\n * const registry = new FacilitatorRegistry();\n * const result = await registry.verify(paymentPayload, requirements);\n * \n * // Or with custom config\n * const registry = new FacilitatorRegistry({\n * primary: 'cdp',\n * fallback: ['chaoschain'], // Coming in v0.9.0\n * strategy: 'failover',\n * config: {\n * cdp: { useMainnet: true }\n * }\n * });\n * ```\n */\n\n// Interface & types\nexport {\n Facilitator,\n BaseFacilitator,\n FacilitatorConfig,\n X402PaymentPayload,\n X402PaymentRequirements,\n VerifyResult,\n SettleResult,\n HealthCheckResult,\n FacilitatorFee,\n} from './interface.js';\n\n// CDP Facilitator\nexport {\n CDPFacilitator,\n CDPFacilitatorConfig,\n} from './cdp.js';\n\n// Tempo Facilitator\nexport {\n TempoFacilitator,\n} from './tempo.js';\n\n// BNB Facilitator\nexport {\n BNBFacilitator,\n BNBPaymentIntent,\n createIntentTypedData,\n} from './bnb.js';\n\n// Solana Facilitator\nexport {\n SolanaFacilitator,\n createSolanaPaymentTransaction,\n type SolanaPaymentPayload,\n} from './solana.js';\n\n// Alipay AI Pay Facilitator (2.0.0)\nexport {\n AlipayFacilitator,\n AlipayFacilitatorConfig,\n AlipayPaymentRequirements,\n AlipayPaymentProof,\n CreatePaymentRequirementsOpts,\n ALIPAY_NETWORK,\n ALIPAY_SCHEME,\n ALIPAY_GATEWAY_PROD,\n ALIPAY_GATEWAY_SANDBOX,\n} from './alipay.js';\n\n// WeChat Pay v3 Native Facilitator (2.1.0)\nexport {\n WechatFacilitator,\n WechatFacilitatorConfig,\n WechatPaymentRequirements,\n WECHAT_NETWORK,\n WECHAT_SCHEME,\n WECHAT_API_BASE,\n WECHAT_AMOUNT_REGEX,\n WECHAT_TIME_EXPIRE_MS,\n parseWechatAttach,\n} from './wechat.js';\n\n// Custodial Balance Facilitator (password-free rail, 2.2.0)\nexport {\n BalanceFacilitator,\n BalanceFacilitatorConfig,\n BalancePaymentPayload,\n extractBalancePayload,\n BALANCE_NETWORK,\n BALANCE_SCHEME,\n toSat,\n fromSat,\n BalanceAuthMode,\n BalanceAuthFields,\n verifyDeductAuth,\n buildDeductMessage,\n BALANCE_AUTH_DOMAIN,\n BALANCE_AUTH_MAX_SKEW_MS,\n} from './balance.js';\nexport {\n BalanceLedger,\n BuyerRow,\n LedgerTxRow,\n DeductResult,\n RefundResult,\n} from './balance/ledger.js';\n\n// Registry\nexport {\n FacilitatorRegistry,\n FacilitatorSelection,\n SelectionStrategy,\n getDefaultRegistry,\n createRegistry,\n} from './registry.js';\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"],"mappings":"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","names":["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"]}
|