@payai/x402-evm 2.2.4 → 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.
- package/dist/cjs/exact/client/index.d.ts +2 -2
- package/dist/cjs/exact/client/index.js +412 -168
- package/dist/cjs/exact/client/index.js.map +1 -1
- package/dist/cjs/exact/facilitator/index.d.ts +18 -18
- package/dist/cjs/exact/facilitator/index.js +477 -163
- package/dist/cjs/exact/facilitator/index.js.map +1 -1
- package/dist/cjs/exact/server/index.js +25 -3
- package/dist/cjs/exact/server/index.js.map +1 -1
- package/dist/cjs/exact/v1/client/index.d.ts +1 -1
- package/dist/cjs/exact/v1/client/index.js +18 -18
- package/dist/cjs/exact/v1/client/index.js.map +1 -1
- package/dist/cjs/exact/v1/facilitator/index.d.ts +1 -1
- package/dist/cjs/exact/v1/facilitator/index.js +11 -10
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -1
- package/dist/cjs/index.d.ts +3 -390
- package/dist/cjs/index.js +363 -109
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/permit2-DHAq6FTe.d.ts +517 -0
- package/dist/cjs/signer-DC81R8wQ.d.ts +161 -0
- package/dist/cjs/v1/index.d.ts +12 -2
- package/dist/cjs/v1/index.js +15 -11
- package/dist/cjs/v1/index.js.map +1 -1
- package/dist/esm/chunk-LBIJBD7Q.mjs +425 -0
- package/dist/esm/chunk-LBIJBD7Q.mjs.map +1 -0
- package/dist/esm/{chunk-PFULIQAE.mjs → chunk-TKN5V2BV.mjs} +1 -1
- package/dist/esm/chunk-TKN5V2BV.mjs.map +1 -0
- package/dist/esm/{chunk-MVERYV34.mjs → chunk-XL6IFXCP.mjs} +96 -39
- package/dist/esm/chunk-XL6IFXCP.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +2 -2
- package/dist/esm/exact/client/index.mjs +4 -3
- package/dist/esm/exact/facilitator/index.d.mts +18 -18
- package/dist/esm/exact/facilitator/index.mjs +407 -103
- package/dist/esm/exact/facilitator/index.mjs.map +1 -1
- package/dist/esm/exact/server/index.mjs +25 -3
- package/dist/esm/exact/server/index.mjs.map +1 -1
- package/dist/esm/exact/v1/client/index.d.mts +1 -1
- package/dist/esm/exact/v1/client/index.mjs +2 -2
- package/dist/esm/exact/v1/facilitator/index.d.mts +1 -1
- package/dist/esm/exact/v1/facilitator/index.mjs +2 -2
- package/dist/esm/index.d.mts +3 -390
- package/dist/esm/index.mjs +29 -6
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/permit2-BuAhWvNC.d.mts +517 -0
- package/dist/esm/signer-DC81R8wQ.d.mts +161 -0
- package/dist/esm/v1/index.d.mts +12 -2
- package/dist/esm/v1/index.mjs +6 -4
- package/package.json +1 -1
- package/dist/cjs/permit2-BYv82va2.d.ts +0 -103
- package/dist/cjs/signer-5OVDxViv.d.ts +0 -79
- package/dist/esm/chunk-MVERYV34.mjs.map +0 -1
- package/dist/esm/chunk-PFULIQAE.mjs.map +0 -1
- package/dist/esm/chunk-W556LH23.mjs +0 -229
- package/dist/esm/chunk-W556LH23.mjs.map +0 -1
- package/dist/esm/permit2-BsAoJiWD.d.mts +0 -103
- package/dist/esm/signer-5OVDxViv.d.mts +0 -79
|
@@ -31,7 +31,7 @@ function isPermit2Payload(payload) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// src/exact/facilitator/eip3009.ts
|
|
34
|
-
var
|
|
34
|
+
var import_viem2 = require("viem");
|
|
35
35
|
|
|
36
36
|
// src/constants.ts
|
|
37
37
|
var authorizationTypes = {
|
|
@@ -58,8 +58,7 @@ var permit2WitnessTypes = {
|
|
|
58
58
|
],
|
|
59
59
|
Witness: [
|
|
60
60
|
{ name: "to", type: "address" },
|
|
61
|
-
{ name: "validAfter", type: "uint256" }
|
|
62
|
-
{ name: "extra", type: "bytes" }
|
|
61
|
+
{ name: "validAfter", type: "uint256" }
|
|
63
62
|
]
|
|
64
63
|
};
|
|
65
64
|
var eip3009ABI = [
|
|
@@ -110,8 +109,36 @@ var eip3009ABI = [
|
|
|
110
109
|
type: "function"
|
|
111
110
|
}
|
|
112
111
|
];
|
|
112
|
+
var erc20ApproveAbi = [
|
|
113
|
+
{
|
|
114
|
+
type: "function",
|
|
115
|
+
name: "approve",
|
|
116
|
+
inputs: [
|
|
117
|
+
{ name: "spender", type: "address" },
|
|
118
|
+
{ name: "amount", type: "uint256" }
|
|
119
|
+
],
|
|
120
|
+
outputs: [{ type: "bool" }],
|
|
121
|
+
stateMutability: "nonpayable"
|
|
122
|
+
}
|
|
123
|
+
];
|
|
124
|
+
var erc20AllowanceAbi = [
|
|
125
|
+
{
|
|
126
|
+
type: "function",
|
|
127
|
+
name: "allowance",
|
|
128
|
+
inputs: [
|
|
129
|
+
{ name: "owner", type: "address" },
|
|
130
|
+
{ name: "spender", type: "address" }
|
|
131
|
+
],
|
|
132
|
+
outputs: [{ type: "uint256" }],
|
|
133
|
+
stateMutability: "view"
|
|
134
|
+
}
|
|
135
|
+
];
|
|
113
136
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
114
|
-
var x402ExactPermit2ProxyAddress = "
|
|
137
|
+
var x402ExactPermit2ProxyAddress = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
|
|
138
|
+
var permit2WitnessABIComponents = [
|
|
139
|
+
{ name: "to", type: "address", internalType: "address" },
|
|
140
|
+
{ name: "validAfter", type: "uint256", internalType: "uint256" }
|
|
141
|
+
];
|
|
115
142
|
var x402ExactPermit2ProxyABI = [
|
|
116
143
|
{
|
|
117
144
|
type: "function",
|
|
@@ -134,13 +161,6 @@ var x402ExactPermit2ProxyABI = [
|
|
|
134
161
|
outputs: [{ name: "", type: "string", internalType: "string" }],
|
|
135
162
|
stateMutability: "view"
|
|
136
163
|
},
|
|
137
|
-
{
|
|
138
|
-
type: "function",
|
|
139
|
-
name: "initialize",
|
|
140
|
-
inputs: [{ name: "_permit2", type: "address", internalType: "address" }],
|
|
141
|
-
outputs: [],
|
|
142
|
-
stateMutability: "nonpayable"
|
|
143
|
-
},
|
|
144
164
|
{
|
|
145
165
|
type: "function",
|
|
146
166
|
name: "settle",
|
|
@@ -167,12 +187,8 @@ var x402ExactPermit2ProxyABI = [
|
|
|
167
187
|
{
|
|
168
188
|
name: "witness",
|
|
169
189
|
type: "tuple",
|
|
170
|
-
internalType: "struct
|
|
171
|
-
components:
|
|
172
|
-
{ name: "to", type: "address", internalType: "address" },
|
|
173
|
-
{ name: "validAfter", type: "uint256", internalType: "uint256" },
|
|
174
|
-
{ name: "extra", type: "bytes", internalType: "bytes" }
|
|
175
|
-
]
|
|
190
|
+
internalType: "struct x402ExactPermit2Proxy.Witness",
|
|
191
|
+
components: permit2WitnessABIComponents
|
|
176
192
|
},
|
|
177
193
|
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
178
194
|
],
|
|
@@ -186,7 +202,7 @@ var x402ExactPermit2ProxyABI = [
|
|
|
186
202
|
{
|
|
187
203
|
name: "permit2612",
|
|
188
204
|
type: "tuple",
|
|
189
|
-
internalType: "struct
|
|
205
|
+
internalType: "struct x402ExactPermit2Proxy.EIP2612Permit",
|
|
190
206
|
components: [
|
|
191
207
|
{ name: "value", type: "uint256", internalType: "uint256" },
|
|
192
208
|
{ name: "deadline", type: "uint256", internalType: "uint256" },
|
|
@@ -217,12 +233,8 @@ var x402ExactPermit2ProxyABI = [
|
|
|
217
233
|
{
|
|
218
234
|
name: "witness",
|
|
219
235
|
type: "tuple",
|
|
220
|
-
internalType: "struct
|
|
221
|
-
components:
|
|
222
|
-
{ name: "to", type: "address", internalType: "address" },
|
|
223
|
-
{ name: "validAfter", type: "uint256", internalType: "uint256" },
|
|
224
|
-
{ name: "extra", type: "bytes", internalType: "bytes" }
|
|
225
|
-
]
|
|
236
|
+
internalType: "struct x402ExactPermit2Proxy.Witness",
|
|
237
|
+
components: permit2WitnessABIComponents
|
|
226
238
|
},
|
|
227
239
|
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
228
240
|
],
|
|
@@ -231,14 +243,29 @@ var x402ExactPermit2ProxyABI = [
|
|
|
231
243
|
},
|
|
232
244
|
{ type: "event", name: "Settled", inputs: [], anonymous: false },
|
|
233
245
|
{ type: "event", name: "SettledWithPermit", inputs: [], anonymous: false },
|
|
234
|
-
{ type: "error", name: "
|
|
246
|
+
{ type: "error", name: "InvalidAmount", inputs: [] },
|
|
235
247
|
{ type: "error", name: "InvalidDestination", inputs: [] },
|
|
236
248
|
{ type: "error", name: "InvalidOwner", inputs: [] },
|
|
237
249
|
{ type: "error", name: "InvalidPermit2Address", inputs: [] },
|
|
238
250
|
{ type: "error", name: "PaymentTooEarly", inputs: [] },
|
|
251
|
+
{ type: "error", name: "Permit2612AmountMismatch", inputs: [] },
|
|
239
252
|
{ type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] }
|
|
240
253
|
];
|
|
241
254
|
|
|
255
|
+
// src/utils.ts
|
|
256
|
+
var import_viem = require("viem");
|
|
257
|
+
function getEvmChainId(network) {
|
|
258
|
+
if (network.startsWith("eip155:")) {
|
|
259
|
+
const idStr = network.split(":")[1];
|
|
260
|
+
const chainId = parseInt(idStr, 10);
|
|
261
|
+
if (isNaN(chainId)) {
|
|
262
|
+
throw new Error(`Invalid CAIP-2 chain ID: ${network}`);
|
|
263
|
+
}
|
|
264
|
+
return chainId;
|
|
265
|
+
}
|
|
266
|
+
throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);
|
|
267
|
+
}
|
|
268
|
+
|
|
242
269
|
// src/exact/facilitator/eip3009.ts
|
|
243
270
|
async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
|
|
244
271
|
const payer = eip3009Payload.authorization.from;
|
|
@@ -257,7 +284,7 @@ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
|
|
|
257
284
|
};
|
|
258
285
|
}
|
|
259
286
|
const { name, version } = requirements.extra;
|
|
260
|
-
const erc20Address = (0,
|
|
287
|
+
const erc20Address = (0, import_viem2.getAddress)(requirements.asset);
|
|
261
288
|
if (payload.accepted.network !== requirements.network) {
|
|
262
289
|
return {
|
|
263
290
|
isValid: false,
|
|
@@ -271,7 +298,7 @@ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
|
|
|
271
298
|
domain: {
|
|
272
299
|
name,
|
|
273
300
|
version,
|
|
274
|
-
chainId:
|
|
301
|
+
chainId: getEvmChainId(requirements.network),
|
|
275
302
|
verifyingContract: erc20Address
|
|
276
303
|
},
|
|
277
304
|
message: {
|
|
@@ -304,8 +331,8 @@ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
|
|
|
304
331
|
const payerAddress = eip3009Payload.authorization.from;
|
|
305
332
|
const bytecode = await signer.getCode({ address: payerAddress });
|
|
306
333
|
if (!bytecode || bytecode === "0x") {
|
|
307
|
-
const erc6492Data = (0,
|
|
308
|
-
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0,
|
|
334
|
+
const erc6492Data = (0, import_viem2.parseErc6492Signature)(signature);
|
|
335
|
+
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem2.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
309
336
|
if (!hasDeploymentInfo) {
|
|
310
337
|
return {
|
|
311
338
|
isValid: false,
|
|
@@ -328,7 +355,7 @@ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
|
|
|
328
355
|
};
|
|
329
356
|
}
|
|
330
357
|
}
|
|
331
|
-
if ((0,
|
|
358
|
+
if ((0, import_viem2.getAddress)(eip3009Payload.authorization.to) !== (0, import_viem2.getAddress)(requirements.payTo)) {
|
|
332
359
|
return {
|
|
333
360
|
isValid: false,
|
|
334
361
|
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
@@ -361,15 +388,16 @@ async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
|
|
|
361
388
|
return {
|
|
362
389
|
isValid: false,
|
|
363
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.`,
|
|
364
392
|
payer
|
|
365
393
|
};
|
|
366
394
|
}
|
|
367
395
|
} catch {
|
|
368
396
|
}
|
|
369
|
-
if (BigInt(eip3009Payload.authorization.value)
|
|
397
|
+
if (BigInt(eip3009Payload.authorization.value) !== BigInt(requirements.amount)) {
|
|
370
398
|
return {
|
|
371
399
|
isValid: false,
|
|
372
|
-
invalidReason: "
|
|
400
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value_mismatch",
|
|
373
401
|
payer
|
|
374
402
|
};
|
|
375
403
|
}
|
|
@@ -392,9 +420,9 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
|
|
|
392
420
|
};
|
|
393
421
|
}
|
|
394
422
|
try {
|
|
395
|
-
const parseResult = (0,
|
|
423
|
+
const parseResult = (0, import_viem2.parseErc6492Signature)(eip3009Payload.signature);
|
|
396
424
|
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
397
|
-
if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0,
|
|
425
|
+
if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem2.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
398
426
|
const bytecode = await signer.getCode({ address: payer });
|
|
399
427
|
if (!bytecode || bytecode === "0x") {
|
|
400
428
|
const deployTx = await signer.sendTransaction({
|
|
@@ -408,14 +436,14 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
|
|
|
408
436
|
const isECDSA = signatureLength === 130;
|
|
409
437
|
let tx;
|
|
410
438
|
if (isECDSA) {
|
|
411
|
-
const parsedSig = (0,
|
|
439
|
+
const parsedSig = (0, import_viem2.parseSignature)(signature);
|
|
412
440
|
tx = await signer.writeContract({
|
|
413
|
-
address: (0,
|
|
441
|
+
address: (0, import_viem2.getAddress)(requirements.asset),
|
|
414
442
|
abi: eip3009ABI,
|
|
415
443
|
functionName: "transferWithAuthorization",
|
|
416
444
|
args: [
|
|
417
|
-
(0,
|
|
418
|
-
(0,
|
|
445
|
+
(0, import_viem2.getAddress)(eip3009Payload.authorization.from),
|
|
446
|
+
(0, import_viem2.getAddress)(eip3009Payload.authorization.to),
|
|
419
447
|
BigInt(eip3009Payload.authorization.value),
|
|
420
448
|
BigInt(eip3009Payload.authorization.validAfter),
|
|
421
449
|
BigInt(eip3009Payload.authorization.validBefore),
|
|
@@ -427,12 +455,12 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
|
|
|
427
455
|
});
|
|
428
456
|
} else {
|
|
429
457
|
tx = await signer.writeContract({
|
|
430
|
-
address: (0,
|
|
458
|
+
address: (0, import_viem2.getAddress)(requirements.asset),
|
|
431
459
|
abi: eip3009ABI,
|
|
432
460
|
functionName: "transferWithAuthorization",
|
|
433
461
|
args: [
|
|
434
|
-
(0,
|
|
435
|
-
(0,
|
|
462
|
+
(0, import_viem2.getAddress)(eip3009Payload.authorization.from),
|
|
463
|
+
(0, import_viem2.getAddress)(eip3009Payload.authorization.to),
|
|
436
464
|
BigInt(eip3009Payload.authorization.value),
|
|
437
465
|
BigInt(eip3009Payload.authorization.validAfter),
|
|
438
466
|
BigInt(eip3009Payload.authorization.validBefore),
|
|
@@ -469,20 +497,130 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
|
|
|
469
497
|
}
|
|
470
498
|
|
|
471
499
|
// src/exact/facilitator/permit2.ts
|
|
472
|
-
var
|
|
473
|
-
var
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
500
|
+
var import_extensions2 = require("@x402/extensions");
|
|
501
|
+
var import_viem4 = require("viem");
|
|
502
|
+
|
|
503
|
+
// src/exact/facilitator/errors.ts
|
|
504
|
+
var ErrPermit2InvalidSignature = "invalid_permit2_signature";
|
|
505
|
+
var ErrPermit2InvalidAmount = "permit2_invalid_amount";
|
|
506
|
+
var ErrPermit2InvalidDestination = "permit2_invalid_destination";
|
|
507
|
+
var ErrPermit2InvalidOwner = "permit2_invalid_owner";
|
|
508
|
+
var ErrPermit2PaymentTooEarly = "permit2_payment_too_early";
|
|
509
|
+
var ErrPermit2InvalidNonce = "permit2_invalid_nonce";
|
|
510
|
+
var ErrPermit2612AmountMismatch = "permit2_2612_amount_mismatch";
|
|
511
|
+
var ErrErc20ApprovalInvalidFormat = "invalid_erc20_approval_extension_format";
|
|
512
|
+
var ErrErc20ApprovalFromMismatch = "erc20_approval_from_mismatch";
|
|
513
|
+
var ErrErc20ApprovalAssetMismatch = "erc20_approval_asset_mismatch";
|
|
514
|
+
var ErrErc20ApprovalSpenderNotPermit2 = "erc20_approval_spender_not_permit2";
|
|
515
|
+
var ErrErc20ApprovalTxWrongTarget = "erc20_approval_tx_wrong_target";
|
|
516
|
+
var ErrErc20ApprovalTxWrongSelector = "erc20_approval_tx_wrong_selector";
|
|
517
|
+
var ErrErc20ApprovalTxWrongSpender = "erc20_approval_tx_wrong_spender";
|
|
518
|
+
var ErrErc20ApprovalTxInvalidCalldata = "erc20_approval_tx_invalid_calldata";
|
|
519
|
+
var ErrErc20ApprovalTxSignerMismatch = "erc20_approval_tx_signer_mismatch";
|
|
520
|
+
var ErrErc20ApprovalTxInvalidSignature = "erc20_approval_tx_invalid_signature";
|
|
521
|
+
var ErrErc20ApprovalTxParseFailed = "erc20_approval_tx_parse_failed";
|
|
522
|
+
|
|
523
|
+
// src/exact/facilitator/erc20approval.ts
|
|
524
|
+
var import_viem3 = require("viem");
|
|
525
|
+
var import_extensions = require("@x402/extensions");
|
|
526
|
+
var APPROVE_SELECTOR = "0x095ea7b3";
|
|
527
|
+
async function validateErc20ApprovalForPayment(info, payer, tokenAddress) {
|
|
528
|
+
if (!(0, import_extensions.validateErc20ApprovalGasSponsoringInfo)(info)) {
|
|
529
|
+
return {
|
|
530
|
+
isValid: false,
|
|
531
|
+
invalidReason: ErrErc20ApprovalInvalidFormat,
|
|
532
|
+
invalidMessage: "ERC-20 approval extension info failed schema validation"
|
|
533
|
+
};
|
|
483
534
|
}
|
|
484
|
-
|
|
485
|
-
|
|
535
|
+
if ((0, import_viem3.getAddress)(info.from) !== (0, import_viem3.getAddress)(payer)) {
|
|
536
|
+
return {
|
|
537
|
+
isValid: false,
|
|
538
|
+
invalidReason: ErrErc20ApprovalFromMismatch,
|
|
539
|
+
invalidMessage: `Expected from=${payer}, got ${info.from}`
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
if ((0, import_viem3.getAddress)(info.asset) !== tokenAddress) {
|
|
543
|
+
return {
|
|
544
|
+
isValid: false,
|
|
545
|
+
invalidReason: ErrErc20ApprovalAssetMismatch,
|
|
546
|
+
invalidMessage: `Expected asset=${tokenAddress}, got ${info.asset}`
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
if ((0, import_viem3.getAddress)(info.spender) !== (0, import_viem3.getAddress)(PERMIT2_ADDRESS)) {
|
|
550
|
+
return {
|
|
551
|
+
isValid: false,
|
|
552
|
+
invalidReason: ErrErc20ApprovalSpenderNotPermit2,
|
|
553
|
+
invalidMessage: `Expected spender=${PERMIT2_ADDRESS}, got ${info.spender}`
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
try {
|
|
557
|
+
const serializedTx = info.signedTransaction;
|
|
558
|
+
const tx = (0, import_viem3.parseTransaction)(serializedTx);
|
|
559
|
+
if (!tx.to || (0, import_viem3.getAddress)(tx.to) !== tokenAddress) {
|
|
560
|
+
return {
|
|
561
|
+
isValid: false,
|
|
562
|
+
invalidReason: ErrErc20ApprovalTxWrongTarget,
|
|
563
|
+
invalidMessage: `Transaction targets ${tx.to ?? "null"}, expected ${tokenAddress}`
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const data = tx.data ?? "0x";
|
|
567
|
+
if (!data.startsWith(APPROVE_SELECTOR)) {
|
|
568
|
+
return {
|
|
569
|
+
isValid: false,
|
|
570
|
+
invalidReason: ErrErc20ApprovalTxWrongSelector,
|
|
571
|
+
invalidMessage: `Transaction calldata does not start with approve() selector ${APPROVE_SELECTOR}`
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
try {
|
|
575
|
+
const decoded = (0, import_viem3.decodeFunctionData)({
|
|
576
|
+
abi: erc20ApproveAbi,
|
|
577
|
+
data
|
|
578
|
+
});
|
|
579
|
+
const calldataSpender = (0, import_viem3.getAddress)(decoded.args[0]);
|
|
580
|
+
if (calldataSpender !== (0, import_viem3.getAddress)(PERMIT2_ADDRESS)) {
|
|
581
|
+
return {
|
|
582
|
+
isValid: false,
|
|
583
|
+
invalidReason: ErrErc20ApprovalTxWrongSpender,
|
|
584
|
+
invalidMessage: `approve() spender is ${calldataSpender}, expected Permit2 ${PERMIT2_ADDRESS}`
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
} catch {
|
|
588
|
+
return {
|
|
589
|
+
isValid: false,
|
|
590
|
+
invalidReason: ErrErc20ApprovalTxInvalidCalldata,
|
|
591
|
+
invalidMessage: "Failed to decode approve() calldata from the signed transaction"
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
try {
|
|
595
|
+
const recoveredAddress = await (0, import_viem3.recoverTransactionAddress)({
|
|
596
|
+
serializedTransaction: serializedTx
|
|
597
|
+
});
|
|
598
|
+
if ((0, import_viem3.getAddress)(recoveredAddress) !== (0, import_viem3.getAddress)(payer)) {
|
|
599
|
+
return {
|
|
600
|
+
isValid: false,
|
|
601
|
+
invalidReason: ErrErc20ApprovalTxSignerMismatch,
|
|
602
|
+
invalidMessage: `Transaction signed by ${recoveredAddress}, expected payer ${payer}`
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
} catch {
|
|
606
|
+
return {
|
|
607
|
+
isValid: false,
|
|
608
|
+
invalidReason: ErrErc20ApprovalTxInvalidSignature,
|
|
609
|
+
invalidMessage: "Failed to recover signer from the signed transaction"
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
} catch {
|
|
613
|
+
return {
|
|
614
|
+
isValid: false,
|
|
615
|
+
invalidReason: ErrErc20ApprovalTxParseFailed,
|
|
616
|
+
invalidMessage: "Failed to parse the signed transaction"
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
return { isValid: true };
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// src/exact/facilitator/permit2.ts
|
|
623
|
+
async function verifyPermit2(signer, payload, requirements, permit2Payload, context) {
|
|
486
624
|
const payer = permit2Payload.permit2Authorization.from;
|
|
487
625
|
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
488
626
|
return {
|
|
@@ -498,16 +636,16 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
|
|
|
498
636
|
payer
|
|
499
637
|
};
|
|
500
638
|
}
|
|
501
|
-
const chainId =
|
|
502
|
-
const tokenAddress = (0,
|
|
503
|
-
if ((0,
|
|
639
|
+
const chainId = getEvmChainId(requirements.network);
|
|
640
|
+
const tokenAddress = (0, import_viem4.getAddress)(requirements.asset);
|
|
641
|
+
if ((0, import_viem4.getAddress)(permit2Payload.permit2Authorization.spender) !== (0, import_viem4.getAddress)(x402ExactPermit2ProxyAddress)) {
|
|
504
642
|
return {
|
|
505
643
|
isValid: false,
|
|
506
644
|
invalidReason: "invalid_permit2_spender",
|
|
507
645
|
payer
|
|
508
646
|
};
|
|
509
647
|
}
|
|
510
|
-
if ((0,
|
|
648
|
+
if ((0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to) !== (0, import_viem4.getAddress)(requirements.payTo)) {
|
|
511
649
|
return {
|
|
512
650
|
isValid: false,
|
|
513
651
|
invalidReason: "invalid_permit2_recipient_mismatch",
|
|
@@ -529,14 +667,14 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
|
|
|
529
667
|
payer
|
|
530
668
|
};
|
|
531
669
|
}
|
|
532
|
-
if (BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
670
|
+
if (BigInt(permit2Payload.permit2Authorization.permitted.amount) !== BigInt(requirements.amount)) {
|
|
533
671
|
return {
|
|
534
672
|
isValid: false,
|
|
535
|
-
invalidReason: "
|
|
673
|
+
invalidReason: "permit2_amount_mismatch",
|
|
536
674
|
payer
|
|
537
675
|
};
|
|
538
676
|
}
|
|
539
|
-
if ((0,
|
|
677
|
+
if ((0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
|
|
540
678
|
return {
|
|
541
679
|
isValid: false,
|
|
542
680
|
invalidReason: "permit2_token_mismatch",
|
|
@@ -553,16 +691,15 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
|
|
|
553
691
|
},
|
|
554
692
|
message: {
|
|
555
693
|
permitted: {
|
|
556
|
-
token: (0,
|
|
694
|
+
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
|
|
557
695
|
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
558
696
|
},
|
|
559
|
-
spender: (0,
|
|
697
|
+
spender: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.spender),
|
|
560
698
|
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
561
699
|
deadline: BigInt(permit2Payload.permit2Authorization.deadline),
|
|
562
700
|
witness: {
|
|
563
|
-
to: (0,
|
|
564
|
-
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
565
|
-
extra: permit2Payload.permit2Authorization.witness.extra
|
|
701
|
+
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
|
|
702
|
+
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
566
703
|
}
|
|
567
704
|
}
|
|
568
705
|
};
|
|
@@ -586,21 +723,16 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
|
|
|
586
723
|
payer
|
|
587
724
|
};
|
|
588
725
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
invalidReason: "permit2_allowance_required",
|
|
600
|
-
payer
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
-
} catch {
|
|
726
|
+
const allowanceResult = await _verifyPermit2Allowance(
|
|
727
|
+
signer,
|
|
728
|
+
payload,
|
|
729
|
+
requirements,
|
|
730
|
+
payer,
|
|
731
|
+
tokenAddress,
|
|
732
|
+
context
|
|
733
|
+
);
|
|
734
|
+
if (allowanceResult) {
|
|
735
|
+
return allowanceResult;
|
|
604
736
|
}
|
|
605
737
|
try {
|
|
606
738
|
const balance = await signer.readContract({
|
|
@@ -613,6 +745,7 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
|
|
|
613
745
|
return {
|
|
614
746
|
isValid: false,
|
|
615
747
|
invalidReason: "insufficient_funds",
|
|
748
|
+
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.`,
|
|
616
749
|
payer
|
|
617
750
|
};
|
|
618
751
|
}
|
|
@@ -624,9 +757,53 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload) {
|
|
|
624
757
|
payer
|
|
625
758
|
};
|
|
626
759
|
}
|
|
627
|
-
async function
|
|
760
|
+
async function _verifyPermit2Allowance(signer, payload, requirements, payer, tokenAddress, context) {
|
|
761
|
+
try {
|
|
762
|
+
const allowance = await signer.readContract({
|
|
763
|
+
address: tokenAddress,
|
|
764
|
+
abi: erc20AllowanceAbi,
|
|
765
|
+
functionName: "allowance",
|
|
766
|
+
args: [payer, PERMIT2_ADDRESS]
|
|
767
|
+
});
|
|
768
|
+
if (allowance >= BigInt(requirements.amount)) {
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
const eip2612Info = (0, import_extensions2.extractEip2612GasSponsoringInfo)(payload);
|
|
772
|
+
if (eip2612Info) {
|
|
773
|
+
const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
|
|
774
|
+
if (!result.isValid) {
|
|
775
|
+
return { isValid: false, invalidReason: result.invalidReason, payer };
|
|
776
|
+
}
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
const erc20GasSponsorshipExtension = context?.getExtension(
|
|
780
|
+
import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key
|
|
781
|
+
);
|
|
782
|
+
if (erc20GasSponsorshipExtension) {
|
|
783
|
+
const erc20Info = (0, import_extensions2.extractErc20ApprovalGasSponsoringInfo)(payload);
|
|
784
|
+
if (erc20Info) {
|
|
785
|
+
const result = await validateErc20ApprovalForPayment(erc20Info, payer, tokenAddress);
|
|
786
|
+
if (!result.isValid) {
|
|
787
|
+
return { isValid: false, invalidReason: result.invalidReason, payer };
|
|
788
|
+
}
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return { isValid: false, invalidReason: "permit2_allowance_required", payer };
|
|
793
|
+
} catch {
|
|
794
|
+
const eip2612Info = (0, import_extensions2.extractEip2612GasSponsoringInfo)(payload);
|
|
795
|
+
if (eip2612Info) {
|
|
796
|
+
const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
|
|
797
|
+
if (!result.isValid) {
|
|
798
|
+
return { isValid: false, invalidReason: result.invalidReason, payer };
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
async function settlePermit2(signer, payload, requirements, permit2Payload, context) {
|
|
628
805
|
const payer = permit2Payload.permit2Authorization.from;
|
|
629
|
-
const valid = await verifyPermit2(signer, payload, requirements, permit2Payload);
|
|
806
|
+
const valid = await verifyPermit2(signer, payload, requirements, permit2Payload, context);
|
|
630
807
|
if (!valid.isValid) {
|
|
631
808
|
return {
|
|
632
809
|
success: false,
|
|
@@ -636,82 +813,223 @@ async function settlePermit2(signer, payload, requirements, permit2Payload) {
|
|
|
636
813
|
payer
|
|
637
814
|
};
|
|
638
815
|
}
|
|
816
|
+
const eip2612Info = (0, import_extensions2.extractEip2612GasSponsoringInfo)(payload);
|
|
817
|
+
if (eip2612Info) {
|
|
818
|
+
return _settlePermit2WithEIP2612(signer, payload, permit2Payload, eip2612Info);
|
|
819
|
+
}
|
|
820
|
+
const erc20Info = (0, import_extensions2.extractErc20ApprovalGasSponsoringInfo)(payload);
|
|
821
|
+
if (erc20Info) {
|
|
822
|
+
const erc20GasSponsorshipExtension = context?.getExtension(
|
|
823
|
+
import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key
|
|
824
|
+
);
|
|
825
|
+
if (erc20GasSponsorshipExtension?.signer) {
|
|
826
|
+
return _settlePermit2WithERC20Approval(
|
|
827
|
+
erc20GasSponsorshipExtension.signer,
|
|
828
|
+
payload,
|
|
829
|
+
permit2Payload,
|
|
830
|
+
erc20Info
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return _settlePermit2Direct(signer, payload, permit2Payload);
|
|
835
|
+
}
|
|
836
|
+
async function _settlePermit2WithEIP2612(signer, payload, permit2Payload, eip2612Info) {
|
|
837
|
+
const payer = permit2Payload.permit2Authorization.from;
|
|
639
838
|
try {
|
|
839
|
+
const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
|
|
640
840
|
const tx = await signer.writeContract({
|
|
641
841
|
address: x402ExactPermit2ProxyAddress,
|
|
642
842
|
abi: x402ExactPermit2ProxyABI,
|
|
643
|
-
functionName: "
|
|
843
|
+
functionName: "settleWithPermit",
|
|
644
844
|
args: [
|
|
845
|
+
{
|
|
846
|
+
value: BigInt(eip2612Info.amount),
|
|
847
|
+
deadline: BigInt(eip2612Info.deadline),
|
|
848
|
+
r,
|
|
849
|
+
s,
|
|
850
|
+
v
|
|
851
|
+
},
|
|
645
852
|
{
|
|
646
853
|
permitted: {
|
|
647
|
-
token: (0,
|
|
854
|
+
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
|
|
648
855
|
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
649
856
|
},
|
|
650
857
|
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
651
858
|
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
|
|
652
859
|
},
|
|
653
|
-
(0,
|
|
860
|
+
(0, import_viem4.getAddress)(payer),
|
|
654
861
|
{
|
|
655
|
-
to: (0,
|
|
656
|
-
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
657
|
-
extra: permit2Payload.permit2Authorization.witness.extra
|
|
862
|
+
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
|
|
863
|
+
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
658
864
|
},
|
|
659
865
|
permit2Payload.signature
|
|
660
866
|
]
|
|
661
867
|
});
|
|
662
|
-
|
|
663
|
-
|
|
868
|
+
return _waitAndReturn(signer, tx, payload, payer);
|
|
869
|
+
} catch (error) {
|
|
870
|
+
return _mapSettleError(error, payload, payer);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
async function _settlePermit2WithERC20Approval(extensionSigner, payload, permit2Payload, erc20Info) {
|
|
874
|
+
const payer = permit2Payload.permit2Authorization.from;
|
|
875
|
+
try {
|
|
876
|
+
const approvalTxHash = await extensionSigner.sendRawTransaction({
|
|
877
|
+
serializedTransaction: erc20Info.signedTransaction
|
|
878
|
+
});
|
|
879
|
+
const approvalReceipt = await extensionSigner.waitForTransactionReceipt({
|
|
880
|
+
hash: approvalTxHash
|
|
881
|
+
});
|
|
882
|
+
if (approvalReceipt.status !== "success") {
|
|
664
883
|
return {
|
|
665
884
|
success: false,
|
|
666
|
-
errorReason: "
|
|
667
|
-
transaction:
|
|
885
|
+
errorReason: "erc20_approval_tx_failed",
|
|
886
|
+
transaction: approvalTxHash,
|
|
668
887
|
network: payload.accepted.network,
|
|
669
888
|
payer
|
|
670
889
|
};
|
|
671
890
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
891
|
+
const tx = await extensionSigner.writeContract({
|
|
892
|
+
address: x402ExactPermit2ProxyAddress,
|
|
893
|
+
abi: x402ExactPermit2ProxyABI,
|
|
894
|
+
functionName: "settle",
|
|
895
|
+
args: [
|
|
896
|
+
{
|
|
897
|
+
permitted: {
|
|
898
|
+
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
|
|
899
|
+
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
900
|
+
},
|
|
901
|
+
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
902
|
+
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
|
|
903
|
+
},
|
|
904
|
+
(0, import_viem4.getAddress)(payer),
|
|
905
|
+
{
|
|
906
|
+
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
|
|
907
|
+
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
908
|
+
},
|
|
909
|
+
permit2Payload.signature
|
|
910
|
+
]
|
|
911
|
+
});
|
|
912
|
+
return _waitAndReturn(extensionSigner, tx, payload, payer);
|
|
678
913
|
} catch (error) {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
914
|
+
return _mapSettleError(error, payload, payer);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
async function _settlePermit2Direct(signer, payload, permit2Payload) {
|
|
918
|
+
const payer = permit2Payload.permit2Authorization.from;
|
|
919
|
+
try {
|
|
920
|
+
const tx = await signer.writeContract({
|
|
921
|
+
address: x402ExactPermit2ProxyAddress,
|
|
922
|
+
abi: x402ExactPermit2ProxyABI,
|
|
923
|
+
functionName: "settle",
|
|
924
|
+
args: [
|
|
925
|
+
{
|
|
926
|
+
permitted: {
|
|
927
|
+
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
|
|
928
|
+
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
929
|
+
},
|
|
930
|
+
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
931
|
+
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
|
|
932
|
+
},
|
|
933
|
+
(0, import_viem4.getAddress)(payer),
|
|
934
|
+
{
|
|
935
|
+
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
|
|
936
|
+
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
937
|
+
},
|
|
938
|
+
permit2Payload.signature
|
|
939
|
+
]
|
|
940
|
+
});
|
|
941
|
+
return _waitAndReturn(signer, tx, payload, payer);
|
|
942
|
+
} catch (error) {
|
|
943
|
+
return _mapSettleError(error, payload, payer);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
async function _waitAndReturn(signer, tx, payload, payer) {
|
|
947
|
+
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
|
|
948
|
+
if (receipt.status !== "success") {
|
|
698
949
|
return {
|
|
699
950
|
success: false,
|
|
700
|
-
errorReason,
|
|
701
|
-
transaction:
|
|
951
|
+
errorReason: "invalid_transaction_state",
|
|
952
|
+
transaction: tx,
|
|
702
953
|
network: payload.accepted.network,
|
|
703
954
|
payer
|
|
704
955
|
};
|
|
705
956
|
}
|
|
957
|
+
return {
|
|
958
|
+
success: true,
|
|
959
|
+
transaction: tx,
|
|
960
|
+
network: payload.accepted.network,
|
|
961
|
+
payer
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
function _mapSettleError(error, payload, payer) {
|
|
965
|
+
let errorReason = "transaction_failed";
|
|
966
|
+
if (error instanceof Error) {
|
|
967
|
+
const message = error.message;
|
|
968
|
+
if (message.includes("Permit2612AmountMismatch")) {
|
|
969
|
+
errorReason = ErrPermit2612AmountMismatch;
|
|
970
|
+
} else if (message.includes("InvalidAmount")) {
|
|
971
|
+
errorReason = ErrPermit2InvalidAmount;
|
|
972
|
+
} else if (message.includes("InvalidDestination")) {
|
|
973
|
+
errorReason = ErrPermit2InvalidDestination;
|
|
974
|
+
} else if (message.includes("InvalidOwner")) {
|
|
975
|
+
errorReason = ErrPermit2InvalidOwner;
|
|
976
|
+
} else if (message.includes("PaymentTooEarly")) {
|
|
977
|
+
errorReason = ErrPermit2PaymentTooEarly;
|
|
978
|
+
} else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
|
|
979
|
+
errorReason = ErrPermit2InvalidSignature;
|
|
980
|
+
} else if (message.includes("InvalidNonce")) {
|
|
981
|
+
errorReason = ErrPermit2InvalidNonce;
|
|
982
|
+
} else {
|
|
983
|
+
errorReason = `transaction_failed: ${message.slice(0, 500)}`;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
return {
|
|
987
|
+
success: false,
|
|
988
|
+
errorReason,
|
|
989
|
+
transaction: "",
|
|
990
|
+
network: payload.accepted.network,
|
|
991
|
+
payer
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
function validateEip2612PermitForPayment(info, payer, tokenAddress) {
|
|
995
|
+
if (!(0, import_extensions2.validateEip2612GasSponsoringInfo)(info)) {
|
|
996
|
+
return { isValid: false, invalidReason: "invalid_eip2612_extension_format" };
|
|
997
|
+
}
|
|
998
|
+
if ((0, import_viem4.getAddress)(info.from) !== (0, import_viem4.getAddress)(payer)) {
|
|
999
|
+
return { isValid: false, invalidReason: "eip2612_from_mismatch" };
|
|
1000
|
+
}
|
|
1001
|
+
if ((0, import_viem4.getAddress)(info.asset) !== tokenAddress) {
|
|
1002
|
+
return { isValid: false, invalidReason: "eip2612_asset_mismatch" };
|
|
1003
|
+
}
|
|
1004
|
+
if ((0, import_viem4.getAddress)(info.spender) !== (0, import_viem4.getAddress)(PERMIT2_ADDRESS)) {
|
|
1005
|
+
return { isValid: false, invalidReason: "eip2612_spender_not_permit2" };
|
|
1006
|
+
}
|
|
1007
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1008
|
+
if (BigInt(info.deadline) < BigInt(now + 6)) {
|
|
1009
|
+
return { isValid: false, invalidReason: "eip2612_deadline_expired" };
|
|
1010
|
+
}
|
|
1011
|
+
return { isValid: true };
|
|
1012
|
+
}
|
|
1013
|
+
function splitEip2612Signature(signature) {
|
|
1014
|
+
const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
|
|
1015
|
+
if (sig.length !== 130) {
|
|
1016
|
+
throw new Error(
|
|
1017
|
+
`invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
const r = `0x${sig.slice(0, 64)}`;
|
|
1021
|
+
const s = `0x${sig.slice(64, 128)}`;
|
|
1022
|
+
const v = parseInt(sig.slice(128, 130), 16);
|
|
1023
|
+
return { v, r, s };
|
|
706
1024
|
}
|
|
707
1025
|
|
|
708
1026
|
// src/exact/facilitator/scheme.ts
|
|
709
1027
|
var ExactEvmScheme = class {
|
|
710
1028
|
/**
|
|
711
|
-
* Creates a new
|
|
1029
|
+
* Creates a new ExactEvmScheme facilitator instance.
|
|
712
1030
|
*
|
|
713
1031
|
* @param signer - The EVM signer for facilitator operations
|
|
714
|
-
* @param config - Optional configuration
|
|
1032
|
+
* @param config - Optional configuration
|
|
715
1033
|
*/
|
|
716
1034
|
constructor(signer, config) {
|
|
717
1035
|
this.signer = signer;
|
|
@@ -722,53 +1040,51 @@ var ExactEvmScheme = class {
|
|
|
722
1040
|
};
|
|
723
1041
|
}
|
|
724
1042
|
/**
|
|
725
|
-
*
|
|
726
|
-
* For EVM, no extra data is needed.
|
|
1043
|
+
* Returns undefined — EVM has no mechanism-specific extra data.
|
|
727
1044
|
*
|
|
728
|
-
* @param _ - The network identifier (unused
|
|
729
|
-
* @returns undefined
|
|
1045
|
+
* @param _ - The network identifier (unused)
|
|
1046
|
+
* @returns undefined
|
|
730
1047
|
*/
|
|
731
1048
|
getExtra(_) {
|
|
732
1049
|
return void 0;
|
|
733
1050
|
}
|
|
734
1051
|
/**
|
|
735
|
-
*
|
|
736
|
-
* Returns all addresses this facilitator can use for signing/settling transactions.
|
|
1052
|
+
* Returns facilitator wallet addresses for the supported response.
|
|
737
1053
|
*
|
|
738
|
-
* @param _ - The network identifier (unused
|
|
1054
|
+
* @param _ - The network identifier (unused, addresses are network-agnostic)
|
|
739
1055
|
* @returns Array of facilitator wallet addresses
|
|
740
1056
|
*/
|
|
741
1057
|
getSigners(_) {
|
|
742
1058
|
return [...this.signer.getAddresses()];
|
|
743
1059
|
}
|
|
744
1060
|
/**
|
|
745
|
-
* Verifies a payment payload.
|
|
746
|
-
* Routes to the appropriate verification logic based on payload type.
|
|
1061
|
+
* Verifies a payment payload. Routes to Permit2 or EIP-3009 based on payload type.
|
|
747
1062
|
*
|
|
748
1063
|
* @param payload - The payment payload to verify
|
|
749
1064
|
* @param requirements - The payment requirements
|
|
1065
|
+
* @param context - Optional facilitator context for extension capabilities
|
|
750
1066
|
* @returns Promise resolving to verification response
|
|
751
1067
|
*/
|
|
752
|
-
async verify(payload, requirements) {
|
|
1068
|
+
async verify(payload, requirements, context) {
|
|
753
1069
|
const rawPayload = payload.payload;
|
|
754
1070
|
if (isPermit2Payload(rawPayload)) {
|
|
755
|
-
return verifyPermit2(this.signer, payload, requirements, rawPayload);
|
|
1071
|
+
return verifyPermit2(this.signer, payload, requirements, rawPayload, context);
|
|
756
1072
|
}
|
|
757
1073
|
const eip3009Payload = rawPayload;
|
|
758
1074
|
return verifyEIP3009(this.signer, payload, requirements, eip3009Payload);
|
|
759
1075
|
}
|
|
760
1076
|
/**
|
|
761
|
-
* Settles a payment
|
|
762
|
-
* Routes to the appropriate settlement logic based on payload type.
|
|
1077
|
+
* Settles a payment. Routes to Permit2 or EIP-3009 based on payload type.
|
|
763
1078
|
*
|
|
764
1079
|
* @param payload - The payment payload to settle
|
|
765
1080
|
* @param requirements - The payment requirements
|
|
1081
|
+
* @param context - Optional facilitator context for extension capabilities
|
|
766
1082
|
* @returns Promise resolving to settlement response
|
|
767
1083
|
*/
|
|
768
|
-
async settle(payload, requirements) {
|
|
1084
|
+
async settle(payload, requirements, context) {
|
|
769
1085
|
const rawPayload = payload.payload;
|
|
770
1086
|
if (isPermit2Payload(rawPayload)) {
|
|
771
|
-
return settlePermit2(this.signer, payload, requirements, rawPayload);
|
|
1087
|
+
return settlePermit2(this.signer, payload, requirements, rawPayload, context);
|
|
772
1088
|
}
|
|
773
1089
|
const eip3009Payload = rawPayload;
|
|
774
1090
|
return settleEIP3009(this.signer, payload, requirements, eip3009Payload, this.config);
|
|
@@ -776,13 +1092,10 @@ var ExactEvmScheme = class {
|
|
|
776
1092
|
};
|
|
777
1093
|
|
|
778
1094
|
// src/exact/v1/facilitator/scheme.ts
|
|
779
|
-
var
|
|
780
|
-
|
|
781
|
-
// src/utils.ts
|
|
782
|
-
var import_viem4 = require("viem");
|
|
1095
|
+
var import_viem6 = require("viem");
|
|
783
1096
|
|
|
784
1097
|
// src/exact/v1/client/scheme.ts
|
|
785
|
-
var
|
|
1098
|
+
var import_viem5 = require("viem");
|
|
786
1099
|
|
|
787
1100
|
// src/v1/index.ts
|
|
788
1101
|
var EVM_NETWORK_CHAIN_ID_MAP = {
|
|
@@ -802,15 +1115,15 @@ var EVM_NETWORK_CHAIN_ID_MAP = {
|
|
|
802
1115
|
peaq: 3338,
|
|
803
1116
|
story: 1514,
|
|
804
1117
|
educhain: 41923,
|
|
805
|
-
"skale-base-sepolia": 324705682
|
|
1118
|
+
"skale-base-sepolia": 324705682,
|
|
1119
|
+
megaeth: 4326,
|
|
1120
|
+
monad: 143
|
|
806
1121
|
};
|
|
807
1122
|
var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
|
|
808
|
-
|
|
809
|
-
// src/utils.ts
|
|
810
|
-
function getEvmChainId(network) {
|
|
1123
|
+
function getEvmChainIdV1(network) {
|
|
811
1124
|
const chainId = EVM_NETWORK_CHAIN_ID_MAP[network];
|
|
812
1125
|
if (!chainId) {
|
|
813
|
-
throw new Error(`Unsupported network: ${network}`);
|
|
1126
|
+
throw new Error(`Unsupported v1 network: ${network}`);
|
|
814
1127
|
}
|
|
815
1128
|
return chainId;
|
|
816
1129
|
}
|
|
@@ -871,7 +1184,7 @@ var ExactEvmSchemeV12 = class {
|
|
|
871
1184
|
}
|
|
872
1185
|
let chainId;
|
|
873
1186
|
try {
|
|
874
|
-
chainId =
|
|
1187
|
+
chainId = getEvmChainIdV1(payloadV1.network);
|
|
875
1188
|
} catch {
|
|
876
1189
|
return {
|
|
877
1190
|
isValid: false,
|
|
@@ -887,7 +1200,7 @@ var ExactEvmSchemeV12 = class {
|
|
|
887
1200
|
};
|
|
888
1201
|
}
|
|
889
1202
|
const { name, version } = requirements.extra;
|
|
890
|
-
const erc20Address = (0,
|
|
1203
|
+
const erc20Address = (0, import_viem6.getAddress)(requirements.asset);
|
|
891
1204
|
if (payloadV1.network !== requirements.network) {
|
|
892
1205
|
return {
|
|
893
1206
|
isValid: false,
|
|
@@ -934,8 +1247,8 @@ var ExactEvmSchemeV12 = class {
|
|
|
934
1247
|
const payerAddress = exactEvmPayload.authorization.from;
|
|
935
1248
|
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
936
1249
|
if (!bytecode || bytecode === "0x") {
|
|
937
|
-
const erc6492Data = (0,
|
|
938
|
-
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0,
|
|
1250
|
+
const erc6492Data = (0, import_viem6.parseErc6492Signature)(signature);
|
|
1251
|
+
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem6.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
939
1252
|
if (!hasDeploymentInfo) {
|
|
940
1253
|
return {
|
|
941
1254
|
isValid: false,
|
|
@@ -958,7 +1271,7 @@ var ExactEvmSchemeV12 = class {
|
|
|
958
1271
|
};
|
|
959
1272
|
}
|
|
960
1273
|
}
|
|
961
|
-
if ((0,
|
|
1274
|
+
if ((0, import_viem6.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem6.getAddress)(requirements.payTo)) {
|
|
962
1275
|
return {
|
|
963
1276
|
isValid: false,
|
|
964
1277
|
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
@@ -991,15 +1304,16 @@ var ExactEvmSchemeV12 = class {
|
|
|
991
1304
|
return {
|
|
992
1305
|
isValid: false,
|
|
993
1306
|
invalidReason: "insufficient_funds",
|
|
1307
|
+
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.`,
|
|
994
1308
|
payer: exactEvmPayload.authorization.from
|
|
995
1309
|
};
|
|
996
1310
|
}
|
|
997
1311
|
} catch {
|
|
998
1312
|
}
|
|
999
|
-
if (BigInt(exactEvmPayload.authorization.value)
|
|
1313
|
+
if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {
|
|
1000
1314
|
return {
|
|
1001
1315
|
isValid: false,
|
|
1002
|
-
invalidReason: "
|
|
1316
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value_mismatch",
|
|
1003
1317
|
payer: exactEvmPayload.authorization.from
|
|
1004
1318
|
};
|
|
1005
1319
|
}
|
|
@@ -1030,9 +1344,9 @@ var ExactEvmSchemeV12 = class {
|
|
|
1030
1344
|
};
|
|
1031
1345
|
}
|
|
1032
1346
|
try {
|
|
1033
|
-
const parseResult = (0,
|
|
1347
|
+
const parseResult = (0, import_viem6.parseErc6492Signature)(exactEvmPayload.signature);
|
|
1034
1348
|
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
1035
|
-
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0,
|
|
1349
|
+
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem6.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
1036
1350
|
const payerAddress = exactEvmPayload.authorization.from;
|
|
1037
1351
|
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
1038
1352
|
if (!bytecode || bytecode === "0x") {
|
|
@@ -1056,14 +1370,14 @@ var ExactEvmSchemeV12 = class {
|
|
|
1056
1370
|
const isECDSA = signatureLength === 130;
|
|
1057
1371
|
let tx;
|
|
1058
1372
|
if (isECDSA) {
|
|
1059
|
-
const parsedSig = (0,
|
|
1373
|
+
const parsedSig = (0, import_viem6.parseSignature)(signature);
|
|
1060
1374
|
tx = await this.signer.writeContract({
|
|
1061
|
-
address: (0,
|
|
1375
|
+
address: (0, import_viem6.getAddress)(requirements.asset),
|
|
1062
1376
|
abi: eip3009ABI,
|
|
1063
1377
|
functionName: "transferWithAuthorization",
|
|
1064
1378
|
args: [
|
|
1065
|
-
(0,
|
|
1066
|
-
(0,
|
|
1379
|
+
(0, import_viem6.getAddress)(exactEvmPayload.authorization.from),
|
|
1380
|
+
(0, import_viem6.getAddress)(exactEvmPayload.authorization.to),
|
|
1067
1381
|
BigInt(exactEvmPayload.authorization.value),
|
|
1068
1382
|
BigInt(exactEvmPayload.authorization.validAfter),
|
|
1069
1383
|
BigInt(exactEvmPayload.authorization.validBefore),
|
|
@@ -1075,12 +1389,12 @@ var ExactEvmSchemeV12 = class {
|
|
|
1075
1389
|
});
|
|
1076
1390
|
} else {
|
|
1077
1391
|
tx = await this.signer.writeContract({
|
|
1078
|
-
address: (0,
|
|
1392
|
+
address: (0, import_viem6.getAddress)(requirements.asset),
|
|
1079
1393
|
abi: eip3009ABI,
|
|
1080
1394
|
functionName: "transferWithAuthorization",
|
|
1081
1395
|
args: [
|
|
1082
|
-
(0,
|
|
1083
|
-
(0,
|
|
1396
|
+
(0, import_viem6.getAddress)(exactEvmPayload.authorization.from),
|
|
1397
|
+
(0, import_viem6.getAddress)(exactEvmPayload.authorization.to),
|
|
1084
1398
|
BigInt(exactEvmPayload.authorization.value),
|
|
1085
1399
|
BigInt(exactEvmPayload.authorization.validAfter),
|
|
1086
1400
|
BigInt(exactEvmPayload.authorization.validBefore),
|