@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
@@ -1,16 +1,19 @@
1
1
  import {
2
2
  isPermit2Payload
3
- } from "../../chunk-PFULIQAE.mjs";
3
+ } from "../../chunk-TKN5V2BV.mjs";
4
4
  import {
5
- ExactEvmSchemeV12 as ExactEvmSchemeV1,
5
+ ExactEvmSchemeV1,
6
6
  NETWORKS,
7
7
  PERMIT2_ADDRESS,
8
8
  authorizationTypes,
9
9
  eip3009ABI,
10
+ erc20AllowanceAbi,
11
+ erc20ApproveAbi,
12
+ getEvmChainId,
10
13
  permit2WitnessTypes,
11
14
  x402ExactPermit2ProxyABI,
12
15
  x402ExactPermit2ProxyAddress
13
- } from "../../chunk-RPL6OFJL.mjs";
16
+ } from "../../chunk-7KHQD5KT.mjs";
14
17
 
15
18
  // src/exact/facilitator/eip3009.ts
16
19
  import { getAddress, isAddressEqual, parseErc6492Signature, parseSignature } from "viem";
@@ -45,7 +48,7 @@ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
45
48
  domain: {
46
49
  name,
47
50
  version,
48
- chainId: parseInt(requirements.network.split(":")[1]),
51
+ chainId: getEvmChainId(requirements.network),
49
52
  verifyingContract: erc20Address
50
53
  },
51
54
  message: {
@@ -244,20 +247,142 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
244
247
  }
245
248
 
246
249
  // src/exact/facilitator/permit2.ts
247
- import { getAddress as getAddress2 } from "viem";
248
- var erc20AllowanceABI = [
249
- {
250
- type: "function",
251
- name: "allowance",
252
- inputs: [
253
- { name: "owner", type: "address" },
254
- { name: "spender", type: "address" }
255
- ],
256
- outputs: [{ type: "uint256" }],
257
- stateMutability: "view"
258
- }
259
- ];
260
- async function verifyPermit2(signer, payload, requirements, permit2Payload) {
250
+ import {
251
+ extractEip2612GasSponsoringInfo,
252
+ validateEip2612GasSponsoringInfo,
253
+ extractErc20ApprovalGasSponsoringInfo,
254
+ ERC20_APPROVAL_GAS_SPONSORING
255
+ } from "@x402/extensions";
256
+ import { getAddress as getAddress3 } from "viem";
257
+
258
+ // src/exact/facilitator/errors.ts
259
+ var ErrPermit2InvalidSignature = "invalid_permit2_signature";
260
+ var ErrPermit2InvalidAmount = "permit2_invalid_amount";
261
+ var ErrPermit2InvalidDestination = "permit2_invalid_destination";
262
+ var ErrPermit2InvalidOwner = "permit2_invalid_owner";
263
+ var ErrPermit2PaymentTooEarly = "permit2_payment_too_early";
264
+ var ErrPermit2InvalidNonce = "permit2_invalid_nonce";
265
+ var ErrPermit2612AmountMismatch = "permit2_2612_amount_mismatch";
266
+ var ErrErc20ApprovalInvalidFormat = "invalid_erc20_approval_extension_format";
267
+ var ErrErc20ApprovalFromMismatch = "erc20_approval_from_mismatch";
268
+ var ErrErc20ApprovalAssetMismatch = "erc20_approval_asset_mismatch";
269
+ var ErrErc20ApprovalSpenderNotPermit2 = "erc20_approval_spender_not_permit2";
270
+ var ErrErc20ApprovalTxWrongTarget = "erc20_approval_tx_wrong_target";
271
+ var ErrErc20ApprovalTxWrongSelector = "erc20_approval_tx_wrong_selector";
272
+ var ErrErc20ApprovalTxWrongSpender = "erc20_approval_tx_wrong_spender";
273
+ var ErrErc20ApprovalTxInvalidCalldata = "erc20_approval_tx_invalid_calldata";
274
+ var ErrErc20ApprovalTxSignerMismatch = "erc20_approval_tx_signer_mismatch";
275
+ var ErrErc20ApprovalTxInvalidSignature = "erc20_approval_tx_invalid_signature";
276
+ var ErrErc20ApprovalTxParseFailed = "erc20_approval_tx_parse_failed";
277
+
278
+ // src/exact/facilitator/erc20approval.ts
279
+ import {
280
+ getAddress as getAddress2,
281
+ parseTransaction,
282
+ decodeFunctionData,
283
+ recoverTransactionAddress
284
+ } from "viem";
285
+ import {
286
+ validateErc20ApprovalGasSponsoringInfo
287
+ } from "@x402/extensions";
288
+ var APPROVE_SELECTOR = "0x095ea7b3";
289
+ async function validateErc20ApprovalForPayment(info, payer, tokenAddress) {
290
+ if (!validateErc20ApprovalGasSponsoringInfo(info)) {
291
+ return {
292
+ isValid: false,
293
+ invalidReason: ErrErc20ApprovalInvalidFormat,
294
+ invalidMessage: "ERC-20 approval extension info failed schema validation"
295
+ };
296
+ }
297
+ if (getAddress2(info.from) !== getAddress2(payer)) {
298
+ return {
299
+ isValid: false,
300
+ invalidReason: ErrErc20ApprovalFromMismatch,
301
+ invalidMessage: `Expected from=${payer}, got ${info.from}`
302
+ };
303
+ }
304
+ if (getAddress2(info.asset) !== tokenAddress) {
305
+ return {
306
+ isValid: false,
307
+ invalidReason: ErrErc20ApprovalAssetMismatch,
308
+ invalidMessage: `Expected asset=${tokenAddress}, got ${info.asset}`
309
+ };
310
+ }
311
+ if (getAddress2(info.spender) !== getAddress2(PERMIT2_ADDRESS)) {
312
+ return {
313
+ isValid: false,
314
+ invalidReason: ErrErc20ApprovalSpenderNotPermit2,
315
+ invalidMessage: `Expected spender=${PERMIT2_ADDRESS}, got ${info.spender}`
316
+ };
317
+ }
318
+ try {
319
+ const serializedTx = info.signedTransaction;
320
+ const tx = parseTransaction(serializedTx);
321
+ if (!tx.to || getAddress2(tx.to) !== tokenAddress) {
322
+ return {
323
+ isValid: false,
324
+ invalidReason: ErrErc20ApprovalTxWrongTarget,
325
+ invalidMessage: `Transaction targets ${tx.to ?? "null"}, expected ${tokenAddress}`
326
+ };
327
+ }
328
+ const data = tx.data ?? "0x";
329
+ if (!data.startsWith(APPROVE_SELECTOR)) {
330
+ return {
331
+ isValid: false,
332
+ invalidReason: ErrErc20ApprovalTxWrongSelector,
333
+ invalidMessage: `Transaction calldata does not start with approve() selector ${APPROVE_SELECTOR}`
334
+ };
335
+ }
336
+ try {
337
+ const decoded = decodeFunctionData({
338
+ abi: erc20ApproveAbi,
339
+ data
340
+ });
341
+ const calldataSpender = getAddress2(decoded.args[0]);
342
+ if (calldataSpender !== getAddress2(PERMIT2_ADDRESS)) {
343
+ return {
344
+ isValid: false,
345
+ invalidReason: ErrErc20ApprovalTxWrongSpender,
346
+ invalidMessage: `approve() spender is ${calldataSpender}, expected Permit2 ${PERMIT2_ADDRESS}`
347
+ };
348
+ }
349
+ } catch {
350
+ return {
351
+ isValid: false,
352
+ invalidReason: ErrErc20ApprovalTxInvalidCalldata,
353
+ invalidMessage: "Failed to decode approve() calldata from the signed transaction"
354
+ };
355
+ }
356
+ try {
357
+ const recoveredAddress = await recoverTransactionAddress({
358
+ serializedTransaction: serializedTx
359
+ });
360
+ if (getAddress2(recoveredAddress) !== getAddress2(payer)) {
361
+ return {
362
+ isValid: false,
363
+ invalidReason: ErrErc20ApprovalTxSignerMismatch,
364
+ invalidMessage: `Transaction signed by ${recoveredAddress}, expected payer ${payer}`
365
+ };
366
+ }
367
+ } catch {
368
+ return {
369
+ isValid: false,
370
+ invalidReason: ErrErc20ApprovalTxInvalidSignature,
371
+ invalidMessage: "Failed to recover signer from the signed transaction"
372
+ };
373
+ }
374
+ } catch {
375
+ return {
376
+ isValid: false,
377
+ invalidReason: ErrErc20ApprovalTxParseFailed,
378
+ invalidMessage: "Failed to parse the signed transaction"
379
+ };
380
+ }
381
+ return { isValid: true };
382
+ }
383
+
384
+ // src/exact/facilitator/permit2.ts
385
+ async function verifyPermit2(signer, payload, requirements, permit2Payload, context) {
261
386
  const payer = permit2Payload.permit2Authorization.from;
262
387
  if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
263
388
  return {
@@ -273,16 +398,16 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
273
398
  payer
274
399
  };
275
400
  }
276
- const chainId = parseInt(requirements.network.split(":")[1]);
277
- const tokenAddress = getAddress2(requirements.asset);
278
- if (getAddress2(permit2Payload.permit2Authorization.spender) !== getAddress2(x402ExactPermit2ProxyAddress)) {
401
+ const chainId = getEvmChainId(requirements.network);
402
+ const tokenAddress = getAddress3(requirements.asset);
403
+ if (getAddress3(permit2Payload.permit2Authorization.spender) !== getAddress3(x402ExactPermit2ProxyAddress)) {
279
404
  return {
280
405
  isValid: false,
281
406
  invalidReason: "invalid_permit2_spender",
282
407
  payer
283
408
  };
284
409
  }
285
- if (getAddress2(permit2Payload.permit2Authorization.witness.to) !== getAddress2(requirements.payTo)) {
410
+ if (getAddress3(permit2Payload.permit2Authorization.witness.to) !== getAddress3(requirements.payTo)) {
286
411
  return {
287
412
  isValid: false,
288
413
  invalidReason: "invalid_permit2_recipient_mismatch",
@@ -311,7 +436,7 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
311
436
  payer
312
437
  };
313
438
  }
314
- if (getAddress2(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
439
+ if (getAddress3(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
315
440
  return {
316
441
  isValid: false,
317
442
  invalidReason: "permit2_token_mismatch",
@@ -328,16 +453,15 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
328
453
  },
329
454
  message: {
330
455
  permitted: {
331
- token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
456
+ token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
332
457
  amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
333
458
  },
334
- spender: getAddress2(permit2Payload.permit2Authorization.spender),
459
+ spender: getAddress3(permit2Payload.permit2Authorization.spender),
335
460
  nonce: BigInt(permit2Payload.permit2Authorization.nonce),
336
461
  deadline: BigInt(permit2Payload.permit2Authorization.deadline),
337
462
  witness: {
338
- to: getAddress2(permit2Payload.permit2Authorization.witness.to),
339
- validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
340
- extra: permit2Payload.permit2Authorization.witness.extra
463
+ to: getAddress3(permit2Payload.permit2Authorization.witness.to),
464
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
341
465
  }
342
466
  }
343
467
  };
@@ -361,21 +485,16 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
361
485
  payer
362
486
  };
363
487
  }
364
- try {
365
- const allowance = await signer.readContract({
366
- address: tokenAddress,
367
- abi: erc20AllowanceABI,
368
- functionName: "allowance",
369
- args: [payer, PERMIT2_ADDRESS]
370
- });
371
- if (allowance < BigInt(requirements.amount)) {
372
- return {
373
- isValid: false,
374
- invalidReason: "permit2_allowance_required",
375
- payer
376
- };
377
- }
378
- } catch {
488
+ const allowanceResult = await _verifyPermit2Allowance(
489
+ signer,
490
+ payload,
491
+ requirements,
492
+ payer,
493
+ tokenAddress,
494
+ context
495
+ );
496
+ if (allowanceResult) {
497
+ return allowanceResult;
379
498
  }
380
499
  try {
381
500
  const balance = await signer.readContract({
@@ -400,9 +519,53 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
400
519
  payer
401
520
  };
402
521
  }
403
- async function settlePermit2(signer, payload, requirements, permit2Payload) {
522
+ async function _verifyPermit2Allowance(signer, payload, requirements, payer, tokenAddress, context) {
523
+ try {
524
+ const allowance = await signer.readContract({
525
+ address: tokenAddress,
526
+ abi: erc20AllowanceAbi,
527
+ functionName: "allowance",
528
+ args: [payer, PERMIT2_ADDRESS]
529
+ });
530
+ if (allowance >= BigInt(requirements.amount)) {
531
+ return null;
532
+ }
533
+ const eip2612Info = extractEip2612GasSponsoringInfo(payload);
534
+ if (eip2612Info) {
535
+ const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
536
+ if (!result.isValid) {
537
+ return { isValid: false, invalidReason: result.invalidReason, payer };
538
+ }
539
+ return null;
540
+ }
541
+ const erc20GasSponsorshipExtension = context?.getExtension(
542
+ ERC20_APPROVAL_GAS_SPONSORING.key
543
+ );
544
+ if (erc20GasSponsorshipExtension) {
545
+ const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
546
+ if (erc20Info) {
547
+ const result = await validateErc20ApprovalForPayment(erc20Info, payer, tokenAddress);
548
+ if (!result.isValid) {
549
+ return { isValid: false, invalidReason: result.invalidReason, payer };
550
+ }
551
+ return null;
552
+ }
553
+ }
554
+ return { isValid: false, invalidReason: "permit2_allowance_required", payer };
555
+ } catch {
556
+ const eip2612Info = extractEip2612GasSponsoringInfo(payload);
557
+ if (eip2612Info) {
558
+ const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
559
+ if (!result.isValid) {
560
+ return { isValid: false, invalidReason: result.invalidReason, payer };
561
+ }
562
+ }
563
+ return null;
564
+ }
565
+ }
566
+ async function settlePermit2(signer, payload, requirements, permit2Payload, context) {
404
567
  const payer = permit2Payload.permit2Authorization.from;
405
- const valid = await verifyPermit2(signer, payload, requirements, permit2Payload);
568
+ const valid = await verifyPermit2(signer, payload, requirements, permit2Payload, context);
406
569
  if (!valid.isValid) {
407
570
  return {
408
571
  success: false,
@@ -412,82 +575,223 @@ async function settlePermit2(signer, payload, requirements, permit2Payload) {
412
575
  payer
413
576
  };
414
577
  }
578
+ const eip2612Info = extractEip2612GasSponsoringInfo(payload);
579
+ if (eip2612Info) {
580
+ return _settlePermit2WithEIP2612(signer, payload, permit2Payload, eip2612Info);
581
+ }
582
+ const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
583
+ if (erc20Info) {
584
+ const erc20GasSponsorshipExtension = context?.getExtension(
585
+ ERC20_APPROVAL_GAS_SPONSORING.key
586
+ );
587
+ if (erc20GasSponsorshipExtension?.signer) {
588
+ return _settlePermit2WithERC20Approval(
589
+ erc20GasSponsorshipExtension.signer,
590
+ payload,
591
+ permit2Payload,
592
+ erc20Info
593
+ );
594
+ }
595
+ }
596
+ return _settlePermit2Direct(signer, payload, permit2Payload);
597
+ }
598
+ async function _settlePermit2WithEIP2612(signer, payload, permit2Payload, eip2612Info) {
599
+ const payer = permit2Payload.permit2Authorization.from;
415
600
  try {
601
+ const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
416
602
  const tx = await signer.writeContract({
417
603
  address: x402ExactPermit2ProxyAddress,
418
604
  abi: x402ExactPermit2ProxyABI,
419
- functionName: "settle",
605
+ functionName: "settleWithPermit",
420
606
  args: [
607
+ {
608
+ value: BigInt(eip2612Info.amount),
609
+ deadline: BigInt(eip2612Info.deadline),
610
+ r,
611
+ s,
612
+ v
613
+ },
421
614
  {
422
615
  permitted: {
423
- token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
616
+ token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
424
617
  amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
425
618
  },
426
619
  nonce: BigInt(permit2Payload.permit2Authorization.nonce),
427
620
  deadline: BigInt(permit2Payload.permit2Authorization.deadline)
428
621
  },
429
- getAddress2(payer),
622
+ getAddress3(payer),
430
623
  {
431
- to: getAddress2(permit2Payload.permit2Authorization.witness.to),
432
- validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
433
- extra: permit2Payload.permit2Authorization.witness.extra
624
+ to: getAddress3(permit2Payload.permit2Authorization.witness.to),
625
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
434
626
  },
435
627
  permit2Payload.signature
436
628
  ]
437
629
  });
438
- const receipt = await signer.waitForTransactionReceipt({ hash: tx });
439
- if (receipt.status !== "success") {
630
+ return _waitAndReturn(signer, tx, payload, payer);
631
+ } catch (error) {
632
+ return _mapSettleError(error, payload, payer);
633
+ }
634
+ }
635
+ async function _settlePermit2WithERC20Approval(extensionSigner, payload, permit2Payload, erc20Info) {
636
+ const payer = permit2Payload.permit2Authorization.from;
637
+ try {
638
+ const approvalTxHash = await extensionSigner.sendRawTransaction({
639
+ serializedTransaction: erc20Info.signedTransaction
640
+ });
641
+ const approvalReceipt = await extensionSigner.waitForTransactionReceipt({
642
+ hash: approvalTxHash
643
+ });
644
+ if (approvalReceipt.status !== "success") {
440
645
  return {
441
646
  success: false,
442
- errorReason: "invalid_transaction_state",
443
- transaction: tx,
647
+ errorReason: "erc20_approval_tx_failed",
648
+ transaction: approvalTxHash,
444
649
  network: payload.accepted.network,
445
650
  payer
446
651
  };
447
652
  }
448
- return {
449
- success: true,
450
- transaction: tx,
451
- network: payload.accepted.network,
452
- payer
453
- };
653
+ const tx = await extensionSigner.writeContract({
654
+ address: x402ExactPermit2ProxyAddress,
655
+ abi: x402ExactPermit2ProxyABI,
656
+ functionName: "settle",
657
+ args: [
658
+ {
659
+ permitted: {
660
+ token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
661
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
662
+ },
663
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
664
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline)
665
+ },
666
+ getAddress3(payer),
667
+ {
668
+ to: getAddress3(permit2Payload.permit2Authorization.witness.to),
669
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
670
+ },
671
+ permit2Payload.signature
672
+ ]
673
+ });
674
+ return _waitAndReturn(extensionSigner, tx, payload, payer);
454
675
  } catch (error) {
455
- let errorReason = "transaction_failed";
456
- if (error instanceof Error) {
457
- const message = error.message;
458
- if (message.includes("AmountExceedsPermitted")) {
459
- errorReason = "permit2_amount_exceeds_permitted";
460
- } else if (message.includes("InvalidDestination")) {
461
- errorReason = "permit2_invalid_destination";
462
- } else if (message.includes("InvalidOwner")) {
463
- errorReason = "permit2_invalid_owner";
464
- } else if (message.includes("PaymentTooEarly")) {
465
- errorReason = "permit2_payment_too_early";
466
- } else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
467
- errorReason = "permit2_invalid_signature";
468
- } else if (message.includes("InvalidNonce")) {
469
- errorReason = "permit2_invalid_nonce";
470
- } else {
471
- errorReason = `transaction_failed: ${message.slice(0, 500)}`;
472
- }
473
- }
676
+ return _mapSettleError(error, payload, payer);
677
+ }
678
+ }
679
+ async function _settlePermit2Direct(signer, payload, permit2Payload) {
680
+ const payer = permit2Payload.permit2Authorization.from;
681
+ try {
682
+ const tx = await signer.writeContract({
683
+ address: x402ExactPermit2ProxyAddress,
684
+ abi: x402ExactPermit2ProxyABI,
685
+ functionName: "settle",
686
+ args: [
687
+ {
688
+ permitted: {
689
+ token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
690
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
691
+ },
692
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
693
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline)
694
+ },
695
+ getAddress3(payer),
696
+ {
697
+ to: getAddress3(permit2Payload.permit2Authorization.witness.to),
698
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
699
+ },
700
+ permit2Payload.signature
701
+ ]
702
+ });
703
+ return _waitAndReturn(signer, tx, payload, payer);
704
+ } catch (error) {
705
+ return _mapSettleError(error, payload, payer);
706
+ }
707
+ }
708
+ async function _waitAndReturn(signer, tx, payload, payer) {
709
+ const receipt = await signer.waitForTransactionReceipt({ hash: tx });
710
+ if (receipt.status !== "success") {
474
711
  return {
475
712
  success: false,
476
- errorReason,
477
- transaction: "",
713
+ errorReason: "invalid_transaction_state",
714
+ transaction: tx,
478
715
  network: payload.accepted.network,
479
716
  payer
480
717
  };
481
718
  }
719
+ return {
720
+ success: true,
721
+ transaction: tx,
722
+ network: payload.accepted.network,
723
+ payer
724
+ };
725
+ }
726
+ function _mapSettleError(error, payload, payer) {
727
+ let errorReason = "transaction_failed";
728
+ if (error instanceof Error) {
729
+ const message = error.message;
730
+ if (message.includes("Permit2612AmountMismatch")) {
731
+ errorReason = ErrPermit2612AmountMismatch;
732
+ } else if (message.includes("InvalidAmount")) {
733
+ errorReason = ErrPermit2InvalidAmount;
734
+ } else if (message.includes("InvalidDestination")) {
735
+ errorReason = ErrPermit2InvalidDestination;
736
+ } else if (message.includes("InvalidOwner")) {
737
+ errorReason = ErrPermit2InvalidOwner;
738
+ } else if (message.includes("PaymentTooEarly")) {
739
+ errorReason = ErrPermit2PaymentTooEarly;
740
+ } else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
741
+ errorReason = ErrPermit2InvalidSignature;
742
+ } else if (message.includes("InvalidNonce")) {
743
+ errorReason = ErrPermit2InvalidNonce;
744
+ } else {
745
+ errorReason = `transaction_failed: ${message.slice(0, 500)}`;
746
+ }
747
+ }
748
+ return {
749
+ success: false,
750
+ errorReason,
751
+ transaction: "",
752
+ network: payload.accepted.network,
753
+ payer
754
+ };
755
+ }
756
+ function validateEip2612PermitForPayment(info, payer, tokenAddress) {
757
+ if (!validateEip2612GasSponsoringInfo(info)) {
758
+ return { isValid: false, invalidReason: "invalid_eip2612_extension_format" };
759
+ }
760
+ if (getAddress3(info.from) !== getAddress3(payer)) {
761
+ return { isValid: false, invalidReason: "eip2612_from_mismatch" };
762
+ }
763
+ if (getAddress3(info.asset) !== tokenAddress) {
764
+ return { isValid: false, invalidReason: "eip2612_asset_mismatch" };
765
+ }
766
+ if (getAddress3(info.spender) !== getAddress3(PERMIT2_ADDRESS)) {
767
+ return { isValid: false, invalidReason: "eip2612_spender_not_permit2" };
768
+ }
769
+ const now = Math.floor(Date.now() / 1e3);
770
+ if (BigInt(info.deadline) < BigInt(now + 6)) {
771
+ return { isValid: false, invalidReason: "eip2612_deadline_expired" };
772
+ }
773
+ return { isValid: true };
774
+ }
775
+ function splitEip2612Signature(signature) {
776
+ const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
777
+ if (sig.length !== 130) {
778
+ throw new Error(
779
+ `invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
780
+ );
781
+ }
782
+ const r = `0x${sig.slice(0, 64)}`;
783
+ const s = `0x${sig.slice(64, 128)}`;
784
+ const v = parseInt(sig.slice(128, 130), 16);
785
+ return { v, r, s };
482
786
  }
483
787
 
484
788
  // src/exact/facilitator/scheme.ts
485
789
  var ExactEvmScheme = class {
486
790
  /**
487
- * Creates a new ExactEvmFacilitator instance.
791
+ * Creates a new ExactEvmScheme facilitator instance.
488
792
  *
489
793
  * @param signer - The EVM signer for facilitator operations
490
- * @param config - Optional configuration for the facilitator
794
+ * @param config - Optional configuration
491
795
  */
492
796
  constructor(signer, config) {
493
797
  this.signer = signer;
@@ -498,53 +802,51 @@ var ExactEvmScheme = class {
498
802
  };
499
803
  }
500
804
  /**
501
- * Get mechanism-specific extra data for the supported kinds endpoint.
502
- * For EVM, no extra data is needed.
805
+ * Returns undefined — EVM has no mechanism-specific extra data.
503
806
  *
504
- * @param _ - The network identifier (unused for EVM)
505
- * @returns undefined (EVM has no extra data)
807
+ * @param _ - The network identifier (unused)
808
+ * @returns undefined
506
809
  */
507
810
  getExtra(_) {
508
811
  return void 0;
509
812
  }
510
813
  /**
511
- * Get signer addresses used by this facilitator.
512
- * Returns all addresses this facilitator can use for signing/settling transactions.
814
+ * Returns facilitator wallet addresses for the supported response.
513
815
  *
514
- * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)
816
+ * @param _ - The network identifier (unused, addresses are network-agnostic)
515
817
  * @returns Array of facilitator wallet addresses
516
818
  */
517
819
  getSigners(_) {
518
820
  return [...this.signer.getAddresses()];
519
821
  }
520
822
  /**
521
- * Verifies a payment payload.
522
- * Routes to the appropriate verification logic based on payload type.
823
+ * Verifies a payment payload. Routes to Permit2 or EIP-3009 based on payload type.
523
824
  *
524
825
  * @param payload - The payment payload to verify
525
826
  * @param requirements - The payment requirements
827
+ * @param context - Optional facilitator context for extension capabilities
526
828
  * @returns Promise resolving to verification response
527
829
  */
528
- async verify(payload, requirements) {
830
+ async verify(payload, requirements, context) {
529
831
  const rawPayload = payload.payload;
530
832
  if (isPermit2Payload(rawPayload)) {
531
- return verifyPermit2(this.signer, payload, requirements, rawPayload);
833
+ return verifyPermit2(this.signer, payload, requirements, rawPayload, context);
532
834
  }
533
835
  const eip3009Payload = rawPayload;
534
836
  return verifyEIP3009(this.signer, payload, requirements, eip3009Payload);
535
837
  }
536
838
  /**
537
- * Settles a payment by executing the transfer.
538
- * Routes to the appropriate settlement logic based on payload type.
839
+ * Settles a payment. Routes to Permit2 or EIP-3009 based on payload type.
539
840
  *
540
841
  * @param payload - The payment payload to settle
541
842
  * @param requirements - The payment requirements
843
+ * @param context - Optional facilitator context for extension capabilities
542
844
  * @returns Promise resolving to settlement response
543
845
  */
544
- async settle(payload, requirements) {
846
+ async settle(payload, requirements, context) {
545
847
  const rawPayload = payload.payload;
546
848
  if (isPermit2Payload(rawPayload)) {
547
- return settlePermit2(this.signer, payload, requirements, rawPayload);
849
+ return settlePermit2(this.signer, payload, requirements, rawPayload, context);
548
850
  }
549
851
  const eip3009Payload = rawPayload;
550
852
  return settleEIP3009(this.signer, payload, requirements, eip3009Payload, this.config);