@bankofai/x402-evm 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +172 -0
  2. package/dist/cjs/auth-capture/client/index.d.ts +44 -0
  3. package/dist/cjs/auth-capture/client/index.js +298 -0
  4. package/dist/cjs/auth-capture/client/index.js.map +1 -0
  5. package/dist/cjs/batch-settlement/client/file-storage.d.ts +47 -0
  6. package/dist/cjs/batch-settlement/client/file-storage.js +116 -0
  7. package/dist/cjs/batch-settlement/client/file-storage.js.map +1 -0
  8. package/dist/cjs/batch-settlement/client/index.d.ts +111 -0
  9. package/dist/cjs/batch-settlement/client/index.js +1565 -0
  10. package/dist/cjs/batch-settlement/client/index.js.map +1 -0
  11. package/dist/cjs/batch-settlement/facilitator/index.d.ts +72 -0
  12. package/dist/cjs/batch-settlement/facilitator/index.js +2102 -0
  13. package/dist/cjs/batch-settlement/facilitator/index.js.map +1 -0
  14. package/dist/cjs/batch-settlement/server/file-storage.d.ts +53 -0
  15. package/dist/cjs/batch-settlement/server/file-storage.js +181 -0
  16. package/dist/cjs/batch-settlement/server/file-storage.js.map +1 -0
  17. package/dist/cjs/batch-settlement/server/index.d.ts +491 -0
  18. package/dist/cjs/batch-settlement/server/index.js +1978 -0
  19. package/dist/cjs/batch-settlement/server/index.js.map +1 -0
  20. package/dist/cjs/batch-settlement/server/redis-storage.d.ts +87 -0
  21. package/dist/cjs/batch-settlement/server/redis-storage.js +181 -0
  22. package/dist/cjs/batch-settlement/server/redis-storage.js.map +1 -0
  23. package/dist/cjs/client/agent-wallet.d.ts +69 -0
  24. package/dist/cjs/client/agent-wallet.js +84 -0
  25. package/dist/cjs/client/agent-wallet.js.map +1 -0
  26. package/dist/cjs/exact/client/index.d.ts +63 -0
  27. package/dist/cjs/exact/client/index.js +739 -0
  28. package/dist/cjs/exact/client/index.js.map +1 -0
  29. package/dist/cjs/exact/facilitator/index.d.ts +141 -0
  30. package/dist/cjs/exact/facilitator/index.js +1989 -0
  31. package/dist/cjs/exact/facilitator/index.js.map +1 -0
  32. package/dist/cjs/exact/server/index.d.ts +118 -0
  33. package/dist/cjs/exact/server/index.js +326 -0
  34. package/dist/cjs/exact/server/index.js.map +1 -0
  35. package/dist/cjs/exact/v1/client/index.d.ts +38 -0
  36. package/dist/cjs/exact/v1/client/index.js +193 -0
  37. package/dist/cjs/exact/v1/client/index.js.map +1 -0
  38. package/dist/cjs/exact/v1/facilitator/index.d.ts +84 -0
  39. package/dist/cjs/exact/v1/facilitator/index.js +739 -0
  40. package/dist/cjs/exact/v1/facilitator/index.js.map +1 -0
  41. package/dist/cjs/facilitator/agent-wallet.d.ts +109 -0
  42. package/dist/cjs/facilitator/agent-wallet.js +105 -0
  43. package/dist/cjs/facilitator/agent-wallet.js.map +1 -0
  44. package/dist/cjs/index.d.ts +338 -0
  45. package/dist/cjs/index.js +2860 -0
  46. package/dist/cjs/index.js.map +1 -0
  47. package/dist/cjs/permit2-DK5A8alk.d.ts +729 -0
  48. package/dist/cjs/permit2-DhJRUcgY.d.ts +729 -0
  49. package/dist/cjs/rpc-DULZzRne.d.ts +13 -0
  50. package/dist/cjs/scheme-7ehldYoO.d.ts +307 -0
  51. package/dist/cjs/scheme-BjBJzHF7.d.ts +307 -0
  52. package/dist/cjs/scheme-DWgpkDgz.d.ts +47 -0
  53. package/dist/cjs/signer-BFelv8DL.d.ts +170 -0
  54. package/dist/cjs/storage-6W5MO46W.d.ts +50 -0
  55. package/dist/cjs/storage-CHNote8s.d.ts +81 -0
  56. package/dist/cjs/storage-DjCv5IPh.d.ts +81 -0
  57. package/dist/cjs/types-CKd3Xoi1.d.ts +180 -0
  58. package/dist/cjs/types-DIt9uAUy.d.ts +180 -0
  59. package/dist/cjs/upto/client/index.d.ts +34 -0
  60. package/dist/cjs/upto/client/index.js +509 -0
  61. package/dist/cjs/upto/client/index.js.map +1 -0
  62. package/dist/cjs/upto/facilitator/index.d.ts +54 -0
  63. package/dist/cjs/upto/facilitator/index.js +1313 -0
  64. package/dist/cjs/upto/facilitator/index.js.map +1 -0
  65. package/dist/cjs/upto/server/index.d.ts +69 -0
  66. package/dist/cjs/upto/server/index.js +296 -0
  67. package/dist/cjs/upto/server/index.js.map +1 -0
  68. package/dist/cjs/v1/index.d.ts +40 -0
  69. package/dist/cjs/v1/index.js +199 -0
  70. package/dist/cjs/v1/index.js.map +1 -0
  71. package/dist/esm/auth-capture/client/index.d.mts +44 -0
  72. package/dist/esm/auth-capture/client/index.mjs +8 -0
  73. package/dist/esm/auth-capture/client/index.mjs.map +1 -0
  74. package/dist/esm/batch-settlement/client/file-storage.d.mts +47 -0
  75. package/dist/esm/batch-settlement/client/file-storage.mjs +63 -0
  76. package/dist/esm/batch-settlement/client/file-storage.mjs.map +1 -0
  77. package/dist/esm/batch-settlement/client/index.d.mts +111 -0
  78. package/dist/esm/batch-settlement/client/index.mjs +58 -0
  79. package/dist/esm/batch-settlement/client/index.mjs.map +1 -0
  80. package/dist/esm/batch-settlement/facilitator/index.d.mts +72 -0
  81. package/dist/esm/batch-settlement/facilitator/index.mjs +1252 -0
  82. package/dist/esm/batch-settlement/facilitator/index.mjs.map +1 -0
  83. package/dist/esm/batch-settlement/server/file-storage.d.mts +53 -0
  84. package/dist/esm/batch-settlement/server/file-storage.mjs +128 -0
  85. package/dist/esm/batch-settlement/server/file-storage.mjs.map +1 -0
  86. package/dist/esm/batch-settlement/server/index.d.mts +491 -0
  87. package/dist/esm/batch-settlement/server/index.mjs +1640 -0
  88. package/dist/esm/batch-settlement/server/index.mjs.map +1 -0
  89. package/dist/esm/batch-settlement/server/redis-storage.d.mts +87 -0
  90. package/dist/esm/batch-settlement/server/redis-storage.mjs +156 -0
  91. package/dist/esm/batch-settlement/server/redis-storage.mjs.map +1 -0
  92. package/dist/esm/chunk-2EUQTNJO.mjs +38 -0
  93. package/dist/esm/chunk-2EUQTNJO.mjs.map +1 -0
  94. package/dist/esm/chunk-3WZF6722.mjs +36 -0
  95. package/dist/esm/chunk-3WZF6722.mjs.map +1 -0
  96. package/dist/esm/chunk-E4Z7PNXC.mjs +275 -0
  97. package/dist/esm/chunk-E4Z7PNXC.mjs.map +1 -0
  98. package/dist/esm/chunk-GQVMVP4N.mjs +911 -0
  99. package/dist/esm/chunk-GQVMVP4N.mjs.map +1 -0
  100. package/dist/esm/chunk-H2EYJIZL.mjs +489 -0
  101. package/dist/esm/chunk-H2EYJIZL.mjs.map +1 -0
  102. package/dist/esm/chunk-H3KPLYGI.mjs +152 -0
  103. package/dist/esm/chunk-H3KPLYGI.mjs.map +1 -0
  104. package/dist/esm/chunk-HYABYUBD.mjs +432 -0
  105. package/dist/esm/chunk-HYABYUBD.mjs.map +1 -0
  106. package/dist/esm/chunk-I2DVUHM5.mjs +123 -0
  107. package/dist/esm/chunk-I2DVUHM5.mjs.map +1 -0
  108. package/dist/esm/chunk-JK7SLLF7.mjs +34 -0
  109. package/dist/esm/chunk-JK7SLLF7.mjs.map +1 -0
  110. package/dist/esm/chunk-JNT7C46S.mjs +352 -0
  111. package/dist/esm/chunk-JNT7C46S.mjs.map +1 -0
  112. package/dist/esm/chunk-MACPBXCT.mjs +415 -0
  113. package/dist/esm/chunk-MACPBXCT.mjs.map +1 -0
  114. package/dist/esm/chunk-P3QOX3QZ.mjs +113 -0
  115. package/dist/esm/chunk-P3QOX3QZ.mjs.map +1 -0
  116. package/dist/esm/chunk-QVATVA3J.mjs +47 -0
  117. package/dist/esm/chunk-QVATVA3J.mjs.map +1 -0
  118. package/dist/esm/chunk-SHJFA25H.mjs +159 -0
  119. package/dist/esm/chunk-SHJFA25H.mjs.map +1 -0
  120. package/dist/esm/chunk-TW7Z65AO.mjs +34 -0
  121. package/dist/esm/chunk-TW7Z65AO.mjs.map +1 -0
  122. package/dist/esm/chunk-U4HCGTLU.mjs +35 -0
  123. package/dist/esm/chunk-U4HCGTLU.mjs.map +1 -0
  124. package/dist/esm/chunk-VS3RYAYE.mjs +80 -0
  125. package/dist/esm/chunk-VS3RYAYE.mjs.map +1 -0
  126. package/dist/esm/chunk-W6ON4LG2.mjs +39 -0
  127. package/dist/esm/chunk-W6ON4LG2.mjs.map +1 -0
  128. package/dist/esm/chunk-XG2JLZVJ.mjs +627 -0
  129. package/dist/esm/chunk-XG2JLZVJ.mjs.map +1 -0
  130. package/dist/esm/chunk-ZCJRY5LQ.mjs +162 -0
  131. package/dist/esm/chunk-ZCJRY5LQ.mjs.map +1 -0
  132. package/dist/esm/client/agent-wallet.d.mts +69 -0
  133. package/dist/esm/client/agent-wallet.mjs +36 -0
  134. package/dist/esm/client/agent-wallet.mjs.map +1 -0
  135. package/dist/esm/exact/client/index.d.mts +63 -0
  136. package/dist/esm/exact/client/index.mjs +25 -0
  137. package/dist/esm/exact/client/index.mjs.map +1 -0
  138. package/dist/esm/exact/facilitator/index.d.mts +141 -0
  139. package/dist/esm/exact/facilitator/index.mjs +694 -0
  140. package/dist/esm/exact/facilitator/index.mjs.map +1 -0
  141. package/dist/esm/exact/server/index.d.mts +118 -0
  142. package/dist/esm/exact/server/index.mjs +153 -0
  143. package/dist/esm/exact/server/index.mjs.map +1 -0
  144. package/dist/esm/exact/v1/client/index.d.mts +38 -0
  145. package/dist/esm/exact/v1/client/index.mjs +12 -0
  146. package/dist/esm/exact/v1/client/index.mjs.map +1 -0
  147. package/dist/esm/exact/v1/facilitator/index.d.mts +84 -0
  148. package/dist/esm/exact/v1/facilitator/index.mjs +12 -0
  149. package/dist/esm/exact/v1/facilitator/index.mjs.map +1 -0
  150. package/dist/esm/facilitator/agent-wallet.d.mts +109 -0
  151. package/dist/esm/facilitator/agent-wallet.mjs +74 -0
  152. package/dist/esm/facilitator/agent-wallet.mjs.map +1 -0
  153. package/dist/esm/index.d.mts +338 -0
  154. package/dist/esm/index.mjs +144 -0
  155. package/dist/esm/index.mjs.map +1 -0
  156. package/dist/esm/permit2-DhJRUcgY.d.mts +729 -0
  157. package/dist/esm/rpc-DULZzRne.d.mts +13 -0
  158. package/dist/esm/scheme-CkNhpXrG.d.mts +307 -0
  159. package/dist/esm/scheme-D8ZbykGV.d.mts +47 -0
  160. package/dist/esm/signer-BFelv8DL.d.mts +170 -0
  161. package/dist/esm/storage-6W5MO46W.d.mts +50 -0
  162. package/dist/esm/storage-BEzTEiUr.d.mts +81 -0
  163. package/dist/esm/types-DIt9uAUy.d.mts +180 -0
  164. package/dist/esm/upto/client/index.d.mts +34 -0
  165. package/dist/esm/upto/client/index.mjs +22 -0
  166. package/dist/esm/upto/client/index.mjs.map +1 -0
  167. package/dist/esm/upto/facilitator/index.d.mts +54 -0
  168. package/dist/esm/upto/facilitator/index.mjs +507 -0
  169. package/dist/esm/upto/facilitator/index.mjs.map +1 -0
  170. package/dist/esm/upto/server/index.d.mts +69 -0
  171. package/dist/esm/upto/server/index.mjs +124 -0
  172. package/dist/esm/upto/server/index.mjs.map +1 -0
  173. package/dist/esm/v1/index.d.mts +40 -0
  174. package/dist/esm/v1/index.mjs +18 -0
  175. package/dist/esm/v1/index.mjs.map +1 -0
  176. package/package.json +250 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/batch-settlement/client/voucher.ts","../../src/batch-settlement/client/eip3009.ts","../../src/batch-settlement/client/storage.ts","../../src/batch-settlement/client/config.ts","../../src/batch-settlement/client/channel.ts","../../src/batch-settlement/client/recovery.ts","../../src/batch-settlement/client/hooks.ts","../../src/batch-settlement/client/refund.ts","../../src/batch-settlement/client/scheme.ts","../../src/batch-settlement/client/permit2.ts"],"sourcesContent":["import { ClientEvmSigner } from \"../../signer\";\nimport { voucherTypes } from \"../constants\";\nimport { BatchSettlementVoucherFields } from \"../types\";\nimport { getEvmChainId } from \"../../utils\";\nimport { getBatchSettlementEip712Domain } from \"../utils\";\n\n/**\n * Signs a cumulative voucher using the client's wallet.\n *\n * The voucher authorises the receiver to claim up to `maxClaimableAmount` from the\n * channel identified by `channelId`. The signature covers the EIP-712 `Voucher` struct\n * under the batched domain.\n *\n * @param signer - Client wallet used to produce the EIP-712 signature.\n * @param channelId - Identifier of the payment channel. This is the EIP-712\n * hash of the `ChannelConfig` typed data for the batch settlement domain; see\n * `computeChannelId`.\n * @param maxClaimableAmount - Cumulative ceiling the receiver may claim (decimal string in token units).\n * @param network - CAIP-2 network identifier (e.g. `eip155:84532`).\n * @returns Signed voucher fields ready to be included in a payment payload.\n */\nexport async function signVoucher(\n signer: ClientEvmSigner,\n channelId: `0x${string}`,\n maxClaimableAmount: string,\n network: string,\n): Promise<BatchSettlementVoucherFields> {\n const chainId = getEvmChainId(network);\n\n const signature = await signer.signTypedData({\n domain: getBatchSettlementEip712Domain(chainId),\n types: voucherTypes,\n primaryType: \"Voucher\",\n message: {\n channelId,\n maxClaimableAmount: BigInt(maxClaimableAmount),\n },\n });\n\n return {\n channelId,\n maxClaimableAmount,\n signature,\n };\n}\n","import { PaymentRequirements, PaymentPayloadResult } from \"@bankofai/x402-core/types\";\nimport { getAddress } from \"viem\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { ChannelConfig, BatchSettlementDepositPayload } from \"../types\";\nimport { ERC3009_DEPOSIT_COLLECTOR_ADDRESS, receiveAuthorizationTypes } from \"../constants\";\nimport { createNonce, getEvmChainId } from \"../../utils\";\nimport { signVoucher } from \"./voucher\";\nimport { computeChannelId } from \"../utils\";\nimport { buildErc3009DepositNonce } from \"../encoding\";\n\n/**\n * Creates a deposit payload that bundles an ERC-3009 `receiveWithAuthorization` approval\n * together with a cumulative voucher signature.\n *\n * When the facilitator submits this payload onchain, the contract atomically transfers\n * tokens from the payer into the channel and records the initial voucher.\n *\n * @param signer - Client wallet used to sign the ERC-3009 authorization (`from` = payer).\n * @param x402Version - Protocol version to embed in the payload envelope.\n * @param paymentRequirements - Server-provided payment requirements (asset, network, amount, etc.).\n * @param channelConfig - Immutable channel configuration (payer, receiver, token, …).\n * @param depositAmount - Number of tokens (decimal string) to deposit into the channel.\n * @param maxClaimableAmount - Cumulative ceiling for the accompanying voucher.\n * @param voucherSigner - Optional key that signs the voucher; defaults to `signer` (same as payer).\n * @returns A {@link PaymentPayloadResult} containing the signed deposit + voucher payload.\n */\nexport async function createBatchSettlementEIP3009DepositPayload(\n signer: ClientEvmSigner,\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n channelConfig: ChannelConfig,\n depositAmount: string,\n maxClaimableAmount: string,\n voucherSigner?: ClientEvmSigner,\n): Promise<PaymentPayloadResult> {\n const salt = createNonce();\n const now = Math.floor(Date.now() / 1000);\n const chainId = getEvmChainId(paymentRequirements.network);\n\n if (!paymentRequirements.extra?.name || !paymentRequirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${paymentRequirements.asset}`,\n );\n }\n\n const { name, version } = paymentRequirements.extra;\n\n const channelId = computeChannelId(channelConfig, paymentRequirements.network);\n\n const erc3009Nonce = buildErc3009DepositNonce(channelId, salt);\n\n const signature = await signer.signTypedData({\n domain: {\n name,\n version,\n chainId,\n verifyingContract: getAddress(paymentRequirements.asset),\n },\n types: receiveAuthorizationTypes,\n primaryType: \"ReceiveWithAuthorization\",\n message: {\n from: getAddress(signer.address),\n to: getAddress(ERC3009_DEPOSIT_COLLECTOR_ADDRESS),\n value: BigInt(depositAmount),\n validAfter: BigInt(0),\n validBefore: BigInt(now + paymentRequirements.maxTimeoutSeconds),\n nonce: erc3009Nonce,\n },\n });\n\n const vSigner = voucherSigner ?? signer;\n const voucher = await signVoucher(\n vSigner,\n channelId,\n maxClaimableAmount,\n paymentRequirements.network,\n );\n\n const payload: BatchSettlementDepositPayload = {\n type: \"deposit\",\n channelConfig,\n voucher,\n deposit: {\n amount: depositAmount,\n authorization: {\n erc3009Authorization: {\n validAfter: \"0\",\n validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),\n salt,\n signature,\n },\n },\n },\n };\n\n return {\n x402Version,\n payload,\n };\n}\n","/**\n * Client-side channel fields mirrored from PAYMENT-RESPONSE / recovery flows.\n */\nexport interface BatchSettlementClientContext {\n /** Current cumulative amount charged by the server for this channel */\n chargedCumulativeAmount?: string;\n /** Current onchain channel balance */\n balance?: string;\n /** Total claimed onchain */\n totalClaimed?: string;\n /** Latest client-signed maxClaimableAmount cap (after corrective recovery, optional) */\n signedMaxClaimable?: string;\n /** Client voucher signature for {@link signedMaxClaimable} (optional) */\n signature?: `0x${string}`;\n}\n\nexport interface ClientChannelStorage {\n get(key: string): Promise<BatchSettlementClientContext | undefined>;\n set(key: string, context: BatchSettlementClientContext): Promise<void>;\n delete(key: string): Promise<void>;\n}\n\n/**\n * Default in-memory {@link ClientChannelStorage} (channel records do not survive process restart).\n */\nexport class InMemoryClientChannelStorage implements ClientChannelStorage {\n private readonly channels = new Map<string, BatchSettlementClientContext>();\n\n /**\n * Returns the channel record for `key` if present.\n *\n * @param key - Channel storage key (channelId).\n * @returns Persisted context or undefined.\n */\n async get(key: string): Promise<BatchSettlementClientContext | undefined> {\n return this.channels.get(key);\n }\n\n /**\n * Stores or replaces the channel record for `key`.\n *\n * @param key - Channel storage key.\n * @param context - Channel fields to persist.\n * @returns Resolves when stored.\n */\n async set(key: string, context: BatchSettlementClientContext): Promise<void> {\n this.channels.set(key, context);\n }\n\n /**\n * Removes the channel record for `key` if it exists.\n *\n * @param key - Channel storage key.\n * @returns Resolves when removed.\n */\n async delete(key: string): Promise<void> {\n this.channels.delete(key);\n }\n}\n","import type { PaymentRequirements } from \"@bankofai/x402-core/types\";\nimport type { ClientEvmSigner } from \"../../signer\";\nimport type { EvmSchemeOptions } from \"../../shared/rpc\";\nimport type { ChannelConfig } from \"../types\";\nimport { type ClientChannelStorage, InMemoryClientChannelStorage } from \"./storage\";\nimport type { BatchSettlementClientContext } from \"./storage\";\n\nconst DEFAULT_SALT =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\" as `0x${string}`;\n\n/**\n * Caller-tunable policy controlling how the client sizes channel deposits.\n */\nexport interface BatchSettlementDepositPolicy {\n depositMultiplier?: number;\n}\n\n/**\n * Return shape for custom deposit sizing.\n */\nexport type BatchSettlementDepositStrategyResult = string | bigint | false | undefined;\n\n/**\n * Information supplied before the client signs a deposit authorization.\n */\nexport interface BatchSettlementDepositStrategyContext {\n paymentRequirements: PaymentRequirements;\n channelConfig: ChannelConfig;\n channelId: `0x${string}`;\n clientContext: BatchSettlementClientContext;\n requestAmount: string;\n maxClaimableAmount: string;\n currentBalance: string;\n minimumDepositAmount: string;\n depositAmount: string;\n}\n\n/**\n * Custom deposit sizing callback for initial deposits and top-ups.\n */\nexport type BatchSettlementDepositStrategy = (\n context: BatchSettlementDepositStrategyContext,\n) => BatchSettlementDepositStrategyResult | Promise<BatchSettlementDepositStrategyResult>;\n\n/**\n * Full options object accepted by `BatchSettlementEvmScheme`. Either this or a\n * bare {@link BatchSettlementDepositPolicy} can be passed as the second\n * constructor argument.\n */\nexport interface BatchSettlementEvmSchemeOptions {\n depositPolicy?: BatchSettlementDepositPolicy;\n /** Optional callback for app-specific deposit sizing or skipping. */\n depositStrategy?: BatchSettlementDepositStrategy;\n storage?: ClientChannelStorage;\n salt?: `0x${string}`;\n payerAuthorizer?: `0x${string}`;\n rpcUrl?: string;\n /** When set, EIP-712 vouchers are signed with this key; deposits still use the main `signer`. */\n voucherSigner?: ClientEvmSigner;\n}\n\n/**\n * Resolved options after merging defaults — used internally by the scheme,\n * recovery, and refund modules.\n */\nexport interface ResolvedClientOptions {\n depositPolicy?: BatchSettlementDepositPolicy;\n depositStrategy?: BatchSettlementDepositStrategy;\n storage: ClientChannelStorage;\n salt: `0x${string}`;\n payerAuthorizer?: `0x${string}`;\n voucherSigner?: ClientEvmSigner;\n extensionRpcOptions?: EvmSchemeOptions;\n}\n\n/**\n * Discriminates a full options object from a bare deposit-policy object.\n *\n * @param o - Constructor argument that may be options, deposit policy only, or undefined.\n * @returns `true` when `o` is a {@link BatchSettlementEvmSchemeOptions} object.\n */\nexport function isBatchSettlementEvmSchemeOptions(\n o: BatchSettlementEvmSchemeOptions | BatchSettlementDepositPolicy | undefined,\n): o is BatchSettlementEvmSchemeOptions {\n return (\n o !== undefined &&\n typeof o === \"object\" &&\n (\"storage\" in o ||\n \"depositPolicy\" in o ||\n \"depositStrategy\" in o ||\n \"salt\" in o ||\n \"payerAuthorizer\" in o ||\n \"rpcUrl\" in o ||\n \"voucherSigner\" in o)\n );\n}\n\n/**\n * Normalises the constructor's second argument into a uniform options shape.\n *\n * @param second - Optional second constructor argument (options or deposit policy).\n * @returns Resolved storage, salt, deposit policy, and optional payer authorizer.\n */\nexport function resolveClientOptions(\n second?: BatchSettlementEvmSchemeOptions | BatchSettlementDepositPolicy,\n): ResolvedClientOptions {\n if (second === undefined) {\n return { storage: new InMemoryClientChannelStorage(), salt: DEFAULT_SALT };\n }\n if (isBatchSettlementEvmSchemeOptions(second)) {\n return {\n storage: second.storage ?? new InMemoryClientChannelStorage(),\n depositPolicy: second.depositPolicy,\n depositStrategy: second.depositStrategy,\n salt: second.salt ?? DEFAULT_SALT,\n payerAuthorizer: second.payerAuthorizer,\n voucherSigner: second.voucherSigner,\n extensionRpcOptions: second.rpcUrl ? { rpcUrl: second.rpcUrl } : undefined,\n };\n }\n return {\n storage: new InMemoryClientChannelStorage(),\n depositPolicy: second,\n salt: DEFAULT_SALT,\n };\n}\n\n/**\n * Validates a {@link BatchSettlementDepositPolicy}, throwing on invalid fields.\n *\n * @param policy - The policy to validate (no-op when undefined).\n */\nexport function validateDepositPolicy(policy: BatchSettlementDepositPolicy | undefined): void {\n if (!policy) return;\n\n const m = policy.depositMultiplier;\n if (m !== undefined && (!Number.isInteger(m) || m < 3)) {\n throw new Error(\"depositMultiplier must be an integer >= 3\");\n }\n}\n\n/**\n * Computes the deposit amount based on the deposit multiplier.\n *\n * @param policy - Deposit policy controlling multiplier (may be undefined).\n * @param requestAmount - Amount requested for this operation, in token base units.\n * @returns Deposit amount string in token base units.\n */\nexport function depositAmountForRequest(\n policy: BatchSettlementDepositPolicy | undefined,\n requestAmount: bigint,\n): string {\n const mult = BigInt(policy?.depositMultiplier ?? 5);\n return (mult * requestAmount).toString();\n}\n","import { decodePaymentResponseHeader } from \"@bankofai/x402-core/http\";\nimport type { PaymentRequirements, SettleResponse } from \"@bankofai/x402-core/types\";\nimport { getAddress } from \"viem\";\nimport type { ClientEvmSigner } from \"../../signer\";\nimport { batchSettlementABI } from \"../abi\";\nimport { BATCH_SETTLEMENT_ADDRESS, MIN_WITHDRAW_DELAY } from \"../constants\";\nimport type {\n BatchSettlementPaymentRequirementsExtra,\n BatchSettlementPaymentResponseExtra,\n ChannelConfig,\n} from \"../types\";\nimport { computeChannelId } from \"../utils\";\nimport type { BatchSettlementClientContext, ClientChannelStorage } from \"./storage\";\n\ntype ResponseChannelState = NonNullable<BatchSettlementPaymentResponseExtra[\"channelState\"]>;\n\n/**\n * Reads the nested channel state from a settlement response extra object.\n *\n * @param extra - Settlement response extra fields.\n * @returns Channel state fields, or undefined when absent.\n */\nfunction readResponseChannelState(\n extra: Record<string, unknown>,\n): ResponseChannelState | undefined {\n const channelState = extra.channelState;\n if (typeof channelState !== \"object\" || channelState === null) {\n return undefined;\n }\n return channelState as ResponseChannelState;\n}\n\n/**\n * Runtime dependency bag shared by every storage-bound client helper (channel,\n * recovery, refund) and the {@link BatchSettlementEvmScheme} class.\n */\nexport interface BatchSettlementClientDeps {\n signer: ClientEvmSigner;\n storage: ClientChannelStorage;\n salt: `0x${string}`;\n payerAuthorizer?: `0x${string}`;\n voucherSigner?: ClientEvmSigner;\n}\n\n/**\n * Constructs the immutable {@link ChannelConfig} from payment requirements and\n * a client deps bag (signer, salt, optional payerAuthorizer / voucherSigner).\n *\n * @param deps - Client identity inputs.\n * @param paymentRequirements - Server payment requirements providing receiver, asset, and extra fields.\n * @returns The ChannelConfig that uniquely identifies this payment channel.\n */\nexport function buildChannelConfig(\n deps: BatchSettlementClientDeps,\n paymentRequirements: PaymentRequirements,\n): ChannelConfig {\n const extra = paymentRequirements.extra as\n | Partial<BatchSettlementPaymentRequirementsExtra>\n | undefined;\n const receiverAuthorizer = extra?.receiverAuthorizer;\n if (\n !receiverAuthorizer ||\n getAddress(receiverAuthorizer) === \"0x0000000000000000000000000000000000000000\"\n ) {\n throw new Error(\"Payment requirements must include a non-zero extra.receiverAuthorizer\");\n }\n\n return {\n payer: deps.signer.address,\n payerAuthorizer: getAddress(\n deps.payerAuthorizer ?? deps.voucherSigner?.address ?? deps.signer.address,\n ),\n receiver: paymentRequirements.payTo as `0x${string}`,\n receiverAuthorizer: getAddress(receiverAuthorizer),\n token: paymentRequirements.asset as `0x${string}`,\n withdrawDelay:\n typeof extra?.withdrawDelay === \"number\" ? extra.withdrawDelay : MIN_WITHDRAW_DELAY,\n salt: deps.salt,\n };\n}\n\n/**\n * Updates local channel state from a parsed `SettleResponse`.\n *\n * @param storage - Client channel storage.\n * @param settle - The parsed settle response.\n */\nexport async function processSettleResponse(\n storage: ClientChannelStorage,\n settle: SettleResponse,\n): Promise<void> {\n const extra = settle.extra ?? {};\n const channelState = readResponseChannelState(extra);\n if (!channelState) return;\n\n const channelId = channelState.channelId;\n const key = channelId.toLowerCase();\n\n const prev = await storage.get(key);\n const next: BatchSettlementClientContext = { ...(prev ?? {}) };\n\n if (channelState.chargedCumulativeAmount !== undefined) {\n next.chargedCumulativeAmount = String(channelState.chargedCumulativeAmount);\n }\n if (channelState.balance !== undefined) {\n next.balance = String(channelState.balance);\n }\n if (channelState.totalClaimed !== undefined) {\n next.totalClaimed = String(channelState.totalClaimed);\n }\n\n await storage.set(key, next);\n}\n\n/**\n * Reconciles local channel state with the outcome of a cooperative refund.\n *\n * Deletes the channel record when the post-refund balance is zero (full refund),\n * otherwise updates local state from the server snapshot.\n *\n * @param storage - Client channel storage.\n * @param channelKey - Lowercased channel id used as the storage key.\n * @param settleExtra - The `extra` block from the refund settle response.\n */\nexport async function updateChannelAfterRefund(\n storage: ClientChannelStorage,\n channelKey: string,\n settleExtra: Record<string, unknown>,\n): Promise<void> {\n const channelState = readResponseChannelState(settleExtra);\n if (!channelState) {\n await storage.delete(channelKey);\n return;\n }\n\n const balanceAfter =\n channelState.balance !== undefined ? BigInt(String(channelState.balance)) : undefined;\n\n if (balanceAfter === undefined || balanceAfter <= 0n) {\n await storage.delete(channelKey);\n return;\n }\n\n const prev = await storage.get(channelKey);\n const next: BatchSettlementClientContext = { ...(prev ?? {}) };\n next.balance = balanceAfter.toString();\n if (channelState.chargedCumulativeAmount !== undefined) {\n next.chargedCumulativeAmount = String(channelState.chargedCumulativeAmount);\n }\n if (channelState.totalClaimed !== undefined) {\n next.totalClaimed = String(channelState.totalClaimed);\n }\n await storage.set(channelKey, next);\n}\n\n/**\n * Processes the `PAYMENT-RESPONSE` header after a successful request.\n *\n * Decodes the header into a `SettleResponse` and delegates to\n * {@link processSettleResponse}.\n *\n * @param storage - Client channel storage.\n * @param getHeader - Function to retrieve a response header by name.\n */\nexport async function processPaymentResponse(\n storage: ClientChannelStorage,\n getHeader: (name: string) => string | null | undefined,\n): Promise<void> {\n const raw = getHeader(\"PAYMENT-RESPONSE\");\n if (!raw) return;\n\n const settle = decodePaymentResponseHeader(raw);\n await processSettleResponse(storage, settle);\n}\n\n/**\n * Recovers a channel record from onchain state (useful after a cold start or\n * channel record loss).\n *\n * @param deps - Signer + storage + identity inputs.\n * @param paymentRequirements - Server payment requirements used to derive the ChannelConfig.\n * @returns The recovered client context.\n */\nexport async function recoverChannel(\n deps: BatchSettlementClientDeps,\n paymentRequirements: PaymentRequirements,\n): Promise<BatchSettlementClientContext> {\n if (!deps.signer.readContract) {\n throw new Error(\"recoverChannel requires ClientEvmSigner.readContract\");\n }\n\n const config = buildChannelConfig(deps, paymentRequirements);\n const channelId = computeChannelId(config, paymentRequirements.network);\n\n const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed(\n deps.signer,\n channelId,\n );\n\n const ctx: BatchSettlementClientContext = {\n chargedCumulativeAmount: chTotalClaimed.toString(),\n balance: chBalance.toString(),\n totalClaimed: chTotalClaimed.toString(),\n };\n\n await deps.storage.set(channelId.toLowerCase(), ctx);\n return ctx;\n}\n\n/**\n * Reads `channels(channelId)` returning `[balance, totalClaimed]`.\n *\n * @param signer - Signer providing `readContract`.\n * @param channelId - The `bytes32` channel id to query.\n * @returns Tuple of `[balance, totalClaimed]` as bigints.\n */\nexport async function readChannelBalanceAndTotalClaimed(\n signer: ClientEvmSigner,\n channelId: `0x${string}`,\n): Promise<[bigint, bigint]> {\n if (!signer.readContract) {\n throw new Error(\"readChannelBalanceAndTotalClaimed requires ClientEvmSigner.readContract\");\n }\n return (await signer.readContract({\n address: BATCH_SETTLEMENT_ADDRESS,\n abi: batchSettlementABI,\n functionName: \"channels\",\n args: [channelId],\n })) as [bigint, bigint];\n}\n\n/**\n * Returns whether a local channel record exists for the given channel.\n *\n * @param storage - Client channel storage.\n * @param channelId - The channel identifier to check.\n * @returns `true` when a channel record is stored.\n */\nexport async function hasChannel(\n storage: ClientChannelStorage,\n channelId: string,\n): Promise<boolean> {\n const channel = await storage.get(channelId.toLowerCase());\n return channel !== undefined;\n}\n\n/**\n * Returns the local channel context for a channel, if present.\n *\n * @param storage - Client channel storage.\n * @param channelId - The channel identifier.\n * @returns Stored context or `undefined`.\n */\nexport async function getChannel(\n storage: ClientChannelStorage,\n channelId: string,\n): Promise<BatchSettlementClientContext | undefined> {\n return storage.get(channelId.toLowerCase());\n}\n","import type { PaymentRequired, PaymentRequirements } from \"@bankofai/x402-core/types\";\nimport { getAddress, recoverTypedDataAddress } from \"viem\";\nimport { BATCH_SETTLEMENT_SCHEME, voucherTypes } from \"../constants\";\nimport type { BatchSettlementClientContext } from \"./storage\";\nimport { computeChannelId, getBatchSettlementEip712Domain } from \"../utils\";\nimport { getEvmChainId } from \"../../utils\";\nimport {\n type BatchSettlementClientDeps,\n buildChannelConfig,\n readChannelBalanceAndTotalClaimed,\n} from \"./channel\";\nimport * as Errors from \"../errors\";\nimport type { BatchSettlementChannelStateExtra, BatchSettlementVoucherStateExtra } from \"../types\";\n\n/**\n * Handles a corrective 402 response from the server when the client's\n * cumulative base is out of sync.\n *\n * Validates the server-provided state (chargedCumulativeAmount,\n * signedMaxClaimable, signature) against onchain data and the client's own\n * signing key, then updates the local channel state if everything checks out.\n *\n * @param deps - Signer + storage + identity inputs.\n * @param paymentRequired - The decoded 402 response body.\n * @returns `true` if the channel state was successfully resynced and the request can be retried.\n */\nexport async function processCorrectivePaymentRequired(\n deps: BatchSettlementClientDeps,\n paymentRequired: PaymentRequired,\n): Promise<boolean> {\n if (\n paymentRequired.error !== Errors.ErrCumulativeAmountMismatch &&\n paymentRequired.error !== Errors.ErrCumulativeAmountBelowClaimed\n ) {\n return false;\n }\n\n const accept = paymentRequired.accepts.find(a => a.scheme === BATCH_SETTLEMENT_SCHEME);\n if (!accept) {\n return false;\n }\n\n const channelState = accept.extra.channelState as BatchSettlementChannelStateExtra | undefined;\n const voucherState = accept.extra.voucherState as BatchSettlementVoucherStateExtra | undefined;\n const hasSig =\n channelState?.chargedCumulativeAmount !== undefined &&\n voucherState?.signedMaxClaimable !== undefined &&\n voucherState.signature !== undefined;\n\n if (!hasSig) {\n return recoverFromOnChainState(deps, accept);\n }\n\n return recoverFromSignature(deps, accept, channelState, voucherState);\n}\n\n/**\n * Recovers channel state from a corrective 402 that includes a server-provided\n * voucher signature. Verifies the signature matches the client's own signing\n * key before accepting.\n *\n * @param deps - Signer + storage + identity inputs.\n * @param accept - Batch settlement payment requirements from the corrective 402.\n * @param channelState - Server channel snapshot from `accept.extra.channelState`.\n * @param voucherState - Latest signed voucher proof from `accept.extra.voucherState`.\n * @returns `true` when local channel state was updated successfully.\n */\nexport async function recoverFromSignature(\n deps: BatchSettlementClientDeps,\n accept: PaymentRequirements,\n channelState: BatchSettlementChannelStateExtra,\n voucherState: BatchSettlementVoucherStateExtra,\n): Promise<boolean> {\n const chargedRaw = channelState.chargedCumulativeAmount;\n const signedRaw = voucherState.signedMaxClaimable;\n const sig = voucherState.signature as `0x${string}`;\n\n const charged = BigInt(String(chargedRaw));\n const signed = BigInt(String(signedRaw));\n\n if (charged > signed) {\n return false;\n }\n\n const config = buildChannelConfig(deps, accept);\n const channelId = computeChannelId(config, accept.network);\n\n if (!deps.signer.readContract) {\n return false;\n }\n\n const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed(\n deps.signer,\n channelId,\n );\n\n if (charged < chTotalClaimed) {\n return false;\n }\n\n const chainId = getEvmChainId(accept.network);\n const recovered = await recoverTypedDataAddress({\n domain: getBatchSettlementEip712Domain(chainId),\n types: voucherTypes,\n primaryType: \"Voucher\",\n message: {\n channelId,\n maxClaimableAmount: signed,\n },\n signature: sig,\n });\n\n const expectedSigner = getAddress(\n deps.payerAuthorizer ?? deps.voucherSigner?.address ?? deps.signer.address,\n );\n if (recovered.toLowerCase() !== expectedSigner.toLowerCase()) {\n return false;\n }\n\n const ctx: BatchSettlementClientContext = {\n chargedCumulativeAmount: charged.toString(),\n signedMaxClaimable: signed.toString(),\n signature: sig,\n balance: chBalance.toString(),\n totalClaimed: chTotalClaimed.toString(),\n };\n\n await deps.storage.set(channelId.toLowerCase(), ctx);\n return true;\n}\n\n/**\n * Recovers channel state purely from onchain state when the server has no stored\n * voucher (e.g. after a cooperative refund deleted the channel record). The onchain\n * `totalClaimed` becomes the new baseline — no signature verification is\n * needed because the contract is the source of truth when no outstanding\n * voucher exists.\n *\n * @param deps - Signer + storage + identity inputs.\n * @param accept - Batch settlement payment requirements from the corrective 402.\n * @returns `true` when local channel state was updated from onchain data.\n */\nexport async function recoverFromOnChainState(\n deps: BatchSettlementClientDeps,\n accept: PaymentRequirements,\n): Promise<boolean> {\n if (!deps.signer.readContract) {\n return false;\n }\n\n const config = buildChannelConfig(deps, accept);\n const channelId = computeChannelId(config, accept.network);\n\n const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed(\n deps.signer,\n channelId,\n );\n\n const ctx: BatchSettlementClientContext = {\n chargedCumulativeAmount: chTotalClaimed.toString(),\n balance: chBalance.toString(),\n totalClaimed: chTotalClaimed.toString(),\n };\n\n await deps.storage.set(channelId.toLowerCase(), ctx);\n return true;\n}\n","import type { PaymentResponseContext } from \"@bankofai/x402-core/client\";\nimport type { SchemeClientHooks } from \"@bankofai/x402-core/types\";\nimport { isBatchSettlementRefundPayload } from \"../types\";\nimport type { BatchSettlementClientDeps } from \"./channel\";\nimport { processSettleResponse, updateChannelAfterRefund } from \"./channel\";\nimport { processCorrectivePaymentRequired } from \"./recovery\";\n\n/**\n * Creates storage-aware client hooks for batch-settlement payment responses.\n *\n * @param deps - Client identity and storage inputs.\n * @returns Scheme hooks for response reconciliation and corrective recovery.\n */\nexport function createBatchSettlementClientHooks(\n deps: BatchSettlementClientDeps,\n): SchemeClientHooks {\n return {\n onPaymentResponse: ctx => handleBatchSettlementPaymentResponse(deps, ctx),\n };\n}\n\n/**\n * Reconciles batch-settlement client state after a paid request or refund attempt.\n *\n * @param deps - Client identity and storage inputs.\n * @param ctx - Core payment response context.\n * @returns A recovery signal when corrective recovery succeeds.\n */\nexport async function handleBatchSettlementPaymentResponse(\n deps: BatchSettlementClientDeps,\n ctx: PaymentResponseContext,\n): Promise<void | { recovered: true }> {\n if (ctx.settleResponse) {\n if (isBatchSettlementRefundPayload(ctx.paymentPayload.payload)) {\n const extra = ctx.settleResponse.extra ?? {};\n const channelState = extra.channelState;\n const channelId =\n typeof channelState === \"object\" && channelState !== null && \"channelId\" in channelState\n ? channelState.channelId\n : undefined;\n if (typeof channelId === \"string\" && channelId) {\n await updateChannelAfterRefund(deps.storage, channelId.toLowerCase(), extra);\n }\n return;\n }\n\n await processSettleResponse(deps.storage, ctx.settleResponse);\n return;\n }\n\n if (ctx.paymentRequired) {\n const recovered = await processCorrectivePaymentRequired(deps, ctx.paymentRequired);\n return recovered ? { recovered: true } : undefined;\n }\n}\n","import { decodePaymentRequiredHeader, decodePaymentResponseHeader } from \"@bankofai/x402-core/http\";\nimport { x402Client, x402HTTPClient } from \"@bankofai/x402-core/client\";\nimport type {\n PaymentPayload,\n PaymentRequired,\n PaymentRequirements,\n SettleResponse,\n} from \"@bankofai/x402-core/types\";\nimport { BATCH_SETTLEMENT_SCHEME } from \"../constants\";\nimport * as Errors from \"../errors\";\nimport type {\n BatchSettlementPaymentRequirementsExtra,\n BatchSettlementRefundPayload,\n} from \"../types\";\nimport { computeChannelId } from \"../utils\";\nimport { type BatchSettlementClientDeps, buildChannelConfig, recoverChannel } from \"./channel\";\nimport { createBatchSettlementClientHooks } from \"./hooks\";\nimport { signVoucher } from \"./voucher\";\n\n/**\n * Refund-specific server errors that the client cannot recover from automatically.\n * Seeing any of these means the user should adjust their request (or accept that the\n * channel has nothing left to refund) — retrying will not help.\n */\nconst NON_RECOVERABLE_REFUND_ERRORS: ReadonlySet<string> = new Set([\n Errors.ErrRefundNoBalance,\n Errors.ErrRefundAmountInvalid,\n]);\n\ninterface RefundRequirementsProbe {\n paymentRequired: PaymentRequired;\n requirements: PaymentRequirements;\n}\n\n/**\n * Caller-facing options for {@link refundChannel}.\n */\nexport interface RefundOptions {\n /** Token base units to refund; omit for a full refund (drains remaining balance). */\n amount?: string;\n /** Custom fetch implementation (defaults to `globalThis.fetch`). */\n fetch?: typeof fetch;\n}\n\n/**\n * Sends a cooperative refund request to the channel that backs `url`.\n *\n * Flow:\n * 1. Probe the URL with `GET` (no payment) to obtain the route's payment requirements.\n * 2. Build the `ChannelConfig` and resolve the local session (or recover it).\n * 3. Sign a zero-charge refund voucher (`maxClaimableAmount = chargedCumulativeAmount`).\n * 4. Send the voucher via `PAYMENT-SIGNATURE`. On a corrective 402, run the\n * standard recovery path and retry once.\n * 5. Return the parsed `SettleResponse` from the server.\n *\n * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer).\n * @param url - Any protected route on the channel to refund (the resource handler is bypassed).\n * @param options - Optional `amount` (partial refund) and `fetch` override.\n * @returns The settle response describing the refund outcome.\n * @throws When the probe fails, the receiver lacks an authorizer, or recovery fails.\n */\nexport async function refundChannel(\n ctx: BatchSettlementClientDeps,\n url: string,\n options?: RefundOptions,\n): Promise<SettleResponse> {\n const fetchImpl = options?.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new Error(\"refund requires a fetch implementation (globalThis.fetch unavailable)\");\n }\n\n const refundAmount = normalizeRefundAmount(options?.amount);\n const probe = await probeRefundRequirements(url, fetchImpl);\n return executeRefund(ctx, url, probe, refundAmount, fetchImpl);\n}\n\n/**\n * Probes a URL with an unauthenticated GET to retrieve batch-settlement payment\n * requirements via the 402 PAYMENT-REQUIRED header.\n *\n * @param url - The protected URL to probe.\n * @param fetchImpl - Fetch implementation used for the probe.\n * @returns Matching batch-settlement payment requirements for the route.\n */\nasync function probeRefundRequirements(\n url: string,\n fetchImpl: typeof fetch,\n): Promise<RefundRequirementsProbe> {\n const probe = await fetchImpl(url, { method: \"GET\" });\n if (probe.status !== 402) {\n throw new Error(`Refund probe expected 402, got ${probe.status}`);\n }\n\n const header = probe.headers.get(\"PAYMENT-REQUIRED\");\n if (!header) {\n throw new Error(\"Refund probe response missing PAYMENT-REQUIRED header\");\n }\n\n const paymentRequired = decodePaymentRequiredHeader(header);\n const requirements = paymentRequired.accepts.find(a => a.scheme === BATCH_SETTLEMENT_SCHEME);\n if (!requirements) {\n throw new Error(`No ${BATCH_SETTLEMENT_SCHEME} payment option at ${url}`);\n }\n\n const extra = requirements.extra as Partial<BatchSettlementPaymentRequirementsExtra> | undefined;\n if (!extra?.receiverAuthorizer) {\n throw new Error(\"Refund requires a configured receiverAuthorizer on the receiver\");\n }\n\n return { paymentRequired, requirements };\n}\n\n/**\n * Builds and submits the refund voucher, retrying once after a corrective 402.\n *\n * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer).\n * @param url - The protected URL to send the refund voucher to.\n * @param probe - Resolved payment requirements and probe metadata for this channel.\n * @param refundAmount - Optional partial refund amount in token base units.\n * @param fetchImpl - Fetch implementation used for the request.\n * @returns The parsed settle response.\n */\nasync function executeRefund(\n ctx: BatchSettlementClientDeps,\n url: string,\n probe: RefundRequirementsProbe,\n refundAmount: string | undefined,\n fetchImpl: typeof fetch,\n): Promise<SettleResponse> {\n const maxAttempts = 2;\n const { paymentRequired, requirements } = probe;\n const httpClient = createRefundHttpClient(ctx, requirements);\n\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n const paymentPayload = await buildRefundPaymentPayload(\n ctx,\n paymentRequired,\n requirements,\n refundAmount,\n );\n const headers = httpClient.encodePaymentSignatureHeader(paymentPayload);\n\n const response = await fetchImpl(url, { method: \"GET\", headers });\n\n if (response.status === 402) {\n const nonRecoverable = getNonRecoverableRefundFailure(response);\n if (nonRecoverable) {\n throw new Error(nonRecoverable);\n }\n }\n\n const result = await httpClient.processPaymentResult(\n paymentPayload,\n name => response.headers.get(name),\n response.status,\n );\n\n if (response.status === 402) {\n if (result.recovered && attempt < maxAttempts) {\n continue;\n }\n if (result.recovered) {\n throw new Error(`Refund failed: server returned 402 after ${attempt} attempt(s)`);\n }\n\n const corrective = getRefundPaymentRequired(response);\n throw new Error(`Refund failed: ${corrective.error ?? \"unknown\"}`);\n }\n\n if (!result.settleResponse) {\n throw new Error(\n `Refund response missing PAYMENT-RESPONSE header (status ${response.status})`,\n );\n }\n\n return result.settleResponse;\n }\n\n throw new Error(\"Refund failed: retry budget exhausted\");\n}\n\n/**\n * Builds the refund payload with a zero-charge `maxClaimableAmount`.\n *\n * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer).\n * @param paymentRequired - Decoded 402 body from the probe (resource, extensions, etc.).\n * @param requirements - Resolved payment requirements for the channel.\n * @param refundAmount - Optional partial refund amount in token base units.\n * @returns A full payment payload wrapping the signed refund request.\n */\nasync function buildRefundPaymentPayload(\n ctx: BatchSettlementClientDeps,\n paymentRequired: PaymentRequired,\n requirements: PaymentRequirements,\n refundAmount: string | undefined,\n): Promise<PaymentPayload> {\n const config = buildChannelConfig(ctx, requirements);\n const channelId = computeChannelId(config, requirements.network);\n const key = channelId.toLowerCase();\n\n let channel = await ctx.storage.get(key);\n if (channel === undefined && ctx.signer.readContract) {\n channel = await recoverChannel(ctx, requirements);\n }\n if (channel === undefined) {\n throw new Error(\n \"Refund requires an existing channel record; deposit first or call from a context with an EVM RPC\",\n );\n }\n\n // Avoid a refund request when local state shows the channel has no refundable balance.\n const charged = channel.chargedCumulativeAmount ?? \"0\";\n if (channel.balance !== undefined && BigInt(channel.balance) <= BigInt(charged)) {\n throw new Error(\n `Refund failed: channel has no remaining balance (balance=${channel.balance}, chargedCumulativeAmount=${charged})`,\n );\n }\n\n const voucherSigner = ctx.voucherSigner ?? ctx.signer;\n const voucher = await signVoucher(voucherSigner, channelId, charged, requirements.network);\n\n const payload: BatchSettlementRefundPayload = {\n type: \"refund\",\n channelConfig: config,\n voucher,\n ...(refundAmount !== undefined ? { amount: refundAmount } : {}),\n };\n\n return {\n x402Version: 2,\n accepted: requirements,\n payload: payload as unknown as Record<string, unknown>,\n ...(paymentRequired.resource ? { resource: paymentRequired.resource } : {}),\n ...(paymentRequired.extensions ? { extensions: paymentRequired.extensions } : {}),\n };\n}\n\n/**\n * Creates an x402 HTTP client for batch settlement with hooks; refund payloads are supplied\n * by {@link refundChannel} instead of the default payment builder.\n *\n * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer).\n * @param requirements - Resolved payment requirements for the channel network.\n * @returns An `x402HTTPClient` wired for batch-settlement scheme hooks.\n */\nfunction createRefundHttpClient(\n ctx: BatchSettlementClientDeps,\n requirements: PaymentRequirements,\n): x402HTTPClient {\n const client = new x402Client().register(requirements.network, {\n scheme: BATCH_SETTLEMENT_SCHEME,\n schemeHooks: createBatchSettlementClientHooks(ctx),\n createPaymentPayload: async () => {\n throw new Error(\"Refund payloads are built by refundChannel\");\n },\n });\n return new x402HTTPClient(client);\n}\n\n/**\n * If the refund HTTP response cannot be recovered by retrying, returns a user-facing message;\n * otherwise returns `undefined`.\n *\n * @param response - The refund request response (402 with headers or settle failure).\n * @returns A formatted failure string, or `undefined` when retry may succeed.\n */\nfunction getNonRecoverableRefundFailure(response: Response): string | undefined {\n const settleHeader = response.headers.get(\"PAYMENT-RESPONSE\");\n if (settleHeader) {\n return formatRefundFailure(decodePaymentResponseHeader(settleHeader));\n }\n\n const paymentRequired = getRefundPaymentRequired(response);\n const errorCode = paymentRequired.error;\n if (errorCode && NON_RECOVERABLE_REFUND_ERRORS.has(errorCode)) {\n return `Refund failed: ${errorCode}`;\n }\n}\n\n/**\n * Reads and decodes the `PAYMENT-REQUIRED` header from a refund-related 402 response.\n *\n * @param response - HTTP response that must include `PAYMENT-REQUIRED`.\n * @returns The decoded {@link PaymentRequired} payload.\n * @throws When the header is missing.\n */\nfunction getRefundPaymentRequired(response: Response): PaymentRequired {\n const requiredHeader = response.headers.get(\"PAYMENT-REQUIRED\");\n if (!requiredHeader) {\n throw new Error(\"Refund 402 missing PAYMENT-REQUIRED header\");\n }\n return decodePaymentRequiredHeader(requiredHeader);\n}\n\n/**\n * Builds a human-readable error message from a settle failure response.\n *\n * @param settle - The decoded SettleResponse from the server's 402 reply.\n * @returns A formatted error string suitable for `throw new Error(...)`.\n */\nfunction formatRefundFailure(settle: SettleResponse): string {\n const reason = settle.errorReason ?? \"unknown_settlement_error\";\n const message = settle.errorMessage;\n if (message && message !== reason) {\n return `Refund failed: ${reason}: ${message}`;\n }\n return `Refund failed: ${reason}`;\n}\n\n/**\n * Validates and normalises the optional `refundAmount` argument.\n *\n * @param amount - Raw amount from caller (string of base units).\n * @returns The same string when valid, or `undefined` when omitted.\n */\nfunction normalizeRefundAmount(amount: string | undefined): string | undefined {\n if (amount === undefined) return undefined;\n if (!/^\\d+$/.test(amount) || amount === \"0\") {\n throw new Error(`Invalid refund amount \"${amount}\": must be a positive integer string`);\n }\n return amount;\n}\n","import {\n SchemeNetworkClient,\n SchemeClientHooks,\n PaymentRequired,\n PaymentRequirements,\n PaymentPayloadResult,\n PaymentPayloadContext,\n SettleResponse,\n} from \"@bankofai/x402-core/types\";\nimport { getAddress } from \"viem\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { BATCH_SETTLEMENT_SCHEME } from \"../constants\";\nimport {\n BatchSettlementAssetTransferMethod,\n BatchSettlementVoucherPayload,\n ChannelConfig,\n} from \"../types\";\nimport { computeChannelId } from \"../utils\";\nimport {\n trySignEip2612PermitExtension,\n trySignErc20ApprovalExtension,\n} from \"../../shared/extensions\";\nimport type { EvmSchemeOptions } from \"../../shared/rpc\";\nimport { createBatchSettlementEIP3009DepositPayload } from \"./eip3009\";\nimport { createBatchSettlementPermit2DepositPayload } from \"./permit2\";\nimport {\n type BatchSettlementDepositStrategy,\n type BatchSettlementDepositStrategyContext,\n type BatchSettlementDepositPolicy,\n type BatchSettlementEvmSchemeOptions,\n depositAmountForRequest,\n resolveClientOptions,\n validateDepositPolicy,\n} from \"./config\";\nimport { refundChannel, type RefundOptions } from \"./refund\";\nimport {\n type BatchSettlementClientDeps,\n buildChannelConfig,\n processSettleResponse,\n recoverChannel,\n} from \"./channel\";\nimport { createBatchSettlementClientHooks } from \"./hooks\";\nimport { processCorrectivePaymentRequired } from \"./recovery\";\nimport type { ClientChannelStorage } from \"./storage\";\nimport { signVoucher } from \"./voucher\";\n\nexport type { BatchSettlementClientContext } from \"./storage\";\nexport type {\n BatchSettlementDepositPolicy,\n BatchSettlementDepositStrategy,\n BatchSettlementDepositStrategyContext,\n BatchSettlementDepositStrategyResult,\n BatchSettlementEvmSchemeOptions,\n} from \"./config\";\nexport type { RefundOptions } from \"./refund\";\n\n/**\n * Client-side implementation of the `batch-settlement` scheme for EVM networks.\n *\n * Builds payment payloads (deposit + voucher or voucher-only), processes server\n * responses to update local session state via {@link processSettleResponse},\n * handles corrective 402 resynchronisation via\n * {@link processCorrectivePaymentRequired}, and supports on-demand cooperative\n * refund requests via {@link refundChannel}.\n */\nexport class BatchSettlementEvmScheme implements SchemeNetworkClient {\n readonly scheme = BATCH_SETTLEMENT_SCHEME;\n\n readonly schemeHooks: SchemeClientHooks;\n\n private readonly storage: ClientChannelStorage;\n private readonly depositPolicy: BatchSettlementDepositPolicy | undefined;\n private readonly depositStrategy: BatchSettlementDepositStrategy | undefined;\n private readonly salt: `0x${string}`;\n private readonly payerAuthorizer: `0x${string}` | undefined;\n private readonly voucherSigner: ClientEvmSigner | undefined;\n private readonly extensionRpcOptions: EvmSchemeOptions | undefined;\n\n /**\n * Constructs a batched client scheme.\n *\n * @param signer - Client EVM wallet used for signing vouchers and ERC-3009 authorizations.\n * @param optionsOrPolicy - Either a full options object or a bare deposit-policy.\n */\n constructor(\n private readonly signer: ClientEvmSigner,\n optionsOrPolicy?: BatchSettlementEvmSchemeOptions | BatchSettlementDepositPolicy,\n ) {\n const {\n storage,\n depositPolicy,\n depositStrategy,\n salt,\n payerAuthorizer,\n voucherSigner,\n extensionRpcOptions,\n } = resolveClientOptions(optionsOrPolicy);\n this.storage = storage;\n this.depositPolicy = depositPolicy;\n this.depositStrategy = depositStrategy;\n this.salt = salt;\n this.payerAuthorizer = payerAuthorizer;\n this.voucherSigner = voucherSigner;\n this.extensionRpcOptions = extensionRpcOptions;\n\n if (\n payerAuthorizer !== undefined &&\n voucherSigner !== undefined &&\n getAddress(payerAuthorizer) !== getAddress(voucherSigner.address)\n ) {\n throw new Error(\"payerAuthorizer address must match voucherSigner.address\");\n }\n\n validateDepositPolicy(depositPolicy);\n this.schemeHooks = createBatchSettlementClientHooks(this.deps());\n }\n\n /**\n * Creates the payment payload for a batched request.\n *\n * If the channel has no onchain deposit (or needs a top-up), builds an\n * ERC-3009 deposit payload bundled with a voucher. Otherwise, signs and\n * returns a voucher-only payload.\n *\n * @param x402Version - Protocol version for the payload envelope.\n * @param paymentRequirements - Server payment requirements (scheme, network, asset, amount).\n * @param context - Optional payment payload context with extension hints.\n * @returns A {@link PaymentPayloadResult} ready to be sent as the `X-PAYMENT` header.\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n context?: PaymentPayloadContext,\n ): Promise<PaymentPayloadResult> {\n const deps = this.deps();\n const config = buildChannelConfig(deps, paymentRequirements);\n const channelId = computeChannelId(config, paymentRequirements.network);\n const key = channelId.toLowerCase();\n\n let batchedCtx = await this.storage.get(key);\n if (batchedCtx === undefined && this.signer.readContract) {\n batchedCtx = await recoverChannel(deps, paymentRequirements);\n }\n batchedCtx = batchedCtx ?? {};\n\n const needsInitialDeposit = !batchedCtx.balance || batchedCtx.balance === \"0\";\n\n const baseCumulative = BigInt(batchedCtx.chargedCumulativeAmount ?? \"0\");\n const requestAmount = BigInt(paymentRequirements.amount);\n const maxClaimableAmount = (baseCumulative + requestAmount).toString();\n\n const currentBalance = BigInt(batchedCtx.balance ?? \"0\");\n const needsTopUp = !needsInitialDeposit && BigInt(maxClaimableAmount) > currentBalance;\n\n if (needsInitialDeposit || needsTopUp) {\n const computedDeposit = depositAmountForRequest(this.depositPolicy, requestAmount);\n const minimumDepositAmount = BigInt(maxClaimableAmount) - currentBalance;\n const depositAmount = await this.resolveDepositAmount({\n paymentRequirements,\n channelConfig: config,\n channelId,\n clientContext: batchedCtx,\n requestAmount: requestAmount.toString(),\n maxClaimableAmount,\n currentBalance: currentBalance.toString(),\n minimumDepositAmount: minimumDepositAmount.toString(),\n depositAmount: computedDeposit,\n });\n if (depositAmount === false) {\n return this.createVoucherPayload(\n x402Version,\n channelId,\n maxClaimableAmount,\n paymentRequirements.network,\n config,\n );\n }\n\n const assetTransferMethod =\n (paymentRequirements.extra?.assetTransferMethod as BatchSettlementAssetTransferMethod) ??\n \"eip3009\";\n\n if (assetTransferMethod === \"eip3009\") {\n return createBatchSettlementEIP3009DepositPayload(\n this.signer,\n x402Version,\n paymentRequirements,\n config,\n depositAmount,\n maxClaimableAmount,\n this.voucherSigner,\n );\n }\n\n if (assetTransferMethod !== \"permit2\") {\n throw new Error(`unsupported batch-settlement assetTransferMethod: ${assetTransferMethod}`);\n }\n\n const result = await createBatchSettlementPermit2DepositPayload(\n this.signer,\n x402Version,\n paymentRequirements,\n config,\n depositAmount,\n maxClaimableAmount,\n this.voucherSigner,\n );\n\n const eip2612Extensions = await trySignEip2612PermitExtension(\n this.signer,\n this.extensionRpcOptions,\n paymentRequirements,\n result,\n context,\n depositAmount,\n );\n if (eip2612Extensions) {\n return { ...result, extensions: eip2612Extensions };\n }\n\n const erc20Extensions = await trySignErc20ApprovalExtension(\n this.signer,\n this.extensionRpcOptions,\n paymentRequirements,\n context,\n depositAmount,\n );\n if (erc20Extensions) {\n return { ...result, extensions: erc20Extensions };\n }\n\n return result;\n }\n\n return this.createVoucherPayload(\n x402Version,\n channelId,\n maxClaimableAmount,\n paymentRequirements.network,\n config,\n );\n }\n\n /**\n * Sends a cooperative refund request.\n *\n * @param url - The route URL backing the channel to refund.\n * @param options - Optional `amount` (partial refund) and `fetch` override.\n * @returns The settle response describing the refund outcome.\n */\n async refund(url: string, options?: RefundOptions): Promise<SettleResponse> {\n return refundChannel(this.deps(), url, options);\n }\n\n /**\n * Updates local channel state from a settle response.\n *\n * @param settle - The parsed settle response from the server.\n * @returns Resolves when local channel state has been updated.\n */\n async processSettleResponse(settle: SettleResponse): Promise<void> {\n return processSettleResponse(this.storage, settle);\n }\n\n /**\n * Resyncs local channel state from a corrective 402 response.\n *\n * @param paymentRequired - The decoded 402 response body.\n * @returns `true` if local state was successfully resynced and a retry is warranted.\n */\n async processCorrectivePaymentRequired(paymentRequired: PaymentRequired): Promise<boolean> {\n return processCorrectivePaymentRequired(this.deps(), paymentRequired);\n }\n\n /**\n * Builds the immutable {@link ChannelConfig} for a given set of payment\n * requirements, using the scheme's own signer and salt.\n *\n * @param paymentRequirements - Server payment requirements for the channel.\n * @returns The channel config that uniquely identifies the payment channel.\n */\n buildChannelConfig(paymentRequirements: PaymentRequirements): ChannelConfig {\n return buildChannelConfig(this.deps(), paymentRequirements);\n }\n\n /**\n * Resolves the deposit amount after applying the optional custom strategy.\n *\n * @param context - Deposit attempt context exposed to the strategy.\n * @returns The deposit amount to sign, or `false` to skip this deposit attempt.\n */\n private async resolveDepositAmount(\n context: BatchSettlementDepositStrategyContext,\n ): Promise<string | false> {\n const strategyResult = await this.depositStrategy?.(context);\n if (strategyResult === false) return false;\n if (strategyResult === undefined) return context.depositAmount;\n\n const depositAmount = this.normalizeStrategyDepositAmount(strategyResult);\n if (BigInt(depositAmount) < BigInt(context.minimumDepositAmount)) {\n throw new Error(\n `depositStrategy returned ${depositAmount}, below required top-up ${context.minimumDepositAmount}`,\n );\n }\n return depositAmount;\n }\n\n /**\n * Normalizes and validates a strategy-provided base-unit deposit amount.\n *\n * @param value - Strategy-provided string or bigint amount.\n * @returns Normalized decimal string.\n */\n private normalizeStrategyDepositAmount(value: string | bigint): string {\n if (typeof value === \"bigint\") {\n if (value <= 0n) {\n throw new Error(\"depositStrategy must return a positive integer deposit amount\");\n }\n return value.toString();\n }\n\n if (/^\\d+$/.test(value) && BigInt(value) > 0n) {\n return BigInt(value).toString();\n }\n\n throw new Error(\"depositStrategy must return a positive integer deposit amount\");\n }\n\n /**\n * Signs a voucher-only payment payload for the current channel.\n *\n * @param x402Version - Protocol version for the payload envelope.\n * @param channelId - Channel identifier for the voucher.\n * @param maxClaimableAmount - Cumulative ceiling for the voucher.\n * @param network - CAIP-2 network identifier.\n * @param config - Immutable channel configuration.\n * @returns Voucher-only payment payload.\n */\n private async createVoucherPayload(\n x402Version: number,\n channelId: `0x${string}`,\n maxClaimableAmount: string,\n network: string,\n config: ChannelConfig,\n ): Promise<PaymentPayloadResult> {\n const voucherSigner = this.voucherSigner ?? this.signer;\n const voucher = await signVoucher(voucherSigner, channelId, maxClaimableAmount, network);\n\n const payload: BatchSettlementVoucherPayload = {\n type: \"voucher\",\n channelConfig: config,\n voucher,\n };\n\n return {\n x402Version,\n payload,\n };\n }\n\n /**\n * Bundles the class state into the {@link BatchSettlementClientDeps} shape\n * consumed by the `channel`, `recovery`, and `refund` modules.\n *\n * @returns Client deps wrapping the scheme's own signer and storage.\n */\n private deps(): BatchSettlementClientDeps {\n return {\n signer: this.signer,\n storage: this.storage,\n salt: this.salt,\n payerAuthorizer: this.payerAuthorizer,\n voucherSigner: this.voucherSigner,\n };\n }\n}\n","import { PaymentRequirements, PaymentPayloadResult } from \"@bankofai/x402-core/types\";\nimport { getAddress } from \"viem\";\nimport { PERMIT2_ADDRESS } from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { createPermit2Nonce, getEvmChainId } from \"../../utils\";\nimport { PERMIT2_DEPOSIT_COLLECTOR_ADDRESS, batchPermit2WitnessTypes } from \"../constants\";\nimport { ChannelConfig, BatchSettlementDepositPayload } from \"../types\";\nimport { computeChannelId } from \"../utils\";\nimport { signVoucher } from \"./voucher\";\n\n/**\n * Builds a batch deposit payload using a channel-bound Permit2 witness transfer.\n *\n * @param signer - Payer signer for the Permit2 authorization.\n * @param x402Version - Protocol version for the payment envelope.\n * @param paymentRequirements - Server-provided payment requirements.\n * @param channelConfig - Channel configuration bound into the voucher and witness.\n * @param depositAmount - Token amount deposited into the channel.\n * @param maxClaimableAmount - Cumulative amount signed in the voucher.\n * @param voucherSigner - Optional signer for the voucher.\n * @returns Signed deposit payload and voucher.\n */\nexport async function createBatchSettlementPermit2DepositPayload(\n signer: ClientEvmSigner,\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n channelConfig: ChannelConfig,\n depositAmount: string,\n maxClaimableAmount: string,\n voucherSigner?: ClientEvmSigner,\n): Promise<PaymentPayloadResult> {\n const chainId = getEvmChainId(paymentRequirements.network);\n const nonce = createPermit2Nonce();\n const deadline = Math.floor(Date.now() / 1000 + paymentRequirements.maxTimeoutSeconds).toString();\n const channelId = computeChannelId(channelConfig, paymentRequirements.network);\n\n const permit2Authorization = {\n from: signer.address,\n permitted: {\n token: getAddress(paymentRequirements.asset),\n amount: depositAmount,\n },\n spender: getAddress(PERMIT2_DEPOSIT_COLLECTOR_ADDRESS),\n nonce,\n deadline,\n witness: {\n channelId,\n },\n };\n\n const signature = await signer.signTypedData({\n domain: { name: \"Permit2\", chainId, verifyingContract: PERMIT2_ADDRESS },\n types: batchPermit2WitnessTypes,\n primaryType: \"PermitWitnessTransferFrom\",\n message: {\n permitted: {\n token: permit2Authorization.permitted.token,\n amount: BigInt(permit2Authorization.permitted.amount),\n },\n spender: permit2Authorization.spender,\n nonce: BigInt(permit2Authorization.nonce),\n deadline: BigInt(permit2Authorization.deadline),\n witness: {\n channelId,\n },\n },\n });\n\n const voucher = await signVoucher(\n voucherSigner ?? signer,\n channelId,\n maxClaimableAmount,\n paymentRequirements.network,\n );\n\n const payload: BatchSettlementDepositPayload = {\n type: \"deposit\",\n channelConfig,\n voucher,\n deposit: {\n amount: depositAmount,\n authorization: {\n permit2Authorization: {\n ...permit2Authorization,\n signature,\n },\n },\n },\n };\n\n return { x402Version, payload };\n}\n"],"mappings":"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","names":["getAddress","getAddress","getAddress","getAddress","decodePaymentResponseHeader","decodePaymentResponseHeader","getAddress","getAddress","getAddress","getAddress"]}
@@ -0,0 +1,489 @@
1
+ import {
2
+ ErrEip2612AssetMismatch,
3
+ ErrEip2612DeadlineExpired,
4
+ ErrEip2612FromMismatch,
5
+ ErrEip2612SpenderNotPermit2,
6
+ ErrErc20ApprovalAssetMismatch,
7
+ ErrErc20ApprovalFromMismatch,
8
+ ErrErc20ApprovalInvalidFormat,
9
+ ErrErc20ApprovalSpenderNotPermit2,
10
+ ErrErc20ApprovalTxFailed,
11
+ ErrErc20ApprovalTxInvalidCalldata,
12
+ ErrErc20ApprovalTxInvalidSignature,
13
+ ErrErc20ApprovalTxParseFailed,
14
+ ErrErc20ApprovalTxSignerMismatch,
15
+ ErrErc20ApprovalTxWrongSelector,
16
+ ErrErc20ApprovalTxWrongSpender,
17
+ ErrErc20ApprovalTxWrongTarget,
18
+ ErrInvalidEip2612ExtensionFormat,
19
+ ErrInvalidTransactionState,
20
+ ErrPermit2612AmountMismatch,
21
+ ErrPermit2AllowanceRequired,
22
+ ErrPermit2InsufficientBalance,
23
+ ErrPermit2InvalidAmount,
24
+ ErrPermit2InvalidDestination,
25
+ ErrPermit2InvalidNonce,
26
+ ErrPermit2InvalidOwner,
27
+ ErrPermit2InvalidSignature,
28
+ ErrPermit2PaymentTooEarly,
29
+ ErrPermit2ProxyNotDeployed,
30
+ ErrPermit2SimulationFailed,
31
+ ErrTransactionFailed
32
+ } from "./chunk-P3QOX3QZ.mjs";
33
+ import {
34
+ validateEip2612GasSponsoringInfo,
35
+ validateErc20ApprovalGasSponsoringInfo
36
+ } from "./chunk-JNT7C46S.mjs";
37
+ import {
38
+ PERMIT2_ADDRESS,
39
+ eip3009ABI,
40
+ erc20AllowanceAbi,
41
+ erc20ApproveAbi,
42
+ permit2WitnessTypes
43
+ } from "./chunk-MACPBXCT.mjs";
44
+ import {
45
+ multicall
46
+ } from "./chunk-VS3RYAYE.mjs";
47
+ import {
48
+ createPermit2Nonce,
49
+ getEvmChainId
50
+ } from "./chunk-TW7Z65AO.mjs";
51
+
52
+ // src/shared/permit2.ts
53
+ import { getAddress as getAddress2, encodeFunctionData, parseErc6492Signature } from "viem";
54
+
55
+ // src/shared/erc20approval.ts
56
+ import {
57
+ getAddress,
58
+ parseTransaction,
59
+ decodeFunctionData,
60
+ recoverTransactionAddress
61
+ } from "viem";
62
+ var APPROVE_SELECTOR = "0x095ea7b3";
63
+ async function validateErc20ApprovalForPayment(info, payer, tokenAddress) {
64
+ if (!validateErc20ApprovalGasSponsoringInfo(info)) {
65
+ return {
66
+ isValid: false,
67
+ invalidReason: ErrErc20ApprovalInvalidFormat,
68
+ invalidMessage: "ERC-20 approval extension info failed schema validation"
69
+ };
70
+ }
71
+ if (getAddress(info.from) !== getAddress(payer)) {
72
+ return {
73
+ isValid: false,
74
+ invalidReason: ErrErc20ApprovalFromMismatch,
75
+ invalidMessage: `Expected from=${payer}, got ${info.from}`
76
+ };
77
+ }
78
+ if (getAddress(info.asset) !== tokenAddress) {
79
+ return {
80
+ isValid: false,
81
+ invalidReason: ErrErc20ApprovalAssetMismatch,
82
+ invalidMessage: `Expected asset=${tokenAddress}, got ${info.asset}`
83
+ };
84
+ }
85
+ if (getAddress(info.spender) !== getAddress(PERMIT2_ADDRESS)) {
86
+ return {
87
+ isValid: false,
88
+ invalidReason: ErrErc20ApprovalSpenderNotPermit2,
89
+ invalidMessage: `Expected spender=${PERMIT2_ADDRESS}, got ${info.spender}`
90
+ };
91
+ }
92
+ try {
93
+ const serializedTx = info.signedTransaction;
94
+ const tx = parseTransaction(serializedTx);
95
+ if (!tx.to || getAddress(tx.to) !== tokenAddress) {
96
+ return {
97
+ isValid: false,
98
+ invalidReason: ErrErc20ApprovalTxWrongTarget,
99
+ invalidMessage: `Transaction targets ${tx.to ?? "null"}, expected ${tokenAddress}`
100
+ };
101
+ }
102
+ const data = tx.data ?? "0x";
103
+ if (!data.startsWith(APPROVE_SELECTOR)) {
104
+ return {
105
+ isValid: false,
106
+ invalidReason: ErrErc20ApprovalTxWrongSelector,
107
+ invalidMessage: `Transaction calldata does not start with approve() selector ${APPROVE_SELECTOR}`
108
+ };
109
+ }
110
+ try {
111
+ const decoded = decodeFunctionData({
112
+ abi: erc20ApproveAbi,
113
+ data
114
+ });
115
+ const calldataSpender = getAddress(decoded.args[0]);
116
+ if (calldataSpender !== getAddress(PERMIT2_ADDRESS)) {
117
+ return {
118
+ isValid: false,
119
+ invalidReason: ErrErc20ApprovalTxWrongSpender,
120
+ invalidMessage: `approve() spender is ${calldataSpender}, expected Permit2 ${PERMIT2_ADDRESS}`
121
+ };
122
+ }
123
+ } catch {
124
+ return {
125
+ isValid: false,
126
+ invalidReason: ErrErc20ApprovalTxInvalidCalldata,
127
+ invalidMessage: "Failed to decode approve() calldata from the signed transaction"
128
+ };
129
+ }
130
+ try {
131
+ const recoveredAddress = await recoverTransactionAddress({
132
+ serializedTransaction: serializedTx
133
+ });
134
+ if (getAddress(recoveredAddress) !== getAddress(payer)) {
135
+ return {
136
+ isValid: false,
137
+ invalidReason: ErrErc20ApprovalTxSignerMismatch,
138
+ invalidMessage: `Transaction signed by ${recoveredAddress}, expected payer ${payer}`
139
+ };
140
+ }
141
+ } catch {
142
+ return {
143
+ isValid: false,
144
+ invalidReason: ErrErc20ApprovalTxInvalidSignature,
145
+ invalidMessage: "Failed to recover signer from the signed transaction"
146
+ };
147
+ }
148
+ } catch {
149
+ return {
150
+ isValid: false,
151
+ invalidReason: ErrErc20ApprovalTxParseFailed,
152
+ invalidMessage: "Failed to parse the signed transaction"
153
+ };
154
+ }
155
+ return { isValid: true };
156
+ }
157
+
158
+ // src/upto/facilitator/errors.ts
159
+ var ErrUptoInvalidScheme = "invalid_upto_evm_scheme";
160
+ var ErrUptoNetworkMismatch = "invalid_upto_evm_network_mismatch";
161
+ var ErrUptoSettlementExceedsAmount = "invalid_upto_evm_payload_settlement_exceeds_amount";
162
+ var ErrUptoAmountExceedsPermitted = "upto_amount_exceeds_permitted";
163
+ var ErrUptoUnauthorizedFacilitator = "upto_unauthorized_facilitator";
164
+ var ErrUptoFacilitatorMismatch = "upto_facilitator_mismatch";
165
+
166
+ // src/shared/permit2.ts
167
+ async function waitAndReturnSettleResponse(signer, tx, payload, payer) {
168
+ const receipt = await signer.waitForTransactionReceipt({ hash: tx });
169
+ if (receipt.status !== "success") {
170
+ return {
171
+ success: false,
172
+ errorReason: ErrInvalidTransactionState,
173
+ transaction: tx,
174
+ network: payload.accepted.network,
175
+ payer
176
+ };
177
+ }
178
+ return {
179
+ success: true,
180
+ transaction: tx,
181
+ network: payload.accepted.network,
182
+ payer
183
+ };
184
+ }
185
+ function mapSettleError(error, payload, payer) {
186
+ let errorReason = ErrTransactionFailed;
187
+ if (error instanceof Error) {
188
+ const message = error.message;
189
+ if (message.includes("Permit2612AmountMismatch")) {
190
+ errorReason = ErrPermit2612AmountMismatch;
191
+ } else if (message.includes("InvalidAmount")) {
192
+ errorReason = ErrPermit2InvalidAmount;
193
+ } else if (message.includes("InvalidDestination")) {
194
+ errorReason = ErrPermit2InvalidDestination;
195
+ } else if (message.includes("InvalidOwner")) {
196
+ errorReason = ErrPermit2InvalidOwner;
197
+ } else if (message.includes("PaymentTooEarly")) {
198
+ errorReason = ErrPermit2PaymentTooEarly;
199
+ } else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
200
+ errorReason = ErrPermit2InvalidSignature;
201
+ } else if (message.includes("InvalidNonce")) {
202
+ errorReason = ErrPermit2InvalidNonce;
203
+ } else if (message.includes("erc20_approval_tx_failed")) {
204
+ errorReason = ErrErc20ApprovalTxFailed;
205
+ } else if (message.includes("AmountExceedsPermitted")) {
206
+ errorReason = ErrUptoAmountExceedsPermitted;
207
+ } else if (message.includes("UnauthorizedFacilitator")) {
208
+ errorReason = ErrUptoUnauthorizedFacilitator;
209
+ } else {
210
+ errorReason = `${ErrTransactionFailed}: ${message.slice(0, 500)}`;
211
+ }
212
+ }
213
+ return {
214
+ success: false,
215
+ errorReason,
216
+ transaction: "",
217
+ network: payload.accepted.network,
218
+ payer
219
+ };
220
+ }
221
+ function validateEip2612PermitForPayment(info, payer, tokenAddress) {
222
+ if (!validateEip2612GasSponsoringInfo(info)) {
223
+ return { isValid: false, invalidReason: ErrInvalidEip2612ExtensionFormat };
224
+ }
225
+ if (getAddress2(info.from) !== getAddress2(payer)) {
226
+ return { isValid: false, invalidReason: ErrEip2612FromMismatch };
227
+ }
228
+ if (getAddress2(info.asset) !== tokenAddress) {
229
+ return { isValid: false, invalidReason: ErrEip2612AssetMismatch };
230
+ }
231
+ if (getAddress2(info.spender) !== getAddress2(PERMIT2_ADDRESS)) {
232
+ return { isValid: false, invalidReason: ErrEip2612SpenderNotPermit2 };
233
+ }
234
+ const now = Math.floor(Date.now() / 1e3);
235
+ if (BigInt(info.deadline) < BigInt(now + 6)) {
236
+ return { isValid: false, invalidReason: ErrEip2612DeadlineExpired };
237
+ }
238
+ return { isValid: true };
239
+ }
240
+ async function simulatePermit2Settle(config, signer, settleArgs) {
241
+ try {
242
+ await signer.readContract({
243
+ address: config.proxyAddress,
244
+ abi: config.proxyABI,
245
+ functionName: "settle",
246
+ args: settleArgs
247
+ });
248
+ return true;
249
+ } catch {
250
+ return false;
251
+ }
252
+ }
253
+ async function simulatePermit2SettleWithPermit(config, signer, settleArgs, eip2612Info) {
254
+ try {
255
+ const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
256
+ await signer.readContract({
257
+ address: config.proxyAddress,
258
+ abi: config.proxyABI,
259
+ functionName: "settleWithPermit",
260
+ args: [
261
+ {
262
+ value: BigInt(eip2612Info.amount),
263
+ deadline: BigInt(eip2612Info.deadline),
264
+ r,
265
+ s,
266
+ v
267
+ },
268
+ ...settleArgs
269
+ ]
270
+ });
271
+ return true;
272
+ } catch {
273
+ return false;
274
+ }
275
+ }
276
+ async function simulatePermit2SettleWithErc20Approval(config, extensionSigner, settleArgs, erc20Info) {
277
+ if (!extensionSigner.simulateTransactions) {
278
+ return false;
279
+ }
280
+ try {
281
+ const settleData = encodeFunctionData({
282
+ abi: config.proxyABI,
283
+ functionName: "settle",
284
+ args: settleArgs
285
+ });
286
+ return await extensionSigner.simulateTransactions([
287
+ erc20Info.signedTransaction,
288
+ { to: config.proxyAddress, data: settleData, gas: BigInt(3e5) }
289
+ ]);
290
+ } catch {
291
+ return false;
292
+ }
293
+ }
294
+ async function diagnosePermit2SimulationFailure(config, signer, tokenAddress, permit2Payload, amountRequired) {
295
+ const payer = permit2Payload.permit2Authorization.from;
296
+ const diagnosticCalls = [
297
+ {
298
+ address: config.proxyAddress,
299
+ abi: config.proxyABI,
300
+ functionName: "PERMIT2"
301
+ },
302
+ {
303
+ address: tokenAddress,
304
+ abi: eip3009ABI,
305
+ functionName: "balanceOf",
306
+ args: [payer]
307
+ },
308
+ {
309
+ address: tokenAddress,
310
+ abi: erc20AllowanceAbi,
311
+ functionName: "allowance",
312
+ args: [payer, PERMIT2_ADDRESS]
313
+ }
314
+ ];
315
+ try {
316
+ const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
317
+ const [proxyResult, balanceResult, allowanceResult] = results;
318
+ if (proxyResult.status === "failure") {
319
+ return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
320
+ }
321
+ if (balanceResult.status === "success") {
322
+ const balance = balanceResult.result;
323
+ if (balance < BigInt(amountRequired)) {
324
+ return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
325
+ }
326
+ }
327
+ if (allowanceResult.status === "success") {
328
+ const allowance = allowanceResult.result;
329
+ if (allowance < BigInt(amountRequired)) {
330
+ return { isValid: false, invalidReason: ErrPermit2AllowanceRequired, payer };
331
+ }
332
+ }
333
+ } catch {
334
+ }
335
+ return { isValid: false, invalidReason: ErrPermit2SimulationFailed, payer };
336
+ }
337
+ async function checkPermit2Prerequisites(config, signer, tokenAddress, payer, amountRequired) {
338
+ const diagnosticCalls = [
339
+ {
340
+ address: config.proxyAddress,
341
+ abi: config.proxyABI,
342
+ functionName: "PERMIT2"
343
+ },
344
+ {
345
+ address: tokenAddress,
346
+ abi: eip3009ABI,
347
+ functionName: "balanceOf",
348
+ args: [payer]
349
+ }
350
+ ];
351
+ try {
352
+ const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
353
+ const [proxyResult, balanceResult] = results;
354
+ if (proxyResult.status === "failure") {
355
+ return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
356
+ }
357
+ if (balanceResult.status === "success") {
358
+ const balance = balanceResult.result;
359
+ if (balance < BigInt(amountRequired)) {
360
+ return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
361
+ }
362
+ }
363
+ } catch {
364
+ }
365
+ return { isValid: true, invalidReason: void 0, payer };
366
+ }
367
+ function buildExactPermit2SettleArgs(permit2Payload) {
368
+ const { signature } = parseErc6492Signature(permit2Payload.signature);
369
+ return [
370
+ {
371
+ permitted: {
372
+ token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
373
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
374
+ },
375
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
376
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline)
377
+ },
378
+ getAddress2(permit2Payload.permit2Authorization.from),
379
+ {
380
+ to: getAddress2(permit2Payload.permit2Authorization.witness.to),
381
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
382
+ },
383
+ signature
384
+ ];
385
+ }
386
+ function buildUptoPermit2SettleArgs(permit2Payload, settlementAmount, facilitatorAddress) {
387
+ const { signature } = parseErc6492Signature(permit2Payload.signature);
388
+ return [
389
+ {
390
+ permitted: {
391
+ token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
392
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
393
+ },
394
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
395
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline)
396
+ },
397
+ settlementAmount,
398
+ getAddress2(permit2Payload.permit2Authorization.from),
399
+ {
400
+ to: getAddress2(permit2Payload.permit2Authorization.witness.to),
401
+ facilitator: getAddress2(facilitatorAddress),
402
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
403
+ },
404
+ signature
405
+ ];
406
+ }
407
+ function splitEip2612Signature(signature) {
408
+ const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
409
+ if (sig.length !== 130) {
410
+ throw new Error(
411
+ `invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
412
+ );
413
+ }
414
+ const r = `0x${sig.slice(0, 64)}`;
415
+ const s = `0x${sig.slice(64, 128)}`;
416
+ const v = parseInt(sig.slice(128, 130), 16);
417
+ return { v, r, s };
418
+ }
419
+ async function createPermit2PayloadForProxy(proxyAddress, signer, x402Version, paymentRequirements) {
420
+ const now = Math.floor(Date.now() / 1e3);
421
+ const nonce = createPermit2Nonce();
422
+ const validAfter = "0";
423
+ const deadline = (now + paymentRequirements.maxTimeoutSeconds).toString();
424
+ const permit2Authorization = {
425
+ from: signer.address,
426
+ permitted: {
427
+ token: getAddress2(paymentRequirements.asset),
428
+ amount: paymentRequirements.amount
429
+ },
430
+ spender: proxyAddress,
431
+ nonce,
432
+ deadline,
433
+ witness: {
434
+ to: getAddress2(paymentRequirements.payTo),
435
+ validAfter
436
+ }
437
+ };
438
+ const signature = await signPermit2Authorization(
439
+ signer,
440
+ permit2Authorization,
441
+ paymentRequirements
442
+ );
443
+ return {
444
+ x402Version,
445
+ payload: { signature, permit2Authorization }
446
+ };
447
+ }
448
+ async function signPermit2Authorization(signer, permit2Authorization, requirements) {
449
+ const chainId = getEvmChainId(requirements.network);
450
+ return await signer.signTypedData({
451
+ domain: { name: "Permit2", chainId, verifyingContract: PERMIT2_ADDRESS },
452
+ types: permit2WitnessTypes,
453
+ primaryType: "PermitWitnessTransferFrom",
454
+ message: {
455
+ permitted: {
456
+ token: getAddress2(permit2Authorization.permitted.token),
457
+ amount: BigInt(permit2Authorization.permitted.amount)
458
+ },
459
+ spender: getAddress2(permit2Authorization.spender),
460
+ nonce: BigInt(permit2Authorization.nonce),
461
+ deadline: BigInt(permit2Authorization.deadline),
462
+ witness: {
463
+ to: getAddress2(permit2Authorization.witness.to),
464
+ validAfter: BigInt(permit2Authorization.witness.validAfter)
465
+ }
466
+ }
467
+ });
468
+ }
469
+
470
+ export {
471
+ validateErc20ApprovalForPayment,
472
+ ErrUptoInvalidScheme,
473
+ ErrUptoNetworkMismatch,
474
+ ErrUptoSettlementExceedsAmount,
475
+ ErrUptoFacilitatorMismatch,
476
+ waitAndReturnSettleResponse,
477
+ mapSettleError,
478
+ validateEip2612PermitForPayment,
479
+ simulatePermit2Settle,
480
+ simulatePermit2SettleWithPermit,
481
+ simulatePermit2SettleWithErc20Approval,
482
+ diagnosePermit2SimulationFailure,
483
+ checkPermit2Prerequisites,
484
+ buildExactPermit2SettleArgs,
485
+ buildUptoPermit2SettleArgs,
486
+ splitEip2612Signature,
487
+ createPermit2PayloadForProxy
488
+ };
489
+ //# sourceMappingURL=chunk-H2EYJIZL.mjs.map