@x402/evm 2.2.0 → 2.3.1

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 (52) hide show
  1. package/dist/cjs/exact/client/index.d.ts +2 -2
  2. package/dist/cjs/exact/client/index.js +265 -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 +692 -281
  6. package/dist/cjs/exact/facilitator/index.js.map +1 -1
  7. package/dist/cjs/exact/server/index.js +8 -1
  8. package/dist/cjs/exact/server/index.js.map +1 -1
  9. package/dist/cjs/exact/v1/client/index.js +44 -17
  10. package/dist/cjs/exact/v1/client/index.js.map +1 -1
  11. package/dist/cjs/exact/v1/facilitator/index.js +60 -26
  12. package/dist/cjs/exact/v1/facilitator/index.js.map +1 -1
  13. package/dist/cjs/index.d.ts +458 -31
  14. package/dist/cjs/index.js +439 -63
  15. package/dist/cjs/index.js.map +1 -1
  16. package/dist/cjs/permit2-BYv82va2.d.ts +103 -0
  17. package/dist/cjs/v1/index.d.ts +22 -1
  18. package/dist/cjs/v1/index.js +34 -29
  19. package/dist/cjs/v1/index.js.map +1 -1
  20. package/dist/esm/chunk-E2YMUI3X.mjs +229 -0
  21. package/dist/esm/chunk-E2YMUI3X.mjs.map +1 -0
  22. package/dist/esm/chunk-PFULIQAE.mjs +13 -0
  23. package/dist/esm/chunk-PFULIQAE.mjs.map +1 -0
  24. package/dist/esm/chunk-RPL6OFJL.mjs +659 -0
  25. package/dist/esm/chunk-RPL6OFJL.mjs.map +1 -0
  26. package/dist/esm/exact/client/index.d.mts +2 -2
  27. package/dist/esm/exact/client/index.mjs +10 -30
  28. package/dist/esm/exact/client/index.mjs.map +1 -1
  29. package/dist/esm/exact/facilitator/index.d.mts +3 -0
  30. package/dist/esm/exact/facilitator/index.mjs +491 -241
  31. package/dist/esm/exact/facilitator/index.mjs.map +1 -1
  32. package/dist/esm/exact/server/index.mjs +8 -1
  33. package/dist/esm/exact/server/index.mjs.map +1 -1
  34. package/dist/esm/exact/v1/client/index.mjs +1 -2
  35. package/dist/esm/exact/v1/facilitator/index.mjs +2 -3
  36. package/dist/esm/index.d.mts +458 -31
  37. package/dist/esm/index.mjs +31 -4
  38. package/dist/esm/index.mjs.map +1 -1
  39. package/dist/esm/permit2-BsAoJiWD.d.mts +103 -0
  40. package/dist/esm/v1/index.d.mts +22 -1
  41. package/dist/esm/v1/index.mjs +4 -6
  42. package/package.json +2 -2
  43. package/dist/esm/chunk-FOUXRQAV.mjs +0 -88
  44. package/dist/esm/chunk-FOUXRQAV.mjs.map +0 -1
  45. package/dist/esm/chunk-JYZWCLMP.mjs +0 -305
  46. package/dist/esm/chunk-JYZWCLMP.mjs.map +0 -1
  47. package/dist/esm/chunk-PSA4YVU2.mjs +0 -92
  48. package/dist/esm/chunk-PSA4YVU2.mjs.map +0 -1
  49. package/dist/esm/chunk-QLXM7BIB.mjs +0 -23
  50. package/dist/esm/chunk-QLXM7BIB.mjs.map +0 -1
  51. package/dist/esm/chunk-ZYXTTU74.mjs +0 -88
  52. package/dist/esm/chunk-ZYXTTU74.mjs.map +0 -1
@@ -1,17 +1,487 @@
1
1
  import {
2
- NETWORKS
3
- } from "../../chunk-QLXM7BIB.mjs";
4
- import "../../chunk-PSA4YVU2.mjs";
5
- import {
6
- ExactEvmSchemeV1
7
- } from "../../chunk-JYZWCLMP.mjs";
2
+ isPermit2Payload
3
+ } from "../../chunk-PFULIQAE.mjs";
8
4
  import {
5
+ ExactEvmSchemeV12 as ExactEvmSchemeV1,
6
+ NETWORKS,
7
+ PERMIT2_ADDRESS,
9
8
  authorizationTypes,
10
- eip3009ABI
11
- } from "../../chunk-ZYXTTU74.mjs";
9
+ eip3009ABI,
10
+ permit2WitnessTypes,
11
+ x402ExactPermit2ProxyABI,
12
+ x402ExactPermit2ProxyAddress
13
+ } from "../../chunk-RPL6OFJL.mjs";
12
14
 
13
- // src/exact/facilitator/scheme.ts
15
+ // src/exact/facilitator/eip3009.ts
14
16
  import { getAddress, isAddressEqual, parseErc6492Signature, parseSignature } from "viem";
17
+ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
18
+ const payer = eip3009Payload.authorization.from;
19
+ if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
20
+ return {
21
+ isValid: false,
22
+ invalidReason: "unsupported_scheme",
23
+ payer
24
+ };
25
+ }
26
+ if (!requirements.extra?.name || !requirements.extra?.version) {
27
+ return {
28
+ isValid: false,
29
+ invalidReason: "missing_eip712_domain",
30
+ payer
31
+ };
32
+ }
33
+ const { name, version } = requirements.extra;
34
+ const erc20Address = getAddress(requirements.asset);
35
+ if (payload.accepted.network !== requirements.network) {
36
+ return {
37
+ isValid: false,
38
+ invalidReason: "network_mismatch",
39
+ payer
40
+ };
41
+ }
42
+ const permitTypedData = {
43
+ types: authorizationTypes,
44
+ primaryType: "TransferWithAuthorization",
45
+ domain: {
46
+ name,
47
+ version,
48
+ chainId: parseInt(requirements.network.split(":")[1]),
49
+ verifyingContract: erc20Address
50
+ },
51
+ message: {
52
+ from: eip3009Payload.authorization.from,
53
+ to: eip3009Payload.authorization.to,
54
+ value: BigInt(eip3009Payload.authorization.value),
55
+ validAfter: BigInt(eip3009Payload.authorization.validAfter),
56
+ validBefore: BigInt(eip3009Payload.authorization.validBefore),
57
+ nonce: eip3009Payload.authorization.nonce
58
+ }
59
+ };
60
+ try {
61
+ const recoveredAddress = await signer.verifyTypedData({
62
+ address: eip3009Payload.authorization.from,
63
+ ...permitTypedData,
64
+ signature: eip3009Payload.signature
65
+ });
66
+ if (!recoveredAddress) {
67
+ return {
68
+ isValid: false,
69
+ invalidReason: "invalid_exact_evm_payload_signature",
70
+ payer
71
+ };
72
+ }
73
+ } catch {
74
+ const signature = eip3009Payload.signature;
75
+ const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
76
+ const isSmartWallet = signatureLength > 130;
77
+ if (isSmartWallet) {
78
+ const payerAddress = eip3009Payload.authorization.from;
79
+ const bytecode = await signer.getCode({ address: payerAddress });
80
+ if (!bytecode || bytecode === "0x") {
81
+ const erc6492Data = parseErc6492Signature(signature);
82
+ const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !isAddressEqual(erc6492Data.address, "0x0000000000000000000000000000000000000000");
83
+ if (!hasDeploymentInfo) {
84
+ return {
85
+ isValid: false,
86
+ invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
87
+ payer: payerAddress
88
+ };
89
+ }
90
+ } else {
91
+ return {
92
+ isValid: false,
93
+ invalidReason: "invalid_exact_evm_payload_signature",
94
+ payer
95
+ };
96
+ }
97
+ } else {
98
+ return {
99
+ isValid: false,
100
+ invalidReason: "invalid_exact_evm_payload_signature",
101
+ payer
102
+ };
103
+ }
104
+ }
105
+ if (getAddress(eip3009Payload.authorization.to) !== getAddress(requirements.payTo)) {
106
+ return {
107
+ isValid: false,
108
+ invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
109
+ payer
110
+ };
111
+ }
112
+ const now = Math.floor(Date.now() / 1e3);
113
+ if (BigInt(eip3009Payload.authorization.validBefore) < BigInt(now + 6)) {
114
+ return {
115
+ isValid: false,
116
+ invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
117
+ payer
118
+ };
119
+ }
120
+ if (BigInt(eip3009Payload.authorization.validAfter) > BigInt(now)) {
121
+ return {
122
+ isValid: false,
123
+ invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
124
+ payer
125
+ };
126
+ }
127
+ try {
128
+ const balance = await signer.readContract({
129
+ address: erc20Address,
130
+ abi: eip3009ABI,
131
+ functionName: "balanceOf",
132
+ args: [eip3009Payload.authorization.from]
133
+ });
134
+ if (BigInt(balance) < BigInt(requirements.amount)) {
135
+ return {
136
+ isValid: false,
137
+ invalidReason: "insufficient_funds",
138
+ 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.`,
139
+ payer
140
+ };
141
+ }
142
+ } catch {
143
+ }
144
+ if (BigInt(eip3009Payload.authorization.value) < BigInt(requirements.amount)) {
145
+ return {
146
+ isValid: false,
147
+ invalidReason: "invalid_exact_evm_payload_authorization_value",
148
+ payer
149
+ };
150
+ }
151
+ return {
152
+ isValid: true,
153
+ invalidReason: void 0,
154
+ payer
155
+ };
156
+ }
157
+ async function settleEIP3009(signer, payload, requirements, eip3009Payload, config) {
158
+ const payer = eip3009Payload.authorization.from;
159
+ const valid = await verifyEIP3009(signer, payload, requirements, eip3009Payload);
160
+ if (!valid.isValid) {
161
+ return {
162
+ success: false,
163
+ network: payload.accepted.network,
164
+ transaction: "",
165
+ errorReason: valid.invalidReason ?? "invalid_scheme",
166
+ payer
167
+ };
168
+ }
169
+ try {
170
+ const parseResult = parseErc6492Signature(eip3009Payload.signature);
171
+ const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
172
+ if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !isAddressEqual(factoryAddress, "0x0000000000000000000000000000000000000000")) {
173
+ const bytecode = await signer.getCode({ address: payer });
174
+ if (!bytecode || bytecode === "0x") {
175
+ const deployTx = await signer.sendTransaction({
176
+ to: factoryAddress,
177
+ data: factoryCalldata
178
+ });
179
+ await signer.waitForTransactionReceipt({ hash: deployTx });
180
+ }
181
+ }
182
+ const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
183
+ const isECDSA = signatureLength === 130;
184
+ let tx;
185
+ if (isECDSA) {
186
+ const parsedSig = parseSignature(signature);
187
+ tx = await signer.writeContract({
188
+ address: getAddress(requirements.asset),
189
+ abi: eip3009ABI,
190
+ functionName: "transferWithAuthorization",
191
+ args: [
192
+ getAddress(eip3009Payload.authorization.from),
193
+ getAddress(eip3009Payload.authorization.to),
194
+ BigInt(eip3009Payload.authorization.value),
195
+ BigInt(eip3009Payload.authorization.validAfter),
196
+ BigInt(eip3009Payload.authorization.validBefore),
197
+ eip3009Payload.authorization.nonce,
198
+ parsedSig.v || parsedSig.yParity,
199
+ parsedSig.r,
200
+ parsedSig.s
201
+ ]
202
+ });
203
+ } else {
204
+ tx = await signer.writeContract({
205
+ address: getAddress(requirements.asset),
206
+ abi: eip3009ABI,
207
+ functionName: "transferWithAuthorization",
208
+ args: [
209
+ getAddress(eip3009Payload.authorization.from),
210
+ getAddress(eip3009Payload.authorization.to),
211
+ BigInt(eip3009Payload.authorization.value),
212
+ BigInt(eip3009Payload.authorization.validAfter),
213
+ BigInt(eip3009Payload.authorization.validBefore),
214
+ eip3009Payload.authorization.nonce,
215
+ signature
216
+ ]
217
+ });
218
+ }
219
+ const receipt = await signer.waitForTransactionReceipt({ hash: tx });
220
+ if (receipt.status !== "success") {
221
+ return {
222
+ success: false,
223
+ errorReason: "invalid_transaction_state",
224
+ transaction: tx,
225
+ network: payload.accepted.network,
226
+ payer
227
+ };
228
+ }
229
+ return {
230
+ success: true,
231
+ transaction: tx,
232
+ network: payload.accepted.network,
233
+ payer
234
+ };
235
+ } catch {
236
+ return {
237
+ success: false,
238
+ errorReason: "transaction_failed",
239
+ transaction: "",
240
+ network: payload.accepted.network,
241
+ payer
242
+ };
243
+ }
244
+ }
245
+
246
+ // 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) {
261
+ const payer = permit2Payload.permit2Authorization.from;
262
+ if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
263
+ return {
264
+ isValid: false,
265
+ invalidReason: "unsupported_scheme",
266
+ payer
267
+ };
268
+ }
269
+ if (payload.accepted.network !== requirements.network) {
270
+ return {
271
+ isValid: false,
272
+ invalidReason: "network_mismatch",
273
+ payer
274
+ };
275
+ }
276
+ const chainId = parseInt(requirements.network.split(":")[1]);
277
+ const tokenAddress = getAddress2(requirements.asset);
278
+ if (getAddress2(permit2Payload.permit2Authorization.spender) !== getAddress2(x402ExactPermit2ProxyAddress)) {
279
+ return {
280
+ isValid: false,
281
+ invalidReason: "invalid_permit2_spender",
282
+ payer
283
+ };
284
+ }
285
+ if (getAddress2(permit2Payload.permit2Authorization.witness.to) !== getAddress2(requirements.payTo)) {
286
+ return {
287
+ isValid: false,
288
+ invalidReason: "invalid_permit2_recipient_mismatch",
289
+ payer
290
+ };
291
+ }
292
+ const now = Math.floor(Date.now() / 1e3);
293
+ if (BigInt(permit2Payload.permit2Authorization.deadline) < BigInt(now + 6)) {
294
+ return {
295
+ isValid: false,
296
+ invalidReason: "permit2_deadline_expired",
297
+ payer
298
+ };
299
+ }
300
+ if (BigInt(permit2Payload.permit2Authorization.witness.validAfter) > BigInt(now)) {
301
+ return {
302
+ isValid: false,
303
+ invalidReason: "permit2_not_yet_valid",
304
+ payer
305
+ };
306
+ }
307
+ if (BigInt(permit2Payload.permit2Authorization.permitted.amount) < BigInt(requirements.amount)) {
308
+ return {
309
+ isValid: false,
310
+ invalidReason: "permit2_insufficient_amount",
311
+ payer
312
+ };
313
+ }
314
+ if (getAddress2(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
315
+ return {
316
+ isValid: false,
317
+ invalidReason: "permit2_token_mismatch",
318
+ payer
319
+ };
320
+ }
321
+ const permit2TypedData = {
322
+ types: permit2WitnessTypes,
323
+ primaryType: "PermitWitnessTransferFrom",
324
+ domain: {
325
+ name: "Permit2",
326
+ chainId,
327
+ verifyingContract: PERMIT2_ADDRESS
328
+ },
329
+ message: {
330
+ permitted: {
331
+ token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
332
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
333
+ },
334
+ spender: getAddress2(permit2Payload.permit2Authorization.spender),
335
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
336
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline),
337
+ witness: {
338
+ to: getAddress2(permit2Payload.permit2Authorization.witness.to),
339
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
340
+ extra: permit2Payload.permit2Authorization.witness.extra
341
+ }
342
+ }
343
+ };
344
+ try {
345
+ const isValid = await signer.verifyTypedData({
346
+ address: payer,
347
+ ...permit2TypedData,
348
+ signature: permit2Payload.signature
349
+ });
350
+ if (!isValid) {
351
+ return {
352
+ isValid: false,
353
+ invalidReason: "invalid_permit2_signature",
354
+ payer
355
+ };
356
+ }
357
+ } catch {
358
+ return {
359
+ isValid: false,
360
+ invalidReason: "invalid_permit2_signature",
361
+ payer
362
+ };
363
+ }
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 {
379
+ }
380
+ try {
381
+ const balance = await signer.readContract({
382
+ address: tokenAddress,
383
+ abi: eip3009ABI,
384
+ functionName: "balanceOf",
385
+ args: [payer]
386
+ });
387
+ if (balance < BigInt(requirements.amount)) {
388
+ return {
389
+ isValid: false,
390
+ invalidReason: "insufficient_funds",
391
+ 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.`,
392
+ payer
393
+ };
394
+ }
395
+ } catch {
396
+ }
397
+ return {
398
+ isValid: true,
399
+ invalidReason: void 0,
400
+ payer
401
+ };
402
+ }
403
+ async function settlePermit2(signer, payload, requirements, permit2Payload) {
404
+ const payer = permit2Payload.permit2Authorization.from;
405
+ const valid = await verifyPermit2(signer, payload, requirements, permit2Payload);
406
+ if (!valid.isValid) {
407
+ return {
408
+ success: false,
409
+ network: payload.accepted.network,
410
+ transaction: "",
411
+ errorReason: valid.invalidReason ?? "invalid_scheme",
412
+ payer
413
+ };
414
+ }
415
+ try {
416
+ const tx = await signer.writeContract({
417
+ address: x402ExactPermit2ProxyAddress,
418
+ abi: x402ExactPermit2ProxyABI,
419
+ functionName: "settle",
420
+ args: [
421
+ {
422
+ permitted: {
423
+ token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
424
+ amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
425
+ },
426
+ nonce: BigInt(permit2Payload.permit2Authorization.nonce),
427
+ deadline: BigInt(permit2Payload.permit2Authorization.deadline)
428
+ },
429
+ getAddress2(payer),
430
+ {
431
+ to: getAddress2(permit2Payload.permit2Authorization.witness.to),
432
+ validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
433
+ extra: permit2Payload.permit2Authorization.witness.extra
434
+ },
435
+ permit2Payload.signature
436
+ ]
437
+ });
438
+ const receipt = await signer.waitForTransactionReceipt({ hash: tx });
439
+ if (receipt.status !== "success") {
440
+ return {
441
+ success: false,
442
+ errorReason: "invalid_transaction_state",
443
+ transaction: tx,
444
+ network: payload.accepted.network,
445
+ payer
446
+ };
447
+ }
448
+ return {
449
+ success: true,
450
+ transaction: tx,
451
+ network: payload.accepted.network,
452
+ payer
453
+ };
454
+ } 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
+ }
474
+ return {
475
+ success: false,
476
+ errorReason,
477
+ transaction: "",
478
+ network: payload.accepted.network,
479
+ payer
480
+ };
481
+ }
482
+ }
483
+
484
+ // src/exact/facilitator/scheme.ts
15
485
  var ExactEvmScheme = class {
16
486
  /**
17
487
  * Creates a new ExactEvmFacilitator instance.
@@ -49,255 +519,35 @@ var ExactEvmScheme = class {
49
519
  }
50
520
  /**
51
521
  * Verifies a payment payload.
522
+ * Routes to the appropriate verification logic based on payload type.
52
523
  *
53
524
  * @param payload - The payment payload to verify
54
525
  * @param requirements - The payment requirements
55
526
  * @returns Promise resolving to verification response
56
527
  */
57
528
  async verify(payload, requirements) {
58
- const exactEvmPayload = payload.payload;
59
- if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
60
- return {
61
- isValid: false,
62
- invalidReason: "unsupported_scheme",
63
- payer: exactEvmPayload.authorization.from
64
- };
65
- }
66
- if (!requirements.extra?.name || !requirements.extra?.version) {
67
- return {
68
- isValid: false,
69
- invalidReason: "missing_eip712_domain",
70
- payer: exactEvmPayload.authorization.from
71
- };
72
- }
73
- const { name, version } = requirements.extra;
74
- const erc20Address = getAddress(requirements.asset);
75
- if (payload.accepted.network !== requirements.network) {
76
- return {
77
- isValid: false,
78
- invalidReason: "network_mismatch",
79
- payer: exactEvmPayload.authorization.from
80
- };
81
- }
82
- const permitTypedData = {
83
- types: authorizationTypes,
84
- primaryType: "TransferWithAuthorization",
85
- domain: {
86
- name,
87
- version,
88
- chainId: parseInt(requirements.network.split(":")[1]),
89
- verifyingContract: erc20Address
90
- },
91
- message: {
92
- from: exactEvmPayload.authorization.from,
93
- to: exactEvmPayload.authorization.to,
94
- value: BigInt(exactEvmPayload.authorization.value),
95
- validAfter: BigInt(exactEvmPayload.authorization.validAfter),
96
- validBefore: BigInt(exactEvmPayload.authorization.validBefore),
97
- nonce: exactEvmPayload.authorization.nonce
98
- }
99
- };
100
- try {
101
- const recoveredAddress = await this.signer.verifyTypedData({
102
- address: exactEvmPayload.authorization.from,
103
- ...permitTypedData,
104
- signature: exactEvmPayload.signature
105
- });
106
- if (!recoveredAddress) {
107
- return {
108
- isValid: false,
109
- invalidReason: "invalid_exact_evm_payload_signature",
110
- payer: exactEvmPayload.authorization.from
111
- };
112
- }
113
- } catch {
114
- const signature = exactEvmPayload.signature;
115
- const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
116
- const isSmartWallet = signatureLength > 130;
117
- if (isSmartWallet) {
118
- const payerAddress = exactEvmPayload.authorization.from;
119
- const bytecode = await this.signer.getCode({ address: payerAddress });
120
- if (!bytecode || bytecode === "0x") {
121
- const erc6492Data = parseErc6492Signature(signature);
122
- const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !isAddressEqual(erc6492Data.address, "0x0000000000000000000000000000000000000000");
123
- if (!hasDeploymentInfo) {
124
- return {
125
- isValid: false,
126
- invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
127
- payer: payerAddress
128
- };
129
- }
130
- } else {
131
- return {
132
- isValid: false,
133
- invalidReason: "invalid_exact_evm_payload_signature",
134
- payer: exactEvmPayload.authorization.from
135
- };
136
- }
137
- } else {
138
- return {
139
- isValid: false,
140
- invalidReason: "invalid_exact_evm_payload_signature",
141
- payer: exactEvmPayload.authorization.from
142
- };
143
- }
144
- }
145
- if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {
146
- return {
147
- isValid: false,
148
- invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
149
- payer: exactEvmPayload.authorization.from
150
- };
151
- }
152
- const now = Math.floor(Date.now() / 1e3);
153
- if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
154
- return {
155
- isValid: false,
156
- invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
157
- payer: exactEvmPayload.authorization.from
158
- };
159
- }
160
- if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
161
- return {
162
- isValid: false,
163
- invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
164
- payer: exactEvmPayload.authorization.from
165
- };
166
- }
167
- try {
168
- const balance = await this.signer.readContract({
169
- address: erc20Address,
170
- abi: eip3009ABI,
171
- functionName: "balanceOf",
172
- args: [exactEvmPayload.authorization.from]
173
- });
174
- if (BigInt(balance) < BigInt(requirements.amount)) {
175
- return {
176
- isValid: false,
177
- invalidReason: "insufficient_funds",
178
- payer: exactEvmPayload.authorization.from
179
- };
180
- }
181
- } catch {
182
- }
183
- if (BigInt(exactEvmPayload.authorization.value) < BigInt(requirements.amount)) {
184
- return {
185
- isValid: false,
186
- invalidReason: "invalid_exact_evm_payload_authorization_value",
187
- payer: exactEvmPayload.authorization.from
188
- };
529
+ const rawPayload = payload.payload;
530
+ if (isPermit2Payload(rawPayload)) {
531
+ return verifyPermit2(this.signer, payload, requirements, rawPayload);
189
532
  }
190
- return {
191
- isValid: true,
192
- invalidReason: void 0,
193
- payer: exactEvmPayload.authorization.from
194
- };
533
+ const eip3009Payload = rawPayload;
534
+ return verifyEIP3009(this.signer, payload, requirements, eip3009Payload);
195
535
  }
196
536
  /**
197
537
  * Settles a payment by executing the transfer.
538
+ * Routes to the appropriate settlement logic based on payload type.
198
539
  *
199
540
  * @param payload - The payment payload to settle
200
541
  * @param requirements - The payment requirements
201
542
  * @returns Promise resolving to settlement response
202
543
  */
203
544
  async settle(payload, requirements) {
204
- const exactEvmPayload = payload.payload;
205
- const valid = await this.verify(payload, requirements);
206
- if (!valid.isValid) {
207
- return {
208
- success: false,
209
- network: payload.accepted.network,
210
- transaction: "",
211
- errorReason: valid.invalidReason ?? "invalid_scheme",
212
- payer: exactEvmPayload.authorization.from
213
- };
214
- }
215
- try {
216
- const parseResult = parseErc6492Signature(exactEvmPayload.signature);
217
- const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
218
- if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !isAddressEqual(factoryAddress, "0x0000000000000000000000000000000000000000")) {
219
- const payerAddress = exactEvmPayload.authorization.from;
220
- const bytecode = await this.signer.getCode({ address: payerAddress });
221
- if (!bytecode || bytecode === "0x") {
222
- try {
223
- console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
224
- const deployTx = await this.signer.sendTransaction({
225
- to: factoryAddress,
226
- data: factoryCalldata
227
- });
228
- await this.signer.waitForTransactionReceipt({ hash: deployTx });
229
- console.log(`Successfully deployed smart wallet for ${payerAddress}`);
230
- } catch (deployError) {
231
- console.error("Smart wallet deployment failed:", deployError);
232
- throw deployError;
233
- }
234
- } else {
235
- console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
236
- }
237
- }
238
- const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
239
- const isECDSA = signatureLength === 130;
240
- let tx;
241
- if (isECDSA) {
242
- const parsedSig = parseSignature(signature);
243
- tx = await this.signer.writeContract({
244
- address: getAddress(requirements.asset),
245
- abi: eip3009ABI,
246
- functionName: "transferWithAuthorization",
247
- args: [
248
- getAddress(exactEvmPayload.authorization.from),
249
- getAddress(exactEvmPayload.authorization.to),
250
- BigInt(exactEvmPayload.authorization.value),
251
- BigInt(exactEvmPayload.authorization.validAfter),
252
- BigInt(exactEvmPayload.authorization.validBefore),
253
- exactEvmPayload.authorization.nonce,
254
- parsedSig.v || parsedSig.yParity,
255
- parsedSig.r,
256
- parsedSig.s
257
- ]
258
- });
259
- } else {
260
- tx = await this.signer.writeContract({
261
- address: getAddress(requirements.asset),
262
- abi: eip3009ABI,
263
- functionName: "transferWithAuthorization",
264
- args: [
265
- getAddress(exactEvmPayload.authorization.from),
266
- getAddress(exactEvmPayload.authorization.to),
267
- BigInt(exactEvmPayload.authorization.value),
268
- BigInt(exactEvmPayload.authorization.validAfter),
269
- BigInt(exactEvmPayload.authorization.validBefore),
270
- exactEvmPayload.authorization.nonce,
271
- signature
272
- ]
273
- });
274
- }
275
- const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
276
- if (receipt.status !== "success") {
277
- return {
278
- success: false,
279
- errorReason: "invalid_transaction_state",
280
- transaction: tx,
281
- network: payload.accepted.network,
282
- payer: exactEvmPayload.authorization.from
283
- };
284
- }
285
- return {
286
- success: true,
287
- transaction: tx,
288
- network: payload.accepted.network,
289
- payer: exactEvmPayload.authorization.from
290
- };
291
- } catch (error) {
292
- console.error("Failed to settle transaction:", error);
293
- return {
294
- success: false,
295
- errorReason: "transaction_failed",
296
- transaction: "",
297
- network: payload.accepted.network,
298
- payer: exactEvmPayload.authorization.from
299
- };
545
+ const rawPayload = payload.payload;
546
+ if (isPermit2Payload(rawPayload)) {
547
+ return settlePermit2(this.signer, payload, requirements, rawPayload);
300
548
  }
549
+ const eip3009Payload = rawPayload;
550
+ return settleEIP3009(this.signer, payload, requirements, eip3009Payload, this.config);
301
551
  }
302
552
  };
303
553