@payai/x402-evm 2.3.5 → 2.4.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.
- package/dist/cjs/exact/client/index.d.ts +3 -2
- package/dist/cjs/exact/client/index.js +175 -194
- package/dist/cjs/exact/client/index.js.map +1 -1
- package/dist/cjs/exact/facilitator/index.js +201 -185
- package/dist/cjs/exact/facilitator/index.js.map +1 -1
- package/dist/cjs/exact/server/index.d.ts +18 -17
- package/dist/cjs/exact/server/index.js +100 -55
- package/dist/cjs/exact/server/index.js.map +1 -1
- package/dist/cjs/exact/v1/client/index.js +5 -1
- package/dist/cjs/exact/v1/client/index.js.map +1 -1
- package/dist/cjs/exact/v1/facilitator/index.js +5 -1
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -1
- package/dist/cjs/index.d.ts +38 -2
- package/dist/cjs/index.js +443 -191
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/{permit2-U9Zolx3O.d.ts → permit2-CyZxwngN.d.ts} +278 -87
- package/dist/cjs/scheme-CXDF0D2A.d.ts +47 -0
- package/dist/cjs/upto/client/index.d.ts +32 -0
- package/dist/cjs/upto/client/index.js +507 -0
- package/dist/cjs/upto/client/index.js.map +1 -0
- package/dist/cjs/upto/facilitator/index.d.ts +52 -0
- package/dist/cjs/upto/facilitator/index.js +1233 -0
- package/dist/cjs/upto/facilitator/index.js.map +1 -0
- package/dist/cjs/upto/server/index.d.ts +77 -0
- package/dist/cjs/upto/server/index.js +246 -0
- package/dist/cjs/upto/server/index.js.map +1 -0
- package/dist/cjs/v1/index.d.ts +4 -0
- package/dist/cjs/v1/index.js +5 -1
- package/dist/cjs/v1/index.js.map +1 -1
- package/dist/esm/chunk-C4ZQMS77.mjs +629 -0
- package/dist/esm/chunk-C4ZQMS77.mjs.map +1 -0
- package/dist/esm/chunk-CRT6YNY5.mjs +529 -0
- package/dist/esm/chunk-CRT6YNY5.mjs.map +1 -0
- package/dist/esm/chunk-D6RXZXOS.mjs +158 -0
- package/dist/esm/chunk-D6RXZXOS.mjs.map +1 -0
- package/dist/esm/chunk-GJ57SZGI.mjs +121 -0
- package/dist/esm/chunk-GJ57SZGI.mjs.map +1 -0
- package/dist/esm/chunk-JII456TS.mjs +34 -0
- package/dist/esm/chunk-JII456TS.mjs.map +1 -0
- package/dist/esm/chunk-NSFLAANF.mjs +80 -0
- package/dist/esm/chunk-NSFLAANF.mjs.map +1 -0
- package/dist/esm/{chunk-IZEI7JTG.mjs → chunk-RYT6M3PA.mjs} +31 -501
- package/dist/esm/chunk-RYT6M3PA.mjs.map +1 -0
- package/dist/esm/chunk-WKBC5YMI.mjs +291 -0
- package/dist/esm/chunk-WKBC5YMI.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +3 -2
- package/dist/esm/exact/client/index.mjs +8 -5
- package/dist/esm/exact/facilitator/index.mjs +84 -430
- package/dist/esm/exact/facilitator/index.mjs.map +1 -1
- package/dist/esm/exact/server/index.d.mts +18 -17
- package/dist/esm/exact/server/index.mjs +28 -55
- package/dist/esm/exact/server/index.mjs.map +1 -1
- package/dist/esm/exact/v1/client/index.mjs +2 -1
- package/dist/esm/exact/v1/facilitator/index.mjs +2 -1
- package/dist/esm/index.d.mts +38 -2
- package/dist/esm/index.mjs +21 -8
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/{permit2-Bbh3a8_h.d.mts → permit2-CyZxwngN.d.mts} +278 -87
- package/dist/esm/scheme-DCR7hsa3.d.mts +47 -0
- package/dist/esm/upto/client/index.d.mts +32 -0
- package/dist/esm/upto/client/index.mjs +18 -0
- package/dist/esm/upto/client/index.mjs.map +1 -0
- package/dist/esm/upto/facilitator/index.d.mts +52 -0
- package/dist/esm/upto/facilitator/index.mjs +473 -0
- package/dist/esm/upto/facilitator/index.mjs.map +1 -0
- package/dist/esm/upto/server/index.d.mts +77 -0
- package/dist/esm/upto/server/index.mjs +145 -0
- package/dist/esm/upto/server/index.mjs.map +1 -0
- package/dist/esm/v1/index.d.mts +4 -0
- package/dist/esm/v1/index.mjs +2 -1
- package/package.json +31 -1
- package/dist/esm/chunk-GD4MKCN7.mjs +0 -57
- package/dist/esm/chunk-GD4MKCN7.mjs.map +0 -1
- package/dist/esm/chunk-IZEI7JTG.mjs.map +0 -1
- package/dist/esm/chunk-TKN5V2BV.mjs +0 -13
- package/dist/esm/chunk-TKN5V2BV.mjs.map +0 -1
- package/dist/esm/chunk-WJWNS4G4.mjs +0 -518
- package/dist/esm/chunk-WJWNS4G4.mjs.map +0 -1
|
@@ -1,57 +1,42 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isPermit2Payload
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-JII456TS.mjs";
|
|
4
|
+
import {
|
|
5
|
+
ExactEvmSchemeV1,
|
|
6
|
+
NETWORKS,
|
|
7
|
+
diagnoseEip3009SimulationFailure,
|
|
8
|
+
executeTransferWithAuthorization,
|
|
9
|
+
simulateEip3009Transfer
|
|
10
|
+
} from "../../chunk-RYT6M3PA.mjs";
|
|
4
11
|
import {
|
|
5
12
|
ERC20_APPROVAL_GAS_SPONSORING_KEY,
|
|
13
|
+
buildExactPermit2SettleArgs,
|
|
14
|
+
checkPermit2Prerequisites,
|
|
15
|
+
diagnosePermit2SimulationFailure,
|
|
6
16
|
extractEip2612GasSponsoringInfo,
|
|
7
17
|
extractErc20ApprovalGasSponsoringInfo,
|
|
18
|
+
mapSettleError,
|
|
8
19
|
resolveErc20ApprovalExtensionSigner,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
20
|
+
simulatePermit2Settle,
|
|
21
|
+
simulatePermit2SettleWithErc20Approval,
|
|
22
|
+
simulatePermit2SettleWithPermit,
|
|
23
|
+
splitEip2612Signature,
|
|
24
|
+
validateEip2612PermitForPayment,
|
|
25
|
+
validateErc20ApprovalForPayment,
|
|
26
|
+
waitAndReturnSettleResponse
|
|
27
|
+
} from "../../chunk-CRT6YNY5.mjs";
|
|
12
28
|
import {
|
|
13
|
-
DEFAULT_MAX_FEE_PER_GAS,
|
|
14
|
-
ERC20_APPROVE_GAS_LIMIT,
|
|
15
|
-
ErrEip2612AssetMismatch,
|
|
16
|
-
ErrEip2612DeadlineExpired,
|
|
17
|
-
ErrEip2612FromMismatch,
|
|
18
|
-
ErrEip2612SpenderNotPermit2,
|
|
19
|
-
ErrErc20ApprovalAssetMismatch,
|
|
20
|
-
ErrErc20ApprovalFromMismatch,
|
|
21
|
-
ErrErc20ApprovalInsufficientEthForGas,
|
|
22
|
-
ErrErc20ApprovalInvalidFormat,
|
|
23
|
-
ErrErc20ApprovalSpenderNotPermit2,
|
|
24
|
-
ErrErc20ApprovalTxFailed,
|
|
25
|
-
ErrErc20ApprovalTxInvalidCalldata,
|
|
26
|
-
ErrErc20ApprovalTxInvalidSignature,
|
|
27
|
-
ErrErc20ApprovalTxParseFailed,
|
|
28
|
-
ErrErc20ApprovalTxSignerMismatch,
|
|
29
|
-
ErrErc20ApprovalTxWrongSelector,
|
|
30
|
-
ErrErc20ApprovalTxWrongSpender,
|
|
31
|
-
ErrErc20ApprovalTxWrongTarget,
|
|
32
29
|
ErrInvalidAuthorizationValue,
|
|
33
|
-
ErrInvalidEip2612ExtensionFormat,
|
|
34
30
|
ErrInvalidScheme,
|
|
35
31
|
ErrInvalidSignature,
|
|
36
|
-
ErrInvalidTransactionState,
|
|
37
32
|
ErrMissingEip712Domain,
|
|
38
33
|
ErrNetworkMismatch,
|
|
39
|
-
ErrPermit2612AmountMismatch,
|
|
40
|
-
ErrPermit2AllowanceRequired,
|
|
41
34
|
ErrPermit2AmountMismatch,
|
|
42
35
|
ErrPermit2DeadlineExpired,
|
|
43
|
-
ErrPermit2InsufficientBalance,
|
|
44
|
-
ErrPermit2InvalidAmount,
|
|
45
|
-
ErrPermit2InvalidDestination,
|
|
46
|
-
ErrPermit2InvalidNonce,
|
|
47
|
-
ErrPermit2InvalidOwner,
|
|
48
36
|
ErrPermit2InvalidSignature,
|
|
49
37
|
ErrPermit2InvalidSpender,
|
|
50
38
|
ErrPermit2NotYetValid,
|
|
51
|
-
ErrPermit2PaymentTooEarly,
|
|
52
|
-
ErrPermit2ProxyNotDeployed,
|
|
53
39
|
ErrPermit2RecipientMismatch,
|
|
54
|
-
ErrPermit2SimulationFailed,
|
|
55
40
|
ErrPermit2TokenMismatch,
|
|
56
41
|
ErrRecipientMismatch,
|
|
57
42
|
ErrTransactionFailed,
|
|
@@ -59,24 +44,13 @@ import {
|
|
|
59
44
|
ErrUnsupportedPayloadType,
|
|
60
45
|
ErrValidAfterInFuture,
|
|
61
46
|
ErrValidBeforeExpired,
|
|
62
|
-
ExactEvmSchemeV1,
|
|
63
|
-
MULTICALL3_ADDRESS,
|
|
64
|
-
NETWORKS,
|
|
65
47
|
PERMIT2_ADDRESS,
|
|
66
48
|
authorizationTypes,
|
|
67
|
-
diagnoseEip3009SimulationFailure,
|
|
68
|
-
eip3009ABI,
|
|
69
|
-
erc20AllowanceAbi,
|
|
70
|
-
erc20ApproveAbi,
|
|
71
|
-
executeTransferWithAuthorization,
|
|
72
49
|
getEvmChainId,
|
|
73
|
-
multicall,
|
|
74
|
-
multicall3GetEthBalanceAbi,
|
|
75
50
|
permit2WitnessTypes,
|
|
76
|
-
simulateEip3009Transfer,
|
|
77
51
|
x402ExactPermit2ProxyABI,
|
|
78
52
|
x402ExactPermit2ProxyAddress
|
|
79
|
-
} from "../../chunk-
|
|
53
|
+
} from "../../chunk-C4ZQMS77.mjs";
|
|
80
54
|
|
|
81
55
|
// src/exact/facilitator/eip3009.ts
|
|
82
56
|
import { getAddress, isAddressEqual, parseErc6492Signature } from "viem";
|
|
@@ -276,361 +250,11 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
|
|
|
276
250
|
}
|
|
277
251
|
|
|
278
252
|
// src/exact/facilitator/permit2.ts
|
|
279
|
-
import { getAddress as
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
parseTransaction,
|
|
285
|
-
decodeFunctionData,
|
|
286
|
-
recoverTransactionAddress
|
|
287
|
-
} from "viem";
|
|
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-utils.ts
|
|
385
|
-
import { encodeFunctionData, getAddress as getAddress3 } from "viem";
|
|
386
|
-
async function simulatePermit2Settle(signer, permit2Payload) {
|
|
387
|
-
try {
|
|
388
|
-
await signer.readContract({
|
|
389
|
-
address: x402ExactPermit2ProxyAddress,
|
|
390
|
-
abi: x402ExactPermit2ProxyABI,
|
|
391
|
-
functionName: "settle",
|
|
392
|
-
args: buildPermit2SettleArgs(permit2Payload)
|
|
393
|
-
});
|
|
394
|
-
return true;
|
|
395
|
-
} catch {
|
|
396
|
-
return false;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
function splitEip2612Signature(signature) {
|
|
400
|
-
const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
|
|
401
|
-
if (sig.length !== 130) {
|
|
402
|
-
throw new Error(
|
|
403
|
-
`invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
const r = `0x${sig.slice(0, 64)}`;
|
|
407
|
-
const s = `0x${sig.slice(64, 128)}`;
|
|
408
|
-
const v = parseInt(sig.slice(128, 130), 16);
|
|
409
|
-
return { v, r, s };
|
|
410
|
-
}
|
|
411
|
-
function buildPermit2SettleArgs(permit2Payload) {
|
|
412
|
-
return [
|
|
413
|
-
{
|
|
414
|
-
permitted: {
|
|
415
|
-
token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
|
|
416
|
-
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
417
|
-
},
|
|
418
|
-
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
419
|
-
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
|
|
420
|
-
},
|
|
421
|
-
getAddress3(permit2Payload.permit2Authorization.from),
|
|
422
|
-
{
|
|
423
|
-
to: getAddress3(permit2Payload.permit2Authorization.witness.to),
|
|
424
|
-
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
425
|
-
},
|
|
426
|
-
permit2Payload.signature
|
|
427
|
-
];
|
|
428
|
-
}
|
|
429
|
-
function encodePermit2SettleCalldata(permit2Payload) {
|
|
430
|
-
return encodeFunctionData({
|
|
431
|
-
abi: x402ExactPermit2ProxyABI,
|
|
432
|
-
functionName: "settle",
|
|
433
|
-
args: buildPermit2SettleArgs(permit2Payload)
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
async function simulatePermit2SettleWithPermit(signer, permit2Payload, eip2612Info) {
|
|
437
|
-
try {
|
|
438
|
-
const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
|
|
439
|
-
await signer.readContract({
|
|
440
|
-
address: x402ExactPermit2ProxyAddress,
|
|
441
|
-
abi: x402ExactPermit2ProxyABI,
|
|
442
|
-
functionName: "settleWithPermit",
|
|
443
|
-
args: [
|
|
444
|
-
{
|
|
445
|
-
value: BigInt(eip2612Info.amount),
|
|
446
|
-
deadline: BigInt(eip2612Info.deadline),
|
|
447
|
-
r,
|
|
448
|
-
s,
|
|
449
|
-
v
|
|
450
|
-
},
|
|
451
|
-
...buildPermit2SettleArgs(permit2Payload)
|
|
452
|
-
]
|
|
453
|
-
});
|
|
454
|
-
return true;
|
|
455
|
-
} catch {
|
|
456
|
-
return false;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
async function diagnosePermit2SimulationFailure(signer, tokenAddress, permit2Payload, amountRequired) {
|
|
460
|
-
const payer = permit2Payload.permit2Authorization.from;
|
|
461
|
-
const diagnosticCalls = [
|
|
462
|
-
{
|
|
463
|
-
address: x402ExactPermit2ProxyAddress,
|
|
464
|
-
abi: x402ExactPermit2ProxyABI,
|
|
465
|
-
functionName: "PERMIT2"
|
|
466
|
-
},
|
|
467
|
-
{
|
|
468
|
-
address: tokenAddress,
|
|
469
|
-
abi: eip3009ABI,
|
|
470
|
-
functionName: "balanceOf",
|
|
471
|
-
args: [payer]
|
|
472
|
-
},
|
|
473
|
-
{
|
|
474
|
-
address: tokenAddress,
|
|
475
|
-
abi: erc20AllowanceAbi,
|
|
476
|
-
functionName: "allowance",
|
|
477
|
-
args: [payer, PERMIT2_ADDRESS]
|
|
478
|
-
}
|
|
479
|
-
];
|
|
480
|
-
try {
|
|
481
|
-
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
|
|
482
|
-
const [proxyResult, balanceResult, allowanceResult] = results;
|
|
483
|
-
if (proxyResult.status === "failure") {
|
|
484
|
-
return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
|
|
485
|
-
}
|
|
486
|
-
if (balanceResult.status === "success") {
|
|
487
|
-
const balance = balanceResult.result;
|
|
488
|
-
if (balance < BigInt(amountRequired)) {
|
|
489
|
-
return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
if (allowanceResult.status === "success") {
|
|
493
|
-
const allowance = allowanceResult.result;
|
|
494
|
-
if (allowance < BigInt(amountRequired)) {
|
|
495
|
-
return { isValid: false, invalidReason: ErrPermit2AllowanceRequired, payer };
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
} catch {
|
|
499
|
-
}
|
|
500
|
-
return { isValid: false, invalidReason: ErrPermit2SimulationFailed, payer };
|
|
501
|
-
}
|
|
502
|
-
async function checkPermit2Prerequisites(signer, tokenAddress, payer, amountRequired) {
|
|
503
|
-
const diagnosticCalls = [
|
|
504
|
-
{
|
|
505
|
-
address: x402ExactPermit2ProxyAddress,
|
|
506
|
-
abi: x402ExactPermit2ProxyABI,
|
|
507
|
-
functionName: "PERMIT2"
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
address: tokenAddress,
|
|
511
|
-
abi: eip3009ABI,
|
|
512
|
-
functionName: "balanceOf",
|
|
513
|
-
args: [payer]
|
|
514
|
-
},
|
|
515
|
-
{
|
|
516
|
-
address: MULTICALL3_ADDRESS,
|
|
517
|
-
abi: multicall3GetEthBalanceAbi,
|
|
518
|
-
functionName: "getEthBalance",
|
|
519
|
-
args: [payer]
|
|
520
|
-
}
|
|
521
|
-
];
|
|
522
|
-
try {
|
|
523
|
-
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
|
|
524
|
-
const [proxyResult, balanceResult, ethBalanceResult] = results;
|
|
525
|
-
if (proxyResult.status === "failure") {
|
|
526
|
-
return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
|
|
527
|
-
}
|
|
528
|
-
if (balanceResult.status === "success") {
|
|
529
|
-
const balance = balanceResult.result;
|
|
530
|
-
if (balance < BigInt(amountRequired)) {
|
|
531
|
-
return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
if (ethBalanceResult.status === "success") {
|
|
535
|
-
const minEthForApprovalGas = ERC20_APPROVE_GAS_LIMIT * DEFAULT_MAX_FEE_PER_GAS;
|
|
536
|
-
const ethBalance = ethBalanceResult.result;
|
|
537
|
-
if (ethBalance < minEthForApprovalGas) {
|
|
538
|
-
return {
|
|
539
|
-
isValid: false,
|
|
540
|
-
invalidReason: ErrErc20ApprovalInsufficientEthForGas,
|
|
541
|
-
payer
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
} catch {
|
|
546
|
-
}
|
|
547
|
-
return { isValid: true, invalidReason: void 0, payer };
|
|
548
|
-
}
|
|
549
|
-
async function simulatePermit2SettleWithErc20Approval(extensionSigner, permit2Payload, erc20Info) {
|
|
550
|
-
if (!extensionSigner.simulateTransactions) {
|
|
551
|
-
return false;
|
|
552
|
-
}
|
|
553
|
-
try {
|
|
554
|
-
const settleData = encodePermit2SettleCalldata(permit2Payload);
|
|
555
|
-
return await extensionSigner.simulateTransactions([
|
|
556
|
-
erc20Info.signedTransaction,
|
|
557
|
-
{ to: x402ExactPermit2ProxyAddress, data: settleData, gas: BigInt(3e5) }
|
|
558
|
-
]);
|
|
559
|
-
} catch {
|
|
560
|
-
return false;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
async function waitAndReturn(signer, tx, payload, payer) {
|
|
564
|
-
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
|
|
565
|
-
if (receipt.status !== "success") {
|
|
566
|
-
return {
|
|
567
|
-
success: false,
|
|
568
|
-
errorReason: ErrInvalidTransactionState,
|
|
569
|
-
transaction: tx,
|
|
570
|
-
network: payload.accepted.network,
|
|
571
|
-
payer
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
return {
|
|
575
|
-
success: true,
|
|
576
|
-
transaction: tx,
|
|
577
|
-
network: payload.accepted.network,
|
|
578
|
-
payer
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
function mapSettleError(error, payload, payer) {
|
|
582
|
-
let errorReason = ErrTransactionFailed;
|
|
583
|
-
if (error instanceof Error) {
|
|
584
|
-
const message = error.message;
|
|
585
|
-
if (message.includes("Permit2612AmountMismatch")) {
|
|
586
|
-
errorReason = ErrPermit2612AmountMismatch;
|
|
587
|
-
} else if (message.includes("InvalidAmount")) {
|
|
588
|
-
errorReason = ErrPermit2InvalidAmount;
|
|
589
|
-
} else if (message.includes("InvalidDestination")) {
|
|
590
|
-
errorReason = ErrPermit2InvalidDestination;
|
|
591
|
-
} else if (message.includes("InvalidOwner")) {
|
|
592
|
-
errorReason = ErrPermit2InvalidOwner;
|
|
593
|
-
} else if (message.includes("PaymentTooEarly")) {
|
|
594
|
-
errorReason = ErrPermit2PaymentTooEarly;
|
|
595
|
-
} else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
|
|
596
|
-
errorReason = ErrPermit2InvalidSignature;
|
|
597
|
-
} else if (message.includes("InvalidNonce")) {
|
|
598
|
-
errorReason = ErrPermit2InvalidNonce;
|
|
599
|
-
} else if (message.includes("erc20_approval_tx_failed")) {
|
|
600
|
-
errorReason = ErrErc20ApprovalTxFailed;
|
|
601
|
-
} else {
|
|
602
|
-
errorReason = `${ErrTransactionFailed}: ${message.slice(0, 500)}`;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
return {
|
|
606
|
-
success: false,
|
|
607
|
-
errorReason,
|
|
608
|
-
transaction: "",
|
|
609
|
-
network: payload.accepted.network,
|
|
610
|
-
payer
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
function validateEip2612PermitForPayment(info, payer, tokenAddress) {
|
|
614
|
-
if (!validateEip2612GasSponsoringInfo(info)) {
|
|
615
|
-
return { isValid: false, invalidReason: ErrInvalidEip2612ExtensionFormat };
|
|
616
|
-
}
|
|
617
|
-
if (getAddress3(info.from) !== getAddress3(payer)) {
|
|
618
|
-
return { isValid: false, invalidReason: ErrEip2612FromMismatch };
|
|
619
|
-
}
|
|
620
|
-
if (getAddress3(info.asset) !== tokenAddress) {
|
|
621
|
-
return { isValid: false, invalidReason: ErrEip2612AssetMismatch };
|
|
622
|
-
}
|
|
623
|
-
if (getAddress3(info.spender) !== getAddress3(PERMIT2_ADDRESS)) {
|
|
624
|
-
return { isValid: false, invalidReason: ErrEip2612SpenderNotPermit2 };
|
|
625
|
-
}
|
|
626
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
627
|
-
if (BigInt(info.deadline) < BigInt(now + 6)) {
|
|
628
|
-
return { isValid: false, invalidReason: ErrEip2612DeadlineExpired };
|
|
629
|
-
}
|
|
630
|
-
return { isValid: true };
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// src/exact/facilitator/permit2.ts
|
|
253
|
+
import { getAddress as getAddress2, encodeFunctionData } from "viem";
|
|
254
|
+
var exactProxyConfig = {
|
|
255
|
+
proxyAddress: x402ExactPermit2ProxyAddress,
|
|
256
|
+
proxyABI: x402ExactPermit2ProxyABI
|
|
257
|
+
};
|
|
634
258
|
async function verifyPermit2(signer, payload, requirements, permit2Payload, context, options) {
|
|
635
259
|
const payer = permit2Payload.permit2Authorization.from;
|
|
636
260
|
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
@@ -648,15 +272,15 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
648
272
|
};
|
|
649
273
|
}
|
|
650
274
|
const chainId = getEvmChainId(requirements.network);
|
|
651
|
-
const tokenAddress =
|
|
652
|
-
if (
|
|
275
|
+
const tokenAddress = getAddress2(requirements.asset);
|
|
276
|
+
if (getAddress2(permit2Payload.permit2Authorization.spender) !== getAddress2(x402ExactPermit2ProxyAddress)) {
|
|
653
277
|
return {
|
|
654
278
|
isValid: false,
|
|
655
279
|
invalidReason: ErrPermit2InvalidSpender,
|
|
656
280
|
payer
|
|
657
281
|
};
|
|
658
282
|
}
|
|
659
|
-
if (
|
|
283
|
+
if (getAddress2(permit2Payload.permit2Authorization.witness.to) !== getAddress2(requirements.payTo)) {
|
|
660
284
|
return {
|
|
661
285
|
isValid: false,
|
|
662
286
|
invalidReason: ErrPermit2RecipientMismatch,
|
|
@@ -685,7 +309,7 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
685
309
|
payer
|
|
686
310
|
};
|
|
687
311
|
}
|
|
688
|
-
if (
|
|
312
|
+
if (getAddress2(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
|
|
689
313
|
return {
|
|
690
314
|
isValid: false,
|
|
691
315
|
invalidReason: ErrPermit2TokenMismatch,
|
|
@@ -702,14 +326,14 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
702
326
|
},
|
|
703
327
|
message: {
|
|
704
328
|
permitted: {
|
|
705
|
-
token:
|
|
329
|
+
token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
|
|
706
330
|
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
707
331
|
},
|
|
708
|
-
spender:
|
|
332
|
+
spender: getAddress2(permit2Payload.permit2Authorization.spender),
|
|
709
333
|
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
710
334
|
deadline: BigInt(permit2Payload.permit2Authorization.deadline),
|
|
711
335
|
witness: {
|
|
712
|
-
to:
|
|
336
|
+
to: getAddress2(permit2Payload.permit2Authorization.witness.to),
|
|
713
337
|
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
714
338
|
}
|
|
715
339
|
}
|
|
@@ -744,9 +368,16 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
744
368
|
if (!fieldResult.isValid) {
|
|
745
369
|
return { isValid: false, invalidReason: fieldResult.invalidReason, payer };
|
|
746
370
|
}
|
|
747
|
-
const
|
|
371
|
+
const exactSettleArgs = buildExactPermit2SettleArgs(permit2Payload);
|
|
372
|
+
const simOk2 = await simulatePermit2SettleWithPermit(
|
|
373
|
+
exactProxyConfig,
|
|
374
|
+
signer,
|
|
375
|
+
exactSettleArgs,
|
|
376
|
+
eip2612Info
|
|
377
|
+
);
|
|
748
378
|
if (!simOk2) {
|
|
749
379
|
return diagnosePermit2SimulationFailure(
|
|
380
|
+
exactProxyConfig,
|
|
750
381
|
signer,
|
|
751
382
|
tokenAddress,
|
|
752
383
|
permit2Payload,
|
|
@@ -771,12 +402,14 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
771
402
|
);
|
|
772
403
|
if (extensionSigner?.simulateTransactions) {
|
|
773
404
|
const simOk2 = await simulatePermit2SettleWithErc20Approval(
|
|
405
|
+
exactProxyConfig,
|
|
774
406
|
extensionSigner,
|
|
775
|
-
permit2Payload,
|
|
407
|
+
buildExactPermit2SettleArgs(permit2Payload),
|
|
776
408
|
erc20Info
|
|
777
409
|
);
|
|
778
410
|
if (!simOk2) {
|
|
779
411
|
return diagnosePermit2SimulationFailure(
|
|
412
|
+
exactProxyConfig,
|
|
780
413
|
signer,
|
|
781
414
|
tokenAddress,
|
|
782
415
|
permit2Payload,
|
|
@@ -785,12 +418,23 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
785
418
|
}
|
|
786
419
|
return { isValid: true, invalidReason: void 0, payer };
|
|
787
420
|
}
|
|
788
|
-
return checkPermit2Prerequisites(
|
|
421
|
+
return checkPermit2Prerequisites(
|
|
422
|
+
exactProxyConfig,
|
|
423
|
+
signer,
|
|
424
|
+
tokenAddress,
|
|
425
|
+
payer,
|
|
426
|
+
requirements.amount
|
|
427
|
+
);
|
|
789
428
|
}
|
|
790
429
|
}
|
|
791
|
-
const simOk = await simulatePermit2Settle(
|
|
430
|
+
const simOk = await simulatePermit2Settle(
|
|
431
|
+
exactProxyConfig,
|
|
432
|
+
signer,
|
|
433
|
+
buildExactPermit2SettleArgs(permit2Payload)
|
|
434
|
+
);
|
|
792
435
|
if (!simOk) {
|
|
793
436
|
return diagnosePermit2SimulationFailure(
|
|
437
|
+
exactProxyConfig,
|
|
794
438
|
signer,
|
|
795
439
|
tokenAddress,
|
|
796
440
|
permit2Payload,
|
|
@@ -815,7 +459,7 @@ async function settlePermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
815
459
|
}
|
|
816
460
|
const eip2612Info = extractEip2612GasSponsoringInfo(payload);
|
|
817
461
|
if (eip2612Info) {
|
|
818
|
-
return
|
|
462
|
+
return settlePermit2WithEIP2612(exactProxyConfig, signer, payload, permit2Payload, eip2612Info);
|
|
819
463
|
}
|
|
820
464
|
const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
|
|
821
465
|
if (erc20Info) {
|
|
@@ -827,18 +471,24 @@ async function settlePermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
827
471
|
payload.accepted.network
|
|
828
472
|
);
|
|
829
473
|
if (extensionSigner) {
|
|
830
|
-
return
|
|
474
|
+
return settlePermit2WithERC20Approval(
|
|
475
|
+
exactProxyConfig,
|
|
476
|
+
extensionSigner,
|
|
477
|
+
payload,
|
|
478
|
+
permit2Payload,
|
|
479
|
+
erc20Info
|
|
480
|
+
);
|
|
831
481
|
}
|
|
832
482
|
}
|
|
833
|
-
return
|
|
483
|
+
return settlePermit2Direct(exactProxyConfig, signer, payload, permit2Payload);
|
|
834
484
|
}
|
|
835
|
-
async function
|
|
485
|
+
async function settlePermit2WithEIP2612(config, signer, payload, permit2Payload, eip2612Info) {
|
|
836
486
|
const payer = permit2Payload.permit2Authorization.from;
|
|
837
487
|
try {
|
|
838
488
|
const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
|
|
839
489
|
const tx = await signer.writeContract({
|
|
840
|
-
address:
|
|
841
|
-
abi:
|
|
490
|
+
address: config.proxyAddress,
|
|
491
|
+
abi: config.proxyABI,
|
|
842
492
|
functionName: "settleWithPermit",
|
|
843
493
|
args: [
|
|
844
494
|
{
|
|
@@ -848,38 +498,42 @@ async function _settlePermit2WithEIP2612(signer, payload, permit2Payload, eip261
|
|
|
848
498
|
s,
|
|
849
499
|
v
|
|
850
500
|
},
|
|
851
|
-
...
|
|
501
|
+
...buildExactPermit2SettleArgs(permit2Payload)
|
|
852
502
|
]
|
|
853
503
|
});
|
|
854
|
-
return
|
|
504
|
+
return waitAndReturnSettleResponse(signer, tx, payload, payer);
|
|
855
505
|
} catch (error) {
|
|
856
506
|
return mapSettleError(error, payload, payer);
|
|
857
507
|
}
|
|
858
508
|
}
|
|
859
|
-
async function
|
|
509
|
+
async function settlePermit2WithERC20Approval(config, extensionSigner, payload, permit2Payload, erc20Info) {
|
|
860
510
|
const payer = permit2Payload.permit2Authorization.from;
|
|
861
511
|
try {
|
|
862
|
-
const settleData =
|
|
512
|
+
const settleData = encodeFunctionData({
|
|
513
|
+
abi: config.proxyABI,
|
|
514
|
+
functionName: "settle",
|
|
515
|
+
args: buildExactPermit2SettleArgs(permit2Payload)
|
|
516
|
+
});
|
|
863
517
|
const txHashes = await extensionSigner.sendTransactions([
|
|
864
518
|
erc20Info.signedTransaction,
|
|
865
|
-
{ to:
|
|
519
|
+
{ to: config.proxyAddress, data: settleData, gas: BigInt(3e5) }
|
|
866
520
|
]);
|
|
867
521
|
const settleTxHash = txHashes[txHashes.length - 1];
|
|
868
|
-
return
|
|
522
|
+
return waitAndReturnSettleResponse(extensionSigner, settleTxHash, payload, payer);
|
|
869
523
|
} catch (error) {
|
|
870
524
|
return mapSettleError(error, payload, payer);
|
|
871
525
|
}
|
|
872
526
|
}
|
|
873
|
-
async function
|
|
527
|
+
async function settlePermit2Direct(config, signer, payload, permit2Payload) {
|
|
874
528
|
const payer = permit2Payload.permit2Authorization.from;
|
|
875
529
|
try {
|
|
876
530
|
const tx = await signer.writeContract({
|
|
877
|
-
address:
|
|
878
|
-
abi:
|
|
531
|
+
address: config.proxyAddress,
|
|
532
|
+
abi: config.proxyABI,
|
|
879
533
|
functionName: "settle",
|
|
880
|
-
args:
|
|
534
|
+
args: buildExactPermit2SettleArgs(permit2Payload)
|
|
881
535
|
});
|
|
882
|
-
return
|
|
536
|
+
return waitAndReturnSettleResponse(signer, tx, payload, payer);
|
|
883
537
|
} catch (error) {
|
|
884
538
|
return mapSettleError(error, payload, payer);
|
|
885
539
|
}
|