@x402/extensions 2.4.0 → 2.5.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.
@@ -48,7 +48,7 @@ import {
48
48
  verifySIWxSignature,
49
49
  verifySolanaSignature,
50
50
  wrapFetchWithSIWx
51
- } from "./chunk-IASAX5HM.mjs";
51
+ } from "./chunk-O34SGKEP.mjs";
52
52
  import {
53
53
  PAYMENT_IDENTIFIER,
54
54
  PAYMENT_ID_MAX_LENGTH,
@@ -155,9 +155,99 @@ function validateEip2612GasSponsoringInfo(info) {
155
155
  const versionPattern = /^[0-9]+(\.[0-9]+)*$/;
156
156
  return addressPattern.test(info.from) && addressPattern.test(info.asset) && addressPattern.test(info.spender) && numericPattern.test(info.amount) && numericPattern.test(info.nonce) && numericPattern.test(info.deadline) && hexPattern.test(info.signature) && versionPattern.test(info.version);
157
157
  }
158
+
159
+ // src/erc20-approval-gas-sponsoring/types.ts
160
+ var ERC20_APPROVAL_GAS_SPONSORING = {
161
+ key: "erc20ApprovalGasSponsoring"
162
+ };
163
+ var ERC20_APPROVAL_GAS_SPONSORING_VERSION = "1";
164
+ function createErc20ApprovalGasSponsoringExtension(signer, client) {
165
+ return {
166
+ ...ERC20_APPROVAL_GAS_SPONSORING,
167
+ signer: {
168
+ ...signer,
169
+ sendRawTransaction: client.sendRawTransaction.bind(client)
170
+ }
171
+ };
172
+ }
173
+
174
+ // src/erc20-approval-gas-sponsoring/resourceService.ts
175
+ var erc20ApprovalGasSponsoringSchema = {
176
+ $schema: "https://json-schema.org/draft/2020-12/schema",
177
+ type: "object",
178
+ properties: {
179
+ from: {
180
+ type: "string",
181
+ pattern: "^0x[a-fA-F0-9]{40}$",
182
+ description: "The address of the sender (token owner)."
183
+ },
184
+ asset: {
185
+ type: "string",
186
+ pattern: "^0x[a-fA-F0-9]{40}$",
187
+ description: "The address of the ERC-20 token contract."
188
+ },
189
+ spender: {
190
+ type: "string",
191
+ pattern: "^0x[a-fA-F0-9]{40}$",
192
+ description: "The address of the spender (Canonical Permit2)."
193
+ },
194
+ amount: {
195
+ type: "string",
196
+ pattern: "^[0-9]+$",
197
+ description: "The amount approved (uint256). Always MaxUint256."
198
+ },
199
+ signedTransaction: {
200
+ type: "string",
201
+ pattern: "^0x[a-fA-F0-9]+$",
202
+ description: "The RLP-encoded signed EIP-1559 transaction as a hex string."
203
+ },
204
+ version: {
205
+ type: "string",
206
+ pattern: "^[0-9]+(\\.[0-9]+)*$",
207
+ description: "Schema version identifier."
208
+ }
209
+ },
210
+ required: ["from", "asset", "spender", "amount", "signedTransaction", "version"]
211
+ };
212
+ function declareErc20ApprovalGasSponsoringExtension() {
213
+ const key = ERC20_APPROVAL_GAS_SPONSORING.key;
214
+ return {
215
+ [key]: {
216
+ info: {
217
+ description: "The facilitator broadcasts a pre-signed ERC-20 approve() transaction to grant Permit2 allowance.",
218
+ version: ERC20_APPROVAL_GAS_SPONSORING_VERSION
219
+ },
220
+ schema: erc20ApprovalGasSponsoringSchema
221
+ }
222
+ };
223
+ }
224
+
225
+ // src/erc20-approval-gas-sponsoring/facilitator.ts
226
+ import Ajv from "ajv/dist/2020.js";
227
+ function extractErc20ApprovalGasSponsoringInfo(paymentPayload) {
228
+ if (!paymentPayload.extensions) {
229
+ return null;
230
+ }
231
+ const extension = paymentPayload.extensions[ERC20_APPROVAL_GAS_SPONSORING.key];
232
+ if (!extension?.info) {
233
+ return null;
234
+ }
235
+ const info = extension.info;
236
+ if (!info.from || !info.asset || !info.spender || !info.amount || !info.signedTransaction || !info.version) {
237
+ return null;
238
+ }
239
+ return info;
240
+ }
241
+ function validateErc20ApprovalGasSponsoringInfo(info) {
242
+ const ajv = new Ajv({ strict: false, allErrors: true });
243
+ const validate = ajv.compile(erc20ApprovalGasSponsoringSchema);
244
+ return validate(info);
245
+ }
158
246
  export {
159
247
  BAZAAR,
160
248
  EIP2612_GAS_SPONSORING,
249
+ ERC20_APPROVAL_GAS_SPONSORING,
250
+ ERC20_APPROVAL_GAS_SPONSORING_VERSION,
161
251
  InMemorySIWxStorage,
162
252
  PAYMENT_IDENTIFIER,
163
253
  PAYMENT_ID_MAX_LENGTH,
@@ -171,6 +261,7 @@ export {
171
261
  appendPaymentIdentifierToExtensions,
172
262
  bazaarResourceServerExtension,
173
263
  buildSIWxSchema,
264
+ createErc20ApprovalGasSponsoringExtension,
174
265
  createSIWxClientHook,
175
266
  createSIWxMessage,
176
267
  createSIWxPayload,
@@ -178,17 +269,20 @@ export {
178
269
  createSIWxSettleHook,
179
270
  declareDiscoveryExtension,
180
271
  declareEip2612GasSponsoringExtension,
272
+ declareErc20ApprovalGasSponsoringExtension,
181
273
  declarePaymentIdentifierExtension,
182
274
  declareSIWxExtension,
183
275
  decodeBase58,
184
276
  encodeBase58,
185
277
  encodeSIWxHeader,
278
+ erc20ApprovalGasSponsoringSchema,
186
279
  extractAndValidatePaymentIdentifier,
187
280
  extractDiscoveryInfo,
188
281
  extractDiscoveryInfoFromExtension,
189
282
  extractDiscoveryInfoV1,
190
283
  extractEVMChainId,
191
284
  extractEip2612GasSponsoringInfo,
285
+ extractErc20ApprovalGasSponsoringInfo,
192
286
  extractPaymentIdentifier,
193
287
  extractResourceMetadataV1,
194
288
  extractSolanaChainReference,
@@ -216,6 +310,7 @@ export {
216
310
  validateAndExtract,
217
311
  validateDiscoveryExtension,
218
312
  validateEip2612GasSponsoringInfo,
313
+ validateErc20ApprovalGasSponsoringInfo,
219
314
  validatePaymentIdentifier,
220
315
  validatePaymentIdentifierRequirement,
221
316
  validateSIWxMessage,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/eip2612-gas-sponsoring/types.ts","../../src/eip2612-gas-sponsoring/resourceService.ts","../../src/eip2612-gas-sponsoring/facilitator.ts"],"sourcesContent":["/**\n * Type definitions for the EIP-2612 Gas Sponsoring Extension\n *\n * This extension enables gasless approval of the Permit2 contract for tokens\n * that implement EIP-2612. The client signs an off-chain permit, and the\n * facilitator submits it on-chain via `x402Permit2Proxy.settleWithPermit`.\n */\n\nimport type { FacilitatorExtension } from \"@x402/core/types\";\n\n/**\n * Extension identifier for the EIP-2612 gas sponsoring extension.\n */\nexport const EIP2612_GAS_SPONSORING: FacilitatorExtension = { key: \"eip2612GasSponsoring\" };\n\n/**\n * EIP-2612 gas sponsoring info populated by the client.\n *\n * Contains the EIP-2612 permit signature and parameters that the facilitator\n * needs to call `x402Permit2Proxy.settleWithPermit`.\n */\nexport interface Eip2612GasSponsoringInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** The address of the sender (token owner). */\n from: string;\n /** The address of the ERC-20 token contract. */\n asset: string;\n /** The address of the spender (Canonical Permit2). */\n spender: string;\n /** The amount to approve (uint256 as decimal string). Typically MaxUint256. */\n amount: string;\n /** The current EIP-2612 nonce of the sender (decimal string). */\n nonce: string;\n /** The timestamp at which the permit signature expires (decimal string). */\n deadline: string;\n /** The 65-byte concatenated EIP-2612 permit signature (r, s, v) as a hex string. */\n signature: string;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * Server-side EIP-2612 gas sponsoring info included in PaymentRequired.\n * Contains a description and version; the client populates the rest.\n */\nexport interface Eip2612GasSponsoringServerInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** Human-readable description of the extension. */\n description: string;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * The full extension object as it appears in PaymentRequired.extensions\n * and PaymentPayload.extensions.\n */\nexport interface Eip2612GasSponsoringExtension {\n /** Extension info - server-provided or client-enriched. */\n info: Eip2612GasSponsoringServerInfo | Eip2612GasSponsoringInfo;\n /** JSON Schema describing the expected structure of info. */\n schema: Record<string, unknown>;\n}\n","/**\n * Resource Service functions for declaring the EIP-2612 Gas Sponsoring extension.\n *\n * These functions help servers declare support for EIP-2612 gasless Permit2 approvals\n * in the PaymentRequired response extensions.\n */\n\nimport { EIP2612_GAS_SPONSORING, type Eip2612GasSponsoringExtension } from \"./types\";\n\n/**\n * The JSON Schema for the EIP-2612 gas sponsoring extension info.\n * Matches the schema defined in the spec.\n */\nconst eip2612GasSponsoringSchema: Record<string, unknown> = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n from: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the sender.\",\n },\n asset: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the ERC-20 token contract.\",\n },\n spender: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the spender (Canonical Permit2).\",\n },\n amount: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The amount to approve (uint256). Typically MaxUint.\",\n },\n nonce: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The current nonce of the sender.\",\n },\n deadline: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The timestamp at which the signature expires.\",\n },\n signature: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]+$\",\n description: \"The 65-byte concatenated signature (r, s, v) as a hex string.\",\n },\n version: {\n type: \"string\",\n pattern: \"^[0-9]+(\\\\.[0-9]+)*$\",\n description: \"Schema version identifier.\",\n },\n },\n required: [\"from\", \"asset\", \"spender\", \"amount\", \"nonce\", \"deadline\", \"signature\", \"version\"],\n};\n\n/**\n * Declares the EIP-2612 gas sponsoring extension for inclusion in\n * PaymentRequired.extensions.\n *\n * The server advertises that it (or its facilitator) supports EIP-2612\n * gasless Permit2 approval. The client will populate the info with the\n * actual permit signature data.\n *\n * @returns An object keyed by the extension identifier containing the extension declaration\n *\n * @example\n * ```typescript\n * import { declareEip2612GasSponsoringExtension } from '@x402/extensions';\n *\n * const routes = [\n * {\n * path: \"/api/data\",\n * price: \"$0.01\",\n * extensions: {\n * ...declareEip2612GasSponsoringExtension(),\n * },\n * },\n * ];\n * ```\n */\nexport function declareEip2612GasSponsoringExtension(): Record<\n string,\n Eip2612GasSponsoringExtension\n> {\n const key = EIP2612_GAS_SPONSORING.key;\n return {\n [key]: {\n info: {\n description:\n \"The facilitator accepts EIP-2612 gasless Permit to `Permit2` canonical contract.\",\n version: \"1\",\n },\n schema: eip2612GasSponsoringSchema,\n },\n };\n}\n","/**\n * Facilitator functions for extracting and validating EIP-2612 Gas Sponsoring extension data.\n *\n * These functions help facilitators extract the EIP-2612 permit data from payment\n * payloads and validate it before calling settleWithPermit.\n */\n\nimport type { PaymentPayload } from \"@x402/core/types\";\nimport {\n EIP2612_GAS_SPONSORING,\n type Eip2612GasSponsoringInfo,\n type Eip2612GasSponsoringExtension,\n} from \"./types\";\n\n/**\n * Extracts the EIP-2612 gas sponsoring info from a payment payload's extensions.\n *\n * Returns the info if the extension is present and contains the required client-populated\n * fields (from, asset, spender, amount, nonce, deadline, signature, version).\n *\n * @param paymentPayload - The payment payload to extract from\n * @returns The EIP-2612 gas sponsoring info, or null if not present\n */\nexport function extractEip2612GasSponsoringInfo(\n paymentPayload: PaymentPayload,\n): Eip2612GasSponsoringInfo | null {\n if (!paymentPayload.extensions) {\n return null;\n }\n\n const extension = paymentPayload.extensions[EIP2612_GAS_SPONSORING.key] as\n | Eip2612GasSponsoringExtension\n | undefined;\n\n if (!extension?.info) {\n return null;\n }\n\n const info = extension.info as Record<string, unknown>;\n\n // Check that the client has populated the required fields\n if (\n !info.from ||\n !info.asset ||\n !info.spender ||\n !info.amount ||\n !info.nonce ||\n !info.deadline ||\n !info.signature ||\n !info.version\n ) {\n return null;\n }\n\n return info as unknown as Eip2612GasSponsoringInfo;\n}\n\n/**\n * Validates that the EIP-2612 gas sponsoring info has valid format.\n *\n * Performs basic validation on the info fields:\n * - Addresses are valid hex (0x + 40 hex chars)\n * - Amount, nonce, deadline are numeric strings\n * - Signature is a hex string\n * - Version is a numeric version string\n *\n * @param info - The EIP-2612 gas sponsoring info to validate\n * @returns True if the info is valid, false otherwise\n */\nexport function validateEip2612GasSponsoringInfo(info: Eip2612GasSponsoringInfo): boolean {\n const addressPattern = /^0x[a-fA-F0-9]{40}$/;\n const numericPattern = /^[0-9]+$/;\n const hexPattern = /^0x[a-fA-F0-9]+$/;\n const versionPattern = /^[0-9]+(\\.[0-9]+)*$/;\n\n return (\n addressPattern.test(info.from) &&\n addressPattern.test(info.asset) &&\n addressPattern.test(info.spender) &&\n numericPattern.test(info.amount) &&\n numericPattern.test(info.nonce) &&\n numericPattern.test(info.deadline) &&\n hexPattern.test(info.signature) &&\n versionPattern.test(info.version)\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaO,IAAM,yBAA+C,EAAE,KAAK,uBAAuB;;;ACA1F,IAAM,6BAAsD;AAAA,EAC1D,SAAS;AAAA,EACT,MAAM;AAAA,EACN,YAAY;AAAA,IACV,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,WAAW;AAAA,MACT,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,UAAU,CAAC,QAAQ,SAAS,WAAW,UAAU,SAAS,YAAY,aAAa,SAAS;AAC9F;AA2BO,SAAS,uCAGd;AACA,QAAM,MAAM,uBAAuB;AACnC,SAAO;AAAA,IACL,CAAC,GAAG,GAAG;AAAA,MACL,MAAM;AAAA,QACJ,aACE;AAAA,QACF,SAAS;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF;;;AC9EO,SAAS,gCACd,gBACiC;AACjC,MAAI,CAAC,eAAe,YAAY;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,eAAe,WAAW,uBAAuB,GAAG;AAItE,MAAI,CAAC,WAAW,MAAM;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,UAAU;AAGvB,MACE,CAAC,KAAK,QACN,CAAC,KAAK,SACN,CAAC,KAAK,WACN,CAAC,KAAK,UACN,CAAC,KAAK,SACN,CAAC,KAAK,YACN,CAAC,KAAK,aACN,CAAC,KAAK,SACN;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAcO,SAAS,iCAAiC,MAAyC;AACxF,QAAM,iBAAiB;AACvB,QAAM,iBAAiB;AACvB,QAAM,aAAa;AACnB,QAAM,iBAAiB;AAEvB,SACE,eAAe,KAAK,KAAK,IAAI,KAC7B,eAAe,KAAK,KAAK,KAAK,KAC9B,eAAe,KAAK,KAAK,OAAO,KAChC,eAAe,KAAK,KAAK,MAAM,KAC/B,eAAe,KAAK,KAAK,KAAK,KAC9B,eAAe,KAAK,KAAK,QAAQ,KACjC,WAAW,KAAK,KAAK,SAAS,KAC9B,eAAe,KAAK,KAAK,OAAO;AAEpC;","names":[]}
1
+ {"version":3,"sources":["../../src/eip2612-gas-sponsoring/types.ts","../../src/eip2612-gas-sponsoring/resourceService.ts","../../src/eip2612-gas-sponsoring/facilitator.ts","../../src/erc20-approval-gas-sponsoring/types.ts","../../src/erc20-approval-gas-sponsoring/resourceService.ts","../../src/erc20-approval-gas-sponsoring/facilitator.ts"],"sourcesContent":["/**\n * Type definitions for the EIP-2612 Gas Sponsoring Extension\n *\n * This extension enables gasless approval of the Permit2 contract for tokens\n * that implement EIP-2612. The client signs an off-chain permit, and the\n * facilitator submits it on-chain via `x402Permit2Proxy.settleWithPermit`.\n */\n\nimport type { FacilitatorExtension } from \"@x402/core/types\";\n\n/**\n * Extension identifier for the EIP-2612 gas sponsoring extension.\n */\nexport const EIP2612_GAS_SPONSORING: FacilitatorExtension = { key: \"eip2612GasSponsoring\" };\n\n/**\n * EIP-2612 gas sponsoring info populated by the client.\n *\n * Contains the EIP-2612 permit signature and parameters that the facilitator\n * needs to call `x402Permit2Proxy.settleWithPermit`.\n */\nexport interface Eip2612GasSponsoringInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** The address of the sender (token owner). */\n from: string;\n /** The address of the ERC-20 token contract. */\n asset: string;\n /** The address of the spender (Canonical Permit2). */\n spender: string;\n /** The amount to approve (uint256 as decimal string). Typically MaxUint256. */\n amount: string;\n /** The current EIP-2612 nonce of the sender (decimal string). */\n nonce: string;\n /** The timestamp at which the permit signature expires (decimal string). */\n deadline: string;\n /** The 65-byte concatenated EIP-2612 permit signature (r, s, v) as a hex string. */\n signature: string;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * Server-side EIP-2612 gas sponsoring info included in PaymentRequired.\n * Contains a description and version; the client populates the rest.\n */\nexport interface Eip2612GasSponsoringServerInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** Human-readable description of the extension. */\n description: string;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * The full extension object as it appears in PaymentRequired.extensions\n * and PaymentPayload.extensions.\n */\nexport interface Eip2612GasSponsoringExtension {\n /** Extension info - server-provided or client-enriched. */\n info: Eip2612GasSponsoringServerInfo | Eip2612GasSponsoringInfo;\n /** JSON Schema describing the expected structure of info. */\n schema: Record<string, unknown>;\n}\n","/**\n * Resource Service functions for declaring the EIP-2612 Gas Sponsoring extension.\n *\n * These functions help servers declare support for EIP-2612 gasless Permit2 approvals\n * in the PaymentRequired response extensions.\n */\n\nimport { EIP2612_GAS_SPONSORING, type Eip2612GasSponsoringExtension } from \"./types\";\n\n/**\n * The JSON Schema for the EIP-2612 gas sponsoring extension info.\n * Matches the schema defined in the spec.\n */\nconst eip2612GasSponsoringSchema: Record<string, unknown> = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n from: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the sender.\",\n },\n asset: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the ERC-20 token contract.\",\n },\n spender: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the spender (Canonical Permit2).\",\n },\n amount: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The amount to approve (uint256). Typically MaxUint.\",\n },\n nonce: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The current nonce of the sender.\",\n },\n deadline: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The timestamp at which the signature expires.\",\n },\n signature: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]+$\",\n description: \"The 65-byte concatenated signature (r, s, v) as a hex string.\",\n },\n version: {\n type: \"string\",\n pattern: \"^[0-9]+(\\\\.[0-9]+)*$\",\n description: \"Schema version identifier.\",\n },\n },\n required: [\"from\", \"asset\", \"spender\", \"amount\", \"nonce\", \"deadline\", \"signature\", \"version\"],\n};\n\n/**\n * Declares the EIP-2612 gas sponsoring extension for inclusion in\n * PaymentRequired.extensions.\n *\n * The server advertises that it (or its facilitator) supports EIP-2612\n * gasless Permit2 approval. The client will populate the info with the\n * actual permit signature data.\n *\n * @returns An object keyed by the extension identifier containing the extension declaration\n *\n * @example\n * ```typescript\n * import { declareEip2612GasSponsoringExtension } from '@x402/extensions';\n *\n * const routes = [\n * {\n * path: \"/api/data\",\n * price: \"$0.01\",\n * extensions: {\n * ...declareEip2612GasSponsoringExtension(),\n * },\n * },\n * ];\n * ```\n */\nexport function declareEip2612GasSponsoringExtension(): Record<\n string,\n Eip2612GasSponsoringExtension\n> {\n const key = EIP2612_GAS_SPONSORING.key;\n return {\n [key]: {\n info: {\n description:\n \"The facilitator accepts EIP-2612 gasless Permit to `Permit2` canonical contract.\",\n version: \"1\",\n },\n schema: eip2612GasSponsoringSchema,\n },\n };\n}\n","/**\n * Facilitator functions for extracting and validating EIP-2612 Gas Sponsoring extension data.\n *\n * These functions help facilitators extract the EIP-2612 permit data from payment\n * payloads and validate it before calling settleWithPermit.\n */\n\nimport type { PaymentPayload } from \"@x402/core/types\";\nimport {\n EIP2612_GAS_SPONSORING,\n type Eip2612GasSponsoringInfo,\n type Eip2612GasSponsoringExtension,\n} from \"./types\";\n\n/**\n * Extracts the EIP-2612 gas sponsoring info from a payment payload's extensions.\n *\n * Returns the info if the extension is present and contains the required client-populated\n * fields (from, asset, spender, amount, nonce, deadline, signature, version).\n *\n * @param paymentPayload - The payment payload to extract from\n * @returns The EIP-2612 gas sponsoring info, or null if not present\n */\nexport function extractEip2612GasSponsoringInfo(\n paymentPayload: PaymentPayload,\n): Eip2612GasSponsoringInfo | null {\n if (!paymentPayload.extensions) {\n return null;\n }\n\n const extension = paymentPayload.extensions[EIP2612_GAS_SPONSORING.key] as\n | Eip2612GasSponsoringExtension\n | undefined;\n\n if (!extension?.info) {\n return null;\n }\n\n const info = extension.info as Record<string, unknown>;\n\n // Check that the client has populated the required fields\n if (\n !info.from ||\n !info.asset ||\n !info.spender ||\n !info.amount ||\n !info.nonce ||\n !info.deadline ||\n !info.signature ||\n !info.version\n ) {\n return null;\n }\n\n return info as unknown as Eip2612GasSponsoringInfo;\n}\n\n/**\n * Validates that the EIP-2612 gas sponsoring info has valid format.\n *\n * Performs basic validation on the info fields:\n * - Addresses are valid hex (0x + 40 hex chars)\n * - Amount, nonce, deadline are numeric strings\n * - Signature is a hex string\n * - Version is a numeric version string\n *\n * @param info - The EIP-2612 gas sponsoring info to validate\n * @returns True if the info is valid, false otherwise\n */\nexport function validateEip2612GasSponsoringInfo(info: Eip2612GasSponsoringInfo): boolean {\n const addressPattern = /^0x[a-fA-F0-9]{40}$/;\n const numericPattern = /^[0-9]+$/;\n const hexPattern = /^0x[a-fA-F0-9]+$/;\n const versionPattern = /^[0-9]+(\\.[0-9]+)*$/;\n\n return (\n addressPattern.test(info.from) &&\n addressPattern.test(info.asset) &&\n addressPattern.test(info.spender) &&\n numericPattern.test(info.amount) &&\n numericPattern.test(info.nonce) &&\n numericPattern.test(info.deadline) &&\n hexPattern.test(info.signature) &&\n versionPattern.test(info.version)\n );\n}\n","/**\n * Type definitions for the ERC-20 Approval Gas Sponsoring Extension\n *\n * This extension enables gasless Permit2 approval for generic ERC-20 tokens\n * that do NOT implement EIP-2612. The client signs (but does not broadcast) a\n * raw `approve(Permit2, MaxUint256)` transaction, and the facilitator broadcasts\n * it atomically before settling the Permit2 payment.\n */\n\nimport type { FacilitatorExtension } from \"@x402/core/types\";\n\n/**\n * Signer capability carried by the ERC-20 approval extension when registered in a facilitator.\n *\n * Mirrors FacilitatorEvmSigner (from @x402/evm) plus `sendRawTransaction`.\n * The extension signer owns the full approve+settle flow: it broadcasts the\n * pre-signed approval transaction AND executes the Permit2 settle call, enabling\n * production implementations to bundle both atomically (e.g., Flashbots, multicall).\n *\n * The method signatures are duplicated here (rather than extending FacilitatorEvmSigner)\n * to avoid a circular dependency between @x402/extensions and @x402/evm.\n */\nexport interface Erc20ApprovalGasSponsoringSigner {\n getAddresses(): readonly `0x${string}`[];\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n verifyTypedData(args: {\n address: `0x${string}`;\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n signature: `0x${string}`;\n }): Promise<boolean>;\n writeContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args: readonly unknown[];\n }): Promise<`0x${string}`>;\n sendTransaction(args: { to: `0x${string}`; data: `0x${string}` }): Promise<`0x${string}`>;\n waitForTransactionReceipt(args: { hash: `0x${string}` }): Promise<{ status: string }>;\n getCode(args: { address: `0x${string}` }): Promise<`0x${string}` | undefined>;\n sendRawTransaction(args: { serializedTransaction: `0x${string}` }): Promise<`0x${string}`>;\n}\n\n/**\n * Extension identifier for the ERC-20 approval gas sponsoring extension.\n */\nexport const ERC20_APPROVAL_GAS_SPONSORING = {\n key: \"erc20ApprovalGasSponsoring\",\n} as const satisfies FacilitatorExtension;\n\n/** Current schema version for the ERC-20 approval gas sponsoring extension info. */\nexport const ERC20_APPROVAL_GAS_SPONSORING_VERSION = \"1\";\n\n/**\n * Extended extension object registered in a facilitator via registerExtension().\n * Carries the signer that owns the full approve+settle flow for ERC-20 tokens\n * that lack EIP-2612. The signer must have all FacilitatorEvmSigner capabilities\n * plus `sendRawTransaction` for broadcasting the pre-signed approval tx.\n *\n * @example\n * ```typescript\n * import { createErc20ApprovalGasSponsoringExtension } from '@x402/extensions';\n *\n * facilitator.registerExtension(\n * createErc20ApprovalGasSponsoringExtension(evmSigner, viemClient),\n * );\n * ```\n */\nexport interface Erc20ApprovalGasSponsoringFacilitatorExtension extends FacilitatorExtension {\n key: \"erc20ApprovalGasSponsoring\";\n /** Signer with broadcast + settle capability. Optional — settlement fails gracefully if absent. */\n signer?: Erc20ApprovalGasSponsoringSigner;\n}\n\n/**\n * Signer input for {@link createErc20ApprovalGasSponsoringExtension}.\n * Matches the FacilitatorEvmSigner shape from @x402/evm (duplicated to avoid circular dep).\n */\nexport type Erc20ApprovalGasSponsoringBaseSigner = Omit<\n Erc20ApprovalGasSponsoringSigner,\n \"sendRawTransaction\"\n>;\n\n/**\n * Create an ERC-20 approval gas sponsoring extension ready to register in a facilitator.\n *\n * @param signer - The EVM facilitator signer (e.g. from `toFacilitatorEvmSigner()`)\n * @param client - Object providing `sendRawTransaction` (e.g. a viem WalletClient)\n * @param client.sendRawTransaction - Broadcasts a signed transaction to the network\n * @returns A fully configured extension to pass to `facilitator.registerExtension()`\n */\nexport function createErc20ApprovalGasSponsoringExtension(\n signer: Erc20ApprovalGasSponsoringBaseSigner,\n client: {\n sendRawTransaction: (args: { serializedTransaction: `0x${string}` }) => Promise<`0x${string}`>;\n },\n): Erc20ApprovalGasSponsoringFacilitatorExtension {\n return {\n ...ERC20_APPROVAL_GAS_SPONSORING,\n signer: {\n ...signer,\n sendRawTransaction: client.sendRawTransaction.bind(client),\n },\n };\n}\n\n/**\n * ERC-20 approval gas sponsoring info populated by the client.\n *\n * Contains the RLP-encoded signed `approve(Permit2, MaxUint256)` transaction\n * that the facilitator broadcasts before settling the Permit2 payment.\n *\n * Note: Unlike EIP-2612, there is no nonce/deadline/signature — instead the\n * entire signed transaction is included as `signedTransaction`.\n */\nexport interface Erc20ApprovalGasSponsoringInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** The address of the sender (token owner who signed the tx). */\n from: `0x${string}`;\n /** The address of the ERC-20 token contract. */\n asset: `0x${string}`;\n /** The address of the spender (Canonical Permit2). */\n spender: `0x${string}`;\n /** The amount approved (uint256 as decimal string). Always MaxUint256. */\n amount: string;\n /** The RLP-encoded signed EIP-1559 transaction as a hex string. */\n signedTransaction: `0x${string}`;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * Server-side ERC-20 approval gas sponsoring info included in PaymentRequired.\n * Contains a description and version; the client populates the rest.\n */\nexport interface Erc20ApprovalGasSponsoringServerInfo {\n /** Index signature for compatibility with Record<string, unknown> */\n [key: string]: unknown;\n /** Human-readable description of the extension. */\n description: string;\n /** Schema version identifier. */\n version: string;\n}\n\n/**\n * The full extension object as it appears in PaymentRequired.extensions\n * and PaymentPayload.extensions.\n */\nexport interface Erc20ApprovalGasSponsoringExtension {\n /** Extension info - server-provided or client-enriched. */\n info: Erc20ApprovalGasSponsoringServerInfo | Erc20ApprovalGasSponsoringInfo;\n /** JSON Schema describing the expected structure of info. */\n schema: Record<string, unknown>;\n}\n","/**\n * Resource Service functions for declaring the ERC-20 Approval Gas Sponsoring extension.\n *\n * These functions help servers declare support for ERC-20 approval gas sponsoring\n * in the PaymentRequired response extensions. Use this for tokens that do NOT\n * implement EIP-2612 (generic ERC-20 tokens).\n */\n\nimport {\n ERC20_APPROVAL_GAS_SPONSORING,\n ERC20_APPROVAL_GAS_SPONSORING_VERSION,\n type Erc20ApprovalGasSponsoringExtension,\n} from \"./types\";\n\n/**\n * The JSON Schema for the ERC-20 approval gas sponsoring extension info.\n * Matches the schema defined in the spec.\n */\nexport const erc20ApprovalGasSponsoringSchema: Record<string, unknown> = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n from: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the sender (token owner).\",\n },\n asset: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the ERC-20 token contract.\",\n },\n spender: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]{40}$\",\n description: \"The address of the spender (Canonical Permit2).\",\n },\n amount: {\n type: \"string\",\n pattern: \"^[0-9]+$\",\n description: \"The amount approved (uint256). Always MaxUint256.\",\n },\n signedTransaction: {\n type: \"string\",\n pattern: \"^0x[a-fA-F0-9]+$\",\n description: \"The RLP-encoded signed EIP-1559 transaction as a hex string.\",\n },\n version: {\n type: \"string\",\n pattern: \"^[0-9]+(\\\\.[0-9]+)*$\",\n description: \"Schema version identifier.\",\n },\n },\n required: [\"from\", \"asset\", \"spender\", \"amount\", \"signedTransaction\", \"version\"],\n};\n\n/**\n * Declares the ERC-20 approval gas sponsoring extension for inclusion in\n * PaymentRequired.extensions.\n *\n * The server advertises that it (or its facilitator) supports broadcasting\n * a pre-signed `approve(Permit2, MaxUint256)` transaction on the client's behalf.\n * Use this for tokens that do NOT implement EIP-2612.\n *\n * @returns An object keyed by the extension identifier containing the extension declaration\n *\n * @example\n * ```typescript\n * import { declareErc20ApprovalGasSponsoringExtension } from '@x402/extensions';\n *\n * const routes = [\n * {\n * path: \"/api/data\",\n * price: { amount: \"1000\", asset: \"0x...\", extra: { assetTransferMethod: \"permit2\" } },\n * extensions: {\n * ...declareErc20ApprovalGasSponsoringExtension(),\n * },\n * },\n * ];\n * ```\n */\nexport function declareErc20ApprovalGasSponsoringExtension(): Record<\n string,\n Erc20ApprovalGasSponsoringExtension\n> {\n const key = ERC20_APPROVAL_GAS_SPONSORING.key;\n return {\n [key]: {\n info: {\n description:\n \"The facilitator broadcasts a pre-signed ERC-20 approve() transaction to grant Permit2 allowance.\",\n version: ERC20_APPROVAL_GAS_SPONSORING_VERSION,\n },\n schema: erc20ApprovalGasSponsoringSchema,\n },\n };\n}\n","/**\n * Facilitator functions for extracting and validating ERC-20 Approval Gas Sponsoring\n * extension data.\n *\n * These functions help facilitators extract the pre-signed approve() transaction\n * from payment payloads and validate it before broadcasting and settling.\n */\n\nimport Ajv from \"ajv/dist/2020.js\";\nimport type { PaymentPayload } from \"@x402/core/types\";\nimport {\n ERC20_APPROVAL_GAS_SPONSORING,\n type Erc20ApprovalGasSponsoringInfo,\n type Erc20ApprovalGasSponsoringExtension,\n} from \"./types\";\nimport { erc20ApprovalGasSponsoringSchema } from \"./resourceService\";\n\n/**\n * Extracts the ERC-20 approval gas sponsoring info from a payment payload's extensions.\n *\n * Performs structural extraction only — checks that the extension is present and\n * contains all required fields. Does NOT validate field formats (use\n * validateErc20ApprovalGasSponsoringInfo for that).\n *\n * @param paymentPayload - The payment payload to extract from\n * @returns The ERC-20 approval gas sponsoring info, or null if not present\n */\nexport function extractErc20ApprovalGasSponsoringInfo(\n paymentPayload: PaymentPayload,\n): Erc20ApprovalGasSponsoringInfo | null {\n if (!paymentPayload.extensions) {\n return null;\n }\n\n const extension = paymentPayload.extensions[ERC20_APPROVAL_GAS_SPONSORING.key] as\n | Erc20ApprovalGasSponsoringExtension\n | undefined;\n\n if (!extension?.info) {\n return null;\n }\n\n const info = extension.info as Record<string, unknown>;\n\n if (\n !info.from ||\n !info.asset ||\n !info.spender ||\n !info.amount ||\n !info.signedTransaction ||\n !info.version\n ) {\n return null;\n }\n\n return info as unknown as Erc20ApprovalGasSponsoringInfo;\n}\n\n/**\n * Validates that the ERC-20 approval gas sponsoring info has valid format.\n *\n * Validates the info against the canonical JSON Schema, checking:\n * - All required fields are present\n * - Addresses are valid hex (0x + 40 hex chars)\n * - Amount is a numeric string\n * - signedTransaction is a hex string\n * - Version is a numeric version string\n *\n * @param info - The ERC-20 approval gas sponsoring info to validate\n * @returns True if the info is valid, false otherwise\n */\nexport function validateErc20ApprovalGasSponsoringInfo(\n info: Erc20ApprovalGasSponsoringInfo,\n): boolean {\n const ajv = new Ajv({ strict: false, allErrors: true });\n const validate = ajv.compile(erc20ApprovalGasSponsoringSchema);\n return validate(info) as boolean;\n}\n"],"mappings":"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","names":[]}
@@ -1030,7 +1030,7 @@ type SIWxHookEvent = {
1030
1030
  declare function createSIWxSettleHook(options: CreateSIWxHookOptions): (ctx: {
1031
1031
  paymentPayload: {
1032
1032
  payload: unknown;
1033
- resource: {
1033
+ resource?: {
1034
1034
  url: string;
1035
1035
  };
1036
1036
  };
@@ -32,7 +32,7 @@ import {
32
32
  verifySIWxSignature,
33
33
  verifySolanaSignature,
34
34
  wrapFetchWithSIWx
35
- } from "../chunk-IASAX5HM.mjs";
35
+ } from "../chunk-O34SGKEP.mjs";
36
36
  export {
37
37
  InMemorySIWxStorage,
38
38
  SIGN_IN_WITH_X,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x402/extensions",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "main": "./dist/cjs/index.js",
5
5
  "module": "./dist/esm/index.js",
6
6
  "types": "./dist/cjs/index.d.ts",
@@ -38,7 +38,7 @@
38
38
  "tweetnacl": "^1.0.3",
39
39
  "viem": "^2.43.5",
40
40
  "zod": "^3.24.2",
41
- "@x402/core": "~2.4.0"
41
+ "@x402/core": "~2.5.0"
42
42
  },
43
43
  "exports": {
44
44
  ".": {