@x402/evm 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/exact/client/index.d.ts +2 -2
- package/dist/cjs/exact/client/index.js +264 -119
- package/dist/cjs/exact/client/index.js.map +1 -1
- package/dist/cjs/exact/facilitator/index.d.ts +3 -0
- package/dist/cjs/exact/facilitator/index.js +691 -281
- package/dist/cjs/exact/facilitator/index.js.map +1 -1
- package/dist/cjs/exact/v1/client/index.js +43 -17
- package/dist/cjs/exact/v1/client/index.js.map +1 -1
- package/dist/cjs/exact/v1/facilitator/index.js +59 -26
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -1
- package/dist/cjs/index.d.ts +458 -31
- package/dist/cjs/index.js +438 -63
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/permit2-BYv82va2.d.ts +103 -0
- package/dist/cjs/v1/index.d.ts +21 -1
- package/dist/cjs/v1/index.js +33 -29
- package/dist/cjs/v1/index.js.map +1 -1
- package/dist/esm/chunk-DSSJHWGT.mjs +658 -0
- package/dist/esm/chunk-DSSJHWGT.mjs.map +1 -0
- package/dist/esm/chunk-PFULIQAE.mjs +13 -0
- package/dist/esm/chunk-PFULIQAE.mjs.map +1 -0
- package/dist/esm/chunk-U4H6Q62Q.mjs +229 -0
- package/dist/esm/chunk-U4H6Q62Q.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +2 -2
- package/dist/esm/exact/client/index.mjs +10 -30
- package/dist/esm/exact/client/index.mjs.map +1 -1
- package/dist/esm/exact/facilitator/index.d.mts +3 -0
- package/dist/esm/exact/facilitator/index.mjs +491 -241
- package/dist/esm/exact/facilitator/index.mjs.map +1 -1
- package/dist/esm/exact/v1/client/index.mjs +1 -2
- package/dist/esm/exact/v1/facilitator/index.mjs +2 -3
- package/dist/esm/index.d.mts +458 -31
- package/dist/esm/index.mjs +31 -4
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/permit2-BsAoJiWD.d.mts +103 -0
- package/dist/esm/v1/index.d.mts +21 -1
- package/dist/esm/v1/index.mjs +4 -6
- package/package.json +2 -2
- package/dist/esm/chunk-FOUXRQAV.mjs +0 -88
- package/dist/esm/chunk-FOUXRQAV.mjs.map +0 -1
- package/dist/esm/chunk-JYZWCLMP.mjs +0 -305
- package/dist/esm/chunk-JYZWCLMP.mjs.map +0 -1
- package/dist/esm/chunk-PSA4YVU2.mjs +0 -92
- package/dist/esm/chunk-PSA4YVU2.mjs.map +0 -1
- package/dist/esm/chunk-QLXM7BIB.mjs +0 -23
- package/dist/esm/chunk-QLXM7BIB.mjs.map +0 -1
- package/dist/esm/chunk-ZYXTTU74.mjs +0 -88
- package/dist/esm/chunk-ZYXTTU74.mjs.map +0 -1
|
@@ -25,7 +25,12 @@ __export(facilitator_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(facilitator_exports);
|
|
27
27
|
|
|
28
|
-
// src/
|
|
28
|
+
// src/types.ts
|
|
29
|
+
function isPermit2Payload(payload) {
|
|
30
|
+
return "permit2Authorization" in payload;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/exact/facilitator/eip3009.ts
|
|
29
34
|
var import_viem = require("viem");
|
|
30
35
|
|
|
31
36
|
// src/constants.ts
|
|
@@ -39,6 +44,24 @@ var authorizationTypes = {
|
|
|
39
44
|
{ name: "nonce", type: "bytes32" }
|
|
40
45
|
]
|
|
41
46
|
};
|
|
47
|
+
var permit2WitnessTypes = {
|
|
48
|
+
PermitWitnessTransferFrom: [
|
|
49
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
50
|
+
{ name: "spender", type: "address" },
|
|
51
|
+
{ name: "nonce", type: "uint256" },
|
|
52
|
+
{ name: "deadline", type: "uint256" },
|
|
53
|
+
{ name: "witness", type: "Witness" }
|
|
54
|
+
],
|
|
55
|
+
TokenPermissions: [
|
|
56
|
+
{ name: "token", type: "address" },
|
|
57
|
+
{ name: "amount", type: "uint256" }
|
|
58
|
+
],
|
|
59
|
+
Witness: [
|
|
60
|
+
{ name: "to", type: "address" },
|
|
61
|
+
{ name: "validAfter", type: "uint256" },
|
|
62
|
+
{ name: "extra", type: "bytes" }
|
|
63
|
+
]
|
|
64
|
+
};
|
|
42
65
|
var eip3009ABI = [
|
|
43
66
|
{
|
|
44
67
|
inputs: [
|
|
@@ -87,6 +110,602 @@ var eip3009ABI = [
|
|
|
87
110
|
type: "function"
|
|
88
111
|
}
|
|
89
112
|
];
|
|
113
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
114
|
+
var x402ExactPermit2ProxyAddress = "0x4020615294c913F045dc10f0a5cdEbd86c280001";
|
|
115
|
+
var x402ExactPermit2ProxyABI = [
|
|
116
|
+
{
|
|
117
|
+
type: "function",
|
|
118
|
+
name: "PERMIT2",
|
|
119
|
+
inputs: [],
|
|
120
|
+
outputs: [{ name: "", type: "address", internalType: "contract ISignatureTransfer" }],
|
|
121
|
+
stateMutability: "view"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
type: "function",
|
|
125
|
+
name: "WITNESS_TYPEHASH",
|
|
126
|
+
inputs: [],
|
|
127
|
+
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
|
|
128
|
+
stateMutability: "view"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
type: "function",
|
|
132
|
+
name: "WITNESS_TYPE_STRING",
|
|
133
|
+
inputs: [],
|
|
134
|
+
outputs: [{ name: "", type: "string", internalType: "string" }],
|
|
135
|
+
stateMutability: "view"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
type: "function",
|
|
139
|
+
name: "initialize",
|
|
140
|
+
inputs: [{ name: "_permit2", type: "address", internalType: "address" }],
|
|
141
|
+
outputs: [],
|
|
142
|
+
stateMutability: "nonpayable"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: "function",
|
|
146
|
+
name: "settle",
|
|
147
|
+
inputs: [
|
|
148
|
+
{
|
|
149
|
+
name: "permit",
|
|
150
|
+
type: "tuple",
|
|
151
|
+
internalType: "struct ISignatureTransfer.PermitTransferFrom",
|
|
152
|
+
components: [
|
|
153
|
+
{
|
|
154
|
+
name: "permitted",
|
|
155
|
+
type: "tuple",
|
|
156
|
+
internalType: "struct ISignatureTransfer.TokenPermissions",
|
|
157
|
+
components: [
|
|
158
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
159
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{ name: "nonce", type: "uint256", internalType: "uint256" },
|
|
163
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" }
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{ name: "owner", type: "address", internalType: "address" },
|
|
167
|
+
{
|
|
168
|
+
name: "witness",
|
|
169
|
+
type: "tuple",
|
|
170
|
+
internalType: "struct x402BasePermit2Proxy.Witness",
|
|
171
|
+
components: [
|
|
172
|
+
{ name: "to", type: "address", internalType: "address" },
|
|
173
|
+
{ name: "validAfter", type: "uint256", internalType: "uint256" },
|
|
174
|
+
{ name: "extra", type: "bytes", internalType: "bytes" }
|
|
175
|
+
]
|
|
176
|
+
},
|
|
177
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
178
|
+
],
|
|
179
|
+
outputs: [],
|
|
180
|
+
stateMutability: "nonpayable"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: "function",
|
|
184
|
+
name: "settleWithPermit",
|
|
185
|
+
inputs: [
|
|
186
|
+
{
|
|
187
|
+
name: "permit2612",
|
|
188
|
+
type: "tuple",
|
|
189
|
+
internalType: "struct x402BasePermit2Proxy.EIP2612Permit",
|
|
190
|
+
components: [
|
|
191
|
+
{ name: "value", type: "uint256", internalType: "uint256" },
|
|
192
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" },
|
|
193
|
+
{ name: "r", type: "bytes32", internalType: "bytes32" },
|
|
194
|
+
{ name: "s", type: "bytes32", internalType: "bytes32" },
|
|
195
|
+
{ name: "v", type: "uint8", internalType: "uint8" }
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "permit",
|
|
200
|
+
type: "tuple",
|
|
201
|
+
internalType: "struct ISignatureTransfer.PermitTransferFrom",
|
|
202
|
+
components: [
|
|
203
|
+
{
|
|
204
|
+
name: "permitted",
|
|
205
|
+
type: "tuple",
|
|
206
|
+
internalType: "struct ISignatureTransfer.TokenPermissions",
|
|
207
|
+
components: [
|
|
208
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
209
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
{ name: "nonce", type: "uint256", internalType: "uint256" },
|
|
213
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" }
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{ name: "owner", type: "address", internalType: "address" },
|
|
217
|
+
{
|
|
218
|
+
name: "witness",
|
|
219
|
+
type: "tuple",
|
|
220
|
+
internalType: "struct x402BasePermit2Proxy.Witness",
|
|
221
|
+
components: [
|
|
222
|
+
{ name: "to", type: "address", internalType: "address" },
|
|
223
|
+
{ name: "validAfter", type: "uint256", internalType: "uint256" },
|
|
224
|
+
{ name: "extra", type: "bytes", internalType: "bytes" }
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
228
|
+
],
|
|
229
|
+
outputs: [],
|
|
230
|
+
stateMutability: "nonpayable"
|
|
231
|
+
},
|
|
232
|
+
{ type: "event", name: "Settled", inputs: [], anonymous: false },
|
|
233
|
+
{ type: "event", name: "SettledWithPermit", inputs: [], anonymous: false },
|
|
234
|
+
{ type: "error", name: "AlreadyInitialized", inputs: [] },
|
|
235
|
+
{ type: "error", name: "InvalidDestination", inputs: [] },
|
|
236
|
+
{ type: "error", name: "InvalidOwner", inputs: [] },
|
|
237
|
+
{ type: "error", name: "InvalidPermit2Address", inputs: [] },
|
|
238
|
+
{ type: "error", name: "PaymentTooEarly", inputs: [] },
|
|
239
|
+
{ type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] }
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
// src/exact/facilitator/eip3009.ts
|
|
243
|
+
async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
|
|
244
|
+
const payer = eip3009Payload.authorization.from;
|
|
245
|
+
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
246
|
+
return {
|
|
247
|
+
isValid: false,
|
|
248
|
+
invalidReason: "unsupported_scheme",
|
|
249
|
+
payer
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (!requirements.extra?.name || !requirements.extra?.version) {
|
|
253
|
+
return {
|
|
254
|
+
isValid: false,
|
|
255
|
+
invalidReason: "missing_eip712_domain",
|
|
256
|
+
payer
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const { name, version } = requirements.extra;
|
|
260
|
+
const erc20Address = (0, import_viem.getAddress)(requirements.asset);
|
|
261
|
+
if (payload.accepted.network !== requirements.network) {
|
|
262
|
+
return {
|
|
263
|
+
isValid: false,
|
|
264
|
+
invalidReason: "network_mismatch",
|
|
265
|
+
payer
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const permitTypedData = {
|
|
269
|
+
types: authorizationTypes,
|
|
270
|
+
primaryType: "TransferWithAuthorization",
|
|
271
|
+
domain: {
|
|
272
|
+
name,
|
|
273
|
+
version,
|
|
274
|
+
chainId: parseInt(requirements.network.split(":")[1]),
|
|
275
|
+
verifyingContract: erc20Address
|
|
276
|
+
},
|
|
277
|
+
message: {
|
|
278
|
+
from: eip3009Payload.authorization.from,
|
|
279
|
+
to: eip3009Payload.authorization.to,
|
|
280
|
+
value: BigInt(eip3009Payload.authorization.value),
|
|
281
|
+
validAfter: BigInt(eip3009Payload.authorization.validAfter),
|
|
282
|
+
validBefore: BigInt(eip3009Payload.authorization.validBefore),
|
|
283
|
+
nonce: eip3009Payload.authorization.nonce
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
try {
|
|
287
|
+
const recoveredAddress = await signer.verifyTypedData({
|
|
288
|
+
address: eip3009Payload.authorization.from,
|
|
289
|
+
...permitTypedData,
|
|
290
|
+
signature: eip3009Payload.signature
|
|
291
|
+
});
|
|
292
|
+
if (!recoveredAddress) {
|
|
293
|
+
return {
|
|
294
|
+
isValid: false,
|
|
295
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
296
|
+
payer
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
} catch {
|
|
300
|
+
const signature = eip3009Payload.signature;
|
|
301
|
+
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
302
|
+
const isSmartWallet = signatureLength > 130;
|
|
303
|
+
if (isSmartWallet) {
|
|
304
|
+
const payerAddress = eip3009Payload.authorization.from;
|
|
305
|
+
const bytecode = await signer.getCode({ address: payerAddress });
|
|
306
|
+
if (!bytecode || bytecode === "0x") {
|
|
307
|
+
const erc6492Data = (0, import_viem.parseErc6492Signature)(signature);
|
|
308
|
+
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
309
|
+
if (!hasDeploymentInfo) {
|
|
310
|
+
return {
|
|
311
|
+
isValid: false,
|
|
312
|
+
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
|
|
313
|
+
payer: payerAddress
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
return {
|
|
318
|
+
isValid: false,
|
|
319
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
320
|
+
payer
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
} else {
|
|
324
|
+
return {
|
|
325
|
+
isValid: false,
|
|
326
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
327
|
+
payer
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if ((0, import_viem.getAddress)(eip3009Payload.authorization.to) !== (0, import_viem.getAddress)(requirements.payTo)) {
|
|
332
|
+
return {
|
|
333
|
+
isValid: false,
|
|
334
|
+
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
335
|
+
payer
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
339
|
+
if (BigInt(eip3009Payload.authorization.validBefore) < BigInt(now + 6)) {
|
|
340
|
+
return {
|
|
341
|
+
isValid: false,
|
|
342
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
|
|
343
|
+
payer
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (BigInt(eip3009Payload.authorization.validAfter) > BigInt(now)) {
|
|
347
|
+
return {
|
|
348
|
+
isValid: false,
|
|
349
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
|
|
350
|
+
payer
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
const balance = await signer.readContract({
|
|
355
|
+
address: erc20Address,
|
|
356
|
+
abi: eip3009ABI,
|
|
357
|
+
functionName: "balanceOf",
|
|
358
|
+
args: [eip3009Payload.authorization.from]
|
|
359
|
+
});
|
|
360
|
+
if (BigInt(balance) < BigInt(requirements.amount)) {
|
|
361
|
+
return {
|
|
362
|
+
isValid: false,
|
|
363
|
+
invalidReason: "insufficient_funds",
|
|
364
|
+
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
|
|
365
|
+
payer
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
370
|
+
if (BigInt(eip3009Payload.authorization.value) < BigInt(requirements.amount)) {
|
|
371
|
+
return {
|
|
372
|
+
isValid: false,
|
|
373
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value",
|
|
374
|
+
payer
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
isValid: true,
|
|
379
|
+
invalidReason: void 0,
|
|
380
|
+
payer
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
async function settleEIP3009(signer, payload, requirements, eip3009Payload, config) {
|
|
384
|
+
const payer = eip3009Payload.authorization.from;
|
|
385
|
+
const valid = await verifyEIP3009(signer, payload, requirements, eip3009Payload);
|
|
386
|
+
if (!valid.isValid) {
|
|
387
|
+
return {
|
|
388
|
+
success: false,
|
|
389
|
+
network: payload.accepted.network,
|
|
390
|
+
transaction: "",
|
|
391
|
+
errorReason: valid.invalidReason ?? "invalid_scheme",
|
|
392
|
+
payer
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
const parseResult = (0, import_viem.parseErc6492Signature)(eip3009Payload.signature);
|
|
397
|
+
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
398
|
+
if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
399
|
+
const bytecode = await signer.getCode({ address: payer });
|
|
400
|
+
if (!bytecode || bytecode === "0x") {
|
|
401
|
+
const deployTx = await signer.sendTransaction({
|
|
402
|
+
to: factoryAddress,
|
|
403
|
+
data: factoryCalldata
|
|
404
|
+
});
|
|
405
|
+
await signer.waitForTransactionReceipt({ hash: deployTx });
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
409
|
+
const isECDSA = signatureLength === 130;
|
|
410
|
+
let tx;
|
|
411
|
+
if (isECDSA) {
|
|
412
|
+
const parsedSig = (0, import_viem.parseSignature)(signature);
|
|
413
|
+
tx = await signer.writeContract({
|
|
414
|
+
address: (0, import_viem.getAddress)(requirements.asset),
|
|
415
|
+
abi: eip3009ABI,
|
|
416
|
+
functionName: "transferWithAuthorization",
|
|
417
|
+
args: [
|
|
418
|
+
(0, import_viem.getAddress)(eip3009Payload.authorization.from),
|
|
419
|
+
(0, import_viem.getAddress)(eip3009Payload.authorization.to),
|
|
420
|
+
BigInt(eip3009Payload.authorization.value),
|
|
421
|
+
BigInt(eip3009Payload.authorization.validAfter),
|
|
422
|
+
BigInt(eip3009Payload.authorization.validBefore),
|
|
423
|
+
eip3009Payload.authorization.nonce,
|
|
424
|
+
parsedSig.v || parsedSig.yParity,
|
|
425
|
+
parsedSig.r,
|
|
426
|
+
parsedSig.s
|
|
427
|
+
]
|
|
428
|
+
});
|
|
429
|
+
} else {
|
|
430
|
+
tx = await signer.writeContract({
|
|
431
|
+
address: (0, import_viem.getAddress)(requirements.asset),
|
|
432
|
+
abi: eip3009ABI,
|
|
433
|
+
functionName: "transferWithAuthorization",
|
|
434
|
+
args: [
|
|
435
|
+
(0, import_viem.getAddress)(eip3009Payload.authorization.from),
|
|
436
|
+
(0, import_viem.getAddress)(eip3009Payload.authorization.to),
|
|
437
|
+
BigInt(eip3009Payload.authorization.value),
|
|
438
|
+
BigInt(eip3009Payload.authorization.validAfter),
|
|
439
|
+
BigInt(eip3009Payload.authorization.validBefore),
|
|
440
|
+
eip3009Payload.authorization.nonce,
|
|
441
|
+
signature
|
|
442
|
+
]
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
|
|
446
|
+
if (receipt.status !== "success") {
|
|
447
|
+
return {
|
|
448
|
+
success: false,
|
|
449
|
+
errorReason: "invalid_transaction_state",
|
|
450
|
+
transaction: tx,
|
|
451
|
+
network: payload.accepted.network,
|
|
452
|
+
payer
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
success: true,
|
|
457
|
+
transaction: tx,
|
|
458
|
+
network: payload.accepted.network,
|
|
459
|
+
payer
|
|
460
|
+
};
|
|
461
|
+
} catch {
|
|
462
|
+
return {
|
|
463
|
+
success: false,
|
|
464
|
+
errorReason: "transaction_failed",
|
|
465
|
+
transaction: "",
|
|
466
|
+
network: payload.accepted.network,
|
|
467
|
+
payer
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// src/exact/facilitator/permit2.ts
|
|
473
|
+
var import_viem2 = require("viem");
|
|
474
|
+
var erc20AllowanceABI = [
|
|
475
|
+
{
|
|
476
|
+
type: "function",
|
|
477
|
+
name: "allowance",
|
|
478
|
+
inputs: [
|
|
479
|
+
{ name: "owner", type: "address" },
|
|
480
|
+
{ name: "spender", type: "address" }
|
|
481
|
+
],
|
|
482
|
+
outputs: [{ type: "uint256" }],
|
|
483
|
+
stateMutability: "view"
|
|
484
|
+
}
|
|
485
|
+
];
|
|
486
|
+
async function verifyPermit2(signer, payload, requirements, permit2Payload) {
|
|
487
|
+
const payer = permit2Payload.permit2Authorization.from;
|
|
488
|
+
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
489
|
+
return {
|
|
490
|
+
isValid: false,
|
|
491
|
+
invalidReason: "unsupported_scheme",
|
|
492
|
+
payer
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
if (payload.accepted.network !== requirements.network) {
|
|
496
|
+
return {
|
|
497
|
+
isValid: false,
|
|
498
|
+
invalidReason: "network_mismatch",
|
|
499
|
+
payer
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
const chainId = parseInt(requirements.network.split(":")[1]);
|
|
503
|
+
const tokenAddress = (0, import_viem2.getAddress)(requirements.asset);
|
|
504
|
+
if ((0, import_viem2.getAddress)(permit2Payload.permit2Authorization.spender) !== (0, import_viem2.getAddress)(x402ExactPermit2ProxyAddress)) {
|
|
505
|
+
return {
|
|
506
|
+
isValid: false,
|
|
507
|
+
invalidReason: "invalid_permit2_spender",
|
|
508
|
+
payer
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
if ((0, import_viem2.getAddress)(permit2Payload.permit2Authorization.witness.to) !== (0, import_viem2.getAddress)(requirements.payTo)) {
|
|
512
|
+
return {
|
|
513
|
+
isValid: false,
|
|
514
|
+
invalidReason: "invalid_permit2_recipient_mismatch",
|
|
515
|
+
payer
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
519
|
+
if (BigInt(permit2Payload.permit2Authorization.deadline) < BigInt(now + 6)) {
|
|
520
|
+
return {
|
|
521
|
+
isValid: false,
|
|
522
|
+
invalidReason: "permit2_deadline_expired",
|
|
523
|
+
payer
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
if (BigInt(permit2Payload.permit2Authorization.witness.validAfter) > BigInt(now)) {
|
|
527
|
+
return {
|
|
528
|
+
isValid: false,
|
|
529
|
+
invalidReason: "permit2_not_yet_valid",
|
|
530
|
+
payer
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
if (BigInt(permit2Payload.permit2Authorization.permitted.amount) < BigInt(requirements.amount)) {
|
|
534
|
+
return {
|
|
535
|
+
isValid: false,
|
|
536
|
+
invalidReason: "permit2_insufficient_amount",
|
|
537
|
+
payer
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
if ((0, import_viem2.getAddress)(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
|
|
541
|
+
return {
|
|
542
|
+
isValid: false,
|
|
543
|
+
invalidReason: "permit2_token_mismatch",
|
|
544
|
+
payer
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
const permit2TypedData = {
|
|
548
|
+
types: permit2WitnessTypes,
|
|
549
|
+
primaryType: "PermitWitnessTransferFrom",
|
|
550
|
+
domain: {
|
|
551
|
+
name: "Permit2",
|
|
552
|
+
chainId,
|
|
553
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
554
|
+
},
|
|
555
|
+
message: {
|
|
556
|
+
permitted: {
|
|
557
|
+
token: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.permitted.token),
|
|
558
|
+
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
559
|
+
},
|
|
560
|
+
spender: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.spender),
|
|
561
|
+
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
562
|
+
deadline: BigInt(permit2Payload.permit2Authorization.deadline),
|
|
563
|
+
witness: {
|
|
564
|
+
to: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.witness.to),
|
|
565
|
+
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
|
|
566
|
+
extra: permit2Payload.permit2Authorization.witness.extra
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
try {
|
|
571
|
+
const isValid = await signer.verifyTypedData({
|
|
572
|
+
address: payer,
|
|
573
|
+
...permit2TypedData,
|
|
574
|
+
signature: permit2Payload.signature
|
|
575
|
+
});
|
|
576
|
+
if (!isValid) {
|
|
577
|
+
return {
|
|
578
|
+
isValid: false,
|
|
579
|
+
invalidReason: "invalid_permit2_signature",
|
|
580
|
+
payer
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
} catch {
|
|
584
|
+
return {
|
|
585
|
+
isValid: false,
|
|
586
|
+
invalidReason: "invalid_permit2_signature",
|
|
587
|
+
payer
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
try {
|
|
591
|
+
const allowance = await signer.readContract({
|
|
592
|
+
address: tokenAddress,
|
|
593
|
+
abi: erc20AllowanceABI,
|
|
594
|
+
functionName: "allowance",
|
|
595
|
+
args: [payer, PERMIT2_ADDRESS]
|
|
596
|
+
});
|
|
597
|
+
if (allowance < BigInt(requirements.amount)) {
|
|
598
|
+
return {
|
|
599
|
+
isValid: false,
|
|
600
|
+
invalidReason: "permit2_allowance_required",
|
|
601
|
+
payer
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
} catch {
|
|
605
|
+
}
|
|
606
|
+
try {
|
|
607
|
+
const balance = await signer.readContract({
|
|
608
|
+
address: tokenAddress,
|
|
609
|
+
abi: eip3009ABI,
|
|
610
|
+
functionName: "balanceOf",
|
|
611
|
+
args: [payer]
|
|
612
|
+
});
|
|
613
|
+
if (balance < BigInt(requirements.amount)) {
|
|
614
|
+
return {
|
|
615
|
+
isValid: false,
|
|
616
|
+
invalidReason: "insufficient_funds",
|
|
617
|
+
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
|
|
618
|
+
payer
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
} catch {
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
isValid: true,
|
|
625
|
+
invalidReason: void 0,
|
|
626
|
+
payer
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
async function settlePermit2(signer, payload, requirements, permit2Payload) {
|
|
630
|
+
const payer = permit2Payload.permit2Authorization.from;
|
|
631
|
+
const valid = await verifyPermit2(signer, payload, requirements, permit2Payload);
|
|
632
|
+
if (!valid.isValid) {
|
|
633
|
+
return {
|
|
634
|
+
success: false,
|
|
635
|
+
network: payload.accepted.network,
|
|
636
|
+
transaction: "",
|
|
637
|
+
errorReason: valid.invalidReason ?? "invalid_scheme",
|
|
638
|
+
payer
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
try {
|
|
642
|
+
const tx = await signer.writeContract({
|
|
643
|
+
address: x402ExactPermit2ProxyAddress,
|
|
644
|
+
abi: x402ExactPermit2ProxyABI,
|
|
645
|
+
functionName: "settle",
|
|
646
|
+
args: [
|
|
647
|
+
{
|
|
648
|
+
permitted: {
|
|
649
|
+
token: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.permitted.token),
|
|
650
|
+
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
|
|
651
|
+
},
|
|
652
|
+
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
|
|
653
|
+
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
|
|
654
|
+
},
|
|
655
|
+
(0, import_viem2.getAddress)(payer),
|
|
656
|
+
{
|
|
657
|
+
to: (0, import_viem2.getAddress)(permit2Payload.permit2Authorization.witness.to),
|
|
658
|
+
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter),
|
|
659
|
+
extra: permit2Payload.permit2Authorization.witness.extra
|
|
660
|
+
},
|
|
661
|
+
permit2Payload.signature
|
|
662
|
+
]
|
|
663
|
+
});
|
|
664
|
+
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
|
|
665
|
+
if (receipt.status !== "success") {
|
|
666
|
+
return {
|
|
667
|
+
success: false,
|
|
668
|
+
errorReason: "invalid_transaction_state",
|
|
669
|
+
transaction: tx,
|
|
670
|
+
network: payload.accepted.network,
|
|
671
|
+
payer
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
return {
|
|
675
|
+
success: true,
|
|
676
|
+
transaction: tx,
|
|
677
|
+
network: payload.accepted.network,
|
|
678
|
+
payer
|
|
679
|
+
};
|
|
680
|
+
} catch (error) {
|
|
681
|
+
let errorReason = "transaction_failed";
|
|
682
|
+
if (error instanceof Error) {
|
|
683
|
+
const message = error.message;
|
|
684
|
+
if (message.includes("AmountExceedsPermitted")) {
|
|
685
|
+
errorReason = "permit2_amount_exceeds_permitted";
|
|
686
|
+
} else if (message.includes("InvalidDestination")) {
|
|
687
|
+
errorReason = "permit2_invalid_destination";
|
|
688
|
+
} else if (message.includes("InvalidOwner")) {
|
|
689
|
+
errorReason = "permit2_invalid_owner";
|
|
690
|
+
} else if (message.includes("PaymentTooEarly")) {
|
|
691
|
+
errorReason = "permit2_payment_too_early";
|
|
692
|
+
} else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
|
|
693
|
+
errorReason = "permit2_invalid_signature";
|
|
694
|
+
} else if (message.includes("InvalidNonce")) {
|
|
695
|
+
errorReason = "permit2_invalid_nonce";
|
|
696
|
+
} else {
|
|
697
|
+
errorReason = `transaction_failed: ${message.slice(0, 500)}`;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return {
|
|
701
|
+
success: false,
|
|
702
|
+
errorReason,
|
|
703
|
+
transaction: "",
|
|
704
|
+
network: payload.accepted.network,
|
|
705
|
+
payer
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
}
|
|
90
709
|
|
|
91
710
|
// src/exact/facilitator/scheme.ts
|
|
92
711
|
var ExactEvmScheme = class {
|
|
@@ -126,277 +745,80 @@ var ExactEvmScheme = class {
|
|
|
126
745
|
}
|
|
127
746
|
/**
|
|
128
747
|
* Verifies a payment payload.
|
|
748
|
+
* Routes to the appropriate verification logic based on payload type.
|
|
129
749
|
*
|
|
130
750
|
* @param payload - The payment payload to verify
|
|
131
751
|
* @param requirements - The payment requirements
|
|
132
752
|
* @returns Promise resolving to verification response
|
|
133
753
|
*/
|
|
134
754
|
async verify(payload, requirements) {
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
return
|
|
138
|
-
isValid: false,
|
|
139
|
-
invalidReason: "unsupported_scheme",
|
|
140
|
-
payer: exactEvmPayload.authorization.from
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
if (!requirements.extra?.name || !requirements.extra?.version) {
|
|
144
|
-
return {
|
|
145
|
-
isValid: false,
|
|
146
|
-
invalidReason: "missing_eip712_domain",
|
|
147
|
-
payer: exactEvmPayload.authorization.from
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
const { name, version } = requirements.extra;
|
|
151
|
-
const erc20Address = (0, import_viem.getAddress)(requirements.asset);
|
|
152
|
-
if (payload.accepted.network !== requirements.network) {
|
|
153
|
-
return {
|
|
154
|
-
isValid: false,
|
|
155
|
-
invalidReason: "network_mismatch",
|
|
156
|
-
payer: exactEvmPayload.authorization.from
|
|
157
|
-
};
|
|
755
|
+
const rawPayload = payload.payload;
|
|
756
|
+
if (isPermit2Payload(rawPayload)) {
|
|
757
|
+
return verifyPermit2(this.signer, payload, requirements, rawPayload);
|
|
158
758
|
}
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
primaryType: "TransferWithAuthorization",
|
|
162
|
-
domain: {
|
|
163
|
-
name,
|
|
164
|
-
version,
|
|
165
|
-
chainId: parseInt(requirements.network.split(":")[1]),
|
|
166
|
-
verifyingContract: erc20Address
|
|
167
|
-
},
|
|
168
|
-
message: {
|
|
169
|
-
from: exactEvmPayload.authorization.from,
|
|
170
|
-
to: exactEvmPayload.authorization.to,
|
|
171
|
-
value: BigInt(exactEvmPayload.authorization.value),
|
|
172
|
-
validAfter: BigInt(exactEvmPayload.authorization.validAfter),
|
|
173
|
-
validBefore: BigInt(exactEvmPayload.authorization.validBefore),
|
|
174
|
-
nonce: exactEvmPayload.authorization.nonce
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
try {
|
|
178
|
-
const recoveredAddress = await this.signer.verifyTypedData({
|
|
179
|
-
address: exactEvmPayload.authorization.from,
|
|
180
|
-
...permitTypedData,
|
|
181
|
-
signature: exactEvmPayload.signature
|
|
182
|
-
});
|
|
183
|
-
if (!recoveredAddress) {
|
|
184
|
-
return {
|
|
185
|
-
isValid: false,
|
|
186
|
-
invalidReason: "invalid_exact_evm_payload_signature",
|
|
187
|
-
payer: exactEvmPayload.authorization.from
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
} catch {
|
|
191
|
-
const signature = exactEvmPayload.signature;
|
|
192
|
-
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
193
|
-
const isSmartWallet = signatureLength > 130;
|
|
194
|
-
if (isSmartWallet) {
|
|
195
|
-
const payerAddress = exactEvmPayload.authorization.from;
|
|
196
|
-
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
197
|
-
if (!bytecode || bytecode === "0x") {
|
|
198
|
-
const erc6492Data = (0, import_viem.parseErc6492Signature)(signature);
|
|
199
|
-
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
200
|
-
if (!hasDeploymentInfo) {
|
|
201
|
-
return {
|
|
202
|
-
isValid: false,
|
|
203
|
-
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
|
|
204
|
-
payer: payerAddress
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
return {
|
|
209
|
-
isValid: false,
|
|
210
|
-
invalidReason: "invalid_exact_evm_payload_signature",
|
|
211
|
-
payer: exactEvmPayload.authorization.from
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
return {
|
|
216
|
-
isValid: false,
|
|
217
|
-
invalidReason: "invalid_exact_evm_payload_signature",
|
|
218
|
-
payer: exactEvmPayload.authorization.from
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
if ((0, import_viem.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem.getAddress)(requirements.payTo)) {
|
|
223
|
-
return {
|
|
224
|
-
isValid: false,
|
|
225
|
-
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
226
|
-
payer: exactEvmPayload.authorization.from
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
230
|
-
if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
|
|
231
|
-
return {
|
|
232
|
-
isValid: false,
|
|
233
|
-
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
|
|
234
|
-
payer: exactEvmPayload.authorization.from
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
|
|
238
|
-
return {
|
|
239
|
-
isValid: false,
|
|
240
|
-
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
|
|
241
|
-
payer: exactEvmPayload.authorization.from
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
try {
|
|
245
|
-
const balance = await this.signer.readContract({
|
|
246
|
-
address: erc20Address,
|
|
247
|
-
abi: eip3009ABI,
|
|
248
|
-
functionName: "balanceOf",
|
|
249
|
-
args: [exactEvmPayload.authorization.from]
|
|
250
|
-
});
|
|
251
|
-
if (BigInt(balance) < BigInt(requirements.amount)) {
|
|
252
|
-
return {
|
|
253
|
-
isValid: false,
|
|
254
|
-
invalidReason: "insufficient_funds",
|
|
255
|
-
payer: exactEvmPayload.authorization.from
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
} catch {
|
|
259
|
-
}
|
|
260
|
-
if (BigInt(exactEvmPayload.authorization.value) < BigInt(requirements.amount)) {
|
|
261
|
-
return {
|
|
262
|
-
isValid: false,
|
|
263
|
-
invalidReason: "invalid_exact_evm_payload_authorization_value",
|
|
264
|
-
payer: exactEvmPayload.authorization.from
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
return {
|
|
268
|
-
isValid: true,
|
|
269
|
-
invalidReason: void 0,
|
|
270
|
-
payer: exactEvmPayload.authorization.from
|
|
271
|
-
};
|
|
759
|
+
const eip3009Payload = rawPayload;
|
|
760
|
+
return verifyEIP3009(this.signer, payload, requirements, eip3009Payload);
|
|
272
761
|
}
|
|
273
762
|
/**
|
|
274
763
|
* Settles a payment by executing the transfer.
|
|
764
|
+
* Routes to the appropriate settlement logic based on payload type.
|
|
275
765
|
*
|
|
276
766
|
* @param payload - The payment payload to settle
|
|
277
767
|
* @param requirements - The payment requirements
|
|
278
768
|
* @returns Promise resolving to settlement response
|
|
279
769
|
*/
|
|
280
770
|
async settle(payload, requirements) {
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return {
|
|
285
|
-
success: false,
|
|
286
|
-
network: payload.accepted.network,
|
|
287
|
-
transaction: "",
|
|
288
|
-
errorReason: valid.invalidReason ?? "invalid_scheme",
|
|
289
|
-
payer: exactEvmPayload.authorization.from
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
try {
|
|
293
|
-
const parseResult = (0, import_viem.parseErc6492Signature)(exactEvmPayload.signature);
|
|
294
|
-
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
295
|
-
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
296
|
-
const payerAddress = exactEvmPayload.authorization.from;
|
|
297
|
-
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
298
|
-
if (!bytecode || bytecode === "0x") {
|
|
299
|
-
try {
|
|
300
|
-
console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
|
|
301
|
-
const deployTx = await this.signer.sendTransaction({
|
|
302
|
-
to: factoryAddress,
|
|
303
|
-
data: factoryCalldata
|
|
304
|
-
});
|
|
305
|
-
await this.signer.waitForTransactionReceipt({ hash: deployTx });
|
|
306
|
-
console.log(`Successfully deployed smart wallet for ${payerAddress}`);
|
|
307
|
-
} catch (deployError) {
|
|
308
|
-
console.error("Smart wallet deployment failed:", deployError);
|
|
309
|
-
throw deployError;
|
|
310
|
-
}
|
|
311
|
-
} else {
|
|
312
|
-
console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
316
|
-
const isECDSA = signatureLength === 130;
|
|
317
|
-
let tx;
|
|
318
|
-
if (isECDSA) {
|
|
319
|
-
const parsedSig = (0, import_viem.parseSignature)(signature);
|
|
320
|
-
tx = await this.signer.writeContract({
|
|
321
|
-
address: (0, import_viem.getAddress)(requirements.asset),
|
|
322
|
-
abi: eip3009ABI,
|
|
323
|
-
functionName: "transferWithAuthorization",
|
|
324
|
-
args: [
|
|
325
|
-
(0, import_viem.getAddress)(exactEvmPayload.authorization.from),
|
|
326
|
-
(0, import_viem.getAddress)(exactEvmPayload.authorization.to),
|
|
327
|
-
BigInt(exactEvmPayload.authorization.value),
|
|
328
|
-
BigInt(exactEvmPayload.authorization.validAfter),
|
|
329
|
-
BigInt(exactEvmPayload.authorization.validBefore),
|
|
330
|
-
exactEvmPayload.authorization.nonce,
|
|
331
|
-
parsedSig.v || parsedSig.yParity,
|
|
332
|
-
parsedSig.r,
|
|
333
|
-
parsedSig.s
|
|
334
|
-
]
|
|
335
|
-
});
|
|
336
|
-
} else {
|
|
337
|
-
tx = await this.signer.writeContract({
|
|
338
|
-
address: (0, import_viem.getAddress)(requirements.asset),
|
|
339
|
-
abi: eip3009ABI,
|
|
340
|
-
functionName: "transferWithAuthorization",
|
|
341
|
-
args: [
|
|
342
|
-
(0, import_viem.getAddress)(exactEvmPayload.authorization.from),
|
|
343
|
-
(0, import_viem.getAddress)(exactEvmPayload.authorization.to),
|
|
344
|
-
BigInt(exactEvmPayload.authorization.value),
|
|
345
|
-
BigInt(exactEvmPayload.authorization.validAfter),
|
|
346
|
-
BigInt(exactEvmPayload.authorization.validBefore),
|
|
347
|
-
exactEvmPayload.authorization.nonce,
|
|
348
|
-
signature
|
|
349
|
-
]
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
|
|
353
|
-
if (receipt.status !== "success") {
|
|
354
|
-
return {
|
|
355
|
-
success: false,
|
|
356
|
-
errorReason: "invalid_transaction_state",
|
|
357
|
-
transaction: tx,
|
|
358
|
-
network: payload.accepted.network,
|
|
359
|
-
payer: exactEvmPayload.authorization.from
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
return {
|
|
363
|
-
success: true,
|
|
364
|
-
transaction: tx,
|
|
365
|
-
network: payload.accepted.network,
|
|
366
|
-
payer: exactEvmPayload.authorization.from
|
|
367
|
-
};
|
|
368
|
-
} catch (error) {
|
|
369
|
-
console.error("Failed to settle transaction:", error);
|
|
370
|
-
return {
|
|
371
|
-
success: false,
|
|
372
|
-
errorReason: "transaction_failed",
|
|
373
|
-
transaction: "",
|
|
374
|
-
network: payload.accepted.network,
|
|
375
|
-
payer: exactEvmPayload.authorization.from
|
|
376
|
-
};
|
|
771
|
+
const rawPayload = payload.payload;
|
|
772
|
+
if (isPermit2Payload(rawPayload)) {
|
|
773
|
+
return settlePermit2(this.signer, payload, requirements, rawPayload);
|
|
377
774
|
}
|
|
775
|
+
const eip3009Payload = rawPayload;
|
|
776
|
+
return settleEIP3009(this.signer, payload, requirements, eip3009Payload, this.config);
|
|
378
777
|
}
|
|
379
778
|
};
|
|
380
779
|
|
|
381
780
|
// src/exact/v1/facilitator/scheme.ts
|
|
781
|
+
var import_viem5 = require("viem");
|
|
782
|
+
|
|
783
|
+
// src/utils.ts
|
|
784
|
+
var import_viem4 = require("viem");
|
|
785
|
+
|
|
786
|
+
// src/exact/v1/client/scheme.ts
|
|
382
787
|
var import_viem3 = require("viem");
|
|
383
788
|
|
|
789
|
+
// src/v1/index.ts
|
|
790
|
+
var EVM_NETWORK_CHAIN_ID_MAP = {
|
|
791
|
+
ethereum: 1,
|
|
792
|
+
sepolia: 11155111,
|
|
793
|
+
abstract: 2741,
|
|
794
|
+
"abstract-testnet": 11124,
|
|
795
|
+
"base-sepolia": 84532,
|
|
796
|
+
base: 8453,
|
|
797
|
+
"avalanche-fuji": 43113,
|
|
798
|
+
avalanche: 43114,
|
|
799
|
+
iotex: 4689,
|
|
800
|
+
sei: 1329,
|
|
801
|
+
"sei-testnet": 1328,
|
|
802
|
+
polygon: 137,
|
|
803
|
+
"polygon-amoy": 80002,
|
|
804
|
+
peaq: 3338,
|
|
805
|
+
story: 1514,
|
|
806
|
+
educhain: 41923,
|
|
807
|
+
"skale-base-sepolia": 324705682
|
|
808
|
+
};
|
|
809
|
+
var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
|
|
810
|
+
|
|
384
811
|
// src/utils.ts
|
|
385
|
-
var import_viem2 = require("viem");
|
|
386
812
|
function getEvmChainId(network) {
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
polygon: 137,
|
|
393
|
-
"polygon-amoy": 80002
|
|
394
|
-
};
|
|
395
|
-
return networkMap[network] || 1;
|
|
813
|
+
const chainId = EVM_NETWORK_CHAIN_ID_MAP[network];
|
|
814
|
+
if (!chainId) {
|
|
815
|
+
throw new Error(`Unsupported network: ${network}`);
|
|
816
|
+
}
|
|
817
|
+
return chainId;
|
|
396
818
|
}
|
|
397
819
|
|
|
398
820
|
// src/exact/v1/facilitator/scheme.ts
|
|
399
|
-
var
|
|
821
|
+
var ExactEvmSchemeV12 = class {
|
|
400
822
|
/**
|
|
401
823
|
* Creates a new ExactEvmFacilitatorV1 instance.
|
|
402
824
|
*
|
|
@@ -449,7 +871,16 @@ var ExactEvmSchemeV1 = class {
|
|
|
449
871
|
payer: exactEvmPayload.authorization.from
|
|
450
872
|
};
|
|
451
873
|
}
|
|
452
|
-
|
|
874
|
+
let chainId;
|
|
875
|
+
try {
|
|
876
|
+
chainId = getEvmChainId(payloadV1.network);
|
|
877
|
+
} catch {
|
|
878
|
+
return {
|
|
879
|
+
isValid: false,
|
|
880
|
+
invalidReason: `invalid_network`,
|
|
881
|
+
payer: exactEvmPayload.authorization.from
|
|
882
|
+
};
|
|
883
|
+
}
|
|
453
884
|
if (!requirements.extra?.name || !requirements.extra?.version) {
|
|
454
885
|
return {
|
|
455
886
|
isValid: false,
|
|
@@ -458,7 +889,7 @@ var ExactEvmSchemeV1 = class {
|
|
|
458
889
|
};
|
|
459
890
|
}
|
|
460
891
|
const { name, version } = requirements.extra;
|
|
461
|
-
const erc20Address = (0,
|
|
892
|
+
const erc20Address = (0, import_viem5.getAddress)(requirements.asset);
|
|
462
893
|
if (payloadV1.network !== requirements.network) {
|
|
463
894
|
return {
|
|
464
895
|
isValid: false,
|
|
@@ -505,8 +936,8 @@ var ExactEvmSchemeV1 = class {
|
|
|
505
936
|
const payerAddress = exactEvmPayload.authorization.from;
|
|
506
937
|
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
507
938
|
if (!bytecode || bytecode === "0x") {
|
|
508
|
-
const erc6492Data = (0,
|
|
509
|
-
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0,
|
|
939
|
+
const erc6492Data = (0, import_viem5.parseErc6492Signature)(signature);
|
|
940
|
+
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem5.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
510
941
|
if (!hasDeploymentInfo) {
|
|
511
942
|
return {
|
|
512
943
|
isValid: false,
|
|
@@ -529,7 +960,7 @@ var ExactEvmSchemeV1 = class {
|
|
|
529
960
|
};
|
|
530
961
|
}
|
|
531
962
|
}
|
|
532
|
-
if ((0,
|
|
963
|
+
if ((0, import_viem5.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem5.getAddress)(requirements.payTo)) {
|
|
533
964
|
return {
|
|
534
965
|
isValid: false,
|
|
535
966
|
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
@@ -562,6 +993,7 @@ var ExactEvmSchemeV1 = class {
|
|
|
562
993
|
return {
|
|
563
994
|
isValid: false,
|
|
564
995
|
invalidReason: "insufficient_funds",
|
|
996
|
+
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.`,
|
|
565
997
|
payer: exactEvmPayload.authorization.from
|
|
566
998
|
};
|
|
567
999
|
}
|
|
@@ -601,9 +1033,9 @@ var ExactEvmSchemeV1 = class {
|
|
|
601
1033
|
};
|
|
602
1034
|
}
|
|
603
1035
|
try {
|
|
604
|
-
const parseResult = (0,
|
|
1036
|
+
const parseResult = (0, import_viem5.parseErc6492Signature)(exactEvmPayload.signature);
|
|
605
1037
|
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
606
|
-
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0,
|
|
1038
|
+
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem5.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
607
1039
|
const payerAddress = exactEvmPayload.authorization.from;
|
|
608
1040
|
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
609
1041
|
if (!bytecode || bytecode === "0x") {
|
|
@@ -627,14 +1059,14 @@ var ExactEvmSchemeV1 = class {
|
|
|
627
1059
|
const isECDSA = signatureLength === 130;
|
|
628
1060
|
let tx;
|
|
629
1061
|
if (isECDSA) {
|
|
630
|
-
const parsedSig = (0,
|
|
1062
|
+
const parsedSig = (0, import_viem5.parseSignature)(signature);
|
|
631
1063
|
tx = await this.signer.writeContract({
|
|
632
|
-
address: (0,
|
|
1064
|
+
address: (0, import_viem5.getAddress)(requirements.asset),
|
|
633
1065
|
abi: eip3009ABI,
|
|
634
1066
|
functionName: "transferWithAuthorization",
|
|
635
1067
|
args: [
|
|
636
|
-
(0,
|
|
637
|
-
(0,
|
|
1068
|
+
(0, import_viem5.getAddress)(exactEvmPayload.authorization.from),
|
|
1069
|
+
(0, import_viem5.getAddress)(exactEvmPayload.authorization.to),
|
|
638
1070
|
BigInt(exactEvmPayload.authorization.value),
|
|
639
1071
|
BigInt(exactEvmPayload.authorization.validAfter),
|
|
640
1072
|
BigInt(exactEvmPayload.authorization.validBefore),
|
|
@@ -646,12 +1078,12 @@ var ExactEvmSchemeV1 = class {
|
|
|
646
1078
|
});
|
|
647
1079
|
} else {
|
|
648
1080
|
tx = await this.signer.writeContract({
|
|
649
|
-
address: (0,
|
|
1081
|
+
address: (0, import_viem5.getAddress)(requirements.asset),
|
|
650
1082
|
abi: eip3009ABI,
|
|
651
1083
|
functionName: "transferWithAuthorization",
|
|
652
1084
|
args: [
|
|
653
|
-
(0,
|
|
654
|
-
(0,
|
|
1085
|
+
(0, import_viem5.getAddress)(exactEvmPayload.authorization.from),
|
|
1086
|
+
(0, import_viem5.getAddress)(exactEvmPayload.authorization.to),
|
|
655
1087
|
BigInt(exactEvmPayload.authorization.value),
|
|
656
1088
|
BigInt(exactEvmPayload.authorization.validAfter),
|
|
657
1089
|
BigInt(exactEvmPayload.authorization.validBefore),
|
|
@@ -689,28 +1121,6 @@ var ExactEvmSchemeV1 = class {
|
|
|
689
1121
|
}
|
|
690
1122
|
};
|
|
691
1123
|
|
|
692
|
-
// src/exact/v1/client/scheme.ts
|
|
693
|
-
var import_viem4 = require("viem");
|
|
694
|
-
|
|
695
|
-
// src/v1/index.ts
|
|
696
|
-
var NETWORKS = [
|
|
697
|
-
"abstract",
|
|
698
|
-
"abstract-testnet",
|
|
699
|
-
"base-sepolia",
|
|
700
|
-
"base",
|
|
701
|
-
"avalanche-fuji",
|
|
702
|
-
"avalanche",
|
|
703
|
-
"iotex",
|
|
704
|
-
"sei",
|
|
705
|
-
"sei-testnet",
|
|
706
|
-
"polygon",
|
|
707
|
-
"polygon-amoy",
|
|
708
|
-
"peaq",
|
|
709
|
-
"story",
|
|
710
|
-
"educhain",
|
|
711
|
-
"skale-base-sepolia"
|
|
712
|
-
];
|
|
713
|
-
|
|
714
1124
|
// src/exact/facilitator/register.ts
|
|
715
1125
|
function registerExactEvmScheme(facilitator, config) {
|
|
716
1126
|
facilitator.register(
|
|
@@ -721,7 +1131,7 @@ function registerExactEvmScheme(facilitator, config) {
|
|
|
721
1131
|
);
|
|
722
1132
|
facilitator.registerV1(
|
|
723
1133
|
NETWORKS,
|
|
724
|
-
new
|
|
1134
|
+
new ExactEvmSchemeV12(config.signer, {
|
|
725
1135
|
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
|
|
726
1136
|
})
|
|
727
1137
|
);
|