@payai/x402-evm 2.3.4 → 2.3.6
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 +12 -5
- package/dist/cjs/exact/client/index.js +130 -29
- package/dist/cjs/exact/client/index.js.map +1 -1
- package/dist/cjs/exact/facilitator/index.d.ts +13 -1
- package/dist/cjs/exact/facilitator/index.js +990 -607
- package/dist/cjs/exact/facilitator/index.js.map +1 -1
- package/dist/cjs/exact/v1/client/index.d.ts +1 -1
- package/dist/cjs/exact/v1/client/index.js +14 -6
- package/dist/cjs/exact/v1/client/index.js.map +1 -1
- package/dist/cjs/exact/v1/facilitator/index.d.ts +16 -1
- package/dist/cjs/exact/v1/facilitator/index.js +417 -178
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +146 -31
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/{permit2-DHAq6FTe.d.ts → permit2-U9Zolx3O.d.ts} +38 -5
- package/dist/{esm/signer-DC81R8wQ.d.mts → cjs/signer-D912R4mq.d.ts} +9 -3
- package/dist/cjs/v1/index.d.ts +3 -1
- package/dist/cjs/v1/index.js +9 -1
- package/dist/cjs/v1/index.js.map +1 -1
- package/dist/esm/chunk-GD4MKCN7.mjs +57 -0
- package/dist/esm/chunk-GD4MKCN7.mjs.map +1 -0
- package/dist/esm/{chunk-LBIJBD7Q.mjs → chunk-LWO35IGS.mjs} +113 -20
- package/dist/esm/chunk-LWO35IGS.mjs.map +1 -0
- package/dist/esm/{chunk-XL6IFXCP.mjs → chunk-PCJKIY5G.mjs} +519 -179
- package/dist/esm/chunk-PCJKIY5G.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +12 -5
- package/dist/esm/exact/client/index.mjs +3 -2
- package/dist/esm/exact/facilitator/index.d.mts +13 -1
- package/dist/esm/exact/facilitator/index.mjs +498 -391
- package/dist/esm/exact/facilitator/index.mjs.map +1 -1
- package/dist/esm/exact/v1/client/index.d.mts +1 -1
- package/dist/esm/exact/v1/client/index.mjs +1 -1
- package/dist/esm/exact/v1/facilitator/index.d.mts +16 -1
- package/dist/esm/exact/v1/facilitator/index.mjs +1 -1
- package/dist/esm/index.d.mts +2 -2
- package/dist/esm/index.mjs +7 -9
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/{permit2-BuAhWvNC.d.mts → permit2-Bbh3a8_h.d.mts} +38 -5
- package/dist/{cjs/signer-DC81R8wQ.d.ts → esm/signer-D912R4mq.d.mts} +9 -3
- package/dist/esm/v1/index.d.mts +3 -1
- package/dist/esm/v1/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/esm/chunk-LBIJBD7Q.mjs.map +0 -1
- package/dist/esm/chunk-XL6IFXCP.mjs.map +0 -1
|
@@ -25,7 +25,7 @@ __export(facilitator_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(facilitator_exports);
|
|
26
26
|
|
|
27
27
|
// src/exact/v1/facilitator/scheme.ts
|
|
28
|
-
var
|
|
28
|
+
var import_viem5 = require("viem");
|
|
29
29
|
|
|
30
30
|
// src/constants.ts
|
|
31
31
|
var authorizationTypes = {
|
|
@@ -84,6 +84,23 @@ var eip3009ABI = [
|
|
|
84
84
|
outputs: [{ name: "", type: "string" }],
|
|
85
85
|
stateMutability: "view",
|
|
86
86
|
type: "function"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
inputs: [],
|
|
90
|
+
name: "name",
|
|
91
|
+
outputs: [{ name: "", type: "string" }],
|
|
92
|
+
stateMutability: "view",
|
|
93
|
+
type: "function"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
inputs: [
|
|
97
|
+
{ name: "authorizer", type: "address" },
|
|
98
|
+
{ name: "nonce", type: "bytes32" }
|
|
99
|
+
],
|
|
100
|
+
name: "authorizationState",
|
|
101
|
+
outputs: [{ name: "", type: "bool" }],
|
|
102
|
+
stateMutability: "view",
|
|
103
|
+
type: "function"
|
|
87
104
|
}
|
|
88
105
|
];
|
|
89
106
|
|
|
@@ -113,7 +130,9 @@ var EVM_NETWORK_CHAIN_ID_MAP = {
|
|
|
113
130
|
educhain: 41923,
|
|
114
131
|
"skale-base-sepolia": 324705682,
|
|
115
132
|
megaeth: 4326,
|
|
116
|
-
monad: 143
|
|
133
|
+
monad: 143,
|
|
134
|
+
kiteai: 2366,
|
|
135
|
+
"kiteai-testnet": 2368
|
|
117
136
|
};
|
|
118
137
|
var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
|
|
119
138
|
function getEvmChainIdV1(network) {
|
|
@@ -124,6 +143,257 @@ function getEvmChainIdV1(network) {
|
|
|
124
143
|
return chainId;
|
|
125
144
|
}
|
|
126
145
|
|
|
146
|
+
// src/exact/facilitator/errors.ts
|
|
147
|
+
var ErrInvalidScheme = "invalid_exact_evm_scheme";
|
|
148
|
+
var ErrNetworkMismatch = "invalid_exact_evm_network_mismatch";
|
|
149
|
+
var ErrMissingEip712Domain = "invalid_exact_evm_missing_eip712_domain";
|
|
150
|
+
var ErrRecipientMismatch = "invalid_exact_evm_recipient_mismatch";
|
|
151
|
+
var ErrInvalidSignature = "invalid_exact_evm_signature";
|
|
152
|
+
var ErrValidBeforeExpired = "invalid_exact_evm_payload_authorization_valid_before";
|
|
153
|
+
var ErrValidAfterInFuture = "invalid_exact_evm_payload_authorization_valid_after";
|
|
154
|
+
var ErrInvalidAuthorizationValue = "invalid_exact_evm_authorization_value";
|
|
155
|
+
var ErrUndeployedSmartWallet = "invalid_exact_evm_payload_undeployed_smart_wallet";
|
|
156
|
+
var ErrTransactionFailed = "invalid_exact_evm_transaction_failed";
|
|
157
|
+
var ErrEip3009TokenNameMismatch = "invalid_exact_evm_token_name_mismatch";
|
|
158
|
+
var ErrEip3009TokenVersionMismatch = "invalid_exact_evm_token_version_mismatch";
|
|
159
|
+
var ErrEip3009NotSupported = "invalid_exact_evm_eip3009_not_supported";
|
|
160
|
+
var ErrEip3009NonceAlreadyUsed = "invalid_exact_evm_nonce_already_used";
|
|
161
|
+
var ErrEip3009InsufficientBalance = "invalid_exact_evm_insufficient_balance";
|
|
162
|
+
var ErrEip3009SimulationFailed = "invalid_exact_evm_transaction_simulation_failed";
|
|
163
|
+
|
|
164
|
+
// src/exact/facilitator/eip3009-utils.ts
|
|
165
|
+
var import_viem4 = require("viem");
|
|
166
|
+
|
|
167
|
+
// src/multicall.ts
|
|
168
|
+
var import_viem3 = require("viem");
|
|
169
|
+
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
170
|
+
var multicall3ABI = [
|
|
171
|
+
{
|
|
172
|
+
inputs: [
|
|
173
|
+
{ name: "requireSuccess", type: "bool" },
|
|
174
|
+
{
|
|
175
|
+
name: "calls",
|
|
176
|
+
type: "tuple[]",
|
|
177
|
+
components: [
|
|
178
|
+
{ name: "target", type: "address" },
|
|
179
|
+
{ name: "callData", type: "bytes" }
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
name: "tryAggregate",
|
|
184
|
+
outputs: [
|
|
185
|
+
{
|
|
186
|
+
name: "returnData",
|
|
187
|
+
type: "tuple[]",
|
|
188
|
+
components: [
|
|
189
|
+
{ name: "success", type: "bool" },
|
|
190
|
+
{ name: "returnData", type: "bytes" }
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
stateMutability: "payable",
|
|
195
|
+
type: "function"
|
|
196
|
+
}
|
|
197
|
+
];
|
|
198
|
+
async function multicall(readContract, calls) {
|
|
199
|
+
const aggregateCalls = calls.map((call) => {
|
|
200
|
+
if ("callData" in call) {
|
|
201
|
+
return { target: call.address, callData: call.callData };
|
|
202
|
+
}
|
|
203
|
+
const callData = (0, import_viem3.encodeFunctionData)({
|
|
204
|
+
abi: call.abi,
|
|
205
|
+
functionName: call.functionName,
|
|
206
|
+
args: call.args
|
|
207
|
+
});
|
|
208
|
+
return { target: call.address, callData };
|
|
209
|
+
});
|
|
210
|
+
const rawResults = await readContract({
|
|
211
|
+
address: MULTICALL3_ADDRESS,
|
|
212
|
+
abi: multicall3ABI,
|
|
213
|
+
functionName: "tryAggregate",
|
|
214
|
+
args: [false, aggregateCalls]
|
|
215
|
+
});
|
|
216
|
+
return rawResults.map((raw, i) => {
|
|
217
|
+
if (!raw.success) {
|
|
218
|
+
return {
|
|
219
|
+
status: "failure",
|
|
220
|
+
error: new Error(`multicall: call reverted (returnData: ${raw.returnData})`)
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const call = calls[i];
|
|
224
|
+
if ("callData" in call) {
|
|
225
|
+
return { status: "success", result: void 0 };
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const decoded = (0, import_viem3.decodeFunctionResult)({
|
|
229
|
+
abi: call.abi,
|
|
230
|
+
functionName: call.functionName,
|
|
231
|
+
data: raw.returnData
|
|
232
|
+
});
|
|
233
|
+
return { status: "success", result: decoded };
|
|
234
|
+
} catch (err) {
|
|
235
|
+
return {
|
|
236
|
+
status: "failure",
|
|
237
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/exact/facilitator/eip3009-utils.ts
|
|
244
|
+
async function simulateEip3009Transfer(signer, erc20Address, payload, eip6492Deployment) {
|
|
245
|
+
const auth = payload.authorization;
|
|
246
|
+
const transferArgs = [
|
|
247
|
+
(0, import_viem4.getAddress)(auth.from),
|
|
248
|
+
(0, import_viem4.getAddress)(auth.to),
|
|
249
|
+
BigInt(auth.value),
|
|
250
|
+
BigInt(auth.validAfter),
|
|
251
|
+
BigInt(auth.validBefore),
|
|
252
|
+
auth.nonce
|
|
253
|
+
];
|
|
254
|
+
if (eip6492Deployment) {
|
|
255
|
+
const { signature: innerSignature } = (0, import_viem4.parseErc6492Signature)(payload.signature);
|
|
256
|
+
const transferCalldata = (0, import_viem4.encodeFunctionData)({
|
|
257
|
+
abi: eip3009ABI,
|
|
258
|
+
functionName: "transferWithAuthorization",
|
|
259
|
+
args: [...transferArgs, innerSignature]
|
|
260
|
+
});
|
|
261
|
+
try {
|
|
262
|
+
const results = await multicall(signer.readContract.bind(signer), [
|
|
263
|
+
{
|
|
264
|
+
address: (0, import_viem4.getAddress)(eip6492Deployment.factoryAddress),
|
|
265
|
+
callData: eip6492Deployment.factoryCalldata
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
address: erc20Address,
|
|
269
|
+
callData: transferCalldata
|
|
270
|
+
}
|
|
271
|
+
]);
|
|
272
|
+
return results[1]?.status === "success";
|
|
273
|
+
} catch {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const sig = payload.signature;
|
|
278
|
+
const sigLength = sig.startsWith("0x") ? sig.length - 2 : sig.length;
|
|
279
|
+
const isECDSA = sigLength === 130;
|
|
280
|
+
try {
|
|
281
|
+
if (isECDSA) {
|
|
282
|
+
const parsedSig = (0, import_viem4.parseSignature)(sig);
|
|
283
|
+
await signer.readContract({
|
|
284
|
+
address: erc20Address,
|
|
285
|
+
abi: eip3009ABI,
|
|
286
|
+
functionName: "transferWithAuthorization",
|
|
287
|
+
args: [
|
|
288
|
+
...transferArgs,
|
|
289
|
+
parsedSig.v ?? parsedSig.yParity,
|
|
290
|
+
parsedSig.r,
|
|
291
|
+
parsedSig.s
|
|
292
|
+
]
|
|
293
|
+
});
|
|
294
|
+
} else {
|
|
295
|
+
await signer.readContract({
|
|
296
|
+
address: erc20Address,
|
|
297
|
+
abi: eip3009ABI,
|
|
298
|
+
functionName: "transferWithAuthorization",
|
|
299
|
+
args: [...transferArgs, sig]
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return true;
|
|
303
|
+
} catch {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async function diagnoseEip3009SimulationFailure(signer, erc20Address, payload, requirements, amountRequired) {
|
|
308
|
+
const payer = payload.authorization.from;
|
|
309
|
+
const diagnosticCalls = [
|
|
310
|
+
{
|
|
311
|
+
address: erc20Address,
|
|
312
|
+
abi: eip3009ABI,
|
|
313
|
+
functionName: "balanceOf",
|
|
314
|
+
args: [payload.authorization.from]
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
address: erc20Address,
|
|
318
|
+
abi: eip3009ABI,
|
|
319
|
+
functionName: "name"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
address: erc20Address,
|
|
323
|
+
abi: eip3009ABI,
|
|
324
|
+
functionName: "version"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
address: erc20Address,
|
|
328
|
+
abi: eip3009ABI,
|
|
329
|
+
functionName: "authorizationState",
|
|
330
|
+
args: [payload.authorization.from, payload.authorization.nonce]
|
|
331
|
+
}
|
|
332
|
+
];
|
|
333
|
+
try {
|
|
334
|
+
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
|
|
335
|
+
const [balanceResult, nameResult, versionResult, authStateResult] = results;
|
|
336
|
+
if (authStateResult.status === "failure") {
|
|
337
|
+
return { isValid: false, invalidReason: ErrEip3009NotSupported, payer };
|
|
338
|
+
}
|
|
339
|
+
if (authStateResult.status === "success" && authStateResult.result === true) {
|
|
340
|
+
return { isValid: false, invalidReason: ErrEip3009NonceAlreadyUsed, payer };
|
|
341
|
+
}
|
|
342
|
+
if (nameResult.status === "success" && requirements.extra?.name && nameResult.result !== requirements.extra.name) {
|
|
343
|
+
return { isValid: false, invalidReason: ErrEip3009TokenNameMismatch, payer };
|
|
344
|
+
}
|
|
345
|
+
if (versionResult.status === "success" && requirements.extra?.version && versionResult.result !== requirements.extra.version) {
|
|
346
|
+
return { isValid: false, invalidReason: ErrEip3009TokenVersionMismatch, payer };
|
|
347
|
+
}
|
|
348
|
+
if (balanceResult.status === "success") {
|
|
349
|
+
const balance = balanceResult.result;
|
|
350
|
+
if (balance < BigInt(amountRequired)) {
|
|
351
|
+
return {
|
|
352
|
+
isValid: false,
|
|
353
|
+
invalidReason: ErrEip3009InsufficientBalance,
|
|
354
|
+
payer
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
} catch {
|
|
359
|
+
}
|
|
360
|
+
return { isValid: false, invalidReason: ErrEip3009SimulationFailed, payer };
|
|
361
|
+
}
|
|
362
|
+
async function executeTransferWithAuthorization(signer, erc20Address, payload) {
|
|
363
|
+
const { signature } = (0, import_viem4.parseErc6492Signature)(payload.signature);
|
|
364
|
+
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
365
|
+
const isECDSA = signatureLength === 130;
|
|
366
|
+
const auth = payload.authorization;
|
|
367
|
+
const baseArgs = [
|
|
368
|
+
(0, import_viem4.getAddress)(auth.from),
|
|
369
|
+
(0, import_viem4.getAddress)(auth.to),
|
|
370
|
+
BigInt(auth.value),
|
|
371
|
+
BigInt(auth.validAfter),
|
|
372
|
+
BigInt(auth.validBefore),
|
|
373
|
+
auth.nonce
|
|
374
|
+
];
|
|
375
|
+
if (isECDSA) {
|
|
376
|
+
const parsedSig = (0, import_viem4.parseSignature)(signature);
|
|
377
|
+
return signer.writeContract({
|
|
378
|
+
address: erc20Address,
|
|
379
|
+
abi: eip3009ABI,
|
|
380
|
+
functionName: "transferWithAuthorization",
|
|
381
|
+
args: [
|
|
382
|
+
...baseArgs,
|
|
383
|
+
parsedSig.v || parsedSig.yParity,
|
|
384
|
+
parsedSig.r,
|
|
385
|
+
parsedSig.s
|
|
386
|
+
]
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
return signer.writeContract({
|
|
390
|
+
address: erc20Address,
|
|
391
|
+
abi: eip3009ABI,
|
|
392
|
+
functionName: "transferWithAuthorization",
|
|
393
|
+
args: [...baseArgs, signature]
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
127
397
|
// src/exact/v1/facilitator/scheme.ts
|
|
128
398
|
var ExactEvmSchemeV12 = class {
|
|
129
399
|
/**
|
|
@@ -137,7 +407,8 @@ var ExactEvmSchemeV12 = class {
|
|
|
137
407
|
this.scheme = "exact";
|
|
138
408
|
this.caipFamily = "eip155:*";
|
|
139
409
|
this.config = {
|
|
140
|
-
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
|
|
410
|
+
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,
|
|
411
|
+
simulateInSettle: config?.simulateInSettle ?? false
|
|
141
412
|
};
|
|
142
413
|
}
|
|
143
414
|
/**
|
|
@@ -168,14 +439,95 @@ var ExactEvmSchemeV12 = class {
|
|
|
168
439
|
* @returns Promise resolving to verification response
|
|
169
440
|
*/
|
|
170
441
|
async verify(payload, requirements) {
|
|
442
|
+
return this._verify(payload, requirements);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Settles a payment by executing the transfer (V1).
|
|
446
|
+
*
|
|
447
|
+
* @param payload - The payment payload to settle
|
|
448
|
+
* @param requirements - The payment requirements
|
|
449
|
+
* @returns Promise resolving to settlement response
|
|
450
|
+
*/
|
|
451
|
+
async settle(payload, requirements) {
|
|
452
|
+
const payloadV1 = payload;
|
|
453
|
+
const exactEvmPayload = payload.payload;
|
|
454
|
+
const valid = await this._verify(payload, requirements, {
|
|
455
|
+
simulate: this.config.simulateInSettle ?? false
|
|
456
|
+
});
|
|
457
|
+
if (!valid.isValid) {
|
|
458
|
+
return {
|
|
459
|
+
success: false,
|
|
460
|
+
network: payloadV1.network,
|
|
461
|
+
transaction: "",
|
|
462
|
+
errorReason: valid.invalidReason ?? ErrInvalidScheme,
|
|
463
|
+
payer: exactEvmPayload.authorization.from
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
const { address: factoryAddress, data: factoryCalldata } = (0, import_viem5.parseErc6492Signature)(
|
|
468
|
+
exactEvmPayload.signature
|
|
469
|
+
);
|
|
470
|
+
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem5.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
471
|
+
const payerAddress = exactEvmPayload.authorization.from;
|
|
472
|
+
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
473
|
+
if (!bytecode || bytecode === "0x") {
|
|
474
|
+
const deployTx = await this.signer.sendTransaction({
|
|
475
|
+
to: factoryAddress,
|
|
476
|
+
data: factoryCalldata
|
|
477
|
+
});
|
|
478
|
+
await this.signer.waitForTransactionReceipt({ hash: deployTx });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const tx = await executeTransferWithAuthorization(
|
|
482
|
+
this.signer,
|
|
483
|
+
(0, import_viem5.getAddress)(requirements.asset),
|
|
484
|
+
exactEvmPayload
|
|
485
|
+
);
|
|
486
|
+
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
|
|
487
|
+
if (receipt.status !== "success") {
|
|
488
|
+
return {
|
|
489
|
+
success: false,
|
|
490
|
+
errorReason: ErrTransactionFailed,
|
|
491
|
+
transaction: tx,
|
|
492
|
+
network: payloadV1.network,
|
|
493
|
+
payer: exactEvmPayload.authorization.from
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
success: true,
|
|
498
|
+
transaction: tx,
|
|
499
|
+
network: payloadV1.network,
|
|
500
|
+
payer: exactEvmPayload.authorization.from
|
|
501
|
+
};
|
|
502
|
+
} catch (error) {
|
|
503
|
+
return {
|
|
504
|
+
success: false,
|
|
505
|
+
errorReason: error instanceof Error ? error.message : ErrTransactionFailed,
|
|
506
|
+
transaction: "",
|
|
507
|
+
network: payloadV1.network,
|
|
508
|
+
payer: exactEvmPayload.authorization.from
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Internal verify with optional simulation control.
|
|
514
|
+
*
|
|
515
|
+
* @param payload - The payment payload to verify
|
|
516
|
+
* @param requirements - The payment requirements
|
|
517
|
+
* @param options - Verification options (e.g. simulate)
|
|
518
|
+
* @returns Promise resolving to verification response
|
|
519
|
+
*/
|
|
520
|
+
async _verify(payload, requirements, options) {
|
|
171
521
|
const requirementsV1 = requirements;
|
|
172
522
|
const payloadV1 = payload;
|
|
173
523
|
const exactEvmPayload = payload.payload;
|
|
524
|
+
const payer = exactEvmPayload.authorization.from;
|
|
525
|
+
let eip6492Deployment;
|
|
174
526
|
if (payloadV1.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
175
527
|
return {
|
|
176
528
|
isValid: false,
|
|
177
|
-
invalidReason:
|
|
178
|
-
payer
|
|
529
|
+
invalidReason: ErrInvalidScheme,
|
|
530
|
+
payer
|
|
179
531
|
};
|
|
180
532
|
}
|
|
181
533
|
let chainId;
|
|
@@ -184,24 +536,24 @@ var ExactEvmSchemeV12 = class {
|
|
|
184
536
|
} catch {
|
|
185
537
|
return {
|
|
186
538
|
isValid: false,
|
|
187
|
-
invalidReason:
|
|
188
|
-
payer
|
|
539
|
+
invalidReason: ErrNetworkMismatch,
|
|
540
|
+
payer
|
|
189
541
|
};
|
|
190
542
|
}
|
|
191
543
|
if (!requirements.extra?.name || !requirements.extra?.version) {
|
|
192
544
|
return {
|
|
193
545
|
isValid: false,
|
|
194
|
-
invalidReason:
|
|
195
|
-
payer
|
|
546
|
+
invalidReason: ErrMissingEip712Domain,
|
|
547
|
+
payer
|
|
196
548
|
};
|
|
197
549
|
}
|
|
198
550
|
const { name, version } = requirements.extra;
|
|
199
|
-
const erc20Address = (0,
|
|
551
|
+
const erc20Address = (0, import_viem5.getAddress)(requirements.asset);
|
|
200
552
|
if (payloadV1.network !== requirements.network) {
|
|
201
553
|
return {
|
|
202
554
|
isValid: false,
|
|
203
|
-
invalidReason:
|
|
204
|
-
payer
|
|
555
|
+
invalidReason: ErrNetworkMismatch,
|
|
556
|
+
payer
|
|
205
557
|
};
|
|
206
558
|
}
|
|
207
559
|
const permitTypedData = {
|
|
@@ -222,210 +574,97 @@ var ExactEvmSchemeV12 = class {
|
|
|
222
574
|
nonce: exactEvmPayload.authorization.nonce
|
|
223
575
|
}
|
|
224
576
|
};
|
|
577
|
+
let isValid = false;
|
|
225
578
|
try {
|
|
226
|
-
|
|
227
|
-
address:
|
|
579
|
+
isValid = await this.signer.verifyTypedData({
|
|
580
|
+
address: payer,
|
|
228
581
|
...permitTypedData,
|
|
229
582
|
signature: exactEvmPayload.signature
|
|
230
583
|
});
|
|
231
|
-
|
|
584
|
+
} catch {
|
|
585
|
+
isValid = false;
|
|
586
|
+
}
|
|
587
|
+
const signature = exactEvmPayload.signature;
|
|
588
|
+
const sigLen = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
589
|
+
const erc6492Data = (0, import_viem5.parseErc6492Signature)(signature);
|
|
590
|
+
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem5.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
591
|
+
if (hasDeploymentInfo) {
|
|
592
|
+
eip6492Deployment = {
|
|
593
|
+
factoryAddress: erc6492Data.address,
|
|
594
|
+
factoryCalldata: erc6492Data.data
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
if (!isValid) {
|
|
598
|
+
const isSmartWallet = sigLen > 130;
|
|
599
|
+
if (!isSmartWallet) {
|
|
232
600
|
return {
|
|
233
601
|
isValid: false,
|
|
234
|
-
invalidReason:
|
|
235
|
-
payer
|
|
602
|
+
invalidReason: ErrInvalidSignature,
|
|
603
|
+
payer
|
|
236
604
|
};
|
|
237
605
|
}
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
const isSmartWallet = signatureLength > 130;
|
|
242
|
-
if (isSmartWallet) {
|
|
243
|
-
const payerAddress = exactEvmPayload.authorization.from;
|
|
244
|
-
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
245
|
-
if (!bytecode || bytecode === "0x") {
|
|
246
|
-
const erc6492Data = (0, import_viem3.parseErc6492Signature)(signature);
|
|
247
|
-
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem3.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
248
|
-
if (!hasDeploymentInfo) {
|
|
249
|
-
return {
|
|
250
|
-
isValid: false,
|
|
251
|
-
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
|
|
252
|
-
payer: payerAddress
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
} else {
|
|
256
|
-
return {
|
|
257
|
-
isValid: false,
|
|
258
|
-
invalidReason: "invalid_exact_evm_payload_signature",
|
|
259
|
-
payer: exactEvmPayload.authorization.from
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
} else {
|
|
606
|
+
const bytecode = await this.signer.getCode({ address: payer });
|
|
607
|
+
const isDeployed = bytecode && bytecode !== "0x";
|
|
608
|
+
if (!isDeployed && !hasDeploymentInfo) {
|
|
263
609
|
return {
|
|
264
610
|
isValid: false,
|
|
265
|
-
invalidReason:
|
|
266
|
-
payer
|
|
611
|
+
invalidReason: ErrUndeployedSmartWallet,
|
|
612
|
+
payer
|
|
267
613
|
};
|
|
268
614
|
}
|
|
269
615
|
}
|
|
270
|
-
if ((0,
|
|
616
|
+
if ((0, import_viem5.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem5.getAddress)(requirements.payTo)) {
|
|
271
617
|
return {
|
|
272
618
|
isValid: false,
|
|
273
|
-
invalidReason:
|
|
274
|
-
payer
|
|
619
|
+
invalidReason: ErrRecipientMismatch,
|
|
620
|
+
payer
|
|
275
621
|
};
|
|
276
622
|
}
|
|
277
623
|
const now = Math.floor(Date.now() / 1e3);
|
|
278
624
|
if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
|
|
279
625
|
return {
|
|
280
626
|
isValid: false,
|
|
281
|
-
invalidReason:
|
|
282
|
-
payer
|
|
627
|
+
invalidReason: ErrValidBeforeExpired,
|
|
628
|
+
payer
|
|
283
629
|
};
|
|
284
630
|
}
|
|
285
631
|
if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
|
|
286
632
|
return {
|
|
287
633
|
isValid: false,
|
|
288
|
-
invalidReason:
|
|
289
|
-
payer
|
|
634
|
+
invalidReason: ErrValidAfterInFuture,
|
|
635
|
+
payer
|
|
290
636
|
};
|
|
291
637
|
}
|
|
292
|
-
try {
|
|
293
|
-
const balance = await this.signer.readContract({
|
|
294
|
-
address: erc20Address,
|
|
295
|
-
abi: eip3009ABI,
|
|
296
|
-
functionName: "balanceOf",
|
|
297
|
-
args: [exactEvmPayload.authorization.from]
|
|
298
|
-
});
|
|
299
|
-
if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {
|
|
300
|
-
return {
|
|
301
|
-
isValid: false,
|
|
302
|
-
invalidReason: "insufficient_funds",
|
|
303
|
-
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.`,
|
|
304
|
-
payer: exactEvmPayload.authorization.from
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
} catch {
|
|
308
|
-
}
|
|
309
638
|
if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {
|
|
310
639
|
return {
|
|
311
640
|
isValid: false,
|
|
312
|
-
invalidReason:
|
|
313
|
-
payer
|
|
641
|
+
invalidReason: ErrInvalidAuthorizationValue,
|
|
642
|
+
payer
|
|
314
643
|
};
|
|
315
644
|
}
|
|
645
|
+
if (options?.simulate !== false) {
|
|
646
|
+
const simulationSucceeded = await simulateEip3009Transfer(
|
|
647
|
+
this.signer,
|
|
648
|
+
erc20Address,
|
|
649
|
+
exactEvmPayload,
|
|
650
|
+
eip6492Deployment
|
|
651
|
+
);
|
|
652
|
+
if (!simulationSucceeded) {
|
|
653
|
+
return diagnoseEip3009SimulationFailure(
|
|
654
|
+
this.signer,
|
|
655
|
+
erc20Address,
|
|
656
|
+
exactEvmPayload,
|
|
657
|
+
requirements,
|
|
658
|
+
requirementsV1.maxAmountRequired
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
316
662
|
return {
|
|
317
663
|
isValid: true,
|
|
318
664
|
invalidReason: void 0,
|
|
319
|
-
payer
|
|
665
|
+
payer
|
|
320
666
|
};
|
|
321
667
|
}
|
|
322
|
-
/**
|
|
323
|
-
* Settles a payment by executing the transfer (V1).
|
|
324
|
-
*
|
|
325
|
-
* @param payload - The payment payload to settle
|
|
326
|
-
* @param requirements - The payment requirements
|
|
327
|
-
* @returns Promise resolving to settlement response
|
|
328
|
-
*/
|
|
329
|
-
async settle(payload, requirements) {
|
|
330
|
-
const payloadV1 = payload;
|
|
331
|
-
const exactEvmPayload = payload.payload;
|
|
332
|
-
const valid = await this.verify(payload, requirements);
|
|
333
|
-
if (!valid.isValid) {
|
|
334
|
-
return {
|
|
335
|
-
success: false,
|
|
336
|
-
network: payloadV1.network,
|
|
337
|
-
transaction: "",
|
|
338
|
-
errorReason: valid.invalidReason ?? "invalid_scheme",
|
|
339
|
-
payer: exactEvmPayload.authorization.from
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
try {
|
|
343
|
-
const parseResult = (0, import_viem3.parseErc6492Signature)(exactEvmPayload.signature);
|
|
344
|
-
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
345
|
-
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem3.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
346
|
-
const payerAddress = exactEvmPayload.authorization.from;
|
|
347
|
-
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
348
|
-
if (!bytecode || bytecode === "0x") {
|
|
349
|
-
try {
|
|
350
|
-
console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
|
|
351
|
-
const deployTx = await this.signer.sendTransaction({
|
|
352
|
-
to: factoryAddress,
|
|
353
|
-
data: factoryCalldata
|
|
354
|
-
});
|
|
355
|
-
await this.signer.waitForTransactionReceipt({ hash: deployTx });
|
|
356
|
-
console.log(`Successfully deployed smart wallet for ${payerAddress}`);
|
|
357
|
-
} catch (deployError) {
|
|
358
|
-
console.error("Smart wallet deployment failed:", deployError);
|
|
359
|
-
throw deployError;
|
|
360
|
-
}
|
|
361
|
-
} else {
|
|
362
|
-
console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
366
|
-
const isECDSA = signatureLength === 130;
|
|
367
|
-
let tx;
|
|
368
|
-
if (isECDSA) {
|
|
369
|
-
const parsedSig = (0, import_viem3.parseSignature)(signature);
|
|
370
|
-
tx = await this.signer.writeContract({
|
|
371
|
-
address: (0, import_viem3.getAddress)(requirements.asset),
|
|
372
|
-
abi: eip3009ABI,
|
|
373
|
-
functionName: "transferWithAuthorization",
|
|
374
|
-
args: [
|
|
375
|
-
(0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
|
|
376
|
-
(0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
|
|
377
|
-
BigInt(exactEvmPayload.authorization.value),
|
|
378
|
-
BigInt(exactEvmPayload.authorization.validAfter),
|
|
379
|
-
BigInt(exactEvmPayload.authorization.validBefore),
|
|
380
|
-
exactEvmPayload.authorization.nonce,
|
|
381
|
-
parsedSig.v || parsedSig.yParity,
|
|
382
|
-
parsedSig.r,
|
|
383
|
-
parsedSig.s
|
|
384
|
-
]
|
|
385
|
-
});
|
|
386
|
-
} else {
|
|
387
|
-
tx = await this.signer.writeContract({
|
|
388
|
-
address: (0, import_viem3.getAddress)(requirements.asset),
|
|
389
|
-
abi: eip3009ABI,
|
|
390
|
-
functionName: "transferWithAuthorization",
|
|
391
|
-
args: [
|
|
392
|
-
(0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
|
|
393
|
-
(0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
|
|
394
|
-
BigInt(exactEvmPayload.authorization.value),
|
|
395
|
-
BigInt(exactEvmPayload.authorization.validAfter),
|
|
396
|
-
BigInt(exactEvmPayload.authorization.validBefore),
|
|
397
|
-
exactEvmPayload.authorization.nonce,
|
|
398
|
-
signature
|
|
399
|
-
]
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
|
|
403
|
-
if (receipt.status !== "success") {
|
|
404
|
-
return {
|
|
405
|
-
success: false,
|
|
406
|
-
errorReason: "invalid_transaction_state",
|
|
407
|
-
transaction: tx,
|
|
408
|
-
network: payloadV1.network,
|
|
409
|
-
payer: exactEvmPayload.authorization.from
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
return {
|
|
413
|
-
success: true,
|
|
414
|
-
transaction: tx,
|
|
415
|
-
network: payloadV1.network,
|
|
416
|
-
payer: exactEvmPayload.authorization.from
|
|
417
|
-
};
|
|
418
|
-
} catch (error) {
|
|
419
|
-
console.error("Failed to settle transaction:", error);
|
|
420
|
-
return {
|
|
421
|
-
success: false,
|
|
422
|
-
errorReason: "transaction_failed",
|
|
423
|
-
transaction: "",
|
|
424
|
-
network: payloadV1.network,
|
|
425
|
-
payer: exactEvmPayload.authorization.from
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
668
|
};
|
|
430
669
|
// Annotate the CommonJS export names for ESM import in node:
|
|
431
670
|
0 && (module.exports = {
|