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