@payai/x402-evm 2.3.6 → 2.4.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 +3 -2
- package/dist/cjs/exact/client/index.js +173 -194
- package/dist/cjs/exact/client/index.js.map +1 -1
- package/dist/cjs/exact/facilitator/index.js +220 -187
- package/dist/cjs/exact/facilitator/index.js.map +1 -1
- package/dist/cjs/exact/server/index.d.ts +14 -21
- package/dist/cjs/exact/server/index.js +109 -69
- package/dist/cjs/exact/server/index.js.map +1 -1
- package/dist/cjs/exact/v1/client/index.js +3 -1
- package/dist/cjs/exact/v1/client/index.js.map +1 -1
- package/dist/cjs/exact/v1/facilitator/index.js +3 -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 +441 -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 +69 -0
- package/dist/cjs/upto/server/index.js +239 -0
- package/dist/cjs/upto/server/index.js.map +1 -0
- package/dist/cjs/v1/index.d.ts +2 -0
- package/dist/cjs/v1/index.js +3 -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-PCJKIY5G.mjs → chunk-ERK2ZPOY.mjs} +49 -501
- package/dist/esm/chunk-ERK2ZPOY.mjs.map +1 -0
- package/dist/esm/chunk-F3OOHBAW.mjs +89 -0
- package/dist/esm/chunk-F3OOHBAW.mjs.map +1 -0
- package/dist/esm/chunk-FQJR4RCF.mjs +158 -0
- package/dist/esm/chunk-FQJR4RCF.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-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 +87 -432
- package/dist/esm/exact/facilitator/index.mjs.map +1 -1
- package/dist/esm/exact/server/index.d.mts +14 -21
- package/dist/esm/exact/server/index.mjs +26 -69
- 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 +69 -0
- package/dist/esm/upto/server/index.mjs +129 -0
- package/dist/esm/upto/server/index.mjs.map +1 -0
- package/dist/esm/v1/index.d.mts +2 -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-LWO35IGS.mjs +0 -518
- package/dist/esm/chunk-LWO35IGS.mjs.map +0 -1
- package/dist/esm/chunk-PCJKIY5G.mjs.map +0 -1
- package/dist/esm/chunk-TKN5V2BV.mjs +0 -13
- package/dist/esm/chunk-TKN5V2BV.mjs.map +0 -1
|
@@ -1,57 +1,43 @@
|
|
|
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
|
+
parseEip3009TransferError,
|
|
10
|
+
simulateEip3009Transfer
|
|
11
|
+
} from "../../chunk-ERK2ZPOY.mjs";
|
|
4
12
|
import {
|
|
5
13
|
ERC20_APPROVAL_GAS_SPONSORING_KEY,
|
|
14
|
+
buildExactPermit2SettleArgs,
|
|
15
|
+
checkPermit2Prerequisites,
|
|
16
|
+
diagnosePermit2SimulationFailure,
|
|
6
17
|
extractEip2612GasSponsoringInfo,
|
|
7
18
|
extractErc20ApprovalGasSponsoringInfo,
|
|
19
|
+
mapSettleError,
|
|
8
20
|
resolveErc20ApprovalExtensionSigner,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
21
|
+
simulatePermit2Settle,
|
|
22
|
+
simulatePermit2SettleWithErc20Approval,
|
|
23
|
+
simulatePermit2SettleWithPermit,
|
|
24
|
+
splitEip2612Signature,
|
|
25
|
+
validateEip2612PermitForPayment,
|
|
26
|
+
validateErc20ApprovalForPayment,
|
|
27
|
+
waitAndReturnSettleResponse
|
|
28
|
+
} from "../../chunk-CRT6YNY5.mjs";
|
|
12
29
|
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
30
|
ErrInvalidAuthorizationValue,
|
|
33
|
-
ErrInvalidEip2612ExtensionFormat,
|
|
34
31
|
ErrInvalidScheme,
|
|
35
32
|
ErrInvalidSignature,
|
|
36
|
-
ErrInvalidTransactionState,
|
|
37
33
|
ErrMissingEip712Domain,
|
|
38
34
|
ErrNetworkMismatch,
|
|
39
|
-
ErrPermit2612AmountMismatch,
|
|
40
|
-
ErrPermit2AllowanceRequired,
|
|
41
35
|
ErrPermit2AmountMismatch,
|
|
42
36
|
ErrPermit2DeadlineExpired,
|
|
43
|
-
ErrPermit2InsufficientBalance,
|
|
44
|
-
ErrPermit2InvalidAmount,
|
|
45
|
-
ErrPermit2InvalidDestination,
|
|
46
|
-
ErrPermit2InvalidNonce,
|
|
47
|
-
ErrPermit2InvalidOwner,
|
|
48
37
|
ErrPermit2InvalidSignature,
|
|
49
38
|
ErrPermit2InvalidSpender,
|
|
50
39
|
ErrPermit2NotYetValid,
|
|
51
|
-
ErrPermit2PaymentTooEarly,
|
|
52
|
-
ErrPermit2ProxyNotDeployed,
|
|
53
40
|
ErrPermit2RecipientMismatch,
|
|
54
|
-
ErrPermit2SimulationFailed,
|
|
55
41
|
ErrPermit2TokenMismatch,
|
|
56
42
|
ErrRecipientMismatch,
|
|
57
43
|
ErrTransactionFailed,
|
|
@@ -59,24 +45,13 @@ import {
|
|
|
59
45
|
ErrUnsupportedPayloadType,
|
|
60
46
|
ErrValidAfterInFuture,
|
|
61
47
|
ErrValidBeforeExpired,
|
|
62
|
-
ExactEvmSchemeV1,
|
|
63
|
-
MULTICALL3_ADDRESS,
|
|
64
|
-
NETWORKS,
|
|
65
48
|
PERMIT2_ADDRESS,
|
|
66
49
|
authorizationTypes,
|
|
67
|
-
diagnoseEip3009SimulationFailure,
|
|
68
|
-
eip3009ABI,
|
|
69
|
-
erc20AllowanceAbi,
|
|
70
|
-
erc20ApproveAbi,
|
|
71
|
-
executeTransferWithAuthorization,
|
|
72
50
|
getEvmChainId,
|
|
73
|
-
multicall,
|
|
74
|
-
multicall3GetEthBalanceAbi,
|
|
75
51
|
permit2WitnessTypes,
|
|
76
|
-
simulateEip3009Transfer,
|
|
77
52
|
x402ExactPermit2ProxyABI,
|
|
78
53
|
x402ExactPermit2ProxyAddress
|
|
79
|
-
} from "../../chunk-
|
|
54
|
+
} from "../../chunk-C4ZQMS77.mjs";
|
|
80
55
|
|
|
81
56
|
// src/exact/facilitator/eip3009.ts
|
|
82
57
|
import { getAddress, isAddressEqual, parseErc6492Signature } from "viem";
|
|
@@ -264,10 +239,10 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
|
|
|
264
239
|
network: payload.accepted.network,
|
|
265
240
|
payer
|
|
266
241
|
};
|
|
267
|
-
} catch {
|
|
242
|
+
} catch (error) {
|
|
268
243
|
return {
|
|
269
244
|
success: false,
|
|
270
|
-
errorReason:
|
|
245
|
+
errorReason: parseEip3009TransferError(error),
|
|
271
246
|
transaction: "",
|
|
272
247
|
network: payload.accepted.network,
|
|
273
248
|
payer
|
|
@@ -276,361 +251,11 @@ async function settleEIP3009(signer, payload, requirements, eip3009Payload, conf
|
|
|
276
251
|
}
|
|
277
252
|
|
|
278
253
|
// 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
|
|
254
|
+
import { getAddress as getAddress2, encodeFunctionData } from "viem";
|
|
255
|
+
var exactProxyConfig = {
|
|
256
|
+
proxyAddress: x402ExactPermit2ProxyAddress,
|
|
257
|
+
proxyABI: x402ExactPermit2ProxyABI
|
|
258
|
+
};
|
|
634
259
|
async function verifyPermit2(signer, payload, requirements, permit2Payload, context, options) {
|
|
635
260
|
const payer = permit2Payload.permit2Authorization.from;
|
|
636
261
|
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
@@ -648,15 +273,15 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
648
273
|
};
|
|
649
274
|
}
|
|
650
275
|
const chainId = getEvmChainId(requirements.network);
|
|
651
|
-
const tokenAddress =
|
|
652
|
-
if (
|
|
276
|
+
const tokenAddress = getAddress2(requirements.asset);
|
|
277
|
+
if (getAddress2(permit2Payload.permit2Authorization.spender) !== getAddress2(x402ExactPermit2ProxyAddress)) {
|
|
653
278
|
return {
|
|
654
279
|
isValid: false,
|
|
655
280
|
invalidReason: ErrPermit2InvalidSpender,
|
|
656
281
|
payer
|
|
657
282
|
};
|
|
658
283
|
}
|
|
659
|
-
if (
|
|
284
|
+
if (getAddress2(permit2Payload.permit2Authorization.witness.to) !== getAddress2(requirements.payTo)) {
|
|
660
285
|
return {
|
|
661
286
|
isValid: false,
|
|
662
287
|
invalidReason: ErrPermit2RecipientMismatch,
|
|
@@ -685,7 +310,7 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
685
310
|
payer
|
|
686
311
|
};
|
|
687
312
|
}
|
|
688
|
-
if (
|
|
313
|
+
if (getAddress2(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
|
|
689
314
|
return {
|
|
690
315
|
isValid: false,
|
|
691
316
|
invalidReason: ErrPermit2TokenMismatch,
|
|
@@ -702,14 +327,14 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
702
327
|
},
|
|
703
328
|
message: {
|
|
704
329
|
permitted: {
|
|
705
|
-
token:
|
|
330
|
+
token: getAddress2(permit2Payload.permit2Authorization.permitted.token),
|
|
706
331
|
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
707
332
|
},
|
|
708
|
-
spender:
|
|
333
|
+
spender: getAddress2(permit2Payload.permit2Authorization.spender),
|
|
709
334
|
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
710
335
|
deadline: BigInt(permit2Payload.permit2Authorization.deadline),
|
|
711
336
|
witness: {
|
|
712
|
-
to:
|
|
337
|
+
to: getAddress2(permit2Payload.permit2Authorization.witness.to),
|
|
713
338
|
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
|
|
714
339
|
}
|
|
715
340
|
}
|
|
@@ -744,9 +369,16 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
744
369
|
if (!fieldResult.isValid) {
|
|
745
370
|
return { isValid: false, invalidReason: fieldResult.invalidReason, payer };
|
|
746
371
|
}
|
|
747
|
-
const
|
|
372
|
+
const exactSettleArgs = buildExactPermit2SettleArgs(permit2Payload);
|
|
373
|
+
const simOk2 = await simulatePermit2SettleWithPermit(
|
|
374
|
+
exactProxyConfig,
|
|
375
|
+
signer,
|
|
376
|
+
exactSettleArgs,
|
|
377
|
+
eip2612Info
|
|
378
|
+
);
|
|
748
379
|
if (!simOk2) {
|
|
749
380
|
return diagnosePermit2SimulationFailure(
|
|
381
|
+
exactProxyConfig,
|
|
750
382
|
signer,
|
|
751
383
|
tokenAddress,
|
|
752
384
|
permit2Payload,
|
|
@@ -771,12 +403,14 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
771
403
|
);
|
|
772
404
|
if (extensionSigner?.simulateTransactions) {
|
|
773
405
|
const simOk2 = await simulatePermit2SettleWithErc20Approval(
|
|
406
|
+
exactProxyConfig,
|
|
774
407
|
extensionSigner,
|
|
775
|
-
permit2Payload,
|
|
408
|
+
buildExactPermit2SettleArgs(permit2Payload),
|
|
776
409
|
erc20Info
|
|
777
410
|
);
|
|
778
411
|
if (!simOk2) {
|
|
779
412
|
return diagnosePermit2SimulationFailure(
|
|
413
|
+
exactProxyConfig,
|
|
780
414
|
signer,
|
|
781
415
|
tokenAddress,
|
|
782
416
|
permit2Payload,
|
|
@@ -785,12 +419,23 @@ async function verifyPermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
785
419
|
}
|
|
786
420
|
return { isValid: true, invalidReason: void 0, payer };
|
|
787
421
|
}
|
|
788
|
-
return checkPermit2Prerequisites(
|
|
422
|
+
return checkPermit2Prerequisites(
|
|
423
|
+
exactProxyConfig,
|
|
424
|
+
signer,
|
|
425
|
+
tokenAddress,
|
|
426
|
+
payer,
|
|
427
|
+
requirements.amount
|
|
428
|
+
);
|
|
789
429
|
}
|
|
790
430
|
}
|
|
791
|
-
const simOk = await simulatePermit2Settle(
|
|
431
|
+
const simOk = await simulatePermit2Settle(
|
|
432
|
+
exactProxyConfig,
|
|
433
|
+
signer,
|
|
434
|
+
buildExactPermit2SettleArgs(permit2Payload)
|
|
435
|
+
);
|
|
792
436
|
if (!simOk) {
|
|
793
437
|
return diagnosePermit2SimulationFailure(
|
|
438
|
+
exactProxyConfig,
|
|
794
439
|
signer,
|
|
795
440
|
tokenAddress,
|
|
796
441
|
permit2Payload,
|
|
@@ -815,7 +460,7 @@ async function settlePermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
815
460
|
}
|
|
816
461
|
const eip2612Info = extractEip2612GasSponsoringInfo(payload);
|
|
817
462
|
if (eip2612Info) {
|
|
818
|
-
return
|
|
463
|
+
return settlePermit2WithEIP2612(exactProxyConfig, signer, payload, permit2Payload, eip2612Info);
|
|
819
464
|
}
|
|
820
465
|
const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
|
|
821
466
|
if (erc20Info) {
|
|
@@ -827,18 +472,24 @@ async function settlePermit2(signer, payload, requirements, permit2Payload, cont
|
|
|
827
472
|
payload.accepted.network
|
|
828
473
|
);
|
|
829
474
|
if (extensionSigner) {
|
|
830
|
-
return
|
|
475
|
+
return settlePermit2WithERC20Approval(
|
|
476
|
+
exactProxyConfig,
|
|
477
|
+
extensionSigner,
|
|
478
|
+
payload,
|
|
479
|
+
permit2Payload,
|
|
480
|
+
erc20Info
|
|
481
|
+
);
|
|
831
482
|
}
|
|
832
483
|
}
|
|
833
|
-
return
|
|
484
|
+
return settlePermit2Direct(exactProxyConfig, signer, payload, permit2Payload);
|
|
834
485
|
}
|
|
835
|
-
async function
|
|
486
|
+
async function settlePermit2WithEIP2612(config, signer, payload, permit2Payload, eip2612Info) {
|
|
836
487
|
const payer = permit2Payload.permit2Authorization.from;
|
|
837
488
|
try {
|
|
838
489
|
const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
|
|
839
490
|
const tx = await signer.writeContract({
|
|
840
|
-
address:
|
|
841
|
-
abi:
|
|
491
|
+
address: config.proxyAddress,
|
|
492
|
+
abi: config.proxyABI,
|
|
842
493
|
functionName: "settleWithPermit",
|
|
843
494
|
args: [
|
|
844
495
|
{
|
|
@@ -848,38 +499,42 @@ async function _settlePermit2WithEIP2612(signer, payload, permit2Payload, eip261
|
|
|
848
499
|
s,
|
|
849
500
|
v
|
|
850
501
|
},
|
|
851
|
-
...
|
|
502
|
+
...buildExactPermit2SettleArgs(permit2Payload)
|
|
852
503
|
]
|
|
853
504
|
});
|
|
854
|
-
return
|
|
505
|
+
return waitAndReturnSettleResponse(signer, tx, payload, payer);
|
|
855
506
|
} catch (error) {
|
|
856
507
|
return mapSettleError(error, payload, payer);
|
|
857
508
|
}
|
|
858
509
|
}
|
|
859
|
-
async function
|
|
510
|
+
async function settlePermit2WithERC20Approval(config, extensionSigner, payload, permit2Payload, erc20Info) {
|
|
860
511
|
const payer = permit2Payload.permit2Authorization.from;
|
|
861
512
|
try {
|
|
862
|
-
const settleData =
|
|
513
|
+
const settleData = encodeFunctionData({
|
|
514
|
+
abi: config.proxyABI,
|
|
515
|
+
functionName: "settle",
|
|
516
|
+
args: buildExactPermit2SettleArgs(permit2Payload)
|
|
517
|
+
});
|
|
863
518
|
const txHashes = await extensionSigner.sendTransactions([
|
|
864
519
|
erc20Info.signedTransaction,
|
|
865
|
-
{ to:
|
|
520
|
+
{ to: config.proxyAddress, data: settleData, gas: BigInt(3e5) }
|
|
866
521
|
]);
|
|
867
522
|
const settleTxHash = txHashes[txHashes.length - 1];
|
|
868
|
-
return
|
|
523
|
+
return waitAndReturnSettleResponse(extensionSigner, settleTxHash, payload, payer);
|
|
869
524
|
} catch (error) {
|
|
870
525
|
return mapSettleError(error, payload, payer);
|
|
871
526
|
}
|
|
872
527
|
}
|
|
873
|
-
async function
|
|
528
|
+
async function settlePermit2Direct(config, signer, payload, permit2Payload) {
|
|
874
529
|
const payer = permit2Payload.permit2Authorization.from;
|
|
875
530
|
try {
|
|
876
531
|
const tx = await signer.writeContract({
|
|
877
|
-
address:
|
|
878
|
-
abi:
|
|
532
|
+
address: config.proxyAddress,
|
|
533
|
+
abi: config.proxyABI,
|
|
879
534
|
functionName: "settle",
|
|
880
|
-
args:
|
|
535
|
+
args: buildExactPermit2SettleArgs(permit2Payload)
|
|
881
536
|
});
|
|
882
|
-
return
|
|
537
|
+
return waitAndReturnSettleResponse(signer, tx, payload, payer);
|
|
883
538
|
} catch (error) {
|
|
884
539
|
return mapSettleError(error, payload, payer);
|
|
885
540
|
}
|