@x402x/extensions 2.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commitment.ts","../../src/server-extension.ts","../../src/client/exact-evm-scheme.ts","../../src/client/extension-handler.ts"],"names":["keccak256","encodePacked","getAddress"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Commitment calculation utilities\n *\n * The commitment hash binds all settlement parameters to the client's signature,\n * preventing parameter tampering attacks.\n */\n\nimport { keccak256, encodePacked, type Hex } from \"viem\";\n\nimport type { CommitmentParams } from \"./types.js\";\n\n/**\n * Calculate commitment hash for x402x settlement\n *\n * This hash becomes the EIP-3009 nonce, cryptographically binding all settlement\n * parameters to the client's signature. The parameter order must exactly match\n * SettlementRouter.sol.\n *\n * @param params - All settlement parameters\n * @returns bytes32 commitment hash\n *\n * @example\n * ```typescript\n * const commitment = calculateCommitment({\n * chainId: 84532,\n * hub: '0x...',\n * asset: '0x...',\n * from: '0x...',\n * value: '100000',\n * validAfter: '0',\n * validBefore: '1234567890',\n * salt: '0x...',\n * payTo: '0x...',\n * facilitatorFee: '10000',\n * hook: '0x...',\n * hookData: '0x',\n * });\n * ```\n */\nexport function calculateCommitment(params: CommitmentParams): string {\n // Pack parameters in exact order as in SettlementRouter.sol\n return keccak256(\n encodePacked(\n [\n \"string\", // Protocol identifier\n \"uint256\", // Chain ID\n \"address\", // Hub address\n \"address\", // Token address\n \"address\", // From (payer)\n \"uint256\", // Value\n \"uint256\", // Valid after\n \"uint256\", // Valid before\n \"bytes32\", // Salt\n \"address\", // Pay to\n \"uint256\", // Facilitator fee\n \"address\", // Hook\n \"bytes32\", // keccak256(hookData)\n ],\n [\n \"X402/settle/v1\",\n BigInt(params.chainId),\n params.hub as Hex,\n params.asset as Hex,\n params.from as Hex,\n BigInt(params.value),\n BigInt(params.validAfter),\n BigInt(params.validBefore),\n params.salt as Hex,\n params.payTo as Hex,\n BigInt(params.facilitatorFee),\n params.hook as Hex,\n keccak256(params.hookData as Hex),\n ],\n ),\n );\n}\n\n/**\n * Generate a random salt for settlement uniqueness\n *\n * Works in both Node.js and browser environments.\n * Uses crypto.getRandomValues (Web Crypto API) which is available in:\n * - Modern browsers\n * - Node.js 15+ (via global crypto)\n * - Older Node.js (via crypto.webcrypto)\n *\n * @returns bytes32 hex string (0x + 64 hex characters)\n *\n * @example\n * ```typescript\n * const salt = generateSalt();\n * // => '0x1234567890abcdef...'\n * ```\n */\nexport function generateSalt(): string {\n // Try to get crypto from global (browser or Node.js 15+)\n const globalCrypto = typeof crypto !== \"undefined\" ? crypto : undefined;\n\n if (globalCrypto?.getRandomValues) {\n // Use Web Crypto API (works in browser and modern Node.js)\n const bytes = new Uint8Array(32);\n globalCrypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n }\n\n // Fallback: use Math.random() (less secure, but works everywhere)\n // Note: Salt doesn't require cryptographic security - it's just for uniqueness\n console.warn(\n \"[generateSalt] Using Math.random() fallback - consider upgrading to Node.js 15+ or use in browser\",\n );\n const bytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Validate commitment parameters\n *\n * @param params - Commitment parameters to validate\n * @throws Error if validation fails\n */\nexport function validateCommitmentParams(params: CommitmentParams): void {\n // Validate addresses\n if (!isValidAddress(params.hub)) {\n throw new Error(\"Invalid hub address\");\n }\n if (!isValidAddress(params.asset)) {\n throw new Error(\"Invalid asset address\");\n }\n if (!isValidAddress(params.from)) {\n throw new Error(\"Invalid from address\");\n }\n if (!isValidAddress(params.payTo)) {\n throw new Error(\"Invalid payTo address\");\n }\n if (!isValidAddress(params.hook)) {\n throw new Error(\"Invalid hook address\");\n }\n\n // Validate numeric values\n try {\n BigInt(params.value);\n BigInt(params.validAfter);\n BigInt(params.validBefore);\n BigInt(params.facilitatorFee);\n } catch {\n throw new Error(\"Invalid numeric parameter\");\n }\n\n // Validate bytes32 values\n if (!isValidHex(params.salt) || params.salt.length !== 66) {\n throw new Error(\"Invalid salt: must be bytes32 (0x + 64 hex chars)\");\n }\n\n if (!isValidHex(params.hookData)) {\n throw new Error(\"Invalid hookData: must be hex string\");\n }\n}\n\n/**\n * Check if a string is a valid Ethereum address\n */\nfunction isValidAddress(address: string): boolean {\n return /^0x[0-9a-fA-F]{40}$/.test(address);\n}\n\n/**\n * Check if a string is a valid hex string\n */\nfunction isValidHex(hex: string): boolean {\n return /^0x[0-9a-fA-F]*$/.test(hex);\n}\n","/**\n * x402x Router Settlement Server Extension\n *\n * Implements ResourceServerExtension interface to integrate router settlement\n * functionality into x402 v2 resource servers.\n */\n\nimport type { x402ResourceServer } from \"@x402/core/server\";\nimport type { ResourceServerExtension } from \"@x402/core/types\";\n\nimport { generateSalt } from \"./commitment.js\";\nimport { createRouterSettlementExtension } from \"./extensions.js\";\n\n/**\n * Extension key constant\n */\nexport const ROUTER_SETTLEMENT_KEY = \"x402x-router-settlement\";\n\n/**\n * Type guard to check if context is an HTTP request context.\n *\n * @param ctx - The context to check\n * @returns True if context is an HTTPRequestContext\n */\nfunction isHTTPRequestContext(ctx: unknown): ctx is { method?: string; adapter?: unknown } {\n return ctx !== null && typeof ctx === \"object\" && \"method\" in ctx;\n}\n\n/**\n * Router settlement extension declaration type\n */\ninterface RouterSettlementDeclaration {\n [key: string]: unknown;\n info?: {\n [key: string]: unknown;\n schemaVersion?: number;\n description?: string;\n /** Dynamic fields that need to be generated per-request */\n dynamic?: {\n salt?: boolean;\n [key: string]: unknown;\n };\n };\n schema?: Record<string, unknown>;\n}\n\n/**\n * x402x Router Settlement ResourceServerExtension\n *\n * This extension enriches PaymentRequired responses with router settlement\n * information, enabling clients to use the SettlementRouter for atomic payments.\n *\n * The extension dynamically generates per-request values like salt to ensure\n * each payment authorization is unique and cannot be replayed.\n *\n * @example\n * ```typescript\n * import { x402ResourceServer } from \"@x402/core/server\";\n * import { routerSettlementServerExtension } from \"@x402x/extensions\";\n *\n * const server = new x402ResourceServer(facilitatorClient);\n * server.registerExtension(routerSettlementServerExtension);\n * ```\n */\nexport const routerSettlementServerExtension: ResourceServerExtension = {\n key: ROUTER_SETTLEMENT_KEY,\n\n enrichDeclaration: (declaration, transportContext) => {\n // Cast to typed declaration\n const extension = declaration as RouterSettlementDeclaration;\n\n // Generate dynamic salt for this request\n const salt = generateSalt();\n\n // Basic enrichment - ensure proper structure with dynamic salt\n const enriched: RouterSettlementDeclaration = {\n ...extension,\n info: {\n schemaVersion: 1,\n ...(extension.info || {}),\n // Add the generated salt to the info\n salt,\n },\n };\n\n // If HTTP context is available, we could add additional metadata\n if (isHTTPRequestContext(transportContext)) {\n // Future: could add HTTP-specific metadata here\n // For now, the salt generation is the main dynamic enhancement\n }\n\n return enriched;\n },\n};\n\n/**\n * Register router settlement extension with an x402ResourceServer\n *\n * Convenience function to register the routerSettlementServerExtension.\n * Also registers necessary hooks for handling settlement parameters.\n *\n * @param server - x402ResourceServer instance\n * @returns The server instance for chaining\n *\n * @example\n * ```typescript\n * import { x402ResourceServer } from \"@x402/core/server\";\n * import { registerExactEvmScheme } from \"@x402/evm/exact/server/register\";\n * import { registerRouterSettlement } from \"@x402x/extensions\";\n *\n * const server = new x402ResourceServer(facilitatorClient);\n * registerExactEvmScheme(server, {});\n * registerRouterSettlement(server);\n * ```\n */\nexport function registerRouterSettlement(server: x402ResourceServer): x402ResourceServer {\n // Register the extension for enriching PaymentRequired responses\n server.registerExtension(routerSettlementServerExtension);\n\n // Note: Hooks for verify/settle are registered separately via\n // registerSettlementHooks if needed for custom validation logic\n\n return server;\n}\n\n/**\n * Create extension declaration for routes\n *\n * Helper function to create properly formatted extension declarations\n * for use in route configurations. The extension enables dynamic salt\n * generation per request and includes all settlement parameters.\n *\n * @param params - Extension parameters including settlement info\n * @returns Extension declaration object\n *\n * @example\n * ```typescript\n * const routes = {\n * \"GET /api/data\": {\n * accepts: { scheme: \"exact\", price: \"$0.01\", network: \"eip155:84532\", payTo: \"0x...\" },\n * extensions: createExtensionDeclaration({\n * description: \"Router settlement with dynamic salt\",\n * settlementRouter: \"0x...\",\n * hook: \"0x...\",\n * hookData: \"0x\",\n * finalPayTo: \"0x...\",\n * facilitatorFee: \"0\",\n * salt: \"0x...\" // Optional, will be auto-generated if not provided\n * })\n * }\n * };\n * ```\n */\nexport function createExtensionDeclaration(params?: {\n description?: string;\n schema?: Record<string, unknown>;\n settlementRouter?: string;\n hook?: string;\n hookData?: string;\n finalPayTo?: string;\n facilitatorFee?: string;\n salt?: string; // Optional salt, will be auto-generated if not provided\n}): Record<string, unknown> {\n return {\n [ROUTER_SETTLEMENT_KEY]: createRouterSettlementExtension(params),\n };\n}\n","/**\n * x402x EVM Client Scheme with Router Settlement\n *\n * This scheme extends the standard EVM exact scheme to support x402x router settlement.\n * The key difference is using a commitment hash (binding all settlement parameters)\n * as the EIP-3009 nonce instead of a random value.\n */\n\nimport type { PaymentPayload, PaymentRequirements, SchemeNetworkClient } from \"@x402/core/types\";\nimport { getAddress, type Hex } from \"viem\";\n\nimport { calculateCommitment } from \"../commitment.js\";\nimport { ROUTER_SETTLEMENT_KEY } from \"../server-extension.js\";\nimport type { CommitmentParams } from \"../types.js\";\n\n/**\n * Client EVM signer interface\n * Compatible with viem WalletClient and LocalAccount\n */\nexport type ClientEvmSigner = {\n readonly address: `0x${string}`;\n signTypedData(message: {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<`0x${string}`>;\n};\n\n/**\n * EIP-3009 TransferWithAuthorization types for EIP-712 signing\n */\nconst authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * EVM exact payment payload structure (v2)\n */\ninterface ExactEvmPayloadV2 {\n authorization: {\n from: string;\n to: string;\n value: string;\n validAfter: string;\n validBefore: string;\n nonce: Hex;\n };\n signature: `0x${string}`;\n}\n\n/**\n * x402x router settlement extension info structure\n */\ninterface RouterSettlementExtension {\n info: {\n schemaVersion?: number;\n description?: string;\n salt: string; // bytes32 hex\n settlementRouter?: string; // address\n hook?: string; // address\n hookData?: string; // bytes hex\n finalPayTo?: string; // address\n facilitatorFee?: string; // uint256 string\n };\n schema?: Record<string, unknown>;\n}\n\n/**\n * EVM client implementation for the Exact payment scheme with x402x router settlement.\n *\n * This scheme uses a commitment hash as the EIP-3009 nonce to cryptographically bind\n * all settlement parameters (salt, hook, hookData, etc.) to the user's signature,\n * preventing parameter tampering attacks.\n *\n * @example\n * ```typescript\n * import { ExactEvmSchemeWithRouterSettlement } from '@x402x/extensions/client';\n * import { x402Client } from '@x402/core/client';\n *\n * const signer = { address, signTypedData }; // viem WalletClient or LocalAccount\n * const scheme = new ExactEvmSchemeWithRouterSettlement(signer);\n *\n * const client = new x402Client()\n * .register('eip155:84532', scheme);\n * ```\n */\nexport class ExactEvmSchemeWithRouterSettlement implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Per-request router settlement extension (typically sourced from PaymentRequired.extensions).\n *\n * IMPORTANT: We do NOT put this on `paymentRequirements.extra`, because for x402 v2 the\n * server matches paid requests by deep-equality between `paymentPayload.accepted` and the\n * server-side `accepts[]`. Mutating `accepted` will cause \"No matching payment requirements\".\n */\n private routerSettlementFromPaymentRequired?: RouterSettlementExtension;\n\n /**\n * Creates a new ExactEvmSchemeWithRouterSettlement instance.\n *\n * @param signer - The EVM signer for client operations (viem WalletClient or LocalAccount)\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Set router-settlement extension data for the next payment payload creation.\n *\n * Intended to be called from an `x402Client.onBeforePaymentCreation` hook, which has access\n * to `paymentRequired.extensions`.\n */\n setRouterSettlementExtensionFromPaymentRequired(ext: unknown | undefined): void {\n if (!ext) {\n this.routerSettlementFromPaymentRequired = undefined;\n return;\n }\n // We keep this cast narrow and validate at use-time.\n this.routerSettlementFromPaymentRequired = ext as RouterSettlementExtension;\n }\n\n /**\n * Creates a payment payload for the Exact scheme with router settlement.\n *\n * This method:\n * 1. Extracts settlement parameters from PaymentRequired.extensions\n * 2. Calculates a commitment hash binding all parameters\n * 3. Uses the commitment as the EIP-3009 nonce\n * 4. Signs with settlementRouter as the 'to' address\n *\n * @param x402Version - The x402 protocol version (must be 2)\n * @param paymentRequirements - The payment requirements from the server\n * @returns Promise resolving to a payment payload\n *\n * @throws Error if x402Version is not 2\n * @throws Error if x402x-router-settlement extension is missing\n * @throws Error if required settlement parameters are missing\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<Pick<PaymentPayload, \"x402Version\" | \"payload\">> {\n if (x402Version !== 2) {\n throw new Error(\n `ExactEvmSchemeWithRouterSettlement only supports x402 version 2, got: ${x402Version}`,\n );\n }\n\n // Extract x402x extension.\n // Prefer per-requirement extra (if a server implementation provides it),\n // otherwise use the per-request data injected from PaymentRequired.extensions.\n const routerSettlement =\n (paymentRequirements.extra?.[ROUTER_SETTLEMENT_KEY] as\n | RouterSettlementExtension\n | undefined) ?? this.routerSettlementFromPaymentRequired;\n\n if (!routerSettlement?.info) {\n throw new Error(\n \"x402x-router-settlement extension not available for scheme signing. \" +\n \"Ensure the resource server includes the extension in PaymentRequired.extensions and \" +\n \"the client registered x402x via registerX402xScheme() (or injected the handler).\",\n );\n }\n\n const { salt, settlementRouter, hook, hookData, finalPayTo, facilitatorFee } =\n routerSettlement.info;\n\n // Clear after read to avoid leaking between requests\n this.routerSettlementFromPaymentRequired = undefined;\n\n // Validate required parameters\n if (!salt) throw new Error(\"Missing required parameter: salt\");\n if (!settlementRouter) throw new Error(\"Missing required parameter: settlementRouter\");\n if (!hook) throw new Error(\"Missing required parameter: hook\");\n if (hookData === undefined) throw new Error(\"Missing required parameter: hookData\");\n if (!finalPayTo) throw new Error(\"Missing required parameter: finalPayTo\");\n // facilitatorFee is optional - if not provided, use \"0\" (facilitator will calculate actual fee)\n const resolvedFacilitatorFee = facilitatorFee ?? \"0\";\n\n // Parse chain ID from network (e.g., \"eip155:84532\" -> 84532)\n const chainId = parseInt(paymentRequirements.network.split(\":\")[1]);\n if (isNaN(chainId)) {\n throw new Error(`Invalid network format: ${paymentRequirements.network}`);\n }\n\n // Calculate time window\n const now = Math.floor(Date.now() / 1000);\n const validAfter = (now - 600).toString(); // 10 minutes before\n const validBefore = (now + paymentRequirements.maxTimeoutSeconds).toString();\n\n // Build commitment parameters\n const commitmentParams: CommitmentParams = {\n chainId,\n hub: settlementRouter,\n asset: paymentRequirements.asset,\n from: this.signer.address,\n value: paymentRequirements.amount,\n validAfter,\n validBefore,\n salt,\n payTo: finalPayTo,\n facilitatorFee: resolvedFacilitatorFee,\n hook,\n hookData,\n };\n\n // Calculate commitment hash - this becomes the nonce\n const nonce = calculateCommitment(commitmentParams) as Hex;\n\n // Build authorization (EIP-3009)\n // CRITICAL: 'to' must be settlementRouter, not payTo\n const authorization: ExactEvmPayloadV2[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(settlementRouter),\n value: paymentRequirements.amount,\n validAfter,\n validBefore,\n nonce,\n };\n\n // Sign the authorization using EIP-712\n const signature = await this.signAuthorization(authorization, paymentRequirements, chainId);\n\n // Build payload\n const payload: Record<string, unknown> = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @param chainId - The chain ID\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV2[\"authorization\"],\n requirements: PaymentRequirements,\n chainId: number,\n ): Promise<`0x${string}`> {\n // Extract EIP-712 domain parameters from extra\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","/**\n * x402x Extension Handler\n *\n * Provides utilities to integrate x402x router settlement with official x402 SDK.\n *\n * The challenge: x402 v2 spec places extensions at root level in PaymentRequired,\n * but x402x scheme needs settlement parameters from PaymentRequirements.extra.\n *\n * Solution: Provide two-layer API:\n * 1. High-level: registerX402xScheme() - one line setup (recommended)\n * 2. Low-level: injectX402xExtensionHandler() - flexible configuration\n */\n\nimport { x402Client } from \"@x402/core/client\";\nimport type { Network } from \"@x402/core/types\";\n\nimport { ROUTER_SETTLEMENT_KEY } from \"../server-extension\";\n\nimport { ExactEvmSchemeWithRouterSettlement, type ClientEvmSigner } from \"./exact-evm-scheme\";\n\n/**\n * Injects x402x extension handler into x402Client (Low-level API).\n *\n * IMPORTANT (x402 v2 + x402x multi-network):\n * - Server returns per-option x402x info in `accepts[i].extra[\"x402x-router-settlement\"]`\n * - x402Client only passes `PaymentRequirements` to scheme (no root extensions)\n * - Facilitator v2 reads from `paymentPayload.extensions[\"x402x-router-settlement\"]`\n *\n * Solution: Copy the selected option's x402x info from `selectedRequirements.extra`\n * into `paymentRequired.extensions` so it gets included in `paymentPayload.extensions`.\n *\n * This does NOT mutate `selectedRequirements` (which becomes `paymentPayload.accepted`),\n * so v2 deepEqual matching still works.\n *\n * @param client - x402Client instance to inject handler into\n * @param onRouterSettlementExtension - Callback to receive the per-request extension object\n * @returns The same client instance for chaining\n *\n * @example Low-level API (for advanced users)\n * ```typescript\n * import { x402Client } from '@x402/core/client';\n * import {\n * injectX402xExtensionHandler,\n * ExactEvmSchemeWithRouterSettlement\n * } from '@x402x/extensions';\n *\n * const client = new x402Client();\n * const scheme = new ExactEvmSchemeWithRouterSettlement(signer);\n * injectX402xExtensionHandler(client, (ext) => scheme.setRouterSettlementExtensionFromPaymentRequired(ext))\n * .register('eip155:84532', scheme);\n * ```\n */\nexport function injectX402xExtensionHandler(\n client: x402Client,\n onRouterSettlementExtension?: (extension: unknown | undefined) => void,\n): x402Client {\n return client.onBeforePaymentCreation(async (context) => {\n const { paymentRequired, selectedRequirements } = context;\n\n // Debug: show what we received\n console.log(\"[x402x-handler] onBeforePaymentCreation called\");\n console.log(\"[x402x-handler] selectedRequirements.network:\", selectedRequirements.network);\n console.log(\n \"[x402x-handler] selectedRequirements.extra keys:\",\n Object.keys(selectedRequirements.extra || {}),\n );\n\n // Key insight: Per-option x402x info is in selectedRequirements.extra[x402x-router-settlement].\n // We need to copy it into paymentRequired.extensions[x402x-router-settlement] so that:\n // 1. x402Client copies it into paymentPayload.extensions (v2 standard)\n // 2. Facilitator v2 can read it from paymentPayload.extensions\n // 3. We DON'T mutate selectedRequirements (which becomes paymentPayload.accepted)\n\n const perOptionExtension = selectedRequirements.extra?.[ROUTER_SETTLEMENT_KEY];\n\n if (perOptionExtension) {\n // Initialize extensions object if it doesn't exist\n if (!paymentRequired.extensions) {\n (paymentRequired as any).extensions = {};\n }\n\n // Copy the per-option x402x info into root extensions\n // This will be copied into paymentPayload.extensions by x402Client\n (paymentRequired.extensions as any)[ROUTER_SETTLEMENT_KEY] = perOptionExtension;\n\n console.log(\n \"[x402x-handler] ✅ Copied per-option x402x info into PaymentRequired.extensions\",\n );\n console.log(\"[x402x-handler] Extension info:\", JSON.stringify(perOptionExtension, null, 2));\n } else {\n // Fallback: if no per-option info, use root-level extension (legacy behavior)\n console.warn(\n \"[x402x-handler] ⚠️ No per-option x402x info found in selectedRequirements.extra\",\n );\n console.warn(\n \"[x402x-handler] This may cause facilitator errors. Check server-side createSettlementRouteConfig.\",\n );\n }\n\n // Forward extension to callback (for schemes that need direct access)\n if (onRouterSettlementExtension) {\n const extensionToUse =\n perOptionExtension || paymentRequired.extensions?.[ROUTER_SETTLEMENT_KEY];\n onRouterSettlementExtension(extensionToUse);\n }\n });\n}\n\n/**\n * Register x402x router settlement scheme with automatic extension handling (High-level API).\n *\n * This is the recommended way to set up x402x payments. It combines:\n * 1. Extension handler injection (injectX402xExtensionHandler)\n * 2. Scheme registration (ExactEvmSchemeWithRouterSettlement)\n *\n * Use this for the simplest integration - just provide your signer and network.\n *\n * @param client - x402Client instance\n * @param network - Network identifier in CAIP-2 format (e.g., \"eip155:84532\")\n * @param signer - EVM signer with address and signTypedData method\n * @returns The client instance for chaining\n *\n * @example High-level API (recommended)\n * ```typescript\n * import { x402Client } from '@x402/core/client';\n * import { registerX402xScheme } from '@x402x/extensions';\n * import { useWalletClient } from 'wagmi';\n *\n * const { data: walletClient } = useWalletClient();\n *\n * const client = new x402Client();\n * registerX402xScheme(client, 'eip155:84532', {\n * address: walletClient.account.address,\n * signTypedData: walletClient.signTypedData,\n * });\n *\n * // That's it! Client is ready for x402x payments\n * ```\n *\n * @example Multiple networks\n * ```typescript\n * const client = new x402Client();\n * registerX402xScheme(client, 'eip155:84532', signer); // Base Sepolia\n * registerX402xScheme(client, 'eip155:8453', signer); // Base Mainnet\n * ```\n */\nexport function registerX402xScheme(\n client: x402Client,\n network: Network,\n signer: ClientEvmSigner,\n): x402Client {\n const scheme = new ExactEvmSchemeWithRouterSettlement(signer);\n\n // Inject extension handler: capture root-level extension data (incl. dynamic salt)\n // and pass it into the scheme instance without mutating `accepted`.\n injectX402xExtensionHandler(client, (ext) => {\n // Scope to this specific network to avoid cross-network leakage if user registers multiple.\n // (We don't have direct access to `selectedRequirements` here without mutating accepted,\n // so we keep it simple: this scheme instance is per-network registration.)\n scheme.setRouterSettlementExtensionFromPaymentRequired(ext);\n });\n\n // Register the x402x scheme for this network\n client.register(network, scheme);\n\n return client;\n}\n"]}
@@ -0,0 +1,251 @@
1
+ import { getAddress, keccak256, encodePacked } from 'viem';
2
+
3
+ // src/client/exact-evm-scheme.ts
4
+ function calculateCommitment(params) {
5
+ return keccak256(
6
+ encodePacked(
7
+ [
8
+ "string",
9
+ // Protocol identifier
10
+ "uint256",
11
+ // Chain ID
12
+ "address",
13
+ // Hub address
14
+ "address",
15
+ // Token address
16
+ "address",
17
+ // From (payer)
18
+ "uint256",
19
+ // Value
20
+ "uint256",
21
+ // Valid after
22
+ "uint256",
23
+ // Valid before
24
+ "bytes32",
25
+ // Salt
26
+ "address",
27
+ // Pay to
28
+ "uint256",
29
+ // Facilitator fee
30
+ "address",
31
+ // Hook
32
+ "bytes32"
33
+ // keccak256(hookData)
34
+ ],
35
+ [
36
+ "X402/settle/v1",
37
+ BigInt(params.chainId),
38
+ params.hub,
39
+ params.asset,
40
+ params.from,
41
+ BigInt(params.value),
42
+ BigInt(params.validAfter),
43
+ BigInt(params.validBefore),
44
+ params.salt,
45
+ params.payTo,
46
+ BigInt(params.facilitatorFee),
47
+ params.hook,
48
+ keccak256(params.hookData)
49
+ ]
50
+ )
51
+ );
52
+ }
53
+
54
+ // src/server-extension.ts
55
+ var ROUTER_SETTLEMENT_KEY = "x402x-router-settlement";
56
+
57
+ // src/client/exact-evm-scheme.ts
58
+ var authorizationTypes = {
59
+ TransferWithAuthorization: [
60
+ { name: "from", type: "address" },
61
+ { name: "to", type: "address" },
62
+ { name: "value", type: "uint256" },
63
+ { name: "validAfter", type: "uint256" },
64
+ { name: "validBefore", type: "uint256" },
65
+ { name: "nonce", type: "bytes32" }
66
+ ]
67
+ };
68
+ var ExactEvmSchemeWithRouterSettlement = class {
69
+ /**
70
+ * Creates a new ExactEvmSchemeWithRouterSettlement instance.
71
+ *
72
+ * @param signer - The EVM signer for client operations (viem WalletClient or LocalAccount)
73
+ */
74
+ constructor(signer) {
75
+ this.signer = signer;
76
+ this.scheme = "exact";
77
+ }
78
+ /**
79
+ * Set router-settlement extension data for the next payment payload creation.
80
+ *
81
+ * Intended to be called from an `x402Client.onBeforePaymentCreation` hook, which has access
82
+ * to `paymentRequired.extensions`.
83
+ */
84
+ setRouterSettlementExtensionFromPaymentRequired(ext) {
85
+ if (!ext) {
86
+ this.routerSettlementFromPaymentRequired = void 0;
87
+ return;
88
+ }
89
+ this.routerSettlementFromPaymentRequired = ext;
90
+ }
91
+ /**
92
+ * Creates a payment payload for the Exact scheme with router settlement.
93
+ *
94
+ * This method:
95
+ * 1. Extracts settlement parameters from PaymentRequired.extensions
96
+ * 2. Calculates a commitment hash binding all parameters
97
+ * 3. Uses the commitment as the EIP-3009 nonce
98
+ * 4. Signs with settlementRouter as the 'to' address
99
+ *
100
+ * @param x402Version - The x402 protocol version (must be 2)
101
+ * @param paymentRequirements - The payment requirements from the server
102
+ * @returns Promise resolving to a payment payload
103
+ *
104
+ * @throws Error if x402Version is not 2
105
+ * @throws Error if x402x-router-settlement extension is missing
106
+ * @throws Error if required settlement parameters are missing
107
+ */
108
+ async createPaymentPayload(x402Version, paymentRequirements) {
109
+ if (x402Version !== 2) {
110
+ throw new Error(
111
+ `ExactEvmSchemeWithRouterSettlement only supports x402 version 2, got: ${x402Version}`
112
+ );
113
+ }
114
+ const routerSettlement = paymentRequirements.extra?.[ROUTER_SETTLEMENT_KEY] ?? this.routerSettlementFromPaymentRequired;
115
+ if (!routerSettlement?.info) {
116
+ throw new Error(
117
+ "x402x-router-settlement extension not available for scheme signing. Ensure the resource server includes the extension in PaymentRequired.extensions and the client registered x402x via registerX402xScheme() (or injected the handler)."
118
+ );
119
+ }
120
+ const { salt, settlementRouter, hook, hookData, finalPayTo, facilitatorFee } = routerSettlement.info;
121
+ this.routerSettlementFromPaymentRequired = void 0;
122
+ if (!salt) throw new Error("Missing required parameter: salt");
123
+ if (!settlementRouter) throw new Error("Missing required parameter: settlementRouter");
124
+ if (!hook) throw new Error("Missing required parameter: hook");
125
+ if (hookData === void 0) throw new Error("Missing required parameter: hookData");
126
+ if (!finalPayTo) throw new Error("Missing required parameter: finalPayTo");
127
+ const resolvedFacilitatorFee = facilitatorFee ?? "0";
128
+ const chainId = parseInt(paymentRequirements.network.split(":")[1]);
129
+ if (isNaN(chainId)) {
130
+ throw new Error(`Invalid network format: ${paymentRequirements.network}`);
131
+ }
132
+ const now = Math.floor(Date.now() / 1e3);
133
+ const validAfter = (now - 600).toString();
134
+ const validBefore = (now + paymentRequirements.maxTimeoutSeconds).toString();
135
+ const commitmentParams = {
136
+ chainId,
137
+ hub: settlementRouter,
138
+ asset: paymentRequirements.asset,
139
+ from: this.signer.address,
140
+ value: paymentRequirements.amount,
141
+ validAfter,
142
+ validBefore,
143
+ salt,
144
+ payTo: finalPayTo,
145
+ facilitatorFee: resolvedFacilitatorFee,
146
+ hook,
147
+ hookData
148
+ };
149
+ const nonce = calculateCommitment(commitmentParams);
150
+ const authorization = {
151
+ from: this.signer.address,
152
+ to: getAddress(settlementRouter),
153
+ value: paymentRequirements.amount,
154
+ validAfter,
155
+ validBefore,
156
+ nonce
157
+ };
158
+ const signature = await this.signAuthorization(authorization, paymentRequirements, chainId);
159
+ const payload = {
160
+ authorization,
161
+ signature
162
+ };
163
+ return {
164
+ x402Version,
165
+ payload
166
+ };
167
+ }
168
+ /**
169
+ * Sign the EIP-3009 authorization using EIP-712
170
+ *
171
+ * @param authorization - The authorization to sign
172
+ * @param requirements - The payment requirements
173
+ * @param chainId - The chain ID
174
+ * @returns Promise resolving to the signature
175
+ */
176
+ async signAuthorization(authorization, requirements, chainId) {
177
+ if (!requirements.extra?.name || !requirements.extra?.version) {
178
+ throw new Error(
179
+ `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
180
+ );
181
+ }
182
+ const { name, version } = requirements.extra;
183
+ const domain = {
184
+ name,
185
+ version,
186
+ chainId,
187
+ verifyingContract: getAddress(requirements.asset)
188
+ };
189
+ const message = {
190
+ from: getAddress(authorization.from),
191
+ to: getAddress(authorization.to),
192
+ value: BigInt(authorization.value),
193
+ validAfter: BigInt(authorization.validAfter),
194
+ validBefore: BigInt(authorization.validBefore),
195
+ nonce: authorization.nonce
196
+ };
197
+ return await this.signer.signTypedData({
198
+ domain,
199
+ types: authorizationTypes,
200
+ primaryType: "TransferWithAuthorization",
201
+ message
202
+ });
203
+ }
204
+ };
205
+
206
+ // src/client/extension-handler.ts
207
+ function injectX402xExtensionHandler(client, onRouterSettlementExtension) {
208
+ return client.onBeforePaymentCreation(async (context) => {
209
+ const { paymentRequired, selectedRequirements } = context;
210
+ console.log("[x402x-handler] onBeforePaymentCreation called");
211
+ console.log("[x402x-handler] selectedRequirements.network:", selectedRequirements.network);
212
+ console.log(
213
+ "[x402x-handler] selectedRequirements.extra keys:",
214
+ Object.keys(selectedRequirements.extra || {})
215
+ );
216
+ const perOptionExtension = selectedRequirements.extra?.[ROUTER_SETTLEMENT_KEY];
217
+ if (perOptionExtension) {
218
+ if (!paymentRequired.extensions) {
219
+ paymentRequired.extensions = {};
220
+ }
221
+ paymentRequired.extensions[ROUTER_SETTLEMENT_KEY] = perOptionExtension;
222
+ console.log(
223
+ "[x402x-handler] \u2705 Copied per-option x402x info into PaymentRequired.extensions"
224
+ );
225
+ console.log("[x402x-handler] Extension info:", JSON.stringify(perOptionExtension, null, 2));
226
+ } else {
227
+ console.warn(
228
+ "[x402x-handler] \u26A0\uFE0F No per-option x402x info found in selectedRequirements.extra"
229
+ );
230
+ console.warn(
231
+ "[x402x-handler] This may cause facilitator errors. Check server-side createSettlementRouteConfig."
232
+ );
233
+ }
234
+ if (onRouterSettlementExtension) {
235
+ const extensionToUse = perOptionExtension || paymentRequired.extensions?.[ROUTER_SETTLEMENT_KEY];
236
+ onRouterSettlementExtension(extensionToUse);
237
+ }
238
+ });
239
+ }
240
+ function registerX402xScheme(client, network, signer) {
241
+ const scheme = new ExactEvmSchemeWithRouterSettlement(signer);
242
+ injectX402xExtensionHandler(client, (ext) => {
243
+ scheme.setRouterSettlementExtensionFromPaymentRequired(ext);
244
+ });
245
+ client.register(network, scheme);
246
+ return client;
247
+ }
248
+
249
+ export { ExactEvmSchemeWithRouterSettlement, injectX402xExtensionHandler, registerX402xScheme };
250
+ //# sourceMappingURL=index.mjs.map
251
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commitment.ts","../../src/server-extension.ts","../../src/client/exact-evm-scheme.ts","../../src/client/extension-handler.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Commitment calculation utilities\n *\n * The commitment hash binds all settlement parameters to the client's signature,\n * preventing parameter tampering attacks.\n */\n\nimport { keccak256, encodePacked, type Hex } from \"viem\";\n\nimport type { CommitmentParams } from \"./types.js\";\n\n/**\n * Calculate commitment hash for x402x settlement\n *\n * This hash becomes the EIP-3009 nonce, cryptographically binding all settlement\n * parameters to the client's signature. The parameter order must exactly match\n * SettlementRouter.sol.\n *\n * @param params - All settlement parameters\n * @returns bytes32 commitment hash\n *\n * @example\n * ```typescript\n * const commitment = calculateCommitment({\n * chainId: 84532,\n * hub: '0x...',\n * asset: '0x...',\n * from: '0x...',\n * value: '100000',\n * validAfter: '0',\n * validBefore: '1234567890',\n * salt: '0x...',\n * payTo: '0x...',\n * facilitatorFee: '10000',\n * hook: '0x...',\n * hookData: '0x',\n * });\n * ```\n */\nexport function calculateCommitment(params: CommitmentParams): string {\n // Pack parameters in exact order as in SettlementRouter.sol\n return keccak256(\n encodePacked(\n [\n \"string\", // Protocol identifier\n \"uint256\", // Chain ID\n \"address\", // Hub address\n \"address\", // Token address\n \"address\", // From (payer)\n \"uint256\", // Value\n \"uint256\", // Valid after\n \"uint256\", // Valid before\n \"bytes32\", // Salt\n \"address\", // Pay to\n \"uint256\", // Facilitator fee\n \"address\", // Hook\n \"bytes32\", // keccak256(hookData)\n ],\n [\n \"X402/settle/v1\",\n BigInt(params.chainId),\n params.hub as Hex,\n params.asset as Hex,\n params.from as Hex,\n BigInt(params.value),\n BigInt(params.validAfter),\n BigInt(params.validBefore),\n params.salt as Hex,\n params.payTo as Hex,\n BigInt(params.facilitatorFee),\n params.hook as Hex,\n keccak256(params.hookData as Hex),\n ],\n ),\n );\n}\n\n/**\n * Generate a random salt for settlement uniqueness\n *\n * Works in both Node.js and browser environments.\n * Uses crypto.getRandomValues (Web Crypto API) which is available in:\n * - Modern browsers\n * - Node.js 15+ (via global crypto)\n * - Older Node.js (via crypto.webcrypto)\n *\n * @returns bytes32 hex string (0x + 64 hex characters)\n *\n * @example\n * ```typescript\n * const salt = generateSalt();\n * // => '0x1234567890abcdef...'\n * ```\n */\nexport function generateSalt(): string {\n // Try to get crypto from global (browser or Node.js 15+)\n const globalCrypto = typeof crypto !== \"undefined\" ? crypto : undefined;\n\n if (globalCrypto?.getRandomValues) {\n // Use Web Crypto API (works in browser and modern Node.js)\n const bytes = new Uint8Array(32);\n globalCrypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n }\n\n // Fallback: use Math.random() (less secure, but works everywhere)\n // Note: Salt doesn't require cryptographic security - it's just for uniqueness\n console.warn(\n \"[generateSalt] Using Math.random() fallback - consider upgrading to Node.js 15+ or use in browser\",\n );\n const bytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Validate commitment parameters\n *\n * @param params - Commitment parameters to validate\n * @throws Error if validation fails\n */\nexport function validateCommitmentParams(params: CommitmentParams): void {\n // Validate addresses\n if (!isValidAddress(params.hub)) {\n throw new Error(\"Invalid hub address\");\n }\n if (!isValidAddress(params.asset)) {\n throw new Error(\"Invalid asset address\");\n }\n if (!isValidAddress(params.from)) {\n throw new Error(\"Invalid from address\");\n }\n if (!isValidAddress(params.payTo)) {\n throw new Error(\"Invalid payTo address\");\n }\n if (!isValidAddress(params.hook)) {\n throw new Error(\"Invalid hook address\");\n }\n\n // Validate numeric values\n try {\n BigInt(params.value);\n BigInt(params.validAfter);\n BigInt(params.validBefore);\n BigInt(params.facilitatorFee);\n } catch {\n throw new Error(\"Invalid numeric parameter\");\n }\n\n // Validate bytes32 values\n if (!isValidHex(params.salt) || params.salt.length !== 66) {\n throw new Error(\"Invalid salt: must be bytes32 (0x + 64 hex chars)\");\n }\n\n if (!isValidHex(params.hookData)) {\n throw new Error(\"Invalid hookData: must be hex string\");\n }\n}\n\n/**\n * Check if a string is a valid Ethereum address\n */\nfunction isValidAddress(address: string): boolean {\n return /^0x[0-9a-fA-F]{40}$/.test(address);\n}\n\n/**\n * Check if a string is a valid hex string\n */\nfunction isValidHex(hex: string): boolean {\n return /^0x[0-9a-fA-F]*$/.test(hex);\n}\n","/**\n * x402x Router Settlement Server Extension\n *\n * Implements ResourceServerExtension interface to integrate router settlement\n * functionality into x402 v2 resource servers.\n */\n\nimport type { x402ResourceServer } from \"@x402/core/server\";\nimport type { ResourceServerExtension } from \"@x402/core/types\";\n\nimport { generateSalt } from \"./commitment.js\";\nimport { createRouterSettlementExtension } from \"./extensions.js\";\n\n/**\n * Extension key constant\n */\nexport const ROUTER_SETTLEMENT_KEY = \"x402x-router-settlement\";\n\n/**\n * Type guard to check if context is an HTTP request context.\n *\n * @param ctx - The context to check\n * @returns True if context is an HTTPRequestContext\n */\nfunction isHTTPRequestContext(ctx: unknown): ctx is { method?: string; adapter?: unknown } {\n return ctx !== null && typeof ctx === \"object\" && \"method\" in ctx;\n}\n\n/**\n * Router settlement extension declaration type\n */\ninterface RouterSettlementDeclaration {\n [key: string]: unknown;\n info?: {\n [key: string]: unknown;\n schemaVersion?: number;\n description?: string;\n /** Dynamic fields that need to be generated per-request */\n dynamic?: {\n salt?: boolean;\n [key: string]: unknown;\n };\n };\n schema?: Record<string, unknown>;\n}\n\n/**\n * x402x Router Settlement ResourceServerExtension\n *\n * This extension enriches PaymentRequired responses with router settlement\n * information, enabling clients to use the SettlementRouter for atomic payments.\n *\n * The extension dynamically generates per-request values like salt to ensure\n * each payment authorization is unique and cannot be replayed.\n *\n * @example\n * ```typescript\n * import { x402ResourceServer } from \"@x402/core/server\";\n * import { routerSettlementServerExtension } from \"@x402x/extensions\";\n *\n * const server = new x402ResourceServer(facilitatorClient);\n * server.registerExtension(routerSettlementServerExtension);\n * ```\n */\nexport const routerSettlementServerExtension: ResourceServerExtension = {\n key: ROUTER_SETTLEMENT_KEY,\n\n enrichDeclaration: (declaration, transportContext) => {\n // Cast to typed declaration\n const extension = declaration as RouterSettlementDeclaration;\n\n // Generate dynamic salt for this request\n const salt = generateSalt();\n\n // Basic enrichment - ensure proper structure with dynamic salt\n const enriched: RouterSettlementDeclaration = {\n ...extension,\n info: {\n schemaVersion: 1,\n ...(extension.info || {}),\n // Add the generated salt to the info\n salt,\n },\n };\n\n // If HTTP context is available, we could add additional metadata\n if (isHTTPRequestContext(transportContext)) {\n // Future: could add HTTP-specific metadata here\n // For now, the salt generation is the main dynamic enhancement\n }\n\n return enriched;\n },\n};\n\n/**\n * Register router settlement extension with an x402ResourceServer\n *\n * Convenience function to register the routerSettlementServerExtension.\n * Also registers necessary hooks for handling settlement parameters.\n *\n * @param server - x402ResourceServer instance\n * @returns The server instance for chaining\n *\n * @example\n * ```typescript\n * import { x402ResourceServer } from \"@x402/core/server\";\n * import { registerExactEvmScheme } from \"@x402/evm/exact/server/register\";\n * import { registerRouterSettlement } from \"@x402x/extensions\";\n *\n * const server = new x402ResourceServer(facilitatorClient);\n * registerExactEvmScheme(server, {});\n * registerRouterSettlement(server);\n * ```\n */\nexport function registerRouterSettlement(server: x402ResourceServer): x402ResourceServer {\n // Register the extension for enriching PaymentRequired responses\n server.registerExtension(routerSettlementServerExtension);\n\n // Note: Hooks for verify/settle are registered separately via\n // registerSettlementHooks if needed for custom validation logic\n\n return server;\n}\n\n/**\n * Create extension declaration for routes\n *\n * Helper function to create properly formatted extension declarations\n * for use in route configurations. The extension enables dynamic salt\n * generation per request and includes all settlement parameters.\n *\n * @param params - Extension parameters including settlement info\n * @returns Extension declaration object\n *\n * @example\n * ```typescript\n * const routes = {\n * \"GET /api/data\": {\n * accepts: { scheme: \"exact\", price: \"$0.01\", network: \"eip155:84532\", payTo: \"0x...\" },\n * extensions: createExtensionDeclaration({\n * description: \"Router settlement with dynamic salt\",\n * settlementRouter: \"0x...\",\n * hook: \"0x...\",\n * hookData: \"0x\",\n * finalPayTo: \"0x...\",\n * facilitatorFee: \"0\",\n * salt: \"0x...\" // Optional, will be auto-generated if not provided\n * })\n * }\n * };\n * ```\n */\nexport function createExtensionDeclaration(params?: {\n description?: string;\n schema?: Record<string, unknown>;\n settlementRouter?: string;\n hook?: string;\n hookData?: string;\n finalPayTo?: string;\n facilitatorFee?: string;\n salt?: string; // Optional salt, will be auto-generated if not provided\n}): Record<string, unknown> {\n return {\n [ROUTER_SETTLEMENT_KEY]: createRouterSettlementExtension(params),\n };\n}\n","/**\n * x402x EVM Client Scheme with Router Settlement\n *\n * This scheme extends the standard EVM exact scheme to support x402x router settlement.\n * The key difference is using a commitment hash (binding all settlement parameters)\n * as the EIP-3009 nonce instead of a random value.\n */\n\nimport type { PaymentPayload, PaymentRequirements, SchemeNetworkClient } from \"@x402/core/types\";\nimport { getAddress, type Hex } from \"viem\";\n\nimport { calculateCommitment } from \"../commitment.js\";\nimport { ROUTER_SETTLEMENT_KEY } from \"../server-extension.js\";\nimport type { CommitmentParams } from \"../types.js\";\n\n/**\n * Client EVM signer interface\n * Compatible with viem WalletClient and LocalAccount\n */\nexport type ClientEvmSigner = {\n readonly address: `0x${string}`;\n signTypedData(message: {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<`0x${string}`>;\n};\n\n/**\n * EIP-3009 TransferWithAuthorization types for EIP-712 signing\n */\nconst authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * EVM exact payment payload structure (v2)\n */\ninterface ExactEvmPayloadV2 {\n authorization: {\n from: string;\n to: string;\n value: string;\n validAfter: string;\n validBefore: string;\n nonce: Hex;\n };\n signature: `0x${string}`;\n}\n\n/**\n * x402x router settlement extension info structure\n */\ninterface RouterSettlementExtension {\n info: {\n schemaVersion?: number;\n description?: string;\n salt: string; // bytes32 hex\n settlementRouter?: string; // address\n hook?: string; // address\n hookData?: string; // bytes hex\n finalPayTo?: string; // address\n facilitatorFee?: string; // uint256 string\n };\n schema?: Record<string, unknown>;\n}\n\n/**\n * EVM client implementation for the Exact payment scheme with x402x router settlement.\n *\n * This scheme uses a commitment hash as the EIP-3009 nonce to cryptographically bind\n * all settlement parameters (salt, hook, hookData, etc.) to the user's signature,\n * preventing parameter tampering attacks.\n *\n * @example\n * ```typescript\n * import { ExactEvmSchemeWithRouterSettlement } from '@x402x/extensions/client';\n * import { x402Client } from '@x402/core/client';\n *\n * const signer = { address, signTypedData }; // viem WalletClient or LocalAccount\n * const scheme = new ExactEvmSchemeWithRouterSettlement(signer);\n *\n * const client = new x402Client()\n * .register('eip155:84532', scheme);\n * ```\n */\nexport class ExactEvmSchemeWithRouterSettlement implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Per-request router settlement extension (typically sourced from PaymentRequired.extensions).\n *\n * IMPORTANT: We do NOT put this on `paymentRequirements.extra`, because for x402 v2 the\n * server matches paid requests by deep-equality between `paymentPayload.accepted` and the\n * server-side `accepts[]`. Mutating `accepted` will cause \"No matching payment requirements\".\n */\n private routerSettlementFromPaymentRequired?: RouterSettlementExtension;\n\n /**\n * Creates a new ExactEvmSchemeWithRouterSettlement instance.\n *\n * @param signer - The EVM signer for client operations (viem WalletClient or LocalAccount)\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Set router-settlement extension data for the next payment payload creation.\n *\n * Intended to be called from an `x402Client.onBeforePaymentCreation` hook, which has access\n * to `paymentRequired.extensions`.\n */\n setRouterSettlementExtensionFromPaymentRequired(ext: unknown | undefined): void {\n if (!ext) {\n this.routerSettlementFromPaymentRequired = undefined;\n return;\n }\n // We keep this cast narrow and validate at use-time.\n this.routerSettlementFromPaymentRequired = ext as RouterSettlementExtension;\n }\n\n /**\n * Creates a payment payload for the Exact scheme with router settlement.\n *\n * This method:\n * 1. Extracts settlement parameters from PaymentRequired.extensions\n * 2. Calculates a commitment hash binding all parameters\n * 3. Uses the commitment as the EIP-3009 nonce\n * 4. Signs with settlementRouter as the 'to' address\n *\n * @param x402Version - The x402 protocol version (must be 2)\n * @param paymentRequirements - The payment requirements from the server\n * @returns Promise resolving to a payment payload\n *\n * @throws Error if x402Version is not 2\n * @throws Error if x402x-router-settlement extension is missing\n * @throws Error if required settlement parameters are missing\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<Pick<PaymentPayload, \"x402Version\" | \"payload\">> {\n if (x402Version !== 2) {\n throw new Error(\n `ExactEvmSchemeWithRouterSettlement only supports x402 version 2, got: ${x402Version}`,\n );\n }\n\n // Extract x402x extension.\n // Prefer per-requirement extra (if a server implementation provides it),\n // otherwise use the per-request data injected from PaymentRequired.extensions.\n const routerSettlement =\n (paymentRequirements.extra?.[ROUTER_SETTLEMENT_KEY] as\n | RouterSettlementExtension\n | undefined) ?? this.routerSettlementFromPaymentRequired;\n\n if (!routerSettlement?.info) {\n throw new Error(\n \"x402x-router-settlement extension not available for scheme signing. \" +\n \"Ensure the resource server includes the extension in PaymentRequired.extensions and \" +\n \"the client registered x402x via registerX402xScheme() (or injected the handler).\",\n );\n }\n\n const { salt, settlementRouter, hook, hookData, finalPayTo, facilitatorFee } =\n routerSettlement.info;\n\n // Clear after read to avoid leaking between requests\n this.routerSettlementFromPaymentRequired = undefined;\n\n // Validate required parameters\n if (!salt) throw new Error(\"Missing required parameter: salt\");\n if (!settlementRouter) throw new Error(\"Missing required parameter: settlementRouter\");\n if (!hook) throw new Error(\"Missing required parameter: hook\");\n if (hookData === undefined) throw new Error(\"Missing required parameter: hookData\");\n if (!finalPayTo) throw new Error(\"Missing required parameter: finalPayTo\");\n // facilitatorFee is optional - if not provided, use \"0\" (facilitator will calculate actual fee)\n const resolvedFacilitatorFee = facilitatorFee ?? \"0\";\n\n // Parse chain ID from network (e.g., \"eip155:84532\" -> 84532)\n const chainId = parseInt(paymentRequirements.network.split(\":\")[1]);\n if (isNaN(chainId)) {\n throw new Error(`Invalid network format: ${paymentRequirements.network}`);\n }\n\n // Calculate time window\n const now = Math.floor(Date.now() / 1000);\n const validAfter = (now - 600).toString(); // 10 minutes before\n const validBefore = (now + paymentRequirements.maxTimeoutSeconds).toString();\n\n // Build commitment parameters\n const commitmentParams: CommitmentParams = {\n chainId,\n hub: settlementRouter,\n asset: paymentRequirements.asset,\n from: this.signer.address,\n value: paymentRequirements.amount,\n validAfter,\n validBefore,\n salt,\n payTo: finalPayTo,\n facilitatorFee: resolvedFacilitatorFee,\n hook,\n hookData,\n };\n\n // Calculate commitment hash - this becomes the nonce\n const nonce = calculateCommitment(commitmentParams) as Hex;\n\n // Build authorization (EIP-3009)\n // CRITICAL: 'to' must be settlementRouter, not payTo\n const authorization: ExactEvmPayloadV2[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(settlementRouter),\n value: paymentRequirements.amount,\n validAfter,\n validBefore,\n nonce,\n };\n\n // Sign the authorization using EIP-712\n const signature = await this.signAuthorization(authorization, paymentRequirements, chainId);\n\n // Build payload\n const payload: Record<string, unknown> = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @param chainId - The chain ID\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV2[\"authorization\"],\n requirements: PaymentRequirements,\n chainId: number,\n ): Promise<`0x${string}`> {\n // Extract EIP-712 domain parameters from extra\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","/**\n * x402x Extension Handler\n *\n * Provides utilities to integrate x402x router settlement with official x402 SDK.\n *\n * The challenge: x402 v2 spec places extensions at root level in PaymentRequired,\n * but x402x scheme needs settlement parameters from PaymentRequirements.extra.\n *\n * Solution: Provide two-layer API:\n * 1. High-level: registerX402xScheme() - one line setup (recommended)\n * 2. Low-level: injectX402xExtensionHandler() - flexible configuration\n */\n\nimport { x402Client } from \"@x402/core/client\";\nimport type { Network } from \"@x402/core/types\";\n\nimport { ROUTER_SETTLEMENT_KEY } from \"../server-extension\";\n\nimport { ExactEvmSchemeWithRouterSettlement, type ClientEvmSigner } from \"./exact-evm-scheme\";\n\n/**\n * Injects x402x extension handler into x402Client (Low-level API).\n *\n * IMPORTANT (x402 v2 + x402x multi-network):\n * - Server returns per-option x402x info in `accepts[i].extra[\"x402x-router-settlement\"]`\n * - x402Client only passes `PaymentRequirements` to scheme (no root extensions)\n * - Facilitator v2 reads from `paymentPayload.extensions[\"x402x-router-settlement\"]`\n *\n * Solution: Copy the selected option's x402x info from `selectedRequirements.extra`\n * into `paymentRequired.extensions` so it gets included in `paymentPayload.extensions`.\n *\n * This does NOT mutate `selectedRequirements` (which becomes `paymentPayload.accepted`),\n * so v2 deepEqual matching still works.\n *\n * @param client - x402Client instance to inject handler into\n * @param onRouterSettlementExtension - Callback to receive the per-request extension object\n * @returns The same client instance for chaining\n *\n * @example Low-level API (for advanced users)\n * ```typescript\n * import { x402Client } from '@x402/core/client';\n * import {\n * injectX402xExtensionHandler,\n * ExactEvmSchemeWithRouterSettlement\n * } from '@x402x/extensions';\n *\n * const client = new x402Client();\n * const scheme = new ExactEvmSchemeWithRouterSettlement(signer);\n * injectX402xExtensionHandler(client, (ext) => scheme.setRouterSettlementExtensionFromPaymentRequired(ext))\n * .register('eip155:84532', scheme);\n * ```\n */\nexport function injectX402xExtensionHandler(\n client: x402Client,\n onRouterSettlementExtension?: (extension: unknown | undefined) => void,\n): x402Client {\n return client.onBeforePaymentCreation(async (context) => {\n const { paymentRequired, selectedRequirements } = context;\n\n // Debug: show what we received\n console.log(\"[x402x-handler] onBeforePaymentCreation called\");\n console.log(\"[x402x-handler] selectedRequirements.network:\", selectedRequirements.network);\n console.log(\n \"[x402x-handler] selectedRequirements.extra keys:\",\n Object.keys(selectedRequirements.extra || {}),\n );\n\n // Key insight: Per-option x402x info is in selectedRequirements.extra[x402x-router-settlement].\n // We need to copy it into paymentRequired.extensions[x402x-router-settlement] so that:\n // 1. x402Client copies it into paymentPayload.extensions (v2 standard)\n // 2. Facilitator v2 can read it from paymentPayload.extensions\n // 3. We DON'T mutate selectedRequirements (which becomes paymentPayload.accepted)\n\n const perOptionExtension = selectedRequirements.extra?.[ROUTER_SETTLEMENT_KEY];\n\n if (perOptionExtension) {\n // Initialize extensions object if it doesn't exist\n if (!paymentRequired.extensions) {\n (paymentRequired as any).extensions = {};\n }\n\n // Copy the per-option x402x info into root extensions\n // This will be copied into paymentPayload.extensions by x402Client\n (paymentRequired.extensions as any)[ROUTER_SETTLEMENT_KEY] = perOptionExtension;\n\n console.log(\n \"[x402x-handler] ✅ Copied per-option x402x info into PaymentRequired.extensions\",\n );\n console.log(\"[x402x-handler] Extension info:\", JSON.stringify(perOptionExtension, null, 2));\n } else {\n // Fallback: if no per-option info, use root-level extension (legacy behavior)\n console.warn(\n \"[x402x-handler] ⚠️ No per-option x402x info found in selectedRequirements.extra\",\n );\n console.warn(\n \"[x402x-handler] This may cause facilitator errors. Check server-side createSettlementRouteConfig.\",\n );\n }\n\n // Forward extension to callback (for schemes that need direct access)\n if (onRouterSettlementExtension) {\n const extensionToUse =\n perOptionExtension || paymentRequired.extensions?.[ROUTER_SETTLEMENT_KEY];\n onRouterSettlementExtension(extensionToUse);\n }\n });\n}\n\n/**\n * Register x402x router settlement scheme with automatic extension handling (High-level API).\n *\n * This is the recommended way to set up x402x payments. It combines:\n * 1. Extension handler injection (injectX402xExtensionHandler)\n * 2. Scheme registration (ExactEvmSchemeWithRouterSettlement)\n *\n * Use this for the simplest integration - just provide your signer and network.\n *\n * @param client - x402Client instance\n * @param network - Network identifier in CAIP-2 format (e.g., \"eip155:84532\")\n * @param signer - EVM signer with address and signTypedData method\n * @returns The client instance for chaining\n *\n * @example High-level API (recommended)\n * ```typescript\n * import { x402Client } from '@x402/core/client';\n * import { registerX402xScheme } from '@x402x/extensions';\n * import { useWalletClient } from 'wagmi';\n *\n * const { data: walletClient } = useWalletClient();\n *\n * const client = new x402Client();\n * registerX402xScheme(client, 'eip155:84532', {\n * address: walletClient.account.address,\n * signTypedData: walletClient.signTypedData,\n * });\n *\n * // That's it! Client is ready for x402x payments\n * ```\n *\n * @example Multiple networks\n * ```typescript\n * const client = new x402Client();\n * registerX402xScheme(client, 'eip155:84532', signer); // Base Sepolia\n * registerX402xScheme(client, 'eip155:8453', signer); // Base Mainnet\n * ```\n */\nexport function registerX402xScheme(\n client: x402Client,\n network: Network,\n signer: ClientEvmSigner,\n): x402Client {\n const scheme = new ExactEvmSchemeWithRouterSettlement(signer);\n\n // Inject extension handler: capture root-level extension data (incl. dynamic salt)\n // and pass it into the scheme instance without mutating `accepted`.\n injectX402xExtensionHandler(client, (ext) => {\n // Scope to this specific network to avoid cross-network leakage if user registers multiple.\n // (We don't have direct access to `selectedRequirements` here without mutating accepted,\n // so we keep it simple: this scheme instance is per-network registration.)\n scheme.setRouterSettlementExtensionFromPaymentRequired(ext);\n });\n\n // Register the x402x scheme for this network\n client.register(network, scheme);\n\n return client;\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -1,8 +1,9 @@
1
- import { Network, PaymentRequirements, ResourceServerExtension, SchemeNetworkFacilitator, PaymentPayload, SchemeNetworkClient } from '@x402/core/types';
1
+ import { Network, PaymentRequirements, ResourceServerExtension, SchemeNetworkFacilitator, PaymentPayload } from '@x402/core/types';
2
2
  export { Network, PaymentPayload, PaymentRequirements } from '@x402/core/types';
3
3
  import { Chain, Address as Address$1 } from 'viem';
4
4
  import { x402ResourceServer } from '@x402/core/server';
5
- import { x402Client } from '@x402/core/client';
5
+ export { ClientEvmSigner, ExactEvmSchemeWithRouterSettlement, injectX402xExtensionHandler, registerX402xScheme } from './client/index.mjs';
6
+ import '@x402/core/client';
6
7
 
7
8
  /**
8
9
  * Type definitions for @x402x/extensions
@@ -1888,183 +1889,4 @@ declare function getNetworkAliasesV1ToV2(): Record<string, Network>;
1888
1889
  */
1889
1890
  declare function toCanonicalNetworkKey(network: string): Network;
1890
1891
 
1891
- /**
1892
- * x402x EVM Client Scheme with Router Settlement
1893
- *
1894
- * This scheme extends the standard EVM exact scheme to support x402x router settlement.
1895
- * The key difference is using a commitment hash (binding all settlement parameters)
1896
- * as the EIP-3009 nonce instead of a random value.
1897
- */
1898
-
1899
- /**
1900
- * Client EVM signer interface
1901
- * Compatible with viem WalletClient and LocalAccount
1902
- */
1903
- type ClientEvmSigner = {
1904
- readonly address: `0x${string}`;
1905
- signTypedData(message: {
1906
- domain: Record<string, unknown>;
1907
- types: Record<string, unknown>;
1908
- primaryType: string;
1909
- message: Record<string, unknown>;
1910
- }): Promise<`0x${string}`>;
1911
- };
1912
- /**
1913
- * EVM client implementation for the Exact payment scheme with x402x router settlement.
1914
- *
1915
- * This scheme uses a commitment hash as the EIP-3009 nonce to cryptographically bind
1916
- * all settlement parameters (salt, hook, hookData, etc.) to the user's signature,
1917
- * preventing parameter tampering attacks.
1918
- *
1919
- * @example
1920
- * ```typescript
1921
- * import { ExactEvmSchemeWithRouterSettlement } from '@x402x/extensions/client';
1922
- * import { x402Client } from '@x402/core/client';
1923
- *
1924
- * const signer = { address, signTypedData }; // viem WalletClient or LocalAccount
1925
- * const scheme = new ExactEvmSchemeWithRouterSettlement(signer);
1926
- *
1927
- * const client = new x402Client()
1928
- * .register('eip155:84532', scheme);
1929
- * ```
1930
- */
1931
- declare class ExactEvmSchemeWithRouterSettlement implements SchemeNetworkClient {
1932
- private readonly signer;
1933
- readonly scheme = "exact";
1934
- /**
1935
- * Per-request router settlement extension (typically sourced from PaymentRequired.extensions).
1936
- *
1937
- * IMPORTANT: We do NOT put this on `paymentRequirements.extra`, because for x402 v2 the
1938
- * server matches paid requests by deep-equality between `paymentPayload.accepted` and the
1939
- * server-side `accepts[]`. Mutating `accepted` will cause "No matching payment requirements".
1940
- */
1941
- private routerSettlementFromPaymentRequired?;
1942
- /**
1943
- * Creates a new ExactEvmSchemeWithRouterSettlement instance.
1944
- *
1945
- * @param signer - The EVM signer for client operations (viem WalletClient or LocalAccount)
1946
- */
1947
- constructor(signer: ClientEvmSigner);
1948
- /**
1949
- * Set router-settlement extension data for the next payment payload creation.
1950
- *
1951
- * Intended to be called from an `x402Client.onBeforePaymentCreation` hook, which has access
1952
- * to `paymentRequired.extensions`.
1953
- */
1954
- setRouterSettlementExtensionFromPaymentRequired(ext: unknown | undefined): void;
1955
- /**
1956
- * Creates a payment payload for the Exact scheme with router settlement.
1957
- *
1958
- * This method:
1959
- * 1. Extracts settlement parameters from PaymentRequired.extensions
1960
- * 2. Calculates a commitment hash binding all parameters
1961
- * 3. Uses the commitment as the EIP-3009 nonce
1962
- * 4. Signs with settlementRouter as the 'to' address
1963
- *
1964
- * @param x402Version - The x402 protocol version (must be 2)
1965
- * @param paymentRequirements - The payment requirements from the server
1966
- * @returns Promise resolving to a payment payload
1967
- *
1968
- * @throws Error if x402Version is not 2
1969
- * @throws Error if x402x-router-settlement extension is missing
1970
- * @throws Error if required settlement parameters are missing
1971
- */
1972
- createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements): Promise<Pick<PaymentPayload, "x402Version" | "payload">>;
1973
- /**
1974
- * Sign the EIP-3009 authorization using EIP-712
1975
- *
1976
- * @param authorization - The authorization to sign
1977
- * @param requirements - The payment requirements
1978
- * @param chainId - The chain ID
1979
- * @returns Promise resolving to the signature
1980
- */
1981
- private signAuthorization;
1982
- }
1983
-
1984
- /**
1985
- * x402x Extension Handler
1986
- *
1987
- * Provides utilities to integrate x402x router settlement with official x402 SDK.
1988
- *
1989
- * The challenge: x402 v2 spec places extensions at root level in PaymentRequired,
1990
- * but x402x scheme needs settlement parameters from PaymentRequirements.extra.
1991
- *
1992
- * Solution: Provide two-layer API:
1993
- * 1. High-level: registerX402xScheme() - one line setup (recommended)
1994
- * 2. Low-level: injectX402xExtensionHandler() - flexible configuration
1995
- */
1996
-
1997
- /**
1998
- * Injects x402x extension handler into x402Client (Low-level API).
1999
- *
2000
- * IMPORTANT (x402 v2 + x402x multi-network):
2001
- * - Server returns per-option x402x info in `accepts[i].extra["x402x-router-settlement"]`
2002
- * - x402Client only passes `PaymentRequirements` to scheme (no root extensions)
2003
- * - Facilitator v2 reads from `paymentPayload.extensions["x402x-router-settlement"]`
2004
- *
2005
- * Solution: Copy the selected option's x402x info from `selectedRequirements.extra`
2006
- * into `paymentRequired.extensions` so it gets included in `paymentPayload.extensions`.
2007
- *
2008
- * This does NOT mutate `selectedRequirements` (which becomes `paymentPayload.accepted`),
2009
- * so v2 deepEqual matching still works.
2010
- *
2011
- * @param client - x402Client instance to inject handler into
2012
- * @param onRouterSettlementExtension - Callback to receive the per-request extension object
2013
- * @returns The same client instance for chaining
2014
- *
2015
- * @example Low-level API (for advanced users)
2016
- * ```typescript
2017
- * import { x402Client } from '@x402/core/client';
2018
- * import {
2019
- * injectX402xExtensionHandler,
2020
- * ExactEvmSchemeWithRouterSettlement
2021
- * } from '@x402x/extensions';
2022
- *
2023
- * const client = new x402Client();
2024
- * const scheme = new ExactEvmSchemeWithRouterSettlement(signer);
2025
- * injectX402xExtensionHandler(client, (ext) => scheme.setRouterSettlementExtensionFromPaymentRequired(ext))
2026
- * .register('eip155:84532', scheme);
2027
- * ```
2028
- */
2029
- declare function injectX402xExtensionHandler(client: x402Client, onRouterSettlementExtension?: (extension: unknown | undefined) => void): x402Client;
2030
- /**
2031
- * Register x402x router settlement scheme with automatic extension handling (High-level API).
2032
- *
2033
- * This is the recommended way to set up x402x payments. It combines:
2034
- * 1. Extension handler injection (injectX402xExtensionHandler)
2035
- * 2. Scheme registration (ExactEvmSchemeWithRouterSettlement)
2036
- *
2037
- * Use this for the simplest integration - just provide your signer and network.
2038
- *
2039
- * @param client - x402Client instance
2040
- * @param network - Network identifier in CAIP-2 format (e.g., "eip155:84532")
2041
- * @param signer - EVM signer with address and signTypedData method
2042
- * @returns The client instance for chaining
2043
- *
2044
- * @example High-level API (recommended)
2045
- * ```typescript
2046
- * import { x402Client } from '@x402/core/client';
2047
- * import { registerX402xScheme } from '@x402x/extensions';
2048
- * import { useWalletClient } from 'wagmi';
2049
- *
2050
- * const { data: walletClient } = useWalletClient();
2051
- *
2052
- * const client = new x402Client();
2053
- * registerX402xScheme(client, 'eip155:84532', {
2054
- * address: walletClient.account.address,
2055
- * signTypedData: walletClient.signTypedData,
2056
- * });
2057
- *
2058
- * // That's it! Client is ready for x402x payments
2059
- * ```
2060
- *
2061
- * @example Multiple networks
2062
- * ```typescript
2063
- * const client = new x402Client();
2064
- * registerX402xScheme(client, 'eip155:84532', signer); // Base Sepolia
2065
- * registerX402xScheme(client, 'eip155:8453', signer); // Base Mainnet
2066
- * ```
2067
- */
2068
- declare function registerX402xScheme(client: x402Client, network: Network, signer: ClientEvmSigner): x402Client;
2069
-
2070
- export { type Address, AmountError, type ClientEvmSigner, type CommitmentParams, type DemoHooks, ExactEvmSchemeWithRouterSettlement, type FacilitatorConfig, type SettleResponse$1 as FacilitatorSettleResponse, FacilitatorValidationError, type VerifyResponse$1 as FacilitatorVerifyResponse, type FeeCalculationResult, type RouteConfig as LegacyRouteConfig, type MintConfig, type Money, NETWORK_ALIASES, NETWORK_ALIASES_V1_TO_V2, NFTMintHook, type NetworkConfig, ROUTER_SETTLEMENT_KEY, type Resource, type RewardConfig, RewardHook, type RoutePattern, type RouterSettlementExtension, type RouterSettlementExtensionInfo, type RoutesConfig, SETTLEMENT_ROUTER_ABI, type SettleResponse, type SettlementExtra, type SettlementExtraCore, SettlementExtraError, type SettlementHooksConfig, type SettlementOptions, type SettlementPaymentOption, type SettlementRouteConfig, SettlementRouterError, type SettlementRouterParams, type Signer, TransferHook, type ValidationResult, type VerifyResponse, type WithRouterSettlementOptions, addSettlementExtra, assertValidSettlementExtra, calculateCommitment, calculateFacilitatorFee, clearFeeCache, computeRoutePatterns, createExtensionDeclaration, createRouterSettlementExtension, createSettlementRouteConfig, createX402xFacilitator, findMatchingPaymentRequirements, findMatchingRoute, formatDefaultAssetAmount, generateSalt, getChain, getChainById, getCustomChains, getDefaultAsset, getNetworkAlias, getNetworkAliasesV1ToV2, getNetworkConfig, getRouterSettlementExtensionKey, getSupportedNetworkAliases, getSupportedNetworkIds, getSupportedNetworks, injectX402xExtensionHandler, isCustomChain, isNetworkSupported, isRouterSettlement, isSettlementMode, isValid32ByteHex, isValidAddress, isValidHex, isValidNumericString, networks, parseDefaultAssetAmount, parseSettlementExtra, processPriceToAtomicAmount, registerRouterSettlement, registerSettlementHooks, registerX402xScheme, routerSettlementServerExtension, settle, toCanonicalNetworkKey, toJsonSafe, validateCommitmentParams, validateSettlementExtra, verify, withRouterSettlement };
1892
+ export { type Address, AmountError, type CommitmentParams, type DemoHooks, type FacilitatorConfig, type SettleResponse$1 as FacilitatorSettleResponse, FacilitatorValidationError, type VerifyResponse$1 as FacilitatorVerifyResponse, type FeeCalculationResult, type RouteConfig as LegacyRouteConfig, type MintConfig, type Money, NETWORK_ALIASES, NETWORK_ALIASES_V1_TO_V2, NFTMintHook, type NetworkConfig, ROUTER_SETTLEMENT_KEY, type Resource, type RewardConfig, RewardHook, type RoutePattern, type RouterSettlementExtension, type RouterSettlementExtensionInfo, type RoutesConfig, SETTLEMENT_ROUTER_ABI, type SettleResponse, type SettlementExtra, type SettlementExtraCore, SettlementExtraError, type SettlementHooksConfig, type SettlementOptions, type SettlementPaymentOption, type SettlementRouteConfig, SettlementRouterError, type SettlementRouterParams, type Signer, TransferHook, type ValidationResult, type VerifyResponse, type WithRouterSettlementOptions, addSettlementExtra, assertValidSettlementExtra, calculateCommitment, calculateFacilitatorFee, clearFeeCache, computeRoutePatterns, createExtensionDeclaration, createRouterSettlementExtension, createSettlementRouteConfig, createX402xFacilitator, findMatchingPaymentRequirements, findMatchingRoute, formatDefaultAssetAmount, generateSalt, getChain, getChainById, getCustomChains, getDefaultAsset, getNetworkAlias, getNetworkAliasesV1ToV2, getNetworkConfig, getRouterSettlementExtensionKey, getSupportedNetworkAliases, getSupportedNetworkIds, getSupportedNetworks, isCustomChain, isNetworkSupported, isRouterSettlement, isSettlementMode, isValid32ByteHex, isValidAddress, isValidHex, isValidNumericString, networks, parseDefaultAssetAmount, parseSettlementExtra, processPriceToAtomicAmount, registerRouterSettlement, registerSettlementHooks, routerSettlementServerExtension, settle, toCanonicalNetworkKey, toJsonSafe, validateCommitmentParams, validateSettlementExtra, verify, withRouterSettlement };