@t402/extensions 2.4.0 → 2.6.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 (42) hide show
  1. package/dist/cjs/bazaar/index.d.ts +1 -1
  2. package/dist/cjs/eip2612-gas-sponsoring/index.d.ts +337 -0
  3. package/dist/cjs/eip2612-gas-sponsoring/index.js +314 -0
  4. package/dist/cjs/eip2612-gas-sponsoring/index.js.map +1 -0
  5. package/dist/cjs/erc20-approval-gas-sponsoring/index.d.ts +316 -0
  6. package/dist/cjs/erc20-approval-gas-sponsoring/index.js +264 -0
  7. package/dist/cjs/erc20-approval-gas-sponsoring/index.js.map +1 -0
  8. package/dist/cjs/{index-DYNleT-u.d.ts → index-Mk5Ypp8M.d.ts} +2 -2
  9. package/dist/cjs/index.d.ts +4 -1
  10. package/dist/cjs/index.js +650 -0
  11. package/dist/cjs/index.js.map +1 -1
  12. package/dist/cjs/payment-id/index.d.ts +142 -0
  13. package/dist/cjs/payment-id/index.js +101 -0
  14. package/dist/cjs/payment-id/index.js.map +1 -0
  15. package/dist/cjs/sign-in-with-x/index.d.ts +2 -1
  16. package/dist/cjs/sign-in-with-x/index.js +55 -0
  17. package/dist/cjs/sign-in-with-x/index.js.map +1 -1
  18. package/dist/esm/bazaar/index.d.mts +1 -1
  19. package/dist/esm/chunk-OAWKCEAR.mjs +226 -0
  20. package/dist/esm/chunk-OAWKCEAR.mjs.map +1 -0
  21. package/dist/esm/chunk-S36A7YLQ.mjs +70 -0
  22. package/dist/esm/chunk-S36A7YLQ.mjs.map +1 -0
  23. package/dist/esm/chunk-VINC22RD.mjs +278 -0
  24. package/dist/esm/chunk-VINC22RD.mjs.map +1 -0
  25. package/dist/esm/{chunk-J3ZMNCIA.mjs → chunk-YKZ5P2JW.mjs} +56 -1
  26. package/dist/esm/chunk-YKZ5P2JW.mjs.map +1 -0
  27. package/dist/esm/eip2612-gas-sponsoring/index.d.mts +337 -0
  28. package/dist/esm/eip2612-gas-sponsoring/index.mjs +27 -0
  29. package/dist/esm/eip2612-gas-sponsoring/index.mjs.map +1 -0
  30. package/dist/esm/erc20-approval-gas-sponsoring/index.d.mts +316 -0
  31. package/dist/esm/erc20-approval-gas-sponsoring/index.mjs +31 -0
  32. package/dist/esm/erc20-approval-gas-sponsoring/index.mjs.map +1 -0
  33. package/dist/esm/{index-DYNleT-u.d.mts → index-Mk5Ypp8M.d.mts} +2 -2
  34. package/dist/esm/index.d.mts +4 -1
  35. package/dist/esm/index.mjs +67 -1
  36. package/dist/esm/payment-id/index.d.mts +142 -0
  37. package/dist/esm/payment-id/index.mjs +17 -0
  38. package/dist/esm/payment-id/index.mjs.map +1 -0
  39. package/dist/esm/sign-in-with-x/index.d.mts +2 -1
  40. package/dist/esm/sign-in-with-x/index.mjs +1 -1
  41. package/package.json +53 -16
  42. package/dist/esm/chunk-J3ZMNCIA.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/eip2612-gas-sponsoring/index.ts","../../../src/eip2612-gas-sponsoring/server.ts","../../../src/eip2612-gas-sponsoring/client.ts","../../../src/eip2612-gas-sponsoring/facilitator.ts"],"sourcesContent":["/**\n * @module eip2612-gas-sponsoring - t402 Payment Protocol EIP-2612 Gas Sponsoring Extension\n *\n * This module provides EIP-2612 permit-based gas sponsoring for the t402 protocol.\n * It allows facilitators to sponsor gas fees by having clients sign off-chain permits\n * instead of submitting on-chain approval transactions. The facilitator submits the\n * permit on-chain followed by settlement via Permit2.\n *\n * @example Server-side usage\n * ```typescript\n * import {\n * declareEip2612GasSponsorExtension,\n * parseEip2612GasSponsorHeader,\n * validateEip2612GasSponsorPayload,\n * } from \"@t402/extensions/eip2612-gas-sponsoring\";\n *\n * // Declare extension in 402 response\n * const extension = declareEip2612GasSponsorExtension({\n * sponsoredNetworks: [\"eip155:8453\", \"eip155:42161\"],\n * maxAmount: \"1000000000\",\n * sponsorAddress: \"0xFacilitator...\",\n * });\n *\n * // Parse and validate client header\n * const payload = parseEip2612GasSponsorHeader(\n * request.headers['x-t402-eip2612-gas-sponsoring']\n * );\n * const result = validateEip2612GasSponsorPayload(payload, extension.info);\n * ```\n *\n * @example Client-side usage\n * ```typescript\n * import {\n * createPermitSignature,\n * createEip2612GasSponsorPayload,\n * encodeEip2612GasSponsorHeader,\n * EIP2612_GAS_SPONSOR_HEADER_NAME,\n * } from \"@t402/extensions/eip2612-gas-sponsoring\";\n *\n * const permit = await createPermitSignature({\n * signer: wallet,\n * tokenAddress: \"0xUSDT...\",\n * tokenName: \"Tether USD\",\n * chainId: 8453,\n * spender: facilitatorAddress,\n * value: \"1000000\",\n * deadline: Math.floor(Date.now() / 1000) + 300,\n * });\n *\n * const payload = createEip2612GasSponsorPayload(permit, \"eip155:8453\");\n * fetch(url, {\n * headers: { [EIP2612_GAS_SPONSOR_HEADER_NAME]: encodeEip2612GasSponsorHeader(payload) }\n * });\n * ```\n *\n * @example Facilitator-side usage\n * ```typescript\n * import {\n * extractEip2612GasSponsorPayload,\n * validateAndExtractPermit,\n * buildPermitCallData,\n * } from \"@t402/extensions/eip2612-gas-sponsoring\";\n *\n * const result = validateAndExtractPermit(\n * paymentPayload.extensions,\n * extensionInfo\n * );\n * if (result.valid && result.payload) {\n * const permitCall = buildPermitCallData(result.payload);\n * // Submit permit() tx, then settle via Permit2\n * }\n * ```\n */\n\n// Type exports\nexport type {\n Eip2612GasSponsorExtensionInfo,\n Eip2612GasSponsorExtension,\n Eip2612GasSponsorPayload,\n DeclareEip2612GasSponsorOptions,\n ValidateEip2612GasSponsorOptions,\n Eip2612GasSponsorValidationResult,\n CreatePermitParams,\n PermitSigner,\n} from \"./types.js\";\n\n// Server exports\nexport {\n declareEip2612GasSponsorExtension,\n parseEip2612GasSponsorHeader,\n validateEip2612GasSponsorPayload,\n} from \"./server.js\";\n\n// Client exports\nexport {\n createPermitSignature,\n createEip2612GasSponsorPayload,\n encodeEip2612GasSponsorHeader,\n EIP2612_GAS_SPONSOR_EXTENSION_KEY,\n EIP2612_GAS_SPONSOR_HEADER_NAME,\n} from \"./client.js\";\n\n// Facilitator exports\nexport {\n extractEip2612GasSponsorPayload,\n validateAndExtractPermit,\n buildPermitCallData,\n} from \"./facilitator.js\";\n","/**\n * EIP-2612 Gas Sponsoring Extension Server-Side Implementation\n *\n * Provides functions for servers to declare gas sponsoring requirements,\n * parse client headers, and validate permit payloads.\n */\n\nimport type {\n Eip2612GasSponsorExtension,\n Eip2612GasSponsorExtensionInfo,\n Eip2612GasSponsorPayload,\n DeclareEip2612GasSponsorOptions,\n ValidateEip2612GasSponsorOptions,\n Eip2612GasSponsorValidationResult,\n} from \"./types.js\";\n\n/**\n * JSON Schema for EIP-2612 gas sponsor payload validation.\n */\nconst EIP2612_GAS_SPONSOR_SCHEMA = {\n type: \"object\",\n required: [\"network\", \"permitSignature\", \"owner\", \"spender\", \"value\", \"deadline\", \"v\", \"r\", \"s\"],\n properties: {\n network: { type: \"string\" },\n permitSignature: { type: \"string\" },\n owner: { type: \"string\" },\n spender: { type: \"string\" },\n value: { type: \"string\" },\n deadline: { type: \"number\" },\n v: { type: \"number\" },\n r: { type: \"string\" },\n s: { type: \"string\" },\n },\n};\n\n/**\n * Declares an EIP-2612 gas sponsor extension for server responses.\n *\n * @param options - Extension declaration options\n * @returns Gas sponsor extension object ready for response\n *\n * @example\n * ```typescript\n * const extension = declareEip2612GasSponsorExtension({\n * sponsoredNetworks: [\"eip155:8453\", \"eip155:42161\"],\n * maxAmount: \"1000000000\",\n * sponsorAddress: \"0xFacilitator...\",\n * });\n * ```\n */\nexport function declareEip2612GasSponsorExtension(\n options: DeclareEip2612GasSponsorOptions,\n): Eip2612GasSponsorExtension {\n const info: Eip2612GasSponsorExtensionInfo = {\n sponsoredNetworks: options.sponsoredNetworks,\n maxAmount: options.maxAmount,\n permitDeadline: options.permitDeadline ?? 300,\n sponsorAddress: options.sponsorAddress,\n };\n\n return {\n info,\n schema: EIP2612_GAS_SPONSOR_SCHEMA,\n };\n}\n\n/**\n * Parses an EIP-2612 gas sponsor header from client request.\n *\n * The header format is base64-encoded JSON.\n *\n * @param header - Base64-encoded gas sponsor header value\n * @returns Parsed gas sponsor payload\n * @throws Error if header is invalid\n *\n * @example\n * ```typescript\n * const payload = parseEip2612GasSponsorHeader(\n * request.headers['x-t402-eip2612-gas-sponsoring']\n * );\n * ```\n */\nexport function parseEip2612GasSponsorHeader(header: string): Eip2612GasSponsorPayload {\n if (!header) {\n throw new Error(\"Missing EIP-2612 gas sponsor header\");\n }\n\n try {\n const decoded = Buffer.from(header, \"base64\").toString(\"utf-8\");\n const payload = JSON.parse(decoded) as Eip2612GasSponsorPayload;\n\n const required = [\n \"network\",\n \"permitSignature\",\n \"owner\",\n \"spender\",\n \"value\",\n \"deadline\",\n \"v\",\n \"r\",\n \"s\",\n ];\n for (const field of required) {\n if (!(field in payload)) {\n throw new Error(`Missing required field: ${field}`);\n }\n }\n\n return payload;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(\"Invalid EIP-2612 gas sponsor header: malformed JSON\");\n }\n throw error;\n }\n}\n\n/**\n * Validates an EIP-2612 gas sponsor payload against server extension info.\n *\n * @param payload - The gas sponsor payload from the client\n * @param extensionInfo - The server's gas sponsor extension info\n * @param options - Validation options\n * @returns Validation result\n *\n * @example\n * ```typescript\n * const result = validateEip2612GasSponsorPayload(payload, extension.info);\n * if (!result.valid) {\n * throw new Error(result.error);\n * }\n * ```\n */\nexport function validateEip2612GasSponsorPayload(\n payload: Eip2612GasSponsorPayload,\n extensionInfo: Eip2612GasSponsorExtensionInfo,\n options: ValidateEip2612GasSponsorOptions = {},\n): Eip2612GasSponsorValidationResult {\n const now = options.now ? options.now() : Date.now();\n const nowSeconds = Math.floor(now / 1000);\n\n // Validate network is in sponsoredNetworks\n if (!extensionInfo.sponsoredNetworks.includes(payload.network)) {\n return {\n valid: false,\n error: `Network ${payload.network} is not in sponsored networks: ${extensionInfo.sponsoredNetworks.join(\", \")}`,\n };\n }\n\n // Validate amount does not exceed maxAmount\n const payloadValue = BigInt(payload.value);\n const maxAmount = BigInt(extensionInfo.maxAmount);\n if (payloadValue > maxAmount) {\n return {\n valid: false,\n error: `Value ${payload.value} exceeds maximum amount ${extensionInfo.maxAmount}`,\n };\n }\n\n // Validate deadline is in the future\n if (payload.deadline <= nowSeconds) {\n return {\n valid: false,\n error: \"Permit deadline has expired\",\n };\n }\n\n // Validate deadline does not exceed permitDeadline seconds from now\n const maxDeadline = nowSeconds + extensionInfo.permitDeadline;\n if (payload.deadline > maxDeadline) {\n return {\n valid: false,\n error: `Permit deadline ${payload.deadline} exceeds maximum allowed deadline ${maxDeadline}`,\n };\n }\n\n // Validate spender matches sponsorAddress\n if (payload.spender.toLowerCase() !== extensionInfo.sponsorAddress.toLowerCase()) {\n return {\n valid: false,\n error: `Spender ${payload.spender} does not match sponsor address ${extensionInfo.sponsorAddress}`,\n };\n }\n\n // Validate permitSignature format (65 bytes = 130 hex chars)\n const sigHex = payload.permitSignature.startsWith(\"0x\")\n ? payload.permitSignature.slice(2)\n : payload.permitSignature;\n if (sigHex.length !== 130) {\n return {\n valid: false,\n error: `Invalid permit signature length: expected 130 hex chars, got ${sigHex.length}`,\n };\n }\n\n // Validate v is 27 or 28\n if (payload.v !== 27 && payload.v !== 28) {\n return {\n valid: false,\n error: `Invalid v value: expected 27 or 28, got ${payload.v}`,\n };\n }\n\n // Validate r format (32 bytes = 64 hex chars)\n const rHex = payload.r.startsWith(\"0x\") ? payload.r.slice(2) : payload.r;\n if (rHex.length !== 64) {\n return {\n valid: false,\n error: `Invalid r length: expected 64 hex chars, got ${rHex.length}`,\n };\n }\n\n // Validate s format (32 bytes = 64 hex chars)\n const sHex = payload.s.startsWith(\"0x\") ? payload.s.slice(2) : payload.s;\n if (sHex.length !== 64) {\n return {\n valid: false,\n error: `Invalid s length: expected 64 hex chars, got ${sHex.length}`,\n };\n }\n\n return { valid: true };\n}\n","/**\n * EIP-2612 Gas Sponsoring Extension Client-Side Implementation\n *\n * Provides functions for clients to create EIP-2612 permit signatures\n * and encode gas sponsor payloads for transmission.\n */\n\nimport type { Eip2612GasSponsorPayload, CreatePermitParams } from \"./types.js\";\n\n/**\n * Extension key for EIP-2612 gas sponsoring in payment requirements.\n */\nexport const EIP2612_GAS_SPONSOR_EXTENSION_KEY = \"eip2612GasSponsoring\";\n\n/**\n * HTTP header name for EIP-2612 gas sponsor payload.\n */\nexport const EIP2612_GAS_SPONSOR_HEADER_NAME = \"X-T402-EIP2612-Gas-Sponsoring\";\n\n/**\n * Creates an EIP-2612 permit signature using EIP-712 typed data signing.\n *\n * @param params - Permit signing parameters\n * @returns Permit data including the signature components\n *\n * @example\n * ```typescript\n * const permit = await createPermitSignature({\n * signer: wallet,\n * tokenAddress: \"0xUSDT...\",\n * tokenName: \"Tether USD\",\n * chainId: 8453,\n * spender: facilitatorAddress,\n * value: \"1000000\",\n * deadline: Math.floor(Date.now() / 1000) + 300,\n * });\n * ```\n */\nexport async function createPermitSignature(params: CreatePermitParams): Promise<{\n owner: string;\n spender: string;\n value: string;\n deadline: number;\n v: number;\n r: string;\n s: string;\n permitSignature: string;\n}> {\n const { signer, tokenAddress, tokenName, chainId, spender, value, deadline, nonce = 0 } = params;\n\n const domain = {\n name: tokenName,\n version: \"1\",\n chainId,\n verifyingContract: tokenAddress,\n };\n\n const types = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n };\n\n const message = {\n owner: signer.address,\n spender,\n value,\n nonce,\n deadline,\n };\n\n const signature = await signer.signTypedData({\n domain,\n types,\n primaryType: \"Permit\",\n message,\n });\n\n // Parse signature into components\n const sigHex = signature.startsWith(\"0x\") ? signature.slice(2) : signature;\n\n if (sigHex.length !== 130) {\n throw new Error(`Invalid signature length: expected 130 hex chars, got ${sigHex.length}`);\n }\n\n const r = \"0x\" + sigHex.slice(0, 64);\n const s = \"0x\" + sigHex.slice(64, 128);\n let v = parseInt(sigHex.slice(128, 130), 16);\n\n // Normalize v to 27 or 28\n if (v < 27) {\n v += 27;\n }\n\n return {\n owner: signer.address,\n spender,\n value,\n deadline,\n v,\n r,\n s,\n permitSignature: signature.startsWith(\"0x\") ? signature : \"0x\" + signature,\n };\n}\n\n/**\n * Creates a gas sponsor payload from permit data and network.\n *\n * @param permit - Permit signature data from createPermitSignature\n * @param network - CAIP-2 network identifier (e.g., \"eip155:8453\")\n * @returns Gas sponsor payload ready for header encoding\n *\n * @example\n * ```typescript\n * const payload = createEip2612GasSponsorPayload(permit, \"eip155:8453\");\n * ```\n */\nexport function createEip2612GasSponsorPayload(\n permit: {\n owner: string;\n spender: string;\n value: string;\n deadline: number;\n v: number;\n r: string;\n s: string;\n permitSignature: string;\n },\n network: string,\n): Eip2612GasSponsorPayload {\n return {\n network,\n permitSignature: permit.permitSignature,\n owner: permit.owner,\n spender: permit.spender,\n value: permit.value,\n deadline: permit.deadline,\n v: permit.v,\n r: permit.r,\n s: permit.s,\n };\n}\n\n/**\n * Encodes a gas sponsor payload for transmission in HTTP header.\n *\n * @param payload - The gas sponsor payload to encode\n * @returns Base64-encoded JSON string\n *\n * @example\n * ```typescript\n * const header = encodeEip2612GasSponsorHeader(payload);\n * fetch(url, {\n * headers: { [EIP2612_GAS_SPONSOR_HEADER_NAME]: header }\n * });\n * ```\n */\nexport function encodeEip2612GasSponsorHeader(payload: Eip2612GasSponsorPayload): string {\n const json = JSON.stringify(payload);\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(json, \"utf-8\").toString(\"base64\");\n }\n return btoa(json);\n}\n","/**\n * EIP-2612 Gas Sponsoring Extension Facilitator-Side Implementation\n *\n * Provides functions for facilitators to extract permit data from payment\n * extensions, validate permits, and prepare on-chain submission.\n */\n\nimport type {\n Eip2612GasSponsorPayload,\n Eip2612GasSponsorExtensionInfo,\n Eip2612GasSponsorValidationResult,\n} from \"./types.js\";\nimport { EIP2612_GAS_SPONSOR_EXTENSION_KEY } from \"./client.js\";\nimport { validateEip2612GasSponsorPayload } from \"./server.js\";\n\n/**\n * Extracts the EIP-2612 gas sponsor payload from payment extensions.\n *\n * @param extensions - The extensions map from a PaymentPayload\n * @returns The gas sponsor payload if present, or null\n *\n * @example\n * ```typescript\n * const permit = extractEip2612GasSponsorPayload(paymentPayload.extensions);\n * if (permit) {\n * // Submit permit tx then settle via Permit2\n * }\n * ```\n */\nexport function extractEip2612GasSponsorPayload(\n extensions: Record<string, unknown> | undefined,\n): Eip2612GasSponsorPayload | null {\n if (!extensions) {\n return null;\n }\n\n const raw = extensions[EIP2612_GAS_SPONSOR_EXTENSION_KEY];\n if (!raw || typeof raw !== \"object\") {\n return null;\n }\n\n const payload = raw as Record<string, unknown>;\n\n // Validate required fields are present\n const required = [\n \"network\",\n \"permitSignature\",\n \"owner\",\n \"spender\",\n \"value\",\n \"deadline\",\n \"v\",\n \"r\",\n \"s\",\n ];\n for (const field of required) {\n if (!(field in payload)) {\n return null;\n }\n }\n\n return {\n network: payload.network as string,\n permitSignature: payload.permitSignature as string,\n owner: payload.owner as string,\n spender: payload.spender as string,\n value: payload.value as string,\n deadline: payload.deadline as number,\n v: payload.v as number,\n r: payload.r as string,\n s: payload.s as string,\n };\n}\n\n/**\n * Validates and extracts the EIP-2612 gas sponsor payload in one step.\n *\n * This is a convenience function for facilitators that combines extraction\n * and validation against the server's extension info.\n *\n * @param extensions - The extensions map from a PaymentPayload\n * @param extensionInfo - The server's gas sponsor extension info\n * @returns Validation result with the extracted payload if valid\n *\n * @example\n * ```typescript\n * const result = validateAndExtractPermit(\n * paymentPayload.extensions,\n * extensionInfo\n * );\n * if (result.valid && result.payload) {\n * // Submit permit() on token contract, then settle via Permit2\n * }\n * ```\n */\nexport function validateAndExtractPermit(\n extensions: Record<string, unknown> | undefined,\n extensionInfo: Eip2612GasSponsorExtensionInfo,\n): Eip2612GasSponsorValidationResult & { payload?: Eip2612GasSponsorPayload } {\n const payload = extractEip2612GasSponsorPayload(extensions);\n\n if (!payload) {\n return {\n valid: false,\n error: `Missing or invalid ${EIP2612_GAS_SPONSOR_EXTENSION_KEY} extension in payment`,\n };\n }\n\n const result = validateEip2612GasSponsorPayload(payload, extensionInfo);\n\n if (!result.valid) {\n return result;\n }\n\n return { valid: true, payload };\n}\n\n/**\n * Builds the EIP-2612 permit function call data for on-chain submission.\n *\n * Returns the ABI-encoded parameters needed to call `permit(owner, spender, value, deadline, v, r, s)`\n * on the token contract.\n *\n * @param payload - The validated gas sponsor payload\n * @returns Object with the permit call parameters\n *\n * @example\n * ```typescript\n * const permitCall = buildPermitCallData(payload);\n * // Use permitCall with your preferred web3 library to submit the tx\n * ```\n */\nexport function buildPermitCallData(payload: Eip2612GasSponsorPayload): {\n owner: string;\n spender: string;\n value: string;\n deadline: number;\n v: number;\n r: string;\n s: string;\n} {\n return {\n owner: payload.owner,\n spender: payload.spender,\n value: payload.value,\n deadline: payload.deadline,\n v: payload.v,\n r: payload.r,\n s: payload.s,\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,316 @@
1
+ /**
2
+ * ERC-20 Approval Gas Sponsoring Extension Type Definitions
3
+ *
4
+ * ERC-20 approve()-based gas sponsoring for the t402 payment protocol.
5
+ * For tokens WITHOUT EIP-2612 permit support, the client signs an offline
6
+ * approve() transaction and the facilitator broadcasts it on their behalf.
7
+ */
8
+ /**
9
+ * Information provided by server about ERC-20 approval gas sponsoring availability.
10
+ */
11
+ interface ERC20ApprovalGasSponsorExtensionInfo {
12
+ /** CAIP-2 network identifiers where gas sponsoring is available */
13
+ sponsoredNetworks: string[];
14
+ /** Maximum token amount (in base units) the sponsor will cover per approval */
15
+ maxAmount: string;
16
+ /** Address of the sponsor/facilitator that will submit transactions */
17
+ sponsorAddress: string;
18
+ /** Optional Permit2 proxy address for advanced settlement flows */
19
+ permit2Address?: string;
20
+ /** Whether atomic batch execution is required (e.g., via Multicall3) */
21
+ requiresAtomicBatch: boolean;
22
+ }
23
+ /**
24
+ * ERC-20 approval gas sponsor extension declaration for server responses.
25
+ */
26
+ interface ERC20ApprovalGasSponsorExtension {
27
+ /** Extension information */
28
+ info: ERC20ApprovalGasSponsorExtensionInfo;
29
+ /** JSON Schema for validation */
30
+ schema: object;
31
+ }
32
+ /**
33
+ * Complete ERC-20 approval gas sponsor payload from client.
34
+ */
35
+ interface ERC20ApprovalGasSponsorPayload {
36
+ /** CAIP-2 network identifier (must be in sponsoredNetworks) */
37
+ network: string;
38
+ /** Client wallet address that signed the transaction */
39
+ from: string;
40
+ /** ERC-20 token contract address */
41
+ asset: string;
42
+ /** Approval amount in base units */
43
+ amount: string;
44
+ /** Raw signed approve() transaction (hex-encoded with 0x prefix) */
45
+ signedApprovalTx: string;
46
+ /** Chain ID for replay protection */
47
+ chainId: number;
48
+ /** Client's account nonce (if known) */
49
+ nonce?: number;
50
+ }
51
+ /**
52
+ * Options for declaring ERC-20 approval gas sponsor extension on server.
53
+ */
54
+ interface DeclareERC20ApprovalGasSponsorOptions {
55
+ /** CAIP-2 network identifiers where gas sponsoring is available */
56
+ sponsoredNetworks: string[];
57
+ /** Maximum token amount (in base units) the sponsor will cover per approval */
58
+ maxAmount: string;
59
+ /** Address of the sponsor/facilitator */
60
+ sponsorAddress: string;
61
+ /** Optional Permit2 proxy address */
62
+ permit2Address?: string;
63
+ /** Whether atomic batch execution is required (defaults to false) */
64
+ requiresAtomicBatch?: boolean;
65
+ }
66
+ /**
67
+ * Options for validating ERC-20 approval gas sponsor payloads.
68
+ */
69
+ interface ValidateERC20ApprovalGasSponsorOptions {
70
+ /** Expected chain IDs per CAIP-2 network (e.g., { "eip155:8453": 8453 }) */
71
+ expectedChainIds?: Record<string, number>;
72
+ }
73
+ /**
74
+ * Result of ERC-20 approval gas sponsor payload validation.
75
+ */
76
+ interface ERC20ApprovalGasSponsorValidationResult {
77
+ /** Whether the payload is valid */
78
+ valid: boolean;
79
+ /** Error message if invalid */
80
+ error?: string;
81
+ }
82
+ /**
83
+ * Parameters for creating an ERC-20 approval gas sponsor payload.
84
+ */
85
+ interface CreateERC20ApprovalParams {
86
+ /** CAIP-2 network identifier */
87
+ network: string;
88
+ /** Client wallet address */
89
+ from: string;
90
+ /** ERC-20 token contract address */
91
+ asset: string;
92
+ /** Approval amount in base units */
93
+ amount: string;
94
+ /** Raw signed approve() transaction (hex-encoded) */
95
+ signedApprovalTx: string;
96
+ /** Chain ID for replay protection */
97
+ chainId: number;
98
+ /** Client's account nonce (if known) */
99
+ nonce?: number;
100
+ }
101
+
102
+ /**
103
+ * ERC-20 Approval Gas Sponsoring Extension Server-Side Implementation
104
+ *
105
+ * Provides functions for servers to declare gas sponsoring requirements,
106
+ * parse client headers, and validate approval payloads.
107
+ */
108
+
109
+ /**
110
+ * Declares an ERC-20 approval gas sponsor extension for server responses.
111
+ *
112
+ * @param options - Extension declaration options
113
+ * @returns Gas sponsor extension object ready for response
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * const extension = declareERC20ApprovalGasSponsorExtension({
118
+ * sponsoredNetworks: ["eip155:8453", "eip155:42161"],
119
+ * maxAmount: "1000000000",
120
+ * sponsorAddress: "0xFacilitator...",
121
+ * requiresAtomicBatch: true,
122
+ * });
123
+ * ```
124
+ */
125
+ declare function declareERC20ApprovalGasSponsorExtension(options: DeclareERC20ApprovalGasSponsorOptions): ERC20ApprovalGasSponsorExtension;
126
+ /**
127
+ * Parses an ERC-20 approval gas sponsor header from client request.
128
+ *
129
+ * The header format is base64-encoded JSON.
130
+ *
131
+ * @param header - Base64-encoded gas sponsor header value
132
+ * @returns Parsed gas sponsor payload
133
+ * @throws Error if header is invalid
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * const payload = parseERC20ApprovalGasSponsorHeader(
138
+ * request.headers['x-t402-erc20-approval-gas-sponsoring']
139
+ * );
140
+ * ```
141
+ */
142
+ declare function parseERC20ApprovalGasSponsorHeader(header: string): ERC20ApprovalGasSponsorPayload;
143
+ /**
144
+ * Validates an ERC-20 approval gas sponsor payload against server extension info.
145
+ *
146
+ * @param payload - The gas sponsor payload from the client
147
+ * @param extensionInfo - The server's gas sponsor extension info
148
+ * @param options - Validation options
149
+ * @returns Validation result
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * const result = validateERC20ApprovalGasSponsorPayload(payload, extension.info);
154
+ * if (!result.valid) {
155
+ * throw new Error(result.error);
156
+ * }
157
+ * ```
158
+ */
159
+ declare function validateERC20ApprovalGasSponsorPayload(payload: ERC20ApprovalGasSponsorPayload, extensionInfo: ERC20ApprovalGasSponsorExtensionInfo, options?: ValidateERC20ApprovalGasSponsorOptions): ERC20ApprovalGasSponsorValidationResult;
160
+
161
+ /**
162
+ * ERC-20 Approval Gas Sponsoring Extension Client-Side Implementation
163
+ *
164
+ * Provides functions for clients to construct ERC-20 approve() calldata
165
+ * and encode gas sponsor payloads for transmission.
166
+ */
167
+
168
+ /**
169
+ * Extension key for ERC-20 approval gas sponsoring in payment requirements.
170
+ */
171
+ declare const ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY = "erc20ApprovalGasSponsoring";
172
+ /**
173
+ * HTTP header name for ERC-20 approval gas sponsor payload.
174
+ */
175
+ declare const ERC20_APPROVAL_GAS_SPONSOR_HEADER_NAME = "X-T402-ERC20-Approval-Gas-Sponsoring";
176
+ /**
177
+ * ERC-20 approve(address,uint256) function selector.
178
+ */
179
+ declare const APPROVE_FUNCTION_SELECTOR = "0x095ea7b3";
180
+ /**
181
+ * Encodes ERC-20 approve(address spender, uint256 amount) calldata.
182
+ *
183
+ * @param spender - The spender address to approve
184
+ * @param amount - The approval amount in base units
185
+ * @returns Hex-encoded calldata with 0x prefix
186
+ *
187
+ * @example
188
+ * ```typescript
189
+ * const calldata = encodeApproveCalldata("0xFacilitator...", "1000000");
190
+ * // Returns "0x095ea7b3" + abi-encoded args
191
+ * ```
192
+ */
193
+ declare function encodeApproveCalldata(spender: string, amount: string): string;
194
+ /**
195
+ * Creates an ERC-20 approval gas sponsor payload from params and extension info.
196
+ *
197
+ * @param info - The server's extension info
198
+ * @param params - The approval parameters
199
+ * @returns Gas sponsor payload ready for header encoding
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * const payload = createERC20ApprovalGasSponsorPayload(extensionInfo, {
204
+ * network: "eip155:8453",
205
+ * from: wallet.address,
206
+ * asset: "0xUSDT...",
207
+ * amount: "1000000",
208
+ * signedApprovalTx: signedTx,
209
+ * chainId: 8453,
210
+ * });
211
+ * ```
212
+ */
213
+ declare function createERC20ApprovalGasSponsorPayload(_info: ERC20ApprovalGasSponsorExtensionInfo, params: CreateERC20ApprovalParams): ERC20ApprovalGasSponsorPayload;
214
+ /**
215
+ * Encodes an ERC-20 approval gas sponsor payload for transmission in HTTP header.
216
+ *
217
+ * @param payload - The gas sponsor payload to encode
218
+ * @returns Base64-encoded JSON string
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * const header = encodeERC20ApprovalGasSponsorHeader(payload);
223
+ * fetch(url, {
224
+ * headers: { [ERC20_APPROVAL_GAS_SPONSOR_HEADER_NAME]: header }
225
+ * });
226
+ * ```
227
+ */
228
+ declare function encodeERC20ApprovalGasSponsorHeader(payload: ERC20ApprovalGasSponsorPayload): string;
229
+
230
+ /**
231
+ * ERC-20 Approval Gas Sponsoring Extension Facilitator-Side Implementation
232
+ *
233
+ * Provides functions for facilitators to extract approval data from payment
234
+ * extensions, validate the signed approve() transaction, and prepare for
235
+ * on-chain submission.
236
+ */
237
+
238
+ /**
239
+ * Extracts the ERC-20 approval gas sponsor payload from payment extensions.
240
+ *
241
+ * @param extensions - The extensions map from a PaymentPayload
242
+ * @returns The gas sponsor payload if present, or null
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * const approval = extractERC20ApprovalGasSponsorPayload(paymentPayload.extensions);
247
+ * if (approval) {
248
+ * // Validate and broadcast the approval tx, then settle
249
+ * }
250
+ * ```
251
+ */
252
+ declare function extractERC20ApprovalGasSponsorPayload(extensions: Record<string, unknown> | undefined): ERC20ApprovalGasSponsorPayload | null;
253
+ /**
254
+ * Processes and validates an ERC-20 approval payload for the facilitator.
255
+ *
256
+ * Combines extraction validation with approve() function selector verification.
257
+ * Checks that the signed transaction data contains the correct approve() selector
258
+ * and that the approval amount matches the declared amount.
259
+ *
260
+ * @param payload - The ERC-20 approval gas sponsor payload
261
+ * @param extensionInfo - The server's gas sponsor extension info
262
+ * @returns Validation result
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * const result = processERC20ApprovalPayload(payload, extensionInfo);
267
+ * if (result.valid) {
268
+ * // Safe to broadcast the approval tx and settle
269
+ * }
270
+ * ```
271
+ */
272
+ declare function processERC20ApprovalPayload(payload: ERC20ApprovalGasSponsorPayload, extensionInfo: ERC20ApprovalGasSponsorExtensionInfo): ERC20ApprovalGasSponsorValidationResult;
273
+ /**
274
+ * Validates and extracts the ERC-20 approval gas sponsor payload in one step.
275
+ *
276
+ * This is a convenience function for facilitators that combines extraction
277
+ * and validation against the server's extension info.
278
+ *
279
+ * @param extensions - The extensions map from a PaymentPayload
280
+ * @param extensionInfo - The server's gas sponsor extension info
281
+ * @returns Validation result with the extracted payload if valid
282
+ *
283
+ * @example
284
+ * ```typescript
285
+ * const result = validateAndExtractApproval(
286
+ * paymentPayload.extensions,
287
+ * extensionInfo
288
+ * );
289
+ * if (result.valid && result.payload) {
290
+ * // Broadcast approval tx, then settle
291
+ * }
292
+ * ```
293
+ */
294
+ declare function validateAndExtractApproval(extensions: Record<string, unknown> | undefined, extensionInfo: ERC20ApprovalGasSponsorExtensionInfo): ERC20ApprovalGasSponsorValidationResult & {
295
+ payload?: ERC20ApprovalGasSponsorPayload;
296
+ };
297
+ /**
298
+ * Decodes the approve() calldata from a hex string to extract spender and amount.
299
+ *
300
+ * @param calldata - Hex-encoded approve() calldata (with or without 0x prefix)
301
+ * @returns Decoded spender and amount, or null if not valid approve() calldata
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * const decoded = decodeApproveCalldata("0x095ea7b3...");
306
+ * if (decoded) {
307
+ * console.log(decoded.spender, decoded.amount);
308
+ * }
309
+ * ```
310
+ */
311
+ declare function decodeApproveCalldata(calldata: string): {
312
+ spender: string;
313
+ amount: string;
314
+ } | null;
315
+
316
+ export { APPROVE_FUNCTION_SELECTOR, type CreateERC20ApprovalParams, type DeclareERC20ApprovalGasSponsorOptions, type ERC20ApprovalGasSponsorExtension, type ERC20ApprovalGasSponsorExtensionInfo, type ERC20ApprovalGasSponsorPayload, type ERC20ApprovalGasSponsorValidationResult, ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY, ERC20_APPROVAL_GAS_SPONSOR_HEADER_NAME, type ValidateERC20ApprovalGasSponsorOptions, createERC20ApprovalGasSponsorPayload, declareERC20ApprovalGasSponsorExtension, decodeApproveCalldata, encodeApproveCalldata, encodeERC20ApprovalGasSponsorHeader, extractERC20ApprovalGasSponsorPayload, parseERC20ApprovalGasSponsorHeader, processERC20ApprovalPayload, validateAndExtractApproval, validateERC20ApprovalGasSponsorPayload };
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/erc20-approval-gas-sponsoring/index.ts
21
+ var erc20_approval_gas_sponsoring_exports = {};
22
+ __export(erc20_approval_gas_sponsoring_exports, {
23
+ APPROVE_FUNCTION_SELECTOR: () => APPROVE_FUNCTION_SELECTOR,
24
+ ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY: () => ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY,
25
+ ERC20_APPROVAL_GAS_SPONSOR_HEADER_NAME: () => ERC20_APPROVAL_GAS_SPONSOR_HEADER_NAME,
26
+ createERC20ApprovalGasSponsorPayload: () => createERC20ApprovalGasSponsorPayload,
27
+ declareERC20ApprovalGasSponsorExtension: () => declareERC20ApprovalGasSponsorExtension,
28
+ decodeApproveCalldata: () => decodeApproveCalldata,
29
+ encodeApproveCalldata: () => encodeApproveCalldata,
30
+ encodeERC20ApprovalGasSponsorHeader: () => encodeERC20ApprovalGasSponsorHeader,
31
+ extractERC20ApprovalGasSponsorPayload: () => extractERC20ApprovalGasSponsorPayload,
32
+ parseERC20ApprovalGasSponsorHeader: () => parseERC20ApprovalGasSponsorHeader,
33
+ processERC20ApprovalPayload: () => processERC20ApprovalPayload,
34
+ validateAndExtractApproval: () => validateAndExtractApproval,
35
+ validateERC20ApprovalGasSponsorPayload: () => validateERC20ApprovalGasSponsorPayload
36
+ });
37
+ module.exports = __toCommonJS(erc20_approval_gas_sponsoring_exports);
38
+
39
+ // src/erc20-approval-gas-sponsoring/server.ts
40
+ var ERC20_APPROVAL_GAS_SPONSOR_SCHEMA = {
41
+ type: "object",
42
+ required: ["network", "from", "asset", "amount", "signedApprovalTx", "chainId"],
43
+ properties: {
44
+ network: { type: "string" },
45
+ from: { type: "string" },
46
+ asset: { type: "string" },
47
+ amount: { type: "string" },
48
+ signedApprovalTx: { type: "string" },
49
+ chainId: { type: "number" },
50
+ nonce: { type: "number" }
51
+ }
52
+ };
53
+ function declareERC20ApprovalGasSponsorExtension(options) {
54
+ const info = {
55
+ sponsoredNetworks: options.sponsoredNetworks,
56
+ maxAmount: options.maxAmount,
57
+ sponsorAddress: options.sponsorAddress,
58
+ requiresAtomicBatch: options.requiresAtomicBatch ?? false
59
+ };
60
+ if (options.permit2Address) {
61
+ info.permit2Address = options.permit2Address;
62
+ }
63
+ return {
64
+ info,
65
+ schema: ERC20_APPROVAL_GAS_SPONSOR_SCHEMA
66
+ };
67
+ }
68
+ function parseERC20ApprovalGasSponsorHeader(header) {
69
+ if (!header) {
70
+ throw new Error("Missing ERC-20 approval gas sponsor header");
71
+ }
72
+ try {
73
+ const decoded = Buffer.from(header, "base64").toString("utf-8");
74
+ const payload = JSON.parse(decoded);
75
+ const required = ["network", "from", "asset", "amount", "signedApprovalTx", "chainId"];
76
+ for (const field of required) {
77
+ if (!(field in payload)) {
78
+ throw new Error(`Missing required field: ${field}`);
79
+ }
80
+ }
81
+ return payload;
82
+ } catch (error) {
83
+ if (error instanceof SyntaxError) {
84
+ throw new Error("Invalid ERC-20 approval gas sponsor header: malformed JSON");
85
+ }
86
+ throw error;
87
+ }
88
+ }
89
+ function validateERC20ApprovalGasSponsorPayload(payload, extensionInfo, options = {}) {
90
+ if (!extensionInfo.sponsoredNetworks.includes(payload.network)) {
91
+ return {
92
+ valid: false,
93
+ error: `Network ${payload.network} is not in sponsored networks: ${extensionInfo.sponsoredNetworks.join(", ")}`
94
+ };
95
+ }
96
+ const payloadAmount = BigInt(payload.amount);
97
+ const maxAmount = BigInt(extensionInfo.maxAmount);
98
+ if (payloadAmount > maxAmount) {
99
+ return {
100
+ valid: false,
101
+ error: `Amount ${payload.amount} exceeds maximum amount ${extensionInfo.maxAmount}`
102
+ };
103
+ }
104
+ if (options.expectedChainIds) {
105
+ const expectedChainId = options.expectedChainIds[payload.network];
106
+ if (expectedChainId !== void 0 && payload.chainId !== expectedChainId) {
107
+ return {
108
+ valid: false,
109
+ error: `Chain ID ${payload.chainId} does not match expected chain ID ${expectedChainId} for network ${payload.network}`
110
+ };
111
+ }
112
+ }
113
+ const txHex = payload.signedApprovalTx.startsWith("0x") ? payload.signedApprovalTx.slice(2) : payload.signedApprovalTx;
114
+ if (txHex.length === 0) {
115
+ return {
116
+ valid: false,
117
+ error: "Signed approval transaction is empty"
118
+ };
119
+ }
120
+ if (!/^[0-9a-fA-F]+$/.test(txHex)) {
121
+ return {
122
+ valid: false,
123
+ error: "Signed approval transaction is not valid hex"
124
+ };
125
+ }
126
+ const fromHex = payload.from.startsWith("0x") ? payload.from.slice(2) : payload.from;
127
+ if (fromHex.length !== 40 || !/^[0-9a-fA-F]+$/.test(fromHex)) {
128
+ return {
129
+ valid: false,
130
+ error: `Invalid from address: ${payload.from}`
131
+ };
132
+ }
133
+ const assetHex = payload.asset.startsWith("0x") ? payload.asset.slice(2) : payload.asset;
134
+ if (assetHex.length !== 40 || !/^[0-9a-fA-F]+$/.test(assetHex)) {
135
+ return {
136
+ valid: false,
137
+ error: `Invalid asset address: ${payload.asset}`
138
+ };
139
+ }
140
+ return { valid: true };
141
+ }
142
+
143
+ // src/erc20-approval-gas-sponsoring/client.ts
144
+ var ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY = "erc20ApprovalGasSponsoring";
145
+ var ERC20_APPROVAL_GAS_SPONSOR_HEADER_NAME = "X-T402-ERC20-Approval-Gas-Sponsoring";
146
+ var APPROVE_FUNCTION_SELECTOR = "0x095ea7b3";
147
+ function encodeApproveCalldata(spender, amount) {
148
+ const spenderHex = spender.startsWith("0x") ? spender.slice(2) : spender;
149
+ const paddedSpender = spenderHex.toLowerCase().padStart(64, "0");
150
+ const amountBigInt = BigInt(amount);
151
+ const amountHex = amountBigInt.toString(16).padStart(64, "0");
152
+ return APPROVE_FUNCTION_SELECTOR + paddedSpender + amountHex;
153
+ }
154
+ function createERC20ApprovalGasSponsorPayload(_info, params) {
155
+ const payload = {
156
+ network: params.network,
157
+ from: params.from,
158
+ asset: params.asset,
159
+ amount: params.amount,
160
+ signedApprovalTx: params.signedApprovalTx.startsWith("0x") ? params.signedApprovalTx : "0x" + params.signedApprovalTx,
161
+ chainId: params.chainId
162
+ };
163
+ if (params.nonce !== void 0) {
164
+ payload.nonce = params.nonce;
165
+ }
166
+ return payload;
167
+ }
168
+ function encodeERC20ApprovalGasSponsorHeader(payload) {
169
+ const json = JSON.stringify(payload);
170
+ if (typeof Buffer !== "undefined") {
171
+ return Buffer.from(json, "utf-8").toString("base64");
172
+ }
173
+ return btoa(json);
174
+ }
175
+
176
+ // src/erc20-approval-gas-sponsoring/facilitator.ts
177
+ function extractERC20ApprovalGasSponsorPayload(extensions) {
178
+ if (!extensions) {
179
+ return null;
180
+ }
181
+ const raw = extensions[ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY];
182
+ if (!raw || typeof raw !== "object") {
183
+ return null;
184
+ }
185
+ const payload = raw;
186
+ const required = ["network", "from", "asset", "amount", "signedApprovalTx", "chainId"];
187
+ for (const field of required) {
188
+ if (!(field in payload)) {
189
+ return null;
190
+ }
191
+ }
192
+ const result = {
193
+ network: payload.network,
194
+ from: payload.from,
195
+ asset: payload.asset,
196
+ amount: payload.amount,
197
+ signedApprovalTx: payload.signedApprovalTx,
198
+ chainId: payload.chainId
199
+ };
200
+ if ("nonce" in payload && payload.nonce !== void 0) {
201
+ result.nonce = payload.nonce;
202
+ }
203
+ return result;
204
+ }
205
+ function processERC20ApprovalPayload(payload, extensionInfo) {
206
+ const validationResult = validateERC20ApprovalGasSponsorPayload(payload, extensionInfo);
207
+ if (!validationResult.valid) {
208
+ return validationResult;
209
+ }
210
+ const txHex = payload.signedApprovalTx.startsWith("0x") ? payload.signedApprovalTx.slice(2) : payload.signedApprovalTx;
211
+ if (txHex.length < 8) {
212
+ return {
213
+ valid: false,
214
+ error: "Signed approval transaction is too short to contain function selector"
215
+ };
216
+ }
217
+ return { valid: true };
218
+ }
219
+ function validateAndExtractApproval(extensions, extensionInfo) {
220
+ const payload = extractERC20ApprovalGasSponsorPayload(extensions);
221
+ if (!payload) {
222
+ return {
223
+ valid: false,
224
+ error: `Missing or invalid ${ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY} extension in payment`
225
+ };
226
+ }
227
+ const result = processERC20ApprovalPayload(payload, extensionInfo);
228
+ if (!result.valid) {
229
+ return result;
230
+ }
231
+ return { valid: true, payload };
232
+ }
233
+ function decodeApproveCalldata(calldata) {
234
+ const hex = calldata.startsWith("0x") ? calldata.slice(2) : calldata;
235
+ if (hex.length < 136) {
236
+ return null;
237
+ }
238
+ const selector = "0x" + hex.slice(0, 8);
239
+ if (selector !== APPROVE_FUNCTION_SELECTOR) {
240
+ return null;
241
+ }
242
+ const spenderWord = hex.slice(8, 72);
243
+ const spender = "0x" + spenderWord.slice(24);
244
+ const amountHex = hex.slice(72, 136);
245
+ const amount = BigInt("0x" + amountHex).toString(10);
246
+ return { spender, amount };
247
+ }
248
+ // Annotate the CommonJS export names for ESM import in node:
249
+ 0 && (module.exports = {
250
+ APPROVE_FUNCTION_SELECTOR,
251
+ ERC20_APPROVAL_GAS_SPONSOR_EXTENSION_KEY,
252
+ ERC20_APPROVAL_GAS_SPONSOR_HEADER_NAME,
253
+ createERC20ApprovalGasSponsorPayload,
254
+ declareERC20ApprovalGasSponsorExtension,
255
+ decodeApproveCalldata,
256
+ encodeApproveCalldata,
257
+ encodeERC20ApprovalGasSponsorHeader,
258
+ extractERC20ApprovalGasSponsorPayload,
259
+ parseERC20ApprovalGasSponsorHeader,
260
+ processERC20ApprovalPayload,
261
+ validateAndExtractApproval,
262
+ validateERC20ApprovalGasSponsorPayload
263
+ });
264
+ //# sourceMappingURL=index.js.map