@x402/evm 2.2.0 → 2.3.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 (48) hide show
  1. package/dist/cjs/exact/client/index.d.ts +2 -2
  2. package/dist/cjs/exact/client/index.js +264 -119
  3. package/dist/cjs/exact/client/index.js.map +1 -1
  4. package/dist/cjs/exact/facilitator/index.d.ts +3 -0
  5. package/dist/cjs/exact/facilitator/index.js +691 -281
  6. package/dist/cjs/exact/facilitator/index.js.map +1 -1
  7. package/dist/cjs/exact/v1/client/index.js +43 -17
  8. package/dist/cjs/exact/v1/client/index.js.map +1 -1
  9. package/dist/cjs/exact/v1/facilitator/index.js +59 -26
  10. package/dist/cjs/exact/v1/facilitator/index.js.map +1 -1
  11. package/dist/cjs/index.d.ts +458 -31
  12. package/dist/cjs/index.js +438 -63
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/permit2-BYv82va2.d.ts +103 -0
  15. package/dist/cjs/v1/index.d.ts +21 -1
  16. package/dist/cjs/v1/index.js +33 -29
  17. package/dist/cjs/v1/index.js.map +1 -1
  18. package/dist/esm/chunk-DSSJHWGT.mjs +658 -0
  19. package/dist/esm/chunk-DSSJHWGT.mjs.map +1 -0
  20. package/dist/esm/chunk-PFULIQAE.mjs +13 -0
  21. package/dist/esm/chunk-PFULIQAE.mjs.map +1 -0
  22. package/dist/esm/chunk-U4H6Q62Q.mjs +229 -0
  23. package/dist/esm/chunk-U4H6Q62Q.mjs.map +1 -0
  24. package/dist/esm/exact/client/index.d.mts +2 -2
  25. package/dist/esm/exact/client/index.mjs +10 -30
  26. package/dist/esm/exact/client/index.mjs.map +1 -1
  27. package/dist/esm/exact/facilitator/index.d.mts +3 -0
  28. package/dist/esm/exact/facilitator/index.mjs +491 -241
  29. package/dist/esm/exact/facilitator/index.mjs.map +1 -1
  30. package/dist/esm/exact/v1/client/index.mjs +1 -2
  31. package/dist/esm/exact/v1/facilitator/index.mjs +2 -3
  32. package/dist/esm/index.d.mts +458 -31
  33. package/dist/esm/index.mjs +31 -4
  34. package/dist/esm/index.mjs.map +1 -1
  35. package/dist/esm/permit2-BsAoJiWD.d.mts +103 -0
  36. package/dist/esm/v1/index.d.mts +21 -1
  37. package/dist/esm/v1/index.mjs +4 -6
  38. package/package.json +2 -2
  39. package/dist/esm/chunk-FOUXRQAV.mjs +0 -88
  40. package/dist/esm/chunk-FOUXRQAV.mjs.map +0 -1
  41. package/dist/esm/chunk-JYZWCLMP.mjs +0 -305
  42. package/dist/esm/chunk-JYZWCLMP.mjs.map +0 -1
  43. package/dist/esm/chunk-PSA4YVU2.mjs +0 -92
  44. package/dist/esm/chunk-PSA4YVU2.mjs.map +0 -1
  45. package/dist/esm/chunk-QLXM7BIB.mjs +0 -23
  46. package/dist/esm/chunk-QLXM7BIB.mjs.map +0 -1
  47. package/dist/esm/chunk-ZYXTTU74.mjs +0 -88
  48. package/dist/esm/chunk-ZYXTTU74.mjs.map +0 -1
@@ -25,7 +25,12 @@ __export(facilitator_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(facilitator_exports);
27
27
 
28
- // src/exact/facilitator/scheme.ts
28
+ // src/types.ts
29
+ function isPermit2Payload(payload) {
30
+ return "permit2Authorization" in payload;
31
+ }
32
+
33
+ // src/exact/facilitator/eip3009.ts
29
34
  var import_viem = require("viem");
30
35
 
31
36
  // src/constants.ts
@@ -39,6 +44,24 @@ var authorizationTypes = {
39
44
  { name: "nonce", type: "bytes32" }
40
45
  ]
41
46
  };
47
+ var permit2WitnessTypes = {
48
+ PermitWitnessTransferFrom: [
49
+ { name: "permitted", type: "TokenPermissions" },
50
+ { name: "spender", type: "address" },
51
+ { name: "nonce", type: "uint256" },
52
+ { name: "deadline", type: "uint256" },
53
+ { name: "witness", type: "Witness" }
54
+ ],
55
+ TokenPermissions: [
56
+ { name: "token", type: "address" },
57
+ { name: "amount", type: "uint256" }
58
+ ],
59
+ Witness: [
60
+ { name: "to", type: "address" },
61
+ { name: "validAfter", type: "uint256" },
62
+ { name: "extra", type: "bytes" }
63
+ ]
64
+ };
42
65
  var eip3009ABI = [
43
66
  {
44
67
  inputs: [
@@ -87,6 +110,602 @@ var eip3009ABI = [
87
110
  type: "function"
88
111
  }
89
112
  ];
113
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
114
+ var x402ExactPermit2ProxyAddress = "0x4020615294c913F045dc10f0a5cdEbd86c280001";
115
+ var x402ExactPermit2ProxyABI = [
116
+ {
117
+ type: "function",
118
+ name: "PERMIT2",
119
+ inputs: [],
120
+ outputs: [{ name: "", type: "address", internalType: "contract ISignatureTransfer" }],
121
+ stateMutability: "view"
122
+ },
123
+ {
124
+ type: "function",
125
+ name: "WITNESS_TYPEHASH",
126
+ inputs: [],
127
+ outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
128
+ stateMutability: "view"
129
+ },
130
+ {
131
+ type: "function",
132
+ name: "WITNESS_TYPE_STRING",
133
+ inputs: [],
134
+ outputs: [{ name: "", type: "string", internalType: "string" }],
135
+ stateMutability: "view"
136
+ },
137
+ {
138
+ type: "function",
139
+ name: "initialize",
140
+ inputs: [{ name: "_permit2", type: "address", internalType: "address" }],
141
+ outputs: [],
142
+ stateMutability: "nonpayable"
143
+ },
144
+ {
145
+ type: "function",
146
+ name: "settle",
147
+ inputs: [
148
+ {
149
+ name: "permit",
150
+ type: "tuple",
151
+ internalType: "struct ISignatureTransfer.PermitTransferFrom",
152
+ components: [
153
+ {
154
+ name: "permitted",
155
+ type: "tuple",
156
+ internalType: "struct ISignatureTransfer.TokenPermissions",
157
+ components: [
158
+ { name: "token", type: "address", internalType: "address" },
159
+ { name: "amount", type: "uint256", internalType: "uint256" }
160
+ ]
161
+ },
162
+ { name: "nonce", type: "uint256", internalType: "uint256" },
163
+ { name: "deadline", type: "uint256", internalType: "uint256" }
164
+ ]
165
+ },
166
+ { name: "owner", type: "address", internalType: "address" },
167
+ {
168
+ name: "witness",
169
+ type: "tuple",
170
+ internalType: "struct x402BasePermit2Proxy.Witness",
171
+ components: [
172
+ { name: "to", type: "address", internalType: "address" },
173
+ { name: "validAfter", type: "uint256", internalType: "uint256" },
174
+ { name: "extra", type: "bytes", internalType: "bytes" }
175
+ ]
176
+ },
177
+ { name: "signature", type: "bytes", internalType: "bytes" }
178
+ ],
179
+ outputs: [],
180
+ stateMutability: "nonpayable"
181
+ },
182
+ {
183
+ type: "function",
184
+ name: "settleWithPermit",
185
+ inputs: [
186
+ {
187
+ name: "permit2612",
188
+ type: "tuple",
189
+ internalType: "struct x402BasePermit2Proxy.EIP2612Permit",
190
+ components: [
191
+ { name: "value", type: "uint256", internalType: "uint256" },
192
+ { name: "deadline", type: "uint256", internalType: "uint256" },
193
+ { name: "r", type: "bytes32", internalType: "bytes32" },
194
+ { name: "s", type: "bytes32", internalType: "bytes32" },
195
+ { name: "v", type: "uint8", internalType: "uint8" }
196
+ ]
197
+ },
198
+ {
199
+ name: "permit",
200
+ type: "tuple",
201
+ internalType: "struct ISignatureTransfer.PermitTransferFrom",
202
+ components: [
203
+ {
204
+ name: "permitted",
205
+ type: "tuple",
206
+ internalType: "struct ISignatureTransfer.TokenPermissions",
207
+ components: [
208
+ { name: "token", type: "address", internalType: "address" },
209
+ { name: "amount", type: "uint256", internalType: "uint256" }
210
+ ]
211
+ },
212
+ { name: "nonce", type: "uint256", internalType: "uint256" },
213
+ { name: "deadline", type: "uint256", internalType: "uint256" }
214
+ ]
215
+ },
216
+ { name: "owner", type: "address", internalType: "address" },
217
+ {
218
+ name: "witness",
219
+ type: "tuple",
220
+ internalType: "struct x402BasePermit2Proxy.Witness",
221
+ components: [
222
+ { name: "to", type: "address", internalType: "address" },
223
+ { name: "validAfter", type: "uint256", internalType: "uint256" },
224
+ { name: "extra", type: "bytes", internalType: "bytes" }
225
+ ]
226
+ },
227
+ { name: "signature", type: "bytes", internalType: "bytes" }
228
+ ],
229
+ outputs: [],
230
+ stateMutability: "nonpayable"
231
+ },
232
+ { type: "event", name: "Settled", inputs: [], anonymous: false },
233
+ { type: "event", name: "SettledWithPermit", inputs: [], anonymous: false },
234
+ { type: "error", name: "AlreadyInitialized", inputs: [] },
235
+ { type: "error", name: "InvalidDestination", inputs: [] },
236
+ { type: "error", name: "InvalidOwner", inputs: [] },
237
+ { type: "error", name: "InvalidPermit2Address", inputs: [] },
238
+ { type: "error", name: "PaymentTooEarly", inputs: [] },
239
+ { type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] }
240
+ ];
241
+
242
+ // src/exact/facilitator/eip3009.ts
243
+ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
244
+ const payer = eip3009Payload.authorization.from;
245
+ if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
246
+ return {
247
+ isValid: false,
248
+ invalidReason: "unsupported_scheme",
249
+ payer
250
+ };
251
+ }
252
+ if (!requirements.extra?.name || !requirements.extra?.version) {
253
+ return {
254
+ isValid: false,
255
+ invalidReason: "missing_eip712_domain",
256
+ payer
257
+ };
258
+ }
259
+ const { name, version } = requirements.extra;
260
+ const erc20Address = (0, import_viem.getAddress)(requirements.asset);
261
+ if (payload.accepted.network !== requirements.network) {
262
+ return {
263
+ isValid: false,
264
+ invalidReason: "network_mismatch",
265
+ payer
266
+ };
267
+ }
268
+ const permitTypedData = {
269
+ types: authorizationTypes,
270
+ primaryType: "TransferWithAuthorization",
271
+ domain: {
272
+ name,
273
+ version,
274
+ chainId: parseInt(requirements.network.split(":")[1]),
275
+ verifyingContract: erc20Address
276
+ },
277
+ message: {
278
+ from: eip3009Payload.authorization.from,
279
+ to: eip3009Payload.authorization.to,
280
+ value: BigInt(eip3009Payload.authorization.value),
281
+ validAfter: BigInt(eip3009Payload.authorization.validAfter),
282
+ validBefore: BigInt(eip3009Payload.authorization.validBefore),
283
+ nonce: eip3009Payload.authorization.nonce
284
+ }
285
+ };
286
+ try {
287
+ const recoveredAddress = await signer.verifyTypedData({
288
+ address: eip3009Payload.authorization.from,
289
+ ...permitTypedData,
290
+ signature: eip3009Payload.signature
291
+ });
292
+ if (!recoveredAddress) {
293
+ return {
294
+ isValid: false,
295
+ invalidReason: "invalid_exact_evm_payload_signature",
296
+ payer
297
+ };
298
+ }
299
+ } catch {
300
+ const signature = eip3009Payload.signature;
301
+ const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
302
+ const isSmartWallet = signatureLength > 130;
303
+ if (isSmartWallet) {
304
+ const payerAddress = eip3009Payload.authorization.from;
305
+ const bytecode = await signer.getCode({ address: payerAddress });
306
+ if (!bytecode || bytecode === "0x") {
307
+ const erc6492Data = (0, import_viem.parseErc6492Signature)(signature);
308
+ const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
309
+ if (!hasDeploymentInfo) {
310
+ return {
311
+ isValid: false,
312
+ invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
313
+ payer: payerAddress
314
+ };
315
+ }
316
+ } else {
317
+ return {
318
+ isValid: false,
319
+ invalidReason: "invalid_exact_evm_payload_signature",
320
+ payer
321
+ };
322
+ }
323
+ } else {
324
+ return {
325
+ isValid: false,
326
+ invalidReason: "invalid_exact_evm_payload_signature",
327
+ payer
328
+ };
329
+ }
330
+ }
331
+ if ((0, import_viem.getAddress)(eip3009Payload.authorization.to) !== (0, import_viem.getAddress)(requirements.payTo)) {
332
+ return {
333
+ isValid: false,
334
+ invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
335
+ payer
336
+ };
337
+ }
338
+ const now = Math.floor(Date.now() / 1e3);
339
+ if (BigInt(eip3009Payload.authorization.validBefore) < BigInt(now + 6)) {
340
+ return {
341
+ isValid: false,
342
+ invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
343
+ payer
344
+ };
345
+ }
346
+ if (BigInt(eip3009Payload.authorization.validAfter) > BigInt(now)) {
347
+ return {
348
+ isValid: false,
349
+ invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
350
+ payer
351
+ };
352
+ }
353
+ try {
354
+ const balance = await signer.readContract({
355
+ address: erc20Address,
356
+ abi: eip3009ABI,
357
+ functionName: "balanceOf",
358
+ args: [eip3009Payload.authorization.from]
359
+ });
360
+ if (BigInt(balance) < BigInt(requirements.amount)) {
361
+ return {
362
+ isValid: false,
363
+ invalidReason: "insufficient_funds",
364
+ invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
365
+ payer
366
+ };
367
+ }
368
+ } catch {
369
+ }
370
+ if (BigInt(eip3009Payload.authorization.value) < BigInt(requirements.amount)) {
371
+ return {
372
+ isValid: false,
373
+ invalidReason: "invalid_exact_evm_payload_authorization_value",
374
+ payer
375
+ };
376
+ }
377
+ return {
378
+ isValid: true,
379
+ invalidReason: void 0,
380
+ payer
381
+ };
382
+ }
383
+ async function settleEIP3009(signer, payload, requirements, eip3009Payload, config) {
384
+ const payer = eip3009Payload.authorization.from;
385
+ const valid = await verifyEIP3009(signer, payload, requirements, eip3009Payload);
386
+ if (!valid.isValid) {
387
+ return {
388
+ success: false,
389
+ network: payload.accepted.network,
390
+ transaction: "",
391
+ errorReason: valid.invalidReason ?? "invalid_scheme",
392
+ payer
393
+ };
394
+ }
395
+ try {
396
+ const parseResult = (0, import_viem.parseErc6492Signature)(eip3009Payload.signature);
397
+ const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
398
+ if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
399
+ const bytecode = await signer.getCode({ address: payer });
400
+ if (!bytecode || bytecode === "0x") {
401
+ const deployTx = await signer.sendTransaction({
402
+ to: factoryAddress,
403
+ data: factoryCalldata
404
+ });
405
+ await signer.waitForTransactionReceipt({ hash: deployTx });
406
+ }
407
+ }
408
+ const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
409
+ const isECDSA = signatureLength === 130;
410
+ let tx;
411
+ if (isECDSA) {
412
+ const parsedSig = (0, import_viem.parseSignature)(signature);
413
+ tx = await signer.writeContract({
414
+ address: (0, import_viem.getAddress)(requirements.asset),
415
+ abi: eip3009ABI,
416
+ functionName: "transferWithAuthorization",
417
+ args: [
418
+ (0, import_viem.getAddress)(eip3009Payload.authorization.from),
419
+ (0, import_viem.getAddress)(eip3009Payload.authorization.to),
420
+ BigInt(eip3009Payload.authorization.value),
421
+ BigInt(eip3009Payload.authorization.validAfter),
422
+ BigInt(eip3009Payload.authorization.validBefore),
423
+ eip3009Payload.authorization.nonce,
424
+ parsedSig.v || parsedSig.yParity,
425
+ parsedSig.r,
426
+ parsedSig.s
427
+ ]
428
+ });
429
+ } else {
430
+ tx = await signer.writeContract({
431
+ address: (0, import_viem.getAddress)(requirements.asset),
432
+ abi: eip3009ABI,
433
+ functionName: "transferWithAuthorization",
434
+ args: [
435
+ (0, import_viem.getAddress)(eip3009Payload.authorization.from),
436
+ (0, import_viem.getAddress)(eip3009Payload.authorization.to),
437
+ BigInt(eip3009Payload.authorization.value),
438
+ BigInt(eip3009Payload.authorization.validAfter),
439
+ BigInt(eip3009Payload.authorization.validBefore),
440
+ eip3009Payload.authorization.nonce,
441
+ signature
442
+ ]
443
+ });
444
+ }
445
+ const receipt = await signer.waitForTransactionReceipt({ hash: tx });
446
+ if (receipt.status !== "success") {
447
+ return {
448
+ success: false,
449
+ errorReason: "invalid_transaction_state",
450
+ transaction: tx,
451
+ network: payload.accepted.network,
452
+ payer
453
+ };
454
+ }
455
+ return {
456
+ success: true,
457
+ transaction: tx,
458
+ network: payload.accepted.network,
459
+ payer
460
+ };
461
+ } catch {
462
+ return {
463
+ success: false,
464
+ errorReason: "transaction_failed",
465
+ transaction: "",
466
+ network: payload.accepted.network,
467
+ payer
468
+ };
469
+ }
470
+ }
471
+
472
+ // src/exact/facilitator/permit2.ts
473
+ var import_viem2 = require("viem");
474
+ var erc20AllowanceABI = [
475
+ {
476
+ type: "function",
477
+ name: "allowance",
478
+ inputs: [
479
+ { name: "owner", type: "address" },
480
+ { name: "spender", type: "address" }
481
+ ],
482
+ outputs: [{ type: "uint256" }],
483
+ stateMutability: "view"
484
+ }
485
+ ];
486
+ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
487
+ const payer = permit2Payload.permit2Authorization.from;
488
+ if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
489
+ return {
490
+ isValid: false,
491
+ invalidReason: "unsupported_scheme",
492
+ payer
493
+ };
494
+ }
495
+ if (payload.accepted.network !== requirements.network) {
496
+ return {
497
+ isValid: false,
498
+ invalidReason: "network_mismatch",
499
+ payer
500
+ };
501
+ }
502
+ const chainId = parseInt(requirements.network.split(":")[1]);
503
+ const tokenAddress = (0, import_viem2.getAddress)(requirements.asset);
504
+ if ((0, import_viem2.getAddress)(permit2Payload.permit2Authorization.spender) !== (0, import_viem2.getAddress)(x402ExactPermit2ProxyAddress)) {
505
+ return {
506
+ isValid: false,
507
+ invalidReason: "invalid_permit2_spender",
508
+ payer
509
+ };
510
+ }
511
+ if ((0, import_viem2.getAddress)(permit2Payload.permit2Authorization.witness.to) !== (0, import_viem2.getAddress)(requirements.payTo)) {
512
+ return {
513
+ isValid: false,
514
+ invalidReason: "invalid_permit2_recipient_mismatch",
515
+ payer
516
+ };
517
+ }
518
+ const now = Math.floor(Date.now() / 1e3);
519
+ if (BigInt(permit2Payload.permit2Authorization.deadline) < BigInt(now + 6)) {
520
+ return {
521
+ isValid: false,
522
+ invalidReason: "permit2_deadline_expired",
523
+ payer
524
+ };
525
+ }
526
+ if (BigInt(permit2Payload.permit2Authorization.witness.validAfter) > BigInt(now)) {
527
+ return {
528
+ isValid: false,
529
+ invalidReason: "permit2_not_yet_valid",
530
+ payer
531
+ };
532
+ }
533
+ if (BigInt(permit2Payload.permit2Authorization.permitted.amount) < BigInt(requirements.amount)) {
534
+ return {
535
+ isValid: false,
536
+ invalidReason: "permit2_insufficient_amount",
537
+ payer
538
+ };
539
+ }
540
+ if ((0, import_viem2.getAddress)(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
541
+ return {
542
+ isValid: false,
543
+ invalidReason: "permit2_token_mismatch",
544
+ payer
545
+ };
546
+ }
547
+ const permit2TypedData = {
548
+ types: permit2WitnessTypes,
549
+ primaryType: "PermitWitnessTransferFrom",
550
+ domain: {
551
+ name: "Permit2",
552
+ chainId,
553
+ verifyingContract: PERMIT2_ADDRESS
554
+ },
555
+ message: {
556
+ permitted: {
557
+ token: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.permitted.token),
558
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
559
+ },
560
+ spender: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.spender),
561
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
562
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline),
563
+ witness: {
564
+ to: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.witness.to),
565
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
566
+ extra: permit2Payload.permit2Authorization.witness.extra
567
+ }
568
+ }
569
+ };
570
+ try {
571
+ const isValid = await signer.verifyTypedData({
572
+ address: payer,
573
+ ...permit2TypedData,
574
+ signature: permit2Payload.signature
575
+ });
576
+ if (!isValid) {
577
+ return {
578
+ isValid: false,
579
+ invalidReason: "invalid_permit2_signature",
580
+ payer
581
+ };
582
+ }
583
+ } catch {
584
+ return {
585
+ isValid: false,
586
+ invalidReason: "invalid_permit2_signature",
587
+ payer
588
+ };
589
+ }
590
+ try {
591
+ const allowance = await signer.readContract({
592
+ address: tokenAddress,
593
+ abi: erc20AllowanceABI,
594
+ functionName: "allowance",
595
+ args: [payer, PERMIT2_ADDRESS]
596
+ });
597
+ if (allowance < BigInt(requirements.amount)) {
598
+ return {
599
+ isValid: false,
600
+ invalidReason: "permit2_allowance_required",
601
+ payer
602
+ };
603
+ }
604
+ } catch {
605
+ }
606
+ try {
607
+ const balance = await signer.readContract({
608
+ address: tokenAddress,
609
+ abi: eip3009ABI,
610
+ functionName: "balanceOf",
611
+ args: [payer]
612
+ });
613
+ if (balance < BigInt(requirements.amount)) {
614
+ return {
615
+ isValid: false,
616
+ invalidReason: "insufficient_funds",
617
+ invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
618
+ payer
619
+ };
620
+ }
621
+ } catch {
622
+ }
623
+ return {
624
+ isValid: true,
625
+ invalidReason: void 0,
626
+ payer
627
+ };
628
+ }
629
+ async function settlePermit2(signer, payload, requirements, permit2Payload) {
630
+ const payer = permit2Payload.permit2Authorization.from;
631
+ const valid = await verifyPermit2(signer, payload, requirements, permit2Payload);
632
+ if (!valid.isValid) {
633
+ return {
634
+ success: false,
635
+ network: payload.accepted.network,
636
+ transaction: "",
637
+ errorReason: valid.invalidReason ?? "invalid_scheme",
638
+ payer
639
+ };
640
+ }
641
+ try {
642
+ const tx = await signer.writeContract({
643
+ address: x402ExactPermit2ProxyAddress,
644
+ abi: x402ExactPermit2ProxyABI,
645
+ functionName: "settle",
646
+ args: [
647
+ {
648
+ permitted: {
649
+ token: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.permitted.token),
650
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
651
+ },
652
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
653
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline)
654
+ },
655
+ (0, import_viem2.getAddress)(payer),
656
+ {
657
+ to: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.witness.to),
658
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
659
+ extra: permit2Payload.permit2Authorization.witness.extra
660
+ },
661
+ permit2Payload.signature
662
+ ]
663
+ });
664
+ const receipt = await signer.waitForTransactionReceipt({ hash: tx });
665
+ if (receipt.status !== "success") {
666
+ return {
667
+ success: false,
668
+ errorReason: "invalid_transaction_state",
669
+ transaction: tx,
670
+ network: payload.accepted.network,
671
+ payer
672
+ };
673
+ }
674
+ return {
675
+ success: true,
676
+ transaction: tx,
677
+ network: payload.accepted.network,
678
+ payer
679
+ };
680
+ } catch (error) {
681
+ let errorReason = "transaction_failed";
682
+ if (error instanceof Error) {
683
+ const message = error.message;
684
+ if (message.includes("AmountExceedsPermitted")) {
685
+ errorReason = "permit2_amount_exceeds_permitted";
686
+ } else if (message.includes("InvalidDestination")) {
687
+ errorReason = "permit2_invalid_destination";
688
+ } else if (message.includes("InvalidOwner")) {
689
+ errorReason = "permit2_invalid_owner";
690
+ } else if (message.includes("PaymentTooEarly")) {
691
+ errorReason = "permit2_payment_too_early";
692
+ } else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
693
+ errorReason = "permit2_invalid_signature";
694
+ } else if (message.includes("InvalidNonce")) {
695
+ errorReason = "permit2_invalid_nonce";
696
+ } else {
697
+ errorReason = `transaction_failed: ${message.slice(0, 500)}`;
698
+ }
699
+ }
700
+ return {
701
+ success: false,
702
+ errorReason,
703
+ transaction: "",
704
+ network: payload.accepted.network,
705
+ payer
706
+ };
707
+ }
708
+ }
90
709
 
91
710
  // src/exact/facilitator/scheme.ts
92
711
  var ExactEvmScheme = class {
@@ -126,277 +745,80 @@ var ExactEvmScheme = class {
126
745
  }
127
746
  /**
128
747
  * Verifies a payment payload.
748
+ * Routes to the appropriate verification logic based on payload type.
129
749
  *
130
750
  * @param payload - The payment payload to verify
131
751
  * @param requirements - The payment requirements
132
752
  * @returns Promise resolving to verification response
133
753
  */
134
754
  async verify(payload, requirements) {
135
- const exactEvmPayload = payload.payload;
136
- if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
137
- return {
138
- isValid: false,
139
- invalidReason: "unsupported_scheme",
140
- payer: exactEvmPayload.authorization.from
141
- };
142
- }
143
- if (!requirements.extra?.name || !requirements.extra?.version) {
144
- return {
145
- isValid: false,
146
- invalidReason: "missing_eip712_domain",
147
- payer: exactEvmPayload.authorization.from
148
- };
149
- }
150
- const { name, version } = requirements.extra;
151
- const erc20Address = (0, import_viem.getAddress)(requirements.asset);
152
- if (payload.accepted.network !== requirements.network) {
153
- return {
154
- isValid: false,
155
- invalidReason: "network_mismatch",
156
- payer: exactEvmPayload.authorization.from
157
- };
755
+ const rawPayload = payload.payload;
756
+ if (isPermit2Payload(rawPayload)) {
757
+ return verifyPermit2(this.signer, payload, requirements, rawPayload);
158
758
  }
159
- const permitTypedData = {
160
- types: authorizationTypes,
161
- primaryType: "TransferWithAuthorization",
162
- domain: {
163
- name,
164
- version,
165
- chainId: parseInt(requirements.network.split(":")[1]),
166
- verifyingContract: erc20Address
167
- },
168
- message: {
169
- from: exactEvmPayload.authorization.from,
170
- to: exactEvmPayload.authorization.to,
171
- value: BigInt(exactEvmPayload.authorization.value),
172
- validAfter: BigInt(exactEvmPayload.authorization.validAfter),
173
- validBefore: BigInt(exactEvmPayload.authorization.validBefore),
174
- nonce: exactEvmPayload.authorization.nonce
175
- }
176
- };
177
- try {
178
- const recoveredAddress = await this.signer.verifyTypedData({
179
- address: exactEvmPayload.authorization.from,
180
- ...permitTypedData,
181
- signature: exactEvmPayload.signature
182
- });
183
- if (!recoveredAddress) {
184
- return {
185
- isValid: false,
186
- invalidReason: "invalid_exact_evm_payload_signature",
187
- payer: exactEvmPayload.authorization.from
188
- };
189
- }
190
- } catch {
191
- const signature = exactEvmPayload.signature;
192
- const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
193
- const isSmartWallet = signatureLength > 130;
194
- if (isSmartWallet) {
195
- const payerAddress = exactEvmPayload.authorization.from;
196
- const bytecode = await this.signer.getCode({ address: payerAddress });
197
- if (!bytecode || bytecode === "0x") {
198
- const erc6492Data = (0, import_viem.parseErc6492Signature)(signature);
199
- const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
200
- if (!hasDeploymentInfo) {
201
- return {
202
- isValid: false,
203
- invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
204
- payer: payerAddress
205
- };
206
- }
207
- } else {
208
- return {
209
- isValid: false,
210
- invalidReason: "invalid_exact_evm_payload_signature",
211
- payer: exactEvmPayload.authorization.from
212
- };
213
- }
214
- } else {
215
- return {
216
- isValid: false,
217
- invalidReason: "invalid_exact_evm_payload_signature",
218
- payer: exactEvmPayload.authorization.from
219
- };
220
- }
221
- }
222
- if ((0, import_viem.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem.getAddress)(requirements.payTo)) {
223
- return {
224
- isValid: false,
225
- invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
226
- payer: exactEvmPayload.authorization.from
227
- };
228
- }
229
- const now = Math.floor(Date.now() / 1e3);
230
- if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
231
- return {
232
- isValid: false,
233
- invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
234
- payer: exactEvmPayload.authorization.from
235
- };
236
- }
237
- if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
238
- return {
239
- isValid: false,
240
- invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
241
- payer: exactEvmPayload.authorization.from
242
- };
243
- }
244
- try {
245
- const balance = await this.signer.readContract({
246
- address: erc20Address,
247
- abi: eip3009ABI,
248
- functionName: "balanceOf",
249
- args: [exactEvmPayload.authorization.from]
250
- });
251
- if (BigInt(balance) < BigInt(requirements.amount)) {
252
- return {
253
- isValid: false,
254
- invalidReason: "insufficient_funds",
255
- payer: exactEvmPayload.authorization.from
256
- };
257
- }
258
- } catch {
259
- }
260
- if (BigInt(exactEvmPayload.authorization.value) < BigInt(requirements.amount)) {
261
- return {
262
- isValid: false,
263
- invalidReason: "invalid_exact_evm_payload_authorization_value",
264
- payer: exactEvmPayload.authorization.from
265
- };
266
- }
267
- return {
268
- isValid: true,
269
- invalidReason: void 0,
270
- payer: exactEvmPayload.authorization.from
271
- };
759
+ const eip3009Payload = rawPayload;
760
+ return verifyEIP3009(this.signer, payload, requirements, eip3009Payload);
272
761
  }
273
762
  /**
274
763
  * Settles a payment by executing the transfer.
764
+ * Routes to the appropriate settlement logic based on payload type.
275
765
  *
276
766
  * @param payload - The payment payload to settle
277
767
  * @param requirements - The payment requirements
278
768
  * @returns Promise resolving to settlement response
279
769
  */
280
770
  async settle(payload, requirements) {
281
- const exactEvmPayload = payload.payload;
282
- const valid = await this.verify(payload, requirements);
283
- if (!valid.isValid) {
284
- return {
285
- success: false,
286
- network: payload.accepted.network,
287
- transaction: "",
288
- errorReason: valid.invalidReason ?? "invalid_scheme",
289
- payer: exactEvmPayload.authorization.from
290
- };
291
- }
292
- try {
293
- const parseResult = (0, import_viem.parseErc6492Signature)(exactEvmPayload.signature);
294
- const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
295
- if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
296
- const payerAddress = exactEvmPayload.authorization.from;
297
- const bytecode = await this.signer.getCode({ address: payerAddress });
298
- if (!bytecode || bytecode === "0x") {
299
- try {
300
- console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
301
- const deployTx = await this.signer.sendTransaction({
302
- to: factoryAddress,
303
- data: factoryCalldata
304
- });
305
- await this.signer.waitForTransactionReceipt({ hash: deployTx });
306
- console.log(`Successfully deployed smart wallet for ${payerAddress}`);
307
- } catch (deployError) {
308
- console.error("Smart wallet deployment failed:", deployError);
309
- throw deployError;
310
- }
311
- } else {
312
- console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
313
- }
314
- }
315
- const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
316
- const isECDSA = signatureLength === 130;
317
- let tx;
318
- if (isECDSA) {
319
- const parsedSig = (0, import_viem.parseSignature)(signature);
320
- tx = await this.signer.writeContract({
321
- address: (0, import_viem.getAddress)(requirements.asset),
322
- abi: eip3009ABI,
323
- functionName: "transferWithAuthorization",
324
- args: [
325
- (0, import_viem.getAddress)(exactEvmPayload.authorization.from),
326
- (0, import_viem.getAddress)(exactEvmPayload.authorization.to),
327
- BigInt(exactEvmPayload.authorization.value),
328
- BigInt(exactEvmPayload.authorization.validAfter),
329
- BigInt(exactEvmPayload.authorization.validBefore),
330
- exactEvmPayload.authorization.nonce,
331
- parsedSig.v || parsedSig.yParity,
332
- parsedSig.r,
333
- parsedSig.s
334
- ]
335
- });
336
- } else {
337
- tx = await this.signer.writeContract({
338
- address: (0, import_viem.getAddress)(requirements.asset),
339
- abi: eip3009ABI,
340
- functionName: "transferWithAuthorization",
341
- args: [
342
- (0, import_viem.getAddress)(exactEvmPayload.authorization.from),
343
- (0, import_viem.getAddress)(exactEvmPayload.authorization.to),
344
- BigInt(exactEvmPayload.authorization.value),
345
- BigInt(exactEvmPayload.authorization.validAfter),
346
- BigInt(exactEvmPayload.authorization.validBefore),
347
- exactEvmPayload.authorization.nonce,
348
- signature
349
- ]
350
- });
351
- }
352
- const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
353
- if (receipt.status !== "success") {
354
- return {
355
- success: false,
356
- errorReason: "invalid_transaction_state",
357
- transaction: tx,
358
- network: payload.accepted.network,
359
- payer: exactEvmPayload.authorization.from
360
- };
361
- }
362
- return {
363
- success: true,
364
- transaction: tx,
365
- network: payload.accepted.network,
366
- payer: exactEvmPayload.authorization.from
367
- };
368
- } catch (error) {
369
- console.error("Failed to settle transaction:", error);
370
- return {
371
- success: false,
372
- errorReason: "transaction_failed",
373
- transaction: "",
374
- network: payload.accepted.network,
375
- payer: exactEvmPayload.authorization.from
376
- };
771
+ const rawPayload = payload.payload;
772
+ if (isPermit2Payload(rawPayload)) {
773
+ return settlePermit2(this.signer, payload, requirements, rawPayload);
377
774
  }
775
+ const eip3009Payload = rawPayload;
776
+ return settleEIP3009(this.signer, payload, requirements, eip3009Payload, this.config);
378
777
  }
379
778
  };
380
779
 
381
780
  // src/exact/v1/facilitator/scheme.ts
781
+ var import_viem5 = require("viem");
782
+
783
+ // src/utils.ts
784
+ var import_viem4 = require("viem");
785
+
786
+ // src/exact/v1/client/scheme.ts
382
787
  var import_viem3 = require("viem");
383
788
 
789
+ // src/v1/index.ts
790
+ var EVM_NETWORK_CHAIN_ID_MAP = {
791
+ ethereum: 1,
792
+ sepolia: 11155111,
793
+ abstract: 2741,
794
+ "abstract-testnet": 11124,
795
+ "base-sepolia": 84532,
796
+ base: 8453,
797
+ "avalanche-fuji": 43113,
798
+ avalanche: 43114,
799
+ iotex: 4689,
800
+ sei: 1329,
801
+ "sei-testnet": 1328,
802
+ polygon: 137,
803
+ "polygon-amoy": 80002,
804
+ peaq: 3338,
805
+ story: 1514,
806
+ educhain: 41923,
807
+ "skale-base-sepolia": 324705682
808
+ };
809
+ var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
810
+
384
811
  // src/utils.ts
385
- var import_viem2 = require("viem");
386
812
  function getEvmChainId(network) {
387
- const networkMap = {
388
- base: 8453,
389
- "base-sepolia": 84532,
390
- ethereum: 1,
391
- sepolia: 11155111,
392
- polygon: 137,
393
- "polygon-amoy": 80002
394
- };
395
- return networkMap[network] || 1;
813
+ const chainId = EVM_NETWORK_CHAIN_ID_MAP[network];
814
+ if (!chainId) {
815
+ throw new Error(`Unsupported network: ${network}`);
816
+ }
817
+ return chainId;
396
818
  }
397
819
 
398
820
  // src/exact/v1/facilitator/scheme.ts
399
- var ExactEvmSchemeV1 = class {
821
+ var ExactEvmSchemeV12 = class {
400
822
  /**
401
823
  * Creates a new ExactEvmFacilitatorV1 instance.
402
824
  *
@@ -449,7 +871,16 @@ var ExactEvmSchemeV1 = class {
449
871
  payer: exactEvmPayload.authorization.from
450
872
  };
451
873
  }
452
- const chainId = getEvmChainId(payloadV1.network);
874
+ let chainId;
875
+ try {
876
+ chainId = getEvmChainId(payloadV1.network);
877
+ } catch {
878
+ return {
879
+ isValid: false,
880
+ invalidReason: `invalid_network`,
881
+ payer: exactEvmPayload.authorization.from
882
+ };
883
+ }
453
884
  if (!requirements.extra?.name || !requirements.extra?.version) {
454
885
  return {
455
886
  isValid: false,
@@ -458,7 +889,7 @@ var ExactEvmSchemeV1 = class {
458
889
  };
459
890
  }
460
891
  const { name, version } = requirements.extra;
461
- const erc20Address = (0, import_viem3.getAddress)(requirements.asset);
892
+ const erc20Address = (0, import_viem5.getAddress)(requirements.asset);
462
893
  if (payloadV1.network !== requirements.network) {
463
894
  return {
464
895
  isValid: false,
@@ -505,8 +936,8 @@ var ExactEvmSchemeV1 = class {
505
936
  const payerAddress = exactEvmPayload.authorization.from;
506
937
  const bytecode = await this.signer.getCode({ address: payerAddress });
507
938
  if (!bytecode || bytecode === "0x") {
508
- const erc6492Data = (0, import_viem3.parseErc6492Signature)(signature);
509
- const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem3.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
939
+ const erc6492Data = (0, import_viem5.parseErc6492Signature)(signature);
940
+ const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem5.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
510
941
  if (!hasDeploymentInfo) {
511
942
  return {
512
943
  isValid: false,
@@ -529,7 +960,7 @@ var ExactEvmSchemeV1 = class {
529
960
  };
530
961
  }
531
962
  }
532
- if ((0, import_viem3.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem3.getAddress)(requirements.payTo)) {
963
+ if ((0, import_viem5.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem5.getAddress)(requirements.payTo)) {
533
964
  return {
534
965
  isValid: false,
535
966
  invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
@@ -562,6 +993,7 @@ var ExactEvmSchemeV1 = class {
562
993
  return {
563
994
  isValid: false,
564
995
  invalidReason: "insufficient_funds",
996
+ invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
565
997
  payer: exactEvmPayload.authorization.from
566
998
  };
567
999
  }
@@ -601,9 +1033,9 @@ var ExactEvmSchemeV1 = class {
601
1033
  };
602
1034
  }
603
1035
  try {
604
- const parseResult = (0, import_viem3.parseErc6492Signature)(exactEvmPayload.signature);
1036
+ const parseResult = (0, import_viem5.parseErc6492Signature)(exactEvmPayload.signature);
605
1037
  const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
606
- if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem3.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
1038
+ if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem5.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
607
1039
  const payerAddress = exactEvmPayload.authorization.from;
608
1040
  const bytecode = await this.signer.getCode({ address: payerAddress });
609
1041
  if (!bytecode || bytecode === "0x") {
@@ -627,14 +1059,14 @@ var ExactEvmSchemeV1 = class {
627
1059
  const isECDSA = signatureLength === 130;
628
1060
  let tx;
629
1061
  if (isECDSA) {
630
- const parsedSig = (0, import_viem3.parseSignature)(signature);
1062
+ const parsedSig = (0, import_viem5.parseSignature)(signature);
631
1063
  tx = await this.signer.writeContract({
632
- address: (0, import_viem3.getAddress)(requirements.asset),
1064
+ address: (0, import_viem5.getAddress)(requirements.asset),
633
1065
  abi: eip3009ABI,
634
1066
  functionName: "transferWithAuthorization",
635
1067
  args: [
636
- (0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
637
- (0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
1068
+ (0, import_viem5.getAddress)(exactEvmPayload.authorization.from),
1069
+ (0, import_viem5.getAddress)(exactEvmPayload.authorization.to),
638
1070
  BigInt(exactEvmPayload.authorization.value),
639
1071
  BigInt(exactEvmPayload.authorization.validAfter),
640
1072
  BigInt(exactEvmPayload.authorization.validBefore),
@@ -646,12 +1078,12 @@ var ExactEvmSchemeV1 = class {
646
1078
  });
647
1079
  } else {
648
1080
  tx = await this.signer.writeContract({
649
- address: (0, import_viem3.getAddress)(requirements.asset),
1081
+ address: (0, import_viem5.getAddress)(requirements.asset),
650
1082
  abi: eip3009ABI,
651
1083
  functionName: "transferWithAuthorization",
652
1084
  args: [
653
- (0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
654
- (0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
1085
+ (0, import_viem5.getAddress)(exactEvmPayload.authorization.from),
1086
+ (0, import_viem5.getAddress)(exactEvmPayload.authorization.to),
655
1087
  BigInt(exactEvmPayload.authorization.value),
656
1088
  BigInt(exactEvmPayload.authorization.validAfter),
657
1089
  BigInt(exactEvmPayload.authorization.validBefore),
@@ -689,28 +1121,6 @@ var ExactEvmSchemeV1 = class {
689
1121
  }
690
1122
  };
691
1123
 
692
- // src/exact/v1/client/scheme.ts
693
- var import_viem4 = require("viem");
694
-
695
- // src/v1/index.ts
696
- var NETWORKS = [
697
- "abstract",
698
- "abstract-testnet",
699
- "base-sepolia",
700
- "base",
701
- "avalanche-fuji",
702
- "avalanche",
703
- "iotex",
704
- "sei",
705
- "sei-testnet",
706
- "polygon",
707
- "polygon-amoy",
708
- "peaq",
709
- "story",
710
- "educhain",
711
- "skale-base-sepolia"
712
- ];
713
-
714
1124
  // src/exact/facilitator/register.ts
715
1125
  function registerExactEvmScheme(facilitator, config) {
716
1126
  facilitator.register(
@@ -721,7 +1131,7 @@ function registerExactEvmScheme(facilitator, config) {
721
1131
  );
722
1132
  facilitator.registerV1(
723
1133
  NETWORKS,
724
- new ExactEvmSchemeV1(config.signer, {
1134
+ new ExactEvmSchemeV12(config.signer, {
725
1135
  deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
726
1136
  })
727
1137
  );