@x402/evm 2.3.1 → 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.
Files changed (51) hide show
  1. package/dist/cjs/exact/client/index.d.ts +2 -2
  2. package/dist/cjs/exact/client/index.js +412 -169
  3. package/dist/cjs/exact/client/index.js.map +1 -1
  4. package/dist/cjs/exact/facilitator/index.d.ts +18 -18
  5. package/dist/cjs/exact/facilitator/index.js +467 -157
  6. package/dist/cjs/exact/facilitator/index.js.map +1 -1
  7. package/dist/cjs/exact/v1/client/index.d.ts +1 -1
  8. package/dist/cjs/exact/v1/client/index.js +17 -18
  9. package/dist/cjs/exact/v1/client/index.js.map +1 -1
  10. package/dist/cjs/exact/v1/facilitator/index.d.ts +1 -1
  11. package/dist/cjs/exact/v1/facilitator/index.js +7 -8
  12. package/dist/cjs/exact/v1/facilitator/index.js.map +1 -1
  13. package/dist/cjs/index.d.ts +3 -390
  14. package/dist/cjs/index.js +363 -110
  15. package/dist/cjs/index.js.map +1 -1
  16. package/dist/cjs/permit2-CQbXqCMC.d.ts +517 -0
  17. package/dist/cjs/signer-DC81R8wQ.d.ts +161 -0
  18. package/dist/cjs/v1/index.d.ts +11 -2
  19. package/dist/cjs/v1/index.js +14 -11
  20. package/dist/cjs/v1/index.js.map +1 -1
  21. package/dist/esm/{chunk-RPL6OFJL.mjs → chunk-7KHQD5KT.mjs} +92 -37
  22. package/dist/esm/chunk-7KHQD5KT.mjs.map +1 -0
  23. package/dist/esm/chunk-GY6X5A3G.mjs +425 -0
  24. package/dist/esm/chunk-GY6X5A3G.mjs.map +1 -0
  25. package/dist/esm/{chunk-PFULIQAE.mjs → chunk-TKN5V2BV.mjs} +1 -1
  26. package/dist/esm/chunk-TKN5V2BV.mjs.map +1 -0
  27. package/dist/esm/exact/client/index.d.mts +2 -2
  28. package/dist/esm/exact/client/index.mjs +4 -3
  29. package/dist/esm/exact/facilitator/index.d.mts +18 -18
  30. package/dist/esm/exact/facilitator/index.mjs +401 -99
  31. package/dist/esm/exact/facilitator/index.mjs.map +1 -1
  32. package/dist/esm/exact/v1/client/index.d.mts +1 -1
  33. package/dist/esm/exact/v1/client/index.mjs +2 -2
  34. package/dist/esm/exact/v1/facilitator/index.d.mts +1 -1
  35. package/dist/esm/exact/v1/facilitator/index.mjs +2 -2
  36. package/dist/esm/index.d.mts +3 -390
  37. package/dist/esm/index.mjs +29 -6
  38. package/dist/esm/index.mjs.map +1 -1
  39. package/dist/esm/permit2-CGOcN7Et.d.mts +517 -0
  40. package/dist/esm/signer-DC81R8wQ.d.mts +161 -0
  41. package/dist/esm/v1/index.d.mts +11 -2
  42. package/dist/esm/v1/index.mjs +6 -4
  43. package/package.json +3 -2
  44. package/dist/cjs/permit2-BYv82va2.d.ts +0 -103
  45. package/dist/cjs/signer-5OVDxViv.d.ts +0 -79
  46. package/dist/esm/chunk-E2YMUI3X.mjs +0 -229
  47. package/dist/esm/chunk-E2YMUI3X.mjs.map +0 -1
  48. package/dist/esm/chunk-PFULIQAE.mjs.map +0 -1
  49. package/dist/esm/chunk-RPL6OFJL.mjs.map +0 -1
  50. package/dist/esm/permit2-BsAoJiWD.d.mts +0 -103
  51. package/dist/esm/signer-5OVDxViv.d.mts +0 -79
@@ -28,8 +28,8 @@ __export(client_exports, {
28
28
  });
29
29
  module.exports = __toCommonJS(client_exports);
30
30
 
31
- // src/exact/client/eip3009.ts
32
- var import_viem4 = require("viem");
31
+ // src/exact/client/scheme.ts
32
+ var import_extensions2 = require("@x402/extensions");
33
33
 
34
34
  // src/constants.ts
35
35
  var authorizationTypes = {
@@ -56,131 +56,72 @@ var permit2WitnessTypes = {
56
56
  ],
57
57
  Witness: [
58
58
  { name: "to", type: "address" },
59
- { name: "validAfter", type: "uint256" },
60
- { name: "extra", type: "bytes" }
59
+ { name: "validAfter", type: "uint256" }
61
60
  ]
62
61
  };
63
- var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
64
- var x402ExactPermit2ProxyAddress = "0x4020615294c913F045dc10f0a5cdEbd86c280001";
65
-
66
- // src/utils.ts
67
- var import_viem3 = require("viem");
68
-
69
- // src/exact/v1/client/scheme.ts
70
- var import_viem = require("viem");
71
- var ExactEvmSchemeV1 = class {
72
- /**
73
- * Creates a new ExactEvmClientV1 instance.
74
- *
75
- * @param signer - The EVM signer for client operations
76
- */
77
- constructor(signer) {
78
- this.signer = signer;
79
- this.scheme = "exact";
62
+ var eip2612PermitTypes = {
63
+ Permit: [
64
+ { name: "owner", type: "address" },
65
+ { name: "spender", type: "address" },
66
+ { name: "value", type: "uint256" },
67
+ { name: "nonce", type: "uint256" },
68
+ { name: "deadline", type: "uint256" }
69
+ ]
70
+ };
71
+ var eip2612NoncesAbi = [
72
+ {
73
+ type: "function",
74
+ name: "nonces",
75
+ inputs: [{ name: "owner", type: "address" }],
76
+ outputs: [{ type: "uint256" }],
77
+ stateMutability: "view"
80
78
  }
81
- /**
82
- * Creates a payment payload for the Exact scheme (V1).
83
- *
84
- * @param x402Version - The x402 protocol version
85
- * @param paymentRequirements - The payment requirements
86
- * @returns Promise resolving to a payment payload
87
- */
88
- async createPaymentPayload(x402Version, paymentRequirements) {
89
- const selectedV1 = paymentRequirements;
90
- const nonce = createNonce();
91
- const now = Math.floor(Date.now() / 1e3);
92
- const authorization = {
93
- from: this.signer.address,
94
- to: (0, import_viem.getAddress)(selectedV1.payTo),
95
- value: selectedV1.maxAmountRequired,
96
- validAfter: (now - 600).toString(),
97
- // 10 minutes before
98
- validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),
99
- nonce
100
- };
101
- const signature = await this.signAuthorization(authorization, selectedV1);
102
- const payload = {
103
- authorization,
104
- signature
105
- };
106
- return {
107
- x402Version,
108
- scheme: selectedV1.scheme,
109
- network: selectedV1.network,
110
- payload
111
- };
79
+ ];
80
+ var erc20ApproveAbi = [
81
+ {
82
+ type: "function",
83
+ name: "approve",
84
+ inputs: [
85
+ { name: "spender", type: "address" },
86
+ { name: "amount", type: "uint256" }
87
+ ],
88
+ outputs: [{ type: "bool" }],
89
+ stateMutability: "nonpayable"
112
90
  }
113
- /**
114
- * Sign the EIP-3009 authorization using EIP-712
115
- *
116
- * @param authorization - The authorization to sign
117
- * @param requirements - The payment requirements
118
- * @returns Promise resolving to the signature
119
- */
120
- async signAuthorization(authorization, requirements) {
121
- const chainId = getEvmChainId(requirements.network);
122
- if (!requirements.extra?.name || !requirements.extra?.version) {
123
- throw new Error(
124
- `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
125
- );
126
- }
127
- const { name, version } = requirements.extra;
128
- const domain = {
129
- name,
130
- version,
131
- chainId,
132
- verifyingContract: (0, import_viem.getAddress)(requirements.asset)
133
- };
134
- const message = {
135
- from: (0, import_viem.getAddress)(authorization.from),
136
- to: (0, import_viem.getAddress)(authorization.to),
137
- value: BigInt(authorization.value),
138
- validAfter: BigInt(authorization.validAfter),
139
- validBefore: BigInt(authorization.validBefore),
140
- nonce: authorization.nonce
141
- };
142
- return await this.signer.signTypedData({
143
- domain,
144
- types: authorizationTypes,
145
- primaryType: "TransferWithAuthorization",
146
- message
147
- });
91
+ ];
92
+ var erc20AllowanceAbi = [
93
+ {
94
+ type: "function",
95
+ name: "allowance",
96
+ inputs: [
97
+ { name: "owner", type: "address" },
98
+ { name: "spender", type: "address" }
99
+ ],
100
+ outputs: [{ type: "uint256" }],
101
+ stateMutability: "view"
148
102
  }
149
- };
150
-
151
- // src/exact/v1/facilitator/scheme.ts
152
- var import_viem2 = require("viem");
103
+ ];
104
+ var ERC20_APPROVE_GAS_LIMIT = 70000n;
105
+ var DEFAULT_MAX_FEE_PER_GAS = 1000000000n;
106
+ var DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100000000n;
107
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
108
+ var x402ExactPermit2ProxyAddress = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
153
109
 
154
- // src/v1/index.ts
155
- var EVM_NETWORK_CHAIN_ID_MAP = {
156
- ethereum: 1,
157
- sepolia: 11155111,
158
- abstract: 2741,
159
- "abstract-testnet": 11124,
160
- "base-sepolia": 84532,
161
- base: 8453,
162
- "avalanche-fuji": 43113,
163
- avalanche: 43114,
164
- iotex: 4689,
165
- sei: 1329,
166
- "sei-testnet": 1328,
167
- polygon: 137,
168
- "polygon-amoy": 80002,
169
- peaq: 3338,
170
- story: 1514,
171
- educhain: 41923,
172
- "skale-base-sepolia": 324705682,
173
- megaeth: 4326
174
- };
175
- var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
110
+ // src/exact/client/scheme.ts
111
+ var import_viem6 = require("viem");
176
112
 
177
113
  // src/utils.ts
114
+ var import_viem = require("viem");
178
115
  function getEvmChainId(network) {
179
- const chainId = EVM_NETWORK_CHAIN_ID_MAP[network];
180
- if (!chainId) {
181
- throw new Error(`Unsupported network: ${network}`);
116
+ if (network.startsWith("eip155:")) {
117
+ const idStr = network.split(":")[1];
118
+ const chainId = parseInt(idStr, 10);
119
+ if (isNaN(chainId)) {
120
+ throw new Error(`Invalid CAIP-2 chain ID: ${network}`);
121
+ }
122
+ return chainId;
182
123
  }
183
- return chainId;
124
+ throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);
184
125
  }
185
126
  function getCrypto() {
186
127
  const cryptoObj = globalThis.crypto;
@@ -190,20 +131,21 @@ function getCrypto() {
190
131
  return cryptoObj;
191
132
  }
192
133
  function createNonce() {
193
- return (0, import_viem3.toHex)(getCrypto().getRandomValues(new Uint8Array(32)));
134
+ return (0, import_viem.toHex)(getCrypto().getRandomValues(new Uint8Array(32)));
194
135
  }
195
136
  function createPermit2Nonce() {
196
137
  const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));
197
- return BigInt((0, import_viem3.toHex)(randomBytes)).toString();
138
+ return BigInt((0, import_viem.toHex)(randomBytes)).toString();
198
139
  }
199
140
 
200
141
  // src/exact/client/eip3009.ts
142
+ var import_viem2 = require("viem");
201
143
  async function createEIP3009Payload(signer, x402Version, paymentRequirements) {
202
144
  const nonce = createNonce();
203
145
  const now = Math.floor(Date.now() / 1e3);
204
146
  const authorization = {
205
147
  from: signer.address,
206
- to: (0, import_viem4.getAddress)(paymentRequirements.payTo),
148
+ to: (0, import_viem2.getAddress)(paymentRequirements.payTo),
207
149
  value: paymentRequirements.amount,
208
150
  validAfter: (now - 600).toString(),
209
151
  validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),
@@ -220,7 +162,7 @@ async function createEIP3009Payload(signer, x402Version, paymentRequirements) {
220
162
  };
221
163
  }
222
164
  async function signEIP3009Authorization(signer, authorization, requirements) {
223
- const chainId = parseInt(requirements.network.split(":")[1]);
165
+ const chainId = getEvmChainId(requirements.network);
224
166
  if (!requirements.extra?.name || !requirements.extra?.version) {
225
167
  throw new Error(
226
168
  `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
@@ -231,11 +173,11 @@ async function signEIP3009Authorization(signer, authorization, requirements) {
231
173
  name,
232
174
  version,
233
175
  chainId,
234
- verifyingContract: (0, import_viem4.getAddress)(requirements.asset)
176
+ verifyingContract: (0, import_viem2.getAddress)(requirements.asset)
235
177
  };
236
178
  const message = {
237
- from: (0, import_viem4.getAddress)(authorization.from),
238
- to: (0, import_viem4.getAddress)(authorization.to),
179
+ from: (0, import_viem2.getAddress)(authorization.from),
180
+ to: (0, import_viem2.getAddress)(authorization.to),
239
181
  value: BigInt(authorization.value),
240
182
  validAfter: BigInt(authorization.validAfter),
241
183
  validBefore: BigInt(authorization.validBefore),
@@ -250,7 +192,7 @@ async function signEIP3009Authorization(signer, authorization, requirements) {
250
192
  }
251
193
 
252
194
  // src/exact/client/permit2.ts
253
- var import_viem5 = require("viem");
195
+ var import_viem3 = require("viem");
254
196
  var MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
255
197
  async function createPermit2Payload(signer, x402Version, paymentRequirements) {
256
198
  const now = Math.floor(Date.now() / 1e3);
@@ -260,16 +202,15 @@ async function createPermit2Payload(signer, x402Version, paymentRequirements) {
260
202
  const permit2Authorization = {
261
203
  from: signer.address,
262
204
  permitted: {
263
- token: (0, import_viem5.getAddress)(paymentRequirements.asset),
205
+ token: (0, import_viem3.getAddress)(paymentRequirements.asset),
264
206
  amount: paymentRequirements.amount
265
207
  },
266
208
  spender: x402ExactPermit2ProxyAddress,
267
209
  nonce,
268
210
  deadline,
269
211
  witness: {
270
- to: (0, import_viem5.getAddress)(paymentRequirements.payTo),
271
- validAfter,
272
- extra: "0x"
212
+ to: (0, import_viem3.getAddress)(paymentRequirements.payTo),
213
+ validAfter
273
214
  }
274
215
  };
275
216
  const signature = await signPermit2Authorization(
@@ -287,7 +228,7 @@ async function createPermit2Payload(signer, x402Version, paymentRequirements) {
287
228
  };
288
229
  }
289
230
  async function signPermit2Authorization(signer, permit2Authorization, requirements) {
290
- const chainId = parseInt(requirements.network.split(":")[1]);
231
+ const chainId = getEvmChainId(requirements.network);
291
232
  const domain = {
292
233
  name: "Permit2",
293
234
  chainId,
@@ -295,16 +236,15 @@ async function signPermit2Authorization(signer, permit2Authorization, requiremen
295
236
  };
296
237
  const message = {
297
238
  permitted: {
298
- token: (0, import_viem5.getAddress)(permit2Authorization.permitted.token),
239
+ token: (0, import_viem3.getAddress)(permit2Authorization.permitted.token),
299
240
  amount: BigInt(permit2Authorization.permitted.amount)
300
241
  },
301
- spender: (0, import_viem5.getAddress)(permit2Authorization.spender),
242
+ spender: (0, import_viem3.getAddress)(permit2Authorization.spender),
302
243
  nonce: BigInt(permit2Authorization.nonce),
303
244
  deadline: BigInt(permit2Authorization.deadline),
304
245
  witness: {
305
- to: (0, import_viem5.getAddress)(permit2Authorization.witness.to),
306
- validAfter: BigInt(permit2Authorization.witness.validAfter),
307
- extra: permit2Authorization.witness.extra
246
+ to: (0, import_viem3.getAddress)(permit2Authorization.witness.to),
247
+ validAfter: BigInt(permit2Authorization.witness.validAfter)
308
248
  }
309
249
  };
310
250
  return await signer.signTypedData({
@@ -314,47 +254,107 @@ async function signPermit2Authorization(signer, permit2Authorization, requiremen
314
254
  message
315
255
  });
316
256
  }
317
- var erc20ApproveAbi = [
318
- {
319
- type: "function",
320
- name: "approve",
321
- inputs: [
322
- { name: "spender", type: "address" },
323
- { name: "amount", type: "uint256" }
324
- ],
325
- outputs: [{ type: "bool" }],
326
- stateMutability: "nonpayable"
327
- }
328
- ];
329
- var erc20AllowanceAbi = [
330
- {
331
- type: "function",
332
- name: "allowance",
333
- inputs: [
334
- { name: "owner", type: "address" },
335
- { name: "spender", type: "address" }
336
- ],
337
- outputs: [{ type: "uint256" }],
338
- stateMutability: "view"
339
- }
340
- ];
341
257
  function createPermit2ApprovalTx(tokenAddress) {
342
- const data = (0, import_viem5.encodeFunctionData)({
258
+ const data = (0, import_viem3.encodeFunctionData)({
343
259
  abi: erc20ApproveAbi,
344
260
  functionName: "approve",
345
261
  args: [PERMIT2_ADDRESS, MAX_UINT256]
346
262
  });
347
263
  return {
348
- to: (0, import_viem5.getAddress)(tokenAddress),
264
+ to: (0, import_viem3.getAddress)(tokenAddress),
349
265
  data
350
266
  };
351
267
  }
352
268
  function getPermit2AllowanceReadParams(params) {
353
269
  return {
354
- address: (0, import_viem5.getAddress)(params.tokenAddress),
270
+ address: (0, import_viem3.getAddress)(params.tokenAddress),
355
271
  abi: erc20AllowanceAbi,
356
272
  functionName: "allowance",
357
- args: [(0, import_viem5.getAddress)(params.ownerAddress), PERMIT2_ADDRESS]
273
+ args: [(0, import_viem3.getAddress)(params.ownerAddress), PERMIT2_ADDRESS]
274
+ };
275
+ }
276
+
277
+ // src/exact/client/eip2612.ts
278
+ var import_viem4 = require("viem");
279
+ async function signEip2612Permit(signer, tokenAddress, tokenName, tokenVersion, chainId, deadline, permittedAmount) {
280
+ const owner = signer.address;
281
+ const spender = (0, import_viem4.getAddress)(PERMIT2_ADDRESS);
282
+ const nonce = await signer.readContract({
283
+ address: tokenAddress,
284
+ abi: eip2612NoncesAbi,
285
+ functionName: "nonces",
286
+ args: [owner]
287
+ });
288
+ const domain = {
289
+ name: tokenName,
290
+ version: tokenVersion,
291
+ chainId,
292
+ verifyingContract: tokenAddress
293
+ };
294
+ const approvalAmount = BigInt(permittedAmount);
295
+ const message = {
296
+ owner,
297
+ spender,
298
+ value: approvalAmount,
299
+ nonce,
300
+ deadline: BigInt(deadline)
301
+ };
302
+ const signature = await signer.signTypedData({
303
+ domain,
304
+ types: eip2612PermitTypes,
305
+ primaryType: "Permit",
306
+ message
307
+ });
308
+ return {
309
+ from: owner,
310
+ asset: tokenAddress,
311
+ spender,
312
+ amount: approvalAmount.toString(),
313
+ nonce: nonce.toString(),
314
+ deadline,
315
+ signature,
316
+ version: "1"
317
+ };
318
+ }
319
+
320
+ // src/exact/client/erc20approval.ts
321
+ var import_viem5 = require("viem");
322
+ var import_extensions = require("@x402/extensions");
323
+ async function signErc20ApprovalTransaction(signer, tokenAddress, chainId) {
324
+ const from = signer.address;
325
+ const spender = (0, import_viem5.getAddress)(PERMIT2_ADDRESS);
326
+ const data = (0, import_viem5.encodeFunctionData)({
327
+ abi: erc20ApproveAbi,
328
+ functionName: "approve",
329
+ args: [spender, import_viem5.maxUint256]
330
+ });
331
+ const nonce = await signer.getTransactionCount({ address: from });
332
+ let maxFeePerGas;
333
+ let maxPriorityFeePerGas;
334
+ try {
335
+ const fees = await signer.estimateFeesPerGas();
336
+ maxFeePerGas = fees.maxFeePerGas;
337
+ maxPriorityFeePerGas = fees.maxPriorityFeePerGas;
338
+ } catch {
339
+ maxFeePerGas = DEFAULT_MAX_FEE_PER_GAS;
340
+ maxPriorityFeePerGas = DEFAULT_MAX_PRIORITY_FEE_PER_GAS;
341
+ }
342
+ const signedTransaction = await signer.signTransaction({
343
+ to: tokenAddress,
344
+ data,
345
+ nonce,
346
+ gas: ERC20_APPROVE_GAS_LIMIT,
347
+ maxFeePerGas,
348
+ maxPriorityFeePerGas,
349
+ chainId
350
+ });
351
+ return {
352
+ from,
353
+ asset: tokenAddress,
354
+ spender,
355
+ amount: import_viem5.maxUint256.toString(),
356
+ signedTransaction,
357
+ version: import_extensions.ERC20_APPROVAL_GAS_SPONSORING_VERSION
358
358
  };
359
359
  }
360
360
 
@@ -363,7 +363,9 @@ var ExactEvmScheme = class {
363
363
  /**
364
364
  * Creates a new ExactEvmClient instance.
365
365
  *
366
- * @param signer - The EVM signer for client operations
366
+ * @param signer - The EVM signer for client operations.
367
+ * Must support `readContract` for EIP-2612 gas sponsoring.
368
+ * Use `createWalletClient(...).extend(publicActions)` or `toClientEvmSigner(account, publicClient)`.
367
369
  */
368
370
  constructor(signer) {
369
371
  this.signer = signer;
@@ -373,27 +375,268 @@ var ExactEvmScheme = class {
373
375
  * Creates a payment payload for the Exact scheme.
374
376
  * Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
375
377
  *
378
+ * For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
379
+ * signer supports `readContract`, automatically signs an EIP-2612 permit
380
+ * when Permit2 allowance is insufficient.
381
+ *
376
382
  * @param x402Version - The x402 protocol version
377
383
  * @param paymentRequirements - The payment requirements
378
- * @returns Promise resolving to a payment payload result
384
+ * @param context - Optional context with server-declared extensions
385
+ * @returns Promise resolving to a payment payload result (with optional extensions)
379
386
  */
380
- async createPaymentPayload(x402Version, paymentRequirements) {
387
+ async createPaymentPayload(x402Version, paymentRequirements, context) {
381
388
  const assetTransferMethod = paymentRequirements.extra?.assetTransferMethod ?? "eip3009";
382
389
  if (assetTransferMethod === "permit2") {
383
- return createPermit2Payload(this.signer, x402Version, paymentRequirements);
390
+ const result = await createPermit2Payload(this.signer, x402Version, paymentRequirements);
391
+ const eip2612Extensions = await this.trySignEip2612Permit(
392
+ paymentRequirements,
393
+ result,
394
+ context
395
+ );
396
+ if (eip2612Extensions) {
397
+ return {
398
+ ...result,
399
+ extensions: eip2612Extensions
400
+ };
401
+ }
402
+ const erc20Extensions = await this.trySignErc20Approval(paymentRequirements, result, context);
403
+ if (erc20Extensions) {
404
+ return {
405
+ ...result,
406
+ extensions: erc20Extensions
407
+ };
408
+ }
409
+ return result;
384
410
  }
385
411
  return createEIP3009Payload(this.signer, x402Version, paymentRequirements);
386
412
  }
413
+ /**
414
+ * Attempts to sign an EIP-2612 permit for gasless Permit2 approval.
415
+ *
416
+ * Returns extension data if:
417
+ * 1. Server advertises eip2612GasSponsoring
418
+ * 2. Signer has readContract capability
419
+ * 3. Current Permit2 allowance is insufficient
420
+ *
421
+ * Returns undefined if the extension should not be used.
422
+ *
423
+ * @param requirements - The payment requirements from the server
424
+ * @param result - The payment payload result from the scheme
425
+ * @param context - Optional context containing server extensions and metadata
426
+ * @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable
427
+ */
428
+ async trySignEip2612Permit(requirements, result, context) {
429
+ if (!context?.extensions?.[import_extensions2.EIP2612_GAS_SPONSORING.key]) {
430
+ return void 0;
431
+ }
432
+ const tokenName = requirements.extra?.name;
433
+ const tokenVersion = requirements.extra?.version;
434
+ if (!tokenName || !tokenVersion) {
435
+ return void 0;
436
+ }
437
+ const chainId = getEvmChainId(requirements.network);
438
+ const tokenAddress = (0, import_viem6.getAddress)(requirements.asset);
439
+ try {
440
+ const allowance = await this.signer.readContract({
441
+ address: tokenAddress,
442
+ abi: erc20AllowanceAbi,
443
+ functionName: "allowance",
444
+ args: [this.signer.address, PERMIT2_ADDRESS]
445
+ });
446
+ if (allowance >= BigInt(requirements.amount)) {
447
+ return void 0;
448
+ }
449
+ } catch {
450
+ }
451
+ const permit2Auth = result.payload?.permit2Authorization;
452
+ const deadline = permit2Auth?.deadline ?? Math.floor(Date.now() / 1e3 + requirements.maxTimeoutSeconds).toString();
453
+ const info = await signEip2612Permit(
454
+ this.signer,
455
+ tokenAddress,
456
+ tokenName,
457
+ tokenVersion,
458
+ chainId,
459
+ deadline,
460
+ requirements.amount
461
+ );
462
+ return {
463
+ [import_extensions2.EIP2612_GAS_SPONSORING.key]: { info }
464
+ };
465
+ }
466
+ /**
467
+ * Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.
468
+ *
469
+ * This is the fallback path when the token does not support EIP-2612. The client
470
+ * signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.
471
+ * The facilitator broadcasts it atomically before settling.
472
+ *
473
+ * Returns extension data if:
474
+ * 1. Server advertises erc20ApprovalGasSponsoring
475
+ * 2. Signer has signTransaction + getTransactionCount capabilities
476
+ * 3. Current Permit2 allowance is insufficient
477
+ *
478
+ * Returns undefined if the extension should not be used.
479
+ *
480
+ * @param requirements - The payment requirements from the server
481
+ * @param _result - The payment payload result from the scheme (unused)
482
+ * @param context - Optional context containing server extensions and metadata
483
+ * @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable
484
+ */
485
+ async trySignErc20Approval(requirements, _result, context) {
486
+ if (!context?.extensions?.[import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key]) {
487
+ return void 0;
488
+ }
489
+ if (!this.signer.signTransaction || !this.signer.getTransactionCount) {
490
+ return void 0;
491
+ }
492
+ const chainId = getEvmChainId(requirements.network);
493
+ const tokenAddress = (0, import_viem6.getAddress)(requirements.asset);
494
+ try {
495
+ const allowance = await this.signer.readContract({
496
+ address: tokenAddress,
497
+ abi: erc20AllowanceAbi,
498
+ functionName: "allowance",
499
+ args: [this.signer.address, PERMIT2_ADDRESS]
500
+ });
501
+ if (allowance >= BigInt(requirements.amount)) {
502
+ return void 0;
503
+ }
504
+ } catch {
505
+ }
506
+ const info = await signErc20ApprovalTransaction(this.signer, tokenAddress, chainId);
507
+ return {
508
+ [import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key]: { info }
509
+ };
510
+ }
511
+ };
512
+
513
+ // src/exact/v1/client/scheme.ts
514
+ var import_viem8 = require("viem");
515
+
516
+ // src/exact/v1/facilitator/scheme.ts
517
+ var import_viem7 = require("viem");
518
+
519
+ // src/v1/index.ts
520
+ var EVM_NETWORK_CHAIN_ID_MAP = {
521
+ ethereum: 1,
522
+ sepolia: 11155111,
523
+ abstract: 2741,
524
+ "abstract-testnet": 11124,
525
+ "base-sepolia": 84532,
526
+ base: 8453,
527
+ "avalanche-fuji": 43113,
528
+ avalanche: 43114,
529
+ iotex: 4689,
530
+ sei: 1329,
531
+ "sei-testnet": 1328,
532
+ polygon: 137,
533
+ "polygon-amoy": 80002,
534
+ peaq: 3338,
535
+ story: 1514,
536
+ educhain: 41923,
537
+ "skale-base-sepolia": 324705682,
538
+ megaeth: 4326,
539
+ monad: 143
540
+ };
541
+ var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
542
+ function getEvmChainIdV1(network) {
543
+ const chainId = EVM_NETWORK_CHAIN_ID_MAP[network];
544
+ if (!chainId) {
545
+ throw new Error(`Unsupported v1 network: ${network}`);
546
+ }
547
+ return chainId;
548
+ }
549
+
550
+ // src/exact/v1/client/scheme.ts
551
+ var ExactEvmSchemeV1 = class {
552
+ /**
553
+ * Creates a new ExactEvmClientV1 instance.
554
+ *
555
+ * @param signer - The EVM signer for client operations
556
+ */
557
+ constructor(signer) {
558
+ this.signer = signer;
559
+ this.scheme = "exact";
560
+ }
561
+ /**
562
+ * Creates a payment payload for the Exact scheme (V1).
563
+ *
564
+ * @param x402Version - The x402 protocol version
565
+ * @param paymentRequirements - The payment requirements
566
+ * @returns Promise resolving to a payment payload
567
+ */
568
+ async createPaymentPayload(x402Version, paymentRequirements) {
569
+ const selectedV1 = paymentRequirements;
570
+ const nonce = createNonce();
571
+ const now = Math.floor(Date.now() / 1e3);
572
+ const authorization = {
573
+ from: this.signer.address,
574
+ to: (0, import_viem8.getAddress)(selectedV1.payTo),
575
+ value: selectedV1.maxAmountRequired,
576
+ validAfter: (now - 600).toString(),
577
+ // 10 minutes before
578
+ validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),
579
+ nonce
580
+ };
581
+ const signature = await this.signAuthorization(authorization, selectedV1);
582
+ const payload = {
583
+ authorization,
584
+ signature
585
+ };
586
+ return {
587
+ x402Version,
588
+ scheme: selectedV1.scheme,
589
+ network: selectedV1.network,
590
+ payload
591
+ };
592
+ }
593
+ /**
594
+ * Sign the EIP-3009 authorization using EIP-712
595
+ *
596
+ * @param authorization - The authorization to sign
597
+ * @param requirements - The payment requirements
598
+ * @returns Promise resolving to the signature
599
+ */
600
+ async signAuthorization(authorization, requirements) {
601
+ const chainId = getEvmChainIdV1(requirements.network);
602
+ if (!requirements.extra?.name || !requirements.extra?.version) {
603
+ throw new Error(
604
+ `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
605
+ );
606
+ }
607
+ const { name, version } = requirements.extra;
608
+ const domain = {
609
+ name,
610
+ version,
611
+ chainId,
612
+ verifyingContract: (0, import_viem8.getAddress)(requirements.asset)
613
+ };
614
+ const message = {
615
+ from: (0, import_viem8.getAddress)(authorization.from),
616
+ to: (0, import_viem8.getAddress)(authorization.to),
617
+ value: BigInt(authorization.value),
618
+ validAfter: BigInt(authorization.validAfter),
619
+ validBefore: BigInt(authorization.validBefore),
620
+ nonce: authorization.nonce
621
+ };
622
+ return await this.signer.signTypedData({
623
+ domain,
624
+ types: authorizationTypes,
625
+ primaryType: "TransferWithAuthorization",
626
+ message
627
+ });
628
+ }
387
629
  };
388
630
 
389
631
  // src/exact/client/register.ts
390
632
  function registerExactEvmScheme(client, config) {
633
+ const evmScheme = new ExactEvmScheme(config.signer);
391
634
  if (config.networks && config.networks.length > 0) {
392
635
  config.networks.forEach((network) => {
393
- client.register(network, new ExactEvmScheme(config.signer));
636
+ client.register(network, evmScheme);
394
637
  });
395
638
  } else {
396
- client.register("eip155:*", new ExactEvmScheme(config.signer));
639
+ client.register("eip155:*", evmScheme);
397
640
  }
398
641
  NETWORKS.forEach((network) => {
399
642
  client.registerV1(network, new ExactEvmSchemeV1(config.signer));