@matterlabs/zksync-js 0.0.8 → 0.0.9
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/adapters/ethers/client.cjs +1640 -236
- package/dist/adapters/ethers/client.cjs.map +1 -1
- package/dist/adapters/ethers/client.d.ts +11 -0
- package/dist/adapters/ethers/client.js +5 -5
- package/dist/adapters/ethers/index.cjs +4395 -1525
- package/dist/adapters/ethers/index.cjs.map +1 -1
- package/dist/adapters/ethers/index.d.ts +4 -0
- package/dist/adapters/ethers/index.js +8 -8
- package/dist/adapters/ethers/resources/contracts/types.d.ts +15 -0
- package/dist/adapters/ethers/resources/deposits/context.d.ts +3 -3
- package/dist/adapters/ethers/resources/deposits/services/gas.d.ts +2 -2
- package/dist/adapters/ethers/resources/deposits/services/verification.d.ts +1 -1
- package/dist/adapters/ethers/resources/interop/address.d.ts +18 -0
- package/dist/adapters/ethers/resources/interop/attributes/resource.d.ts +9 -0
- package/dist/adapters/ethers/resources/interop/context.d.ts +36 -0
- package/dist/adapters/ethers/resources/interop/index.d.ts +63 -0
- package/dist/adapters/ethers/resources/interop/resolvers.d.ts +9 -0
- package/dist/adapters/ethers/resources/interop/routes/direct.d.ts +2 -0
- package/dist/adapters/ethers/resources/interop/routes/indirect.d.ts +2 -0
- package/dist/adapters/ethers/resources/interop/routes/types.d.ts +13 -0
- package/dist/adapters/ethers/resources/interop/services/erc20.d.ts +15 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/bundle.d.ts +15 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/data-fetchers.d.ts +17 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/decoders.d.ts +12 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/index.d.ts +13 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/polling.d.ts +7 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/status.d.ts +5 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/topics.d.ts +6 -0
- package/dist/adapters/ethers/resources/interop/services/starter-data.d.ts +6 -0
- package/dist/adapters/ethers/resources/interop/types.d.ts +16 -0
- package/dist/adapters/ethers/resources/withdrawals/context.d.ts +2 -2
- package/dist/adapters/ethers/sdk.cjs +3357 -917
- package/dist/adapters/ethers/sdk.cjs.map +1 -1
- package/dist/adapters/ethers/sdk.d.ts +10 -8
- package/dist/adapters/ethers/sdk.js +6 -6
- package/dist/adapters/viem/client.cjs +685 -31
- package/dist/adapters/viem/client.cjs.map +1 -1
- package/dist/adapters/viem/client.js +5 -3
- package/dist/adapters/viem/index.cjs +282 -203
- package/dist/adapters/viem/index.cjs.map +1 -1
- package/dist/adapters/viem/index.d.ts +1 -0
- package/dist/adapters/viem/index.js +8 -7
- package/dist/adapters/viem/resources/deposits/context.d.ts +3 -3
- package/dist/adapters/viem/resources/deposits/services/gas.d.ts +2 -2
- package/dist/adapters/viem/resources/deposits/services/verification.d.ts +1 -1
- package/dist/adapters/viem/resources/withdrawals/context.d.ts +2 -2
- package/dist/adapters/viem/sdk.cjs +39 -58
- package/dist/adapters/viem/sdk.cjs.map +1 -1
- package/dist/adapters/viem/sdk.js +5 -5
- package/dist/{chunk-LNIEQ7AN.js → chunk-5AG6B7UX.js} +36 -60
- package/dist/{chunk-NODVRI3E.js → chunk-AIFHAPJC.js} +8 -2
- package/dist/{chunk-3GFCAGGI.js → chunk-FBKBF7YM.js} +1533 -1434
- package/dist/{chunk-L343N56B.js → chunk-IYEDEUXG.js} +1 -1
- package/dist/chunk-JNWHQJU3.js +209 -0
- package/dist/{chunk-ODMBZ2VX.js → chunk-KLNFDFLA.js} +42 -31
- package/dist/{chunk-NVULC4JB.js → chunk-QDJOEVGJ.js} +2 -2
- package/dist/{chunk-63DNJXS3.js → chunk-RRKVUW3G.js} +1375 -75
- package/dist/{chunk-5V2JRM5J.js → chunk-SRPKTXIF.js} +1 -1
- package/dist/{chunk-SHQQI3UD.js → chunk-UIXU35ZU.js} +1 -1
- package/dist/{chunk-QZVYN3YA.js → chunk-ZVHFVUDE.js} +2 -37
- package/dist/core/index.cjs +3 -2
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +4 -4
- package/dist/core/resources/interop/attributes/types.d.ts +0 -2
- package/dist/core/resources/interop/finalization.d.ts +0 -1
- package/dist/core/types/errors.d.ts +15 -5
- package/dist/core/types/fees.d.ts +9 -0
- package/dist/core/types/flows/interop.d.ts +12 -36
- package/dist/core/types/primitives.d.ts +1 -0
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-FGXRG2JS.js +0 -142
|
@@ -10,9 +10,14 @@ var utils = require('@noble/hashes/utils');
|
|
|
10
10
|
var RegExpHex = /^0x[0-9a-fA-F]*$/;
|
|
11
11
|
var isHash = (x, length) => {
|
|
12
12
|
if (!x || typeof x !== "string") return false;
|
|
13
|
-
return (x.length === length) && RegExpHex.test(x);
|
|
13
|
+
return (length === void 0 || x.length === length) && RegExpHex.test(x);
|
|
14
|
+
};
|
|
15
|
+
var isHashArray = (x, length) => {
|
|
16
|
+
if (!Array.isArray(x)) return false;
|
|
17
|
+
return x.every((item) => isHash(item, length));
|
|
14
18
|
};
|
|
15
19
|
var isHash66 = (x) => isHash(x, 66);
|
|
20
|
+
var isHash66Array = (x) => isHashArray(x, 66);
|
|
16
21
|
var k256hex = (s) => `0x${utils.bytesToHex(sha3.keccak_256(utils.utf8ToBytes(s)))}`.toLowerCase();
|
|
17
22
|
var FORMAL_ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
18
23
|
var ETH_ADDRESS = "0x0000000000000000000000000000000000000001";
|
|
@@ -20,6 +25,9 @@ var L2_ASSET_ROUTER_ADDRESS = "0x0000000000000000000000000000000000010003";
|
|
|
20
25
|
var L2_NATIVE_TOKEN_VAULT_ADDRESS = "0x0000000000000000000000000000000000010004";
|
|
21
26
|
var L1_MESSENGER_ADDRESS = "0x0000000000000000000000000000000000008008";
|
|
22
27
|
var L2_BASE_TOKEN_ADDRESS = "0x000000000000000000000000000000000000800A";
|
|
28
|
+
var L2_INTEROP_CENTER_ADDRESS = "0x000000000000000000000000000000000001000d";
|
|
29
|
+
var L2_INTEROP_ROOT_STORAGE_ADDRESS = "0x0000000000000000000000000000000000010008";
|
|
30
|
+
var BUNDLE_IDENTIFIER = "0x01";
|
|
23
31
|
var TOPIC_L1_MESSAGE_SENT_NEW = k256hex("L1MessageSent(uint256,bytes32,bytes)");
|
|
24
32
|
var TOPIC_L1_MESSAGE_SENT_LEG = k256hex("L1MessageSent(address,bytes32,bytes)");
|
|
25
33
|
var TOPIC_CANONICAL_ASSIGNED = "0x779f441679936c5441b671969f37400b8c3ed0071cb47444431bf985754560df";
|
|
@@ -36,6 +44,9 @@ var isNumber = (x) => typeof x === "number" && Number.isFinite(x);
|
|
|
36
44
|
var isBigint = (x) => typeof x === "bigint";
|
|
37
45
|
|
|
38
46
|
// src/core/utils/addr.ts
|
|
47
|
+
function isAddress(x) {
|
|
48
|
+
return isHash(x, 42);
|
|
49
|
+
}
|
|
39
50
|
function isAddressEq(a, b) {
|
|
40
51
|
return a.toLowerCase() === b.toLowerCase();
|
|
41
52
|
}
|
|
@@ -54,6 +65,14 @@ function normalizeAddrEq(a, b) {
|
|
|
54
65
|
var hexEq = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
55
66
|
var normalizeL1Token = (token) => isAddressEq(token, FORMAL_ETH_ADDRESS) ? ETH_ADDRESS : token;
|
|
56
67
|
|
|
68
|
+
// src/core/utils/index.ts
|
|
69
|
+
function sleep(ms) {
|
|
70
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
71
|
+
}
|
|
72
|
+
function assertNever(x) {
|
|
73
|
+
throw new Error("Unexpected action type: " + String(x));
|
|
74
|
+
}
|
|
75
|
+
|
|
57
76
|
// src/core/errors/formatter.ts
|
|
58
77
|
function elideMiddle(s, max = 96) {
|
|
59
78
|
if (s.length <= max) return s;
|
|
@@ -199,12 +218,18 @@ if (kInspect) {
|
|
|
199
218
|
enumerable: false
|
|
200
219
|
});
|
|
201
220
|
}
|
|
202
|
-
function isZKsyncError(e) {
|
|
221
|
+
function isZKsyncError(e, opts) {
|
|
203
222
|
if (!e || typeof e !== "object") return false;
|
|
204
223
|
const maybe = e;
|
|
205
224
|
if (!("envelope" in maybe)) return false;
|
|
206
225
|
const envelope = maybe.envelope;
|
|
207
|
-
|
|
226
|
+
if (typeof envelope?.type !== "string" || typeof envelope?.message !== "string") return false;
|
|
227
|
+
if (opts?.type && envelope.type !== opts.type) return false;
|
|
228
|
+
if (opts?.resource && envelope.resource !== opts.resource) return false;
|
|
229
|
+
if (opts?.operation && envelope.operation !== opts.operation) return false;
|
|
230
|
+
if (opts?.messageIncludes && !envelope.message.toLowerCase().includes(opts.messageIncludes.toLowerCase()))
|
|
231
|
+
return false;
|
|
232
|
+
return true;
|
|
208
233
|
}
|
|
209
234
|
function isReceiptNotFound(e) {
|
|
210
235
|
const chain = [];
|
|
@@ -319,11 +344,9 @@ var OP_WITHDRAWALS = {
|
|
|
319
344
|
rawReceipt: "withdrawals.finalize.fetchParams:rawReceipt",
|
|
320
345
|
messengerIndex: "withdrawals.finalize.fetchParams:messengerIndex",
|
|
321
346
|
proof: "withdrawals.finalize.fetchParams:proof",
|
|
322
|
-
network: "withdrawals.finalize.fetchParams:network"
|
|
323
|
-
ensureAddresses: "withdrawals.finalize.fetchParams:ensureAddresses"
|
|
347
|
+
network: "withdrawals.finalize.fetchParams:network"
|
|
324
348
|
},
|
|
325
349
|
readiness: {
|
|
326
|
-
ensureAddresses: "withdrawals.finalize.readiness:ensureAddresses",
|
|
327
350
|
isFinalized: "withdrawals.finalize.readiness:isWithdrawalFinalized",
|
|
328
351
|
simulate: "withdrawals.finalize.readiness:simulate"
|
|
329
352
|
},
|
|
@@ -333,6 +356,54 @@ var OP_WITHDRAWALS = {
|
|
|
333
356
|
estimate: "withdrawals.finalize.estimateFinalizationFees"
|
|
334
357
|
}
|
|
335
358
|
};
|
|
359
|
+
var OP_INTEROP = {
|
|
360
|
+
// high-level flow ops (match resource methods)
|
|
361
|
+
quote: "interop.quote",
|
|
362
|
+
tryQuote: "interop.tryQuote",
|
|
363
|
+
prepare: "interop.prepare",
|
|
364
|
+
tryPrepare: "interop.tryPrepare",
|
|
365
|
+
create: "interop.create",
|
|
366
|
+
tryCreate: "interop.tryCreate",
|
|
367
|
+
status: "interop.status",
|
|
368
|
+
wait: "interop.wait",
|
|
369
|
+
tryWait: "interop.tryWait",
|
|
370
|
+
finalize: "interop.finalize",
|
|
371
|
+
tryFinalize: "interop.tryFinalize",
|
|
372
|
+
context: {
|
|
373
|
+
chainTypeManager: "interop.chainTypeManager",
|
|
374
|
+
protocolVersion: "interop.protocolVersion"
|
|
375
|
+
},
|
|
376
|
+
// route-specific ops (keep names aligned with files)
|
|
377
|
+
routes: {
|
|
378
|
+
direct: {
|
|
379
|
+
preflight: "interop.routes.direct:preflight",
|
|
380
|
+
build: "interop.routes.direct:build"
|
|
381
|
+
},
|
|
382
|
+
indirect: {
|
|
383
|
+
preflight: "interop.routes.indirect:preflight",
|
|
384
|
+
build: "interop.routes.indirect:build"
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
// execution path (nonce, gas, send, wait) – mirrors deposits’ style
|
|
388
|
+
exec: {
|
|
389
|
+
sendStep: "interop.exec:sendStep",
|
|
390
|
+
waitStep: "interop.exec:waitStep"
|
|
391
|
+
},
|
|
392
|
+
// status service (logs & derivation)
|
|
393
|
+
svc: {
|
|
394
|
+
status: {
|
|
395
|
+
sourceReceipt: "interop.svc.status:sourceReceipt",
|
|
396
|
+
parseSentLog: "interop.svc.status:parseSentLog",
|
|
397
|
+
dstLogs: "interop.svc.status:dstLogs",
|
|
398
|
+
derive: "interop.svc.status:derive",
|
|
399
|
+
getRoot: "interop.svc.status:getRoot"
|
|
400
|
+
},
|
|
401
|
+
wait: {
|
|
402
|
+
poll: "interop.svc.wait:poll",
|
|
403
|
+
timeout: "interop.svc.wait:timeout"
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
336
407
|
|
|
337
408
|
// src/core/errors/factory.ts
|
|
338
409
|
function createError(type, input) {
|
|
@@ -369,7 +440,7 @@ var I_BRIDGEHUB = new ethers.Interface([
|
|
|
369
440
|
"event NewPriorityRequest(uint256 indexed chainId, address indexed sender, bytes32 txHash, uint256 txId, bytes data)"
|
|
370
441
|
]);
|
|
371
442
|
var TOPIC_BRIDGEHUB_NPR = I_BRIDGEHUB.getEvent("NewPriorityRequest").topicHash;
|
|
372
|
-
function
|
|
443
|
+
function getL2TransactionHashFromLogs(logs) {
|
|
373
444
|
for (const lg of logs) {
|
|
374
445
|
if ((lg.topics?.[0] ?? "").toLowerCase() === TOPIC_BRIDGEHUB_NPR.toLowerCase()) {
|
|
375
446
|
try {
|
|
@@ -396,7 +467,7 @@ function extractL2TxHashFromL1Logs(logs) {
|
|
|
396
467
|
async function waitForL2ExecutionFromL1Tx(l1, l2, l1TxHash) {
|
|
397
468
|
const l1Receipt = await l1.waitForTransaction(l1TxHash);
|
|
398
469
|
if (!l1Receipt) throw new Error("No L1 receipt found");
|
|
399
|
-
const l2TxHash =
|
|
470
|
+
const l2TxHash = getL2TransactionHashFromLogs(l1Receipt.logs);
|
|
400
471
|
if (!l2TxHash) {
|
|
401
472
|
throw createError("VERIFICATION", {
|
|
402
473
|
message: "Failed to extract L2 transaction hash from L1 logs",
|
|
@@ -3193,6 +3264,63 @@ var IERC20ABI = [
|
|
|
3193
3264
|
];
|
|
3194
3265
|
var IERC20_default = IERC20ABI;
|
|
3195
3266
|
|
|
3267
|
+
// src/core/internal/abis/IERC7786Attributes.ts
|
|
3268
|
+
var IERC7786AttributesABI = [
|
|
3269
|
+
{
|
|
3270
|
+
inputs: [
|
|
3271
|
+
{
|
|
3272
|
+
internalType: "bytes",
|
|
3273
|
+
name: "_executionAddress",
|
|
3274
|
+
type: "bytes"
|
|
3275
|
+
}
|
|
3276
|
+
],
|
|
3277
|
+
name: "executionAddress",
|
|
3278
|
+
outputs: [],
|
|
3279
|
+
stateMutability: "pure",
|
|
3280
|
+
type: "function"
|
|
3281
|
+
},
|
|
3282
|
+
{
|
|
3283
|
+
inputs: [
|
|
3284
|
+
{
|
|
3285
|
+
internalType: "uint256",
|
|
3286
|
+
name: "_indirectCallMessageValue",
|
|
3287
|
+
type: "uint256"
|
|
3288
|
+
}
|
|
3289
|
+
],
|
|
3290
|
+
name: "indirectCall",
|
|
3291
|
+
outputs: [],
|
|
3292
|
+
stateMutability: "pure",
|
|
3293
|
+
type: "function"
|
|
3294
|
+
},
|
|
3295
|
+
{
|
|
3296
|
+
inputs: [
|
|
3297
|
+
{
|
|
3298
|
+
internalType: "uint256",
|
|
3299
|
+
name: "_interopCallValue",
|
|
3300
|
+
type: "uint256"
|
|
3301
|
+
}
|
|
3302
|
+
],
|
|
3303
|
+
name: "interopCallValue",
|
|
3304
|
+
outputs: [],
|
|
3305
|
+
stateMutability: "pure",
|
|
3306
|
+
type: "function"
|
|
3307
|
+
},
|
|
3308
|
+
{
|
|
3309
|
+
inputs: [
|
|
3310
|
+
{
|
|
3311
|
+
internalType: "bytes",
|
|
3312
|
+
name: "_unbundlerAddress",
|
|
3313
|
+
type: "bytes"
|
|
3314
|
+
}
|
|
3315
|
+
],
|
|
3316
|
+
name: "unbundlerAddress",
|
|
3317
|
+
outputs: [],
|
|
3318
|
+
stateMutability: "pure",
|
|
3319
|
+
type: "function"
|
|
3320
|
+
}
|
|
3321
|
+
];
|
|
3322
|
+
var IERC7786Attributes_default = IERC7786AttributesABI;
|
|
3323
|
+
|
|
3196
3324
|
// src/core/internal/abis/Mailbox.ts
|
|
3197
3325
|
var MailboxABI = [
|
|
3198
3326
|
{
|
|
@@ -3569,209 +3697,1216 @@ var MailboxABI = [
|
|
|
3569
3697
|
];
|
|
3570
3698
|
var Mailbox_default = MailboxABI;
|
|
3571
3699
|
|
|
3572
|
-
// src/
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
}
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
[
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
}
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
}
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3700
|
+
// src/core/internal/abis/InteropCenter.ts
|
|
3701
|
+
var InteropCenterABI = [
|
|
3702
|
+
{
|
|
3703
|
+
inputs: [
|
|
3704
|
+
{
|
|
3705
|
+
internalType: "bytes4",
|
|
3706
|
+
name: "selector",
|
|
3707
|
+
type: "bytes4"
|
|
3708
|
+
}
|
|
3709
|
+
],
|
|
3710
|
+
name: "AttributeAlreadySet",
|
|
3711
|
+
type: "error"
|
|
3712
|
+
},
|
|
3713
|
+
{
|
|
3714
|
+
inputs: [
|
|
3715
|
+
{
|
|
3716
|
+
internalType: "bytes4",
|
|
3717
|
+
name: "selector",
|
|
3718
|
+
type: "bytes4"
|
|
3719
|
+
},
|
|
3720
|
+
{
|
|
3721
|
+
internalType: "uint256",
|
|
3722
|
+
name: "restriction",
|
|
3723
|
+
type: "uint256"
|
|
3724
|
+
}
|
|
3725
|
+
],
|
|
3726
|
+
name: "AttributeViolatesRestriction",
|
|
3727
|
+
type: "error"
|
|
3728
|
+
},
|
|
3729
|
+
{
|
|
3730
|
+
inputs: [
|
|
3731
|
+
{
|
|
3732
|
+
internalType: "uint256",
|
|
3733
|
+
name: "expected",
|
|
3734
|
+
type: "uint256"
|
|
3735
|
+
},
|
|
3736
|
+
{
|
|
3737
|
+
internalType: "uint256",
|
|
3738
|
+
name: "actual",
|
|
3739
|
+
type: "uint256"
|
|
3740
|
+
}
|
|
3741
|
+
],
|
|
3742
|
+
name: "IndirectCallValueMismatch",
|
|
3743
|
+
type: "error"
|
|
3744
|
+
},
|
|
3745
|
+
{
|
|
3746
|
+
inputs: [
|
|
3747
|
+
{
|
|
3748
|
+
internalType: "bytes",
|
|
3749
|
+
name: "interoperableAddress",
|
|
3750
|
+
type: "bytes"
|
|
3751
|
+
}
|
|
3752
|
+
],
|
|
3753
|
+
name: "InteroperableAddressChainReferenceNotEmpty",
|
|
3754
|
+
type: "error"
|
|
3755
|
+
},
|
|
3756
|
+
{
|
|
3757
|
+
inputs: [
|
|
3758
|
+
{
|
|
3759
|
+
internalType: "bytes",
|
|
3760
|
+
name: "interoperableAddress",
|
|
3761
|
+
type: "bytes"
|
|
3762
|
+
}
|
|
3763
|
+
],
|
|
3764
|
+
name: "InteroperableAddressNotEmpty",
|
|
3765
|
+
type: "error"
|
|
3766
|
+
},
|
|
3767
|
+
{
|
|
3768
|
+
inputs: [
|
|
3769
|
+
{
|
|
3770
|
+
internalType: "bytes",
|
|
3771
|
+
name: "",
|
|
3772
|
+
type: "bytes"
|
|
3773
|
+
}
|
|
3774
|
+
],
|
|
3775
|
+
name: "InteroperableAddressParsingError",
|
|
3776
|
+
type: "error"
|
|
3777
|
+
},
|
|
3778
|
+
{
|
|
3779
|
+
inputs: [
|
|
3780
|
+
{
|
|
3781
|
+
internalType: "uint256",
|
|
3782
|
+
name: "expectedMsgValue",
|
|
3783
|
+
type: "uint256"
|
|
3784
|
+
},
|
|
3785
|
+
{
|
|
3786
|
+
internalType: "uint256",
|
|
3787
|
+
name: "providedMsgValue",
|
|
3788
|
+
type: "uint256"
|
|
3789
|
+
}
|
|
3790
|
+
],
|
|
3791
|
+
name: "MsgValueMismatch",
|
|
3792
|
+
type: "error"
|
|
3793
|
+
},
|
|
3794
|
+
{
|
|
3795
|
+
inputs: [],
|
|
3796
|
+
name: "NotInGatewayMode",
|
|
3797
|
+
type: "error"
|
|
3798
|
+
},
|
|
3799
|
+
{
|
|
3800
|
+
inputs: [
|
|
3801
|
+
{
|
|
3802
|
+
internalType: "uint256",
|
|
3803
|
+
name: "sourceChainId",
|
|
3804
|
+
type: "uint256"
|
|
3805
|
+
},
|
|
3806
|
+
{
|
|
3807
|
+
internalType: "uint256",
|
|
3808
|
+
name: "destinationChainId",
|
|
3809
|
+
type: "uint256"
|
|
3810
|
+
}
|
|
3811
|
+
],
|
|
3812
|
+
name: "NotL2ToL2",
|
|
3813
|
+
type: "error"
|
|
3814
|
+
},
|
|
3815
|
+
{
|
|
3816
|
+
inputs: [],
|
|
3817
|
+
name: "SlotOccupied",
|
|
3818
|
+
type: "error"
|
|
3819
|
+
},
|
|
3820
|
+
{
|
|
3821
|
+
inputs: [
|
|
3822
|
+
{
|
|
3823
|
+
internalType: "address",
|
|
3824
|
+
name: "caller",
|
|
3825
|
+
type: "address"
|
|
3826
|
+
}
|
|
3827
|
+
],
|
|
3828
|
+
name: "Unauthorized",
|
|
3829
|
+
type: "error"
|
|
3830
|
+
},
|
|
3831
|
+
{
|
|
3832
|
+
inputs: [
|
|
3833
|
+
{
|
|
3834
|
+
internalType: "bytes4",
|
|
3835
|
+
name: "selector",
|
|
3836
|
+
type: "bytes4"
|
|
3837
|
+
}
|
|
3838
|
+
],
|
|
3839
|
+
name: "UnsupportedAttribute",
|
|
3840
|
+
type: "error"
|
|
3841
|
+
},
|
|
3842
|
+
{
|
|
3843
|
+
anonymous: false,
|
|
3844
|
+
inputs: [
|
|
3845
|
+
{
|
|
3846
|
+
indexed: false,
|
|
3847
|
+
internalType: "uint8",
|
|
3848
|
+
name: "version",
|
|
3849
|
+
type: "uint8"
|
|
3850
|
+
}
|
|
3851
|
+
],
|
|
3852
|
+
name: "Initialized",
|
|
3853
|
+
type: "event"
|
|
3854
|
+
},
|
|
3855
|
+
{
|
|
3856
|
+
anonymous: false,
|
|
3857
|
+
inputs: [
|
|
3858
|
+
{
|
|
3859
|
+
indexed: false,
|
|
3860
|
+
internalType: "bytes32",
|
|
3861
|
+
name: "l2l1MsgHash",
|
|
3862
|
+
type: "bytes32"
|
|
3863
|
+
},
|
|
3864
|
+
{
|
|
3865
|
+
indexed: false,
|
|
3866
|
+
internalType: "bytes32",
|
|
3867
|
+
name: "interopBundleHash",
|
|
3868
|
+
type: "bytes32"
|
|
3869
|
+
},
|
|
3870
|
+
{
|
|
3871
|
+
components: [
|
|
3872
|
+
{
|
|
3873
|
+
internalType: "bytes1",
|
|
3874
|
+
name: "version",
|
|
3875
|
+
type: "bytes1"
|
|
3876
|
+
},
|
|
3877
|
+
{
|
|
3878
|
+
internalType: "uint256",
|
|
3879
|
+
name: "sourceChainId",
|
|
3880
|
+
type: "uint256"
|
|
3881
|
+
},
|
|
3882
|
+
{
|
|
3883
|
+
internalType: "uint256",
|
|
3884
|
+
name: "destinationChainId",
|
|
3885
|
+
type: "uint256"
|
|
3886
|
+
},
|
|
3887
|
+
{
|
|
3888
|
+
internalType: "bytes32",
|
|
3889
|
+
name: "interopBundleSalt",
|
|
3890
|
+
type: "bytes32"
|
|
3891
|
+
},
|
|
3892
|
+
{
|
|
3893
|
+
components: [
|
|
3894
|
+
{
|
|
3895
|
+
internalType: "bytes1",
|
|
3896
|
+
name: "version",
|
|
3897
|
+
type: "bytes1"
|
|
3898
|
+
},
|
|
3899
|
+
{
|
|
3900
|
+
internalType: "bool",
|
|
3901
|
+
name: "shadowAccount",
|
|
3902
|
+
type: "bool"
|
|
3903
|
+
},
|
|
3904
|
+
{
|
|
3905
|
+
internalType: "address",
|
|
3906
|
+
name: "to",
|
|
3907
|
+
type: "address"
|
|
3908
|
+
},
|
|
3909
|
+
{
|
|
3910
|
+
internalType: "address",
|
|
3911
|
+
name: "from",
|
|
3912
|
+
type: "address"
|
|
3913
|
+
},
|
|
3914
|
+
{
|
|
3915
|
+
internalType: "uint256",
|
|
3916
|
+
name: "value",
|
|
3917
|
+
type: "uint256"
|
|
3918
|
+
},
|
|
3919
|
+
{
|
|
3920
|
+
internalType: "bytes",
|
|
3921
|
+
name: "data",
|
|
3922
|
+
type: "bytes"
|
|
3923
|
+
}
|
|
3924
|
+
],
|
|
3925
|
+
internalType: "struct InteropCall[]",
|
|
3926
|
+
name: "calls",
|
|
3927
|
+
type: "tuple[]"
|
|
3928
|
+
},
|
|
3929
|
+
{
|
|
3930
|
+
components: [
|
|
3931
|
+
{
|
|
3932
|
+
internalType: "bytes",
|
|
3933
|
+
name: "executionAddress",
|
|
3934
|
+
type: "bytes"
|
|
3935
|
+
},
|
|
3936
|
+
{
|
|
3937
|
+
internalType: "bytes",
|
|
3938
|
+
name: "unbundlerAddress",
|
|
3939
|
+
type: "bytes"
|
|
3940
|
+
}
|
|
3941
|
+
],
|
|
3942
|
+
internalType: "struct BundleAttributes",
|
|
3943
|
+
name: "bundleAttributes",
|
|
3944
|
+
type: "tuple"
|
|
3945
|
+
}
|
|
3946
|
+
],
|
|
3947
|
+
indexed: false,
|
|
3948
|
+
internalType: "struct InteropBundle",
|
|
3949
|
+
name: "interopBundle",
|
|
3950
|
+
type: "tuple"
|
|
3951
|
+
}
|
|
3952
|
+
],
|
|
3953
|
+
name: "InteropBundleSent",
|
|
3954
|
+
type: "event"
|
|
3955
|
+
},
|
|
3956
|
+
{
|
|
3957
|
+
anonymous: false,
|
|
3958
|
+
inputs: [
|
|
3959
|
+
{
|
|
3960
|
+
indexed: true,
|
|
3961
|
+
internalType: "bytes32",
|
|
3962
|
+
name: "sendId",
|
|
3963
|
+
type: "bytes32"
|
|
3964
|
+
},
|
|
3965
|
+
{
|
|
3966
|
+
indexed: false,
|
|
3967
|
+
internalType: "bytes",
|
|
3968
|
+
name: "sender",
|
|
3969
|
+
type: "bytes"
|
|
3970
|
+
},
|
|
3971
|
+
{
|
|
3972
|
+
indexed: false,
|
|
3973
|
+
internalType: "bytes",
|
|
3974
|
+
name: "recipient",
|
|
3975
|
+
type: "bytes"
|
|
3976
|
+
},
|
|
3977
|
+
{
|
|
3978
|
+
indexed: false,
|
|
3979
|
+
internalType: "bytes",
|
|
3980
|
+
name: "payload",
|
|
3981
|
+
type: "bytes"
|
|
3982
|
+
},
|
|
3983
|
+
{
|
|
3984
|
+
indexed: false,
|
|
3985
|
+
internalType: "uint256",
|
|
3986
|
+
name: "value",
|
|
3987
|
+
type: "uint256"
|
|
3988
|
+
},
|
|
3989
|
+
{
|
|
3990
|
+
indexed: false,
|
|
3991
|
+
internalType: "bytes[]",
|
|
3992
|
+
name: "attributes",
|
|
3993
|
+
type: "bytes[]"
|
|
3994
|
+
}
|
|
3995
|
+
],
|
|
3996
|
+
name: "MessageSent",
|
|
3997
|
+
type: "event"
|
|
3998
|
+
},
|
|
3999
|
+
{
|
|
4000
|
+
anonymous: false,
|
|
4001
|
+
inputs: [
|
|
4002
|
+
{
|
|
4003
|
+
indexed: true,
|
|
4004
|
+
internalType: "address",
|
|
4005
|
+
name: "oldAssetRouter",
|
|
4006
|
+
type: "address"
|
|
4007
|
+
},
|
|
4008
|
+
{
|
|
4009
|
+
indexed: true,
|
|
4010
|
+
internalType: "address",
|
|
4011
|
+
name: "newAssetRouter",
|
|
4012
|
+
type: "address"
|
|
4013
|
+
}
|
|
4014
|
+
],
|
|
4015
|
+
name: "NewAssetRouter",
|
|
4016
|
+
type: "event"
|
|
4017
|
+
},
|
|
4018
|
+
{
|
|
4019
|
+
anonymous: false,
|
|
4020
|
+
inputs: [
|
|
4021
|
+
{
|
|
4022
|
+
indexed: true,
|
|
4023
|
+
internalType: "address",
|
|
4024
|
+
name: "oldAssetTracker",
|
|
4025
|
+
type: "address"
|
|
4026
|
+
},
|
|
4027
|
+
{
|
|
4028
|
+
indexed: true,
|
|
4029
|
+
internalType: "address",
|
|
4030
|
+
name: "newAssetTracker",
|
|
4031
|
+
type: "address"
|
|
4032
|
+
}
|
|
4033
|
+
],
|
|
4034
|
+
name: "NewAssetTracker",
|
|
4035
|
+
type: "event"
|
|
4036
|
+
},
|
|
4037
|
+
{
|
|
4038
|
+
anonymous: false,
|
|
4039
|
+
inputs: [
|
|
4040
|
+
{
|
|
4041
|
+
indexed: true,
|
|
4042
|
+
internalType: "address",
|
|
4043
|
+
name: "previousOwner",
|
|
4044
|
+
type: "address"
|
|
4045
|
+
},
|
|
4046
|
+
{
|
|
4047
|
+
indexed: true,
|
|
4048
|
+
internalType: "address",
|
|
4049
|
+
name: "newOwner",
|
|
4050
|
+
type: "address"
|
|
4051
|
+
}
|
|
4052
|
+
],
|
|
4053
|
+
name: "OwnershipTransferStarted",
|
|
4054
|
+
type: "event"
|
|
4055
|
+
},
|
|
4056
|
+
{
|
|
4057
|
+
anonymous: false,
|
|
4058
|
+
inputs: [
|
|
4059
|
+
{
|
|
4060
|
+
indexed: true,
|
|
4061
|
+
internalType: "address",
|
|
4062
|
+
name: "previousOwner",
|
|
4063
|
+
type: "address"
|
|
4064
|
+
},
|
|
4065
|
+
{
|
|
4066
|
+
indexed: true,
|
|
4067
|
+
internalType: "address",
|
|
4068
|
+
name: "newOwner",
|
|
4069
|
+
type: "address"
|
|
4070
|
+
}
|
|
4071
|
+
],
|
|
4072
|
+
name: "OwnershipTransferred",
|
|
4073
|
+
type: "event"
|
|
4074
|
+
},
|
|
4075
|
+
{
|
|
4076
|
+
anonymous: false,
|
|
4077
|
+
inputs: [
|
|
4078
|
+
{
|
|
4079
|
+
indexed: false,
|
|
4080
|
+
internalType: "address",
|
|
4081
|
+
name: "account",
|
|
4082
|
+
type: "address"
|
|
4083
|
+
}
|
|
4084
|
+
],
|
|
4085
|
+
name: "Paused",
|
|
4086
|
+
type: "event"
|
|
4087
|
+
},
|
|
4088
|
+
{
|
|
4089
|
+
anonymous: false,
|
|
4090
|
+
inputs: [
|
|
4091
|
+
{
|
|
4092
|
+
indexed: false,
|
|
4093
|
+
internalType: "address",
|
|
4094
|
+
name: "account",
|
|
4095
|
+
type: "address"
|
|
4096
|
+
}
|
|
4097
|
+
],
|
|
4098
|
+
name: "Unpaused",
|
|
4099
|
+
type: "event"
|
|
4100
|
+
},
|
|
4101
|
+
{
|
|
4102
|
+
inputs: [],
|
|
4103
|
+
name: "L1_CHAIN_ID",
|
|
4104
|
+
outputs: [
|
|
4105
|
+
{
|
|
4106
|
+
internalType: "uint256",
|
|
4107
|
+
name: "",
|
|
4108
|
+
type: "uint256"
|
|
4109
|
+
}
|
|
4110
|
+
],
|
|
4111
|
+
stateMutability: "view",
|
|
4112
|
+
type: "function"
|
|
4113
|
+
},
|
|
4114
|
+
{
|
|
4115
|
+
inputs: [],
|
|
4116
|
+
name: "acceptOwnership",
|
|
4117
|
+
outputs: [],
|
|
4118
|
+
stateMutability: "nonpayable",
|
|
4119
|
+
type: "function"
|
|
4120
|
+
},
|
|
4121
|
+
{
|
|
4122
|
+
inputs: [
|
|
4123
|
+
{
|
|
4124
|
+
internalType: "uint256",
|
|
4125
|
+
name: "_chainId",
|
|
4126
|
+
type: "uint256"
|
|
4127
|
+
},
|
|
4128
|
+
{
|
|
4129
|
+
internalType: "bytes32",
|
|
4130
|
+
name: "_canonicalTxHash",
|
|
4131
|
+
type: "bytes32"
|
|
4132
|
+
},
|
|
4133
|
+
{
|
|
4134
|
+
internalType: "uint64",
|
|
4135
|
+
name: "_expirationTimestamp",
|
|
4136
|
+
type: "uint64"
|
|
4137
|
+
},
|
|
4138
|
+
{
|
|
4139
|
+
components: [
|
|
4140
|
+
{
|
|
4141
|
+
internalType: "bytes1",
|
|
4142
|
+
name: "version",
|
|
4143
|
+
type: "bytes1"
|
|
4144
|
+
},
|
|
4145
|
+
{
|
|
4146
|
+
internalType: "address",
|
|
4147
|
+
name: "originToken",
|
|
4148
|
+
type: "address"
|
|
4149
|
+
},
|
|
4150
|
+
{
|
|
4151
|
+
internalType: "bytes32",
|
|
4152
|
+
name: "baseTokenAssetId",
|
|
4153
|
+
type: "bytes32"
|
|
4154
|
+
},
|
|
4155
|
+
{
|
|
4156
|
+
internalType: "uint256",
|
|
4157
|
+
name: "baseTokenAmount",
|
|
4158
|
+
type: "uint256"
|
|
4159
|
+
},
|
|
4160
|
+
{
|
|
4161
|
+
internalType: "bytes32",
|
|
4162
|
+
name: "assetId",
|
|
4163
|
+
type: "bytes32"
|
|
4164
|
+
},
|
|
4165
|
+
{
|
|
4166
|
+
internalType: "uint256",
|
|
4167
|
+
name: "amount",
|
|
4168
|
+
type: "uint256"
|
|
4169
|
+
},
|
|
4170
|
+
{
|
|
4171
|
+
internalType: "uint256",
|
|
4172
|
+
name: "tokenOriginChainId",
|
|
4173
|
+
type: "uint256"
|
|
4174
|
+
}
|
|
4175
|
+
],
|
|
4176
|
+
internalType: "struct BalanceChange",
|
|
4177
|
+
name: "_balanceChange",
|
|
4178
|
+
type: "tuple"
|
|
4179
|
+
}
|
|
4180
|
+
],
|
|
4181
|
+
name: "forwardTransactionOnGatewayWithBalanceChange",
|
|
4182
|
+
outputs: [],
|
|
4183
|
+
stateMutability: "nonpayable",
|
|
4184
|
+
type: "function"
|
|
4185
|
+
},
|
|
4186
|
+
{
|
|
4187
|
+
inputs: [
|
|
4188
|
+
{
|
|
4189
|
+
internalType: "uint256",
|
|
4190
|
+
name: "_l1ChainId",
|
|
4191
|
+
type: "uint256"
|
|
4192
|
+
},
|
|
4193
|
+
{
|
|
4194
|
+
internalType: "address",
|
|
4195
|
+
name: "_owner",
|
|
4196
|
+
type: "address"
|
|
4197
|
+
}
|
|
4198
|
+
],
|
|
4199
|
+
name: "initL2",
|
|
4200
|
+
outputs: [],
|
|
4201
|
+
stateMutability: "nonpayable",
|
|
4202
|
+
type: "function"
|
|
4203
|
+
},
|
|
4204
|
+
{
|
|
4205
|
+
inputs: [
|
|
4206
|
+
{
|
|
4207
|
+
internalType: "address",
|
|
4208
|
+
name: "sender",
|
|
4209
|
+
type: "address"
|
|
4210
|
+
}
|
|
4211
|
+
],
|
|
4212
|
+
name: "interopBundleNonce",
|
|
4213
|
+
outputs: [
|
|
4214
|
+
{
|
|
4215
|
+
internalType: "uint256",
|
|
4216
|
+
name: "numberOfBundlesSent",
|
|
4217
|
+
type: "uint256"
|
|
4218
|
+
}
|
|
4219
|
+
],
|
|
4220
|
+
stateMutability: "view",
|
|
4221
|
+
type: "function"
|
|
4222
|
+
},
|
|
4223
|
+
{
|
|
4224
|
+
inputs: [],
|
|
4225
|
+
name: "owner",
|
|
4226
|
+
outputs: [
|
|
4227
|
+
{
|
|
4228
|
+
internalType: "address",
|
|
4229
|
+
name: "",
|
|
4230
|
+
type: "address"
|
|
4231
|
+
}
|
|
4232
|
+
],
|
|
4233
|
+
stateMutability: "view",
|
|
4234
|
+
type: "function"
|
|
4235
|
+
},
|
|
4236
|
+
{
|
|
4237
|
+
inputs: [
|
|
4238
|
+
{
|
|
4239
|
+
internalType: "bytes[]",
|
|
4240
|
+
name: "_attributes",
|
|
4241
|
+
type: "bytes[]"
|
|
4242
|
+
},
|
|
4243
|
+
{
|
|
4244
|
+
internalType: "enum IInteropCenter.AttributeParsingRestrictions",
|
|
4245
|
+
name: "_restriction",
|
|
4246
|
+
type: "uint8"
|
|
4247
|
+
}
|
|
4248
|
+
],
|
|
4249
|
+
name: "parseAttributes",
|
|
4250
|
+
outputs: [
|
|
4251
|
+
{
|
|
4252
|
+
components: [
|
|
4253
|
+
{
|
|
4254
|
+
internalType: "uint256",
|
|
4255
|
+
name: "interopCallValue",
|
|
4256
|
+
type: "uint256"
|
|
4257
|
+
},
|
|
4258
|
+
{
|
|
4259
|
+
internalType: "bool",
|
|
4260
|
+
name: "indirectCall",
|
|
4261
|
+
type: "bool"
|
|
4262
|
+
},
|
|
4263
|
+
{
|
|
4264
|
+
internalType: "uint256",
|
|
4265
|
+
name: "indirectCallMessageValue",
|
|
4266
|
+
type: "uint256"
|
|
4267
|
+
}
|
|
4268
|
+
],
|
|
4269
|
+
internalType: "struct CallAttributes",
|
|
4270
|
+
name: "callAttributes",
|
|
4271
|
+
type: "tuple"
|
|
4272
|
+
},
|
|
4273
|
+
{
|
|
4274
|
+
components: [
|
|
4275
|
+
{
|
|
4276
|
+
internalType: "bytes",
|
|
4277
|
+
name: "executionAddress",
|
|
4278
|
+
type: "bytes"
|
|
4279
|
+
},
|
|
4280
|
+
{
|
|
4281
|
+
internalType: "bytes",
|
|
4282
|
+
name: "unbundlerAddress",
|
|
4283
|
+
type: "bytes"
|
|
4284
|
+
}
|
|
4285
|
+
],
|
|
4286
|
+
internalType: "struct BundleAttributes",
|
|
4287
|
+
name: "bundleAttributes",
|
|
4288
|
+
type: "tuple"
|
|
4289
|
+
}
|
|
4290
|
+
],
|
|
4291
|
+
stateMutability: "pure",
|
|
4292
|
+
type: "function"
|
|
4293
|
+
},
|
|
4294
|
+
{
|
|
4295
|
+
inputs: [],
|
|
4296
|
+
name: "pause",
|
|
4297
|
+
outputs: [],
|
|
4298
|
+
stateMutability: "nonpayable",
|
|
4299
|
+
type: "function"
|
|
4300
|
+
},
|
|
4301
|
+
{
|
|
4302
|
+
inputs: [],
|
|
4303
|
+
name: "paused",
|
|
4304
|
+
outputs: [
|
|
4305
|
+
{
|
|
4306
|
+
internalType: "bool",
|
|
4307
|
+
name: "",
|
|
4308
|
+
type: "bool"
|
|
4309
|
+
}
|
|
4310
|
+
],
|
|
4311
|
+
stateMutability: "view",
|
|
4312
|
+
type: "function"
|
|
4313
|
+
},
|
|
4314
|
+
{
|
|
4315
|
+
inputs: [],
|
|
4316
|
+
name: "pendingOwner",
|
|
4317
|
+
outputs: [
|
|
4318
|
+
{
|
|
4319
|
+
internalType: "address",
|
|
4320
|
+
name: "",
|
|
4321
|
+
type: "address"
|
|
4322
|
+
}
|
|
4323
|
+
],
|
|
4324
|
+
stateMutability: "view",
|
|
4325
|
+
type: "function"
|
|
4326
|
+
},
|
|
4327
|
+
{
|
|
4328
|
+
inputs: [],
|
|
4329
|
+
name: "renounceOwnership",
|
|
4330
|
+
outputs: [],
|
|
4331
|
+
stateMutability: "nonpayable",
|
|
4332
|
+
type: "function"
|
|
4333
|
+
},
|
|
4334
|
+
{
|
|
4335
|
+
inputs: [
|
|
4336
|
+
{
|
|
4337
|
+
internalType: "bytes",
|
|
4338
|
+
name: "_destinationChainId",
|
|
4339
|
+
type: "bytes"
|
|
4340
|
+
},
|
|
4341
|
+
{
|
|
4342
|
+
components: [
|
|
4343
|
+
{
|
|
4344
|
+
internalType: "bytes",
|
|
4345
|
+
name: "to",
|
|
4346
|
+
type: "bytes"
|
|
4347
|
+
},
|
|
4348
|
+
{
|
|
4349
|
+
internalType: "bytes",
|
|
4350
|
+
name: "data",
|
|
4351
|
+
type: "bytes"
|
|
4352
|
+
},
|
|
4353
|
+
{
|
|
4354
|
+
internalType: "bytes[]",
|
|
4355
|
+
name: "callAttributes",
|
|
4356
|
+
type: "bytes[]"
|
|
4357
|
+
}
|
|
4358
|
+
],
|
|
4359
|
+
internalType: "struct InteropCallStarter[]",
|
|
4360
|
+
name: "_callStarters",
|
|
4361
|
+
type: "tuple[]"
|
|
4362
|
+
},
|
|
4363
|
+
{
|
|
4364
|
+
internalType: "bytes[]",
|
|
4365
|
+
name: "_bundleAttributes",
|
|
4366
|
+
type: "bytes[]"
|
|
4367
|
+
}
|
|
4368
|
+
],
|
|
4369
|
+
name: "sendBundle",
|
|
4370
|
+
outputs: [
|
|
4371
|
+
{
|
|
4372
|
+
internalType: "bytes32",
|
|
4373
|
+
name: "bundleHash",
|
|
4374
|
+
type: "bytes32"
|
|
4375
|
+
}
|
|
4376
|
+
],
|
|
4377
|
+
stateMutability: "payable",
|
|
4378
|
+
type: "function"
|
|
4379
|
+
},
|
|
4380
|
+
{
|
|
4381
|
+
inputs: [
|
|
4382
|
+
{
|
|
4383
|
+
internalType: "bytes",
|
|
4384
|
+
name: "recipient",
|
|
4385
|
+
type: "bytes"
|
|
4386
|
+
},
|
|
4387
|
+
{
|
|
4388
|
+
internalType: "bytes",
|
|
4389
|
+
name: "payload",
|
|
4390
|
+
type: "bytes"
|
|
4391
|
+
},
|
|
4392
|
+
{
|
|
4393
|
+
internalType: "bytes[]",
|
|
4394
|
+
name: "attributes",
|
|
4395
|
+
type: "bytes[]"
|
|
4396
|
+
}
|
|
4397
|
+
],
|
|
4398
|
+
name: "sendMessage",
|
|
4399
|
+
outputs: [
|
|
4400
|
+
{
|
|
4401
|
+
internalType: "bytes32",
|
|
4402
|
+
name: "sendId",
|
|
4403
|
+
type: "bytes32"
|
|
4404
|
+
}
|
|
4405
|
+
],
|
|
4406
|
+
stateMutability: "payable",
|
|
4407
|
+
type: "function"
|
|
4408
|
+
},
|
|
4409
|
+
{
|
|
4410
|
+
inputs: [
|
|
4411
|
+
{
|
|
4412
|
+
internalType: "bytes4",
|
|
4413
|
+
name: "_attributeSelector",
|
|
4414
|
+
type: "bytes4"
|
|
4415
|
+
}
|
|
4416
|
+
],
|
|
4417
|
+
name: "supportsAttribute",
|
|
4418
|
+
outputs: [
|
|
4419
|
+
{
|
|
4420
|
+
internalType: "bool",
|
|
4421
|
+
name: "",
|
|
4422
|
+
type: "bool"
|
|
4423
|
+
}
|
|
4424
|
+
],
|
|
4425
|
+
stateMutability: "pure",
|
|
4426
|
+
type: "function"
|
|
4427
|
+
},
|
|
4428
|
+
{
|
|
4429
|
+
inputs: [
|
|
4430
|
+
{
|
|
4431
|
+
internalType: "address",
|
|
4432
|
+
name: "newOwner",
|
|
4433
|
+
type: "address"
|
|
4434
|
+
}
|
|
4435
|
+
],
|
|
4436
|
+
name: "transferOwnership",
|
|
4437
|
+
outputs: [],
|
|
4438
|
+
stateMutability: "nonpayable",
|
|
4439
|
+
type: "function"
|
|
4440
|
+
},
|
|
4441
|
+
{
|
|
4442
|
+
inputs: [],
|
|
4443
|
+
name: "unpause",
|
|
4444
|
+
outputs: [],
|
|
4445
|
+
stateMutability: "nonpayable",
|
|
4446
|
+
type: "function"
|
|
4447
|
+
}
|
|
4448
|
+
];
|
|
4449
|
+
var InteropCenter_default = InteropCenterABI;
|
|
4450
|
+
|
|
4451
|
+
// src/core/internal/abis/IInteropHandler.ts
|
|
4452
|
+
var IInteropHandlerABI = [
|
|
4453
|
+
{
|
|
4454
|
+
anonymous: false,
|
|
4455
|
+
inputs: [
|
|
4456
|
+
{
|
|
4457
|
+
indexed: true,
|
|
4458
|
+
internalType: "bytes32",
|
|
4459
|
+
name: "bundleHash",
|
|
4460
|
+
type: "bytes32"
|
|
4461
|
+
}
|
|
4462
|
+
],
|
|
4463
|
+
name: "BundleExecuted",
|
|
4464
|
+
type: "event"
|
|
4465
|
+
},
|
|
4466
|
+
{
|
|
4467
|
+
anonymous: false,
|
|
4468
|
+
inputs: [
|
|
4469
|
+
{
|
|
4470
|
+
indexed: true,
|
|
4471
|
+
internalType: "bytes32",
|
|
4472
|
+
name: "bundleHash",
|
|
4473
|
+
type: "bytes32"
|
|
4474
|
+
}
|
|
4475
|
+
],
|
|
4476
|
+
name: "BundleUnbundled",
|
|
4477
|
+
type: "event"
|
|
4478
|
+
},
|
|
4479
|
+
{
|
|
4480
|
+
anonymous: false,
|
|
4481
|
+
inputs: [
|
|
4482
|
+
{
|
|
4483
|
+
indexed: true,
|
|
4484
|
+
internalType: "bytes32",
|
|
4485
|
+
name: "bundleHash",
|
|
4486
|
+
type: "bytes32"
|
|
4487
|
+
}
|
|
4488
|
+
],
|
|
4489
|
+
name: "BundleVerified",
|
|
4490
|
+
type: "event"
|
|
4491
|
+
},
|
|
4492
|
+
{
|
|
4493
|
+
anonymous: false,
|
|
4494
|
+
inputs: [
|
|
4495
|
+
{
|
|
4496
|
+
indexed: true,
|
|
4497
|
+
internalType: "bytes32",
|
|
4498
|
+
name: "bundleHash",
|
|
4499
|
+
type: "bytes32"
|
|
4500
|
+
},
|
|
4501
|
+
{
|
|
4502
|
+
indexed: true,
|
|
4503
|
+
internalType: "uint256",
|
|
4504
|
+
name: "callIndex",
|
|
4505
|
+
type: "uint256"
|
|
4506
|
+
},
|
|
4507
|
+
{
|
|
4508
|
+
indexed: false,
|
|
4509
|
+
internalType: "enum CallStatus",
|
|
4510
|
+
name: "status",
|
|
4511
|
+
type: "uint8"
|
|
4512
|
+
}
|
|
4513
|
+
],
|
|
4514
|
+
name: "CallProcessed",
|
|
4515
|
+
type: "event"
|
|
4516
|
+
},
|
|
4517
|
+
{
|
|
4518
|
+
inputs: [
|
|
4519
|
+
{
|
|
4520
|
+
internalType: "bytes",
|
|
4521
|
+
name: "_bundle",
|
|
4522
|
+
type: "bytes"
|
|
4523
|
+
},
|
|
4524
|
+
{
|
|
4525
|
+
components: [
|
|
4526
|
+
{
|
|
4527
|
+
internalType: "uint256",
|
|
4528
|
+
name: "chainId",
|
|
4529
|
+
type: "uint256"
|
|
4530
|
+
},
|
|
4531
|
+
{
|
|
4532
|
+
internalType: "uint256",
|
|
4533
|
+
name: "l1BatchNumber",
|
|
4534
|
+
type: "uint256"
|
|
4535
|
+
},
|
|
4536
|
+
{
|
|
4537
|
+
internalType: "uint256",
|
|
4538
|
+
name: "l2MessageIndex",
|
|
4539
|
+
type: "uint256"
|
|
4540
|
+
},
|
|
4541
|
+
{
|
|
4542
|
+
components: [
|
|
4543
|
+
{
|
|
4544
|
+
internalType: "uint16",
|
|
4545
|
+
name: "txNumberInBatch",
|
|
4546
|
+
type: "uint16"
|
|
4547
|
+
},
|
|
4548
|
+
{
|
|
4549
|
+
internalType: "address",
|
|
4550
|
+
name: "sender",
|
|
4551
|
+
type: "address"
|
|
4552
|
+
},
|
|
4553
|
+
{
|
|
4554
|
+
internalType: "bytes",
|
|
4555
|
+
name: "data",
|
|
4556
|
+
type: "bytes"
|
|
4557
|
+
}
|
|
4558
|
+
],
|
|
4559
|
+
internalType: "struct L2Message",
|
|
4560
|
+
name: "message",
|
|
4561
|
+
type: "tuple"
|
|
4562
|
+
},
|
|
4563
|
+
{
|
|
4564
|
+
internalType: "bytes32[]",
|
|
4565
|
+
name: "proof",
|
|
4566
|
+
type: "bytes32[]"
|
|
4567
|
+
}
|
|
4568
|
+
],
|
|
4569
|
+
internalType: "struct MessageInclusionProof",
|
|
4570
|
+
name: "_proof",
|
|
4571
|
+
type: "tuple"
|
|
4572
|
+
}
|
|
4573
|
+
],
|
|
4574
|
+
name: "executeBundle",
|
|
4575
|
+
outputs: [],
|
|
4576
|
+
stateMutability: "nonpayable",
|
|
4577
|
+
type: "function"
|
|
4578
|
+
},
|
|
4579
|
+
{
|
|
4580
|
+
inputs: [
|
|
4581
|
+
{
|
|
4582
|
+
internalType: "uint256",
|
|
4583
|
+
name: "_sourceChainId",
|
|
4584
|
+
type: "uint256"
|
|
4585
|
+
},
|
|
4586
|
+
{
|
|
4587
|
+
internalType: "bytes",
|
|
4588
|
+
name: "_bundle",
|
|
4589
|
+
type: "bytes"
|
|
4590
|
+
},
|
|
4591
|
+
{
|
|
4592
|
+
internalType: "enum CallStatus[]",
|
|
4593
|
+
name: "_callStatus",
|
|
4594
|
+
type: "uint8[]"
|
|
4595
|
+
}
|
|
4596
|
+
],
|
|
4597
|
+
name: "unbundleBundle",
|
|
4598
|
+
outputs: [],
|
|
4599
|
+
stateMutability: "nonpayable",
|
|
4600
|
+
type: "function"
|
|
4601
|
+
},
|
|
4602
|
+
{
|
|
4603
|
+
inputs: [
|
|
4604
|
+
{
|
|
4605
|
+
internalType: "bytes",
|
|
4606
|
+
name: "_bundle",
|
|
4607
|
+
type: "bytes"
|
|
4608
|
+
},
|
|
4609
|
+
{
|
|
4610
|
+
components: [
|
|
4611
|
+
{
|
|
4612
|
+
internalType: "uint256",
|
|
4613
|
+
name: "chainId",
|
|
4614
|
+
type: "uint256"
|
|
4615
|
+
},
|
|
4616
|
+
{
|
|
4617
|
+
internalType: "uint256",
|
|
4618
|
+
name: "l1BatchNumber",
|
|
4619
|
+
type: "uint256"
|
|
4620
|
+
},
|
|
4621
|
+
{
|
|
4622
|
+
internalType: "uint256",
|
|
4623
|
+
name: "l2MessageIndex",
|
|
4624
|
+
type: "uint256"
|
|
4625
|
+
},
|
|
4626
|
+
{
|
|
4627
|
+
components: [
|
|
4628
|
+
{
|
|
4629
|
+
internalType: "uint16",
|
|
4630
|
+
name: "txNumberInBatch",
|
|
4631
|
+
type: "uint16"
|
|
4632
|
+
},
|
|
4633
|
+
{
|
|
4634
|
+
internalType: "address",
|
|
4635
|
+
name: "sender",
|
|
4636
|
+
type: "address"
|
|
4637
|
+
},
|
|
4638
|
+
{
|
|
4639
|
+
internalType: "bytes",
|
|
4640
|
+
name: "data",
|
|
4641
|
+
type: "bytes"
|
|
4642
|
+
}
|
|
4643
|
+
],
|
|
4644
|
+
internalType: "struct L2Message",
|
|
4645
|
+
name: "message",
|
|
4646
|
+
type: "tuple"
|
|
4647
|
+
},
|
|
4648
|
+
{
|
|
4649
|
+
internalType: "bytes32[]",
|
|
4650
|
+
name: "proof",
|
|
4651
|
+
type: "bytes32[]"
|
|
4652
|
+
}
|
|
4653
|
+
],
|
|
4654
|
+
internalType: "struct MessageInclusionProof",
|
|
4655
|
+
name: "_proof",
|
|
4656
|
+
type: "tuple"
|
|
4657
|
+
}
|
|
4658
|
+
],
|
|
4659
|
+
name: "verifyBundle",
|
|
4660
|
+
outputs: [],
|
|
4661
|
+
stateMutability: "nonpayable",
|
|
4662
|
+
type: "function"
|
|
4663
|
+
}
|
|
4664
|
+
];
|
|
4665
|
+
var IInteropHandler_default = IInteropHandlerABI;
|
|
4666
|
+
|
|
4667
|
+
// src/core/internal/abis/InteropRootStorage.ts
|
|
4668
|
+
var InteropRootStorageABI = [
|
|
4669
|
+
{
|
|
4670
|
+
inputs: [
|
|
4671
|
+
{
|
|
4672
|
+
internalType: "uint256",
|
|
4673
|
+
name: "chainId",
|
|
4674
|
+
type: "uint256"
|
|
4675
|
+
},
|
|
4676
|
+
{
|
|
4677
|
+
internalType: "uint256",
|
|
4678
|
+
name: "batchNumber",
|
|
4679
|
+
type: "uint256"
|
|
4680
|
+
}
|
|
4681
|
+
],
|
|
4682
|
+
name: "interopRoots",
|
|
4683
|
+
outputs: [
|
|
4684
|
+
{
|
|
4685
|
+
internalType: "bytes32",
|
|
4686
|
+
name: "",
|
|
4687
|
+
type: "bytes32"
|
|
4688
|
+
}
|
|
4689
|
+
],
|
|
4690
|
+
stateMutability: "view",
|
|
4691
|
+
type: "function"
|
|
4692
|
+
}
|
|
4693
|
+
];
|
|
4694
|
+
var InteropRootStorage_default = InteropRootStorageABI;
|
|
4695
|
+
|
|
4696
|
+
// src/core/types/fees.ts
|
|
4697
|
+
function toGasOverrides(overrides) {
|
|
4698
|
+
const { nonce: _, ...gas } = overrides;
|
|
4699
|
+
return gas;
|
|
4700
|
+
}
|
|
4701
|
+
|
|
4702
|
+
// src/adapters/ethers/resources/deposits/context.ts
|
|
4703
|
+
async function commonCtx(p, client, tokens, contracts) {
|
|
4704
|
+
const { bridgehub, l1AssetRouter } = await contracts.addresses();
|
|
4705
|
+
const { chainId } = await client.l2.getNetwork();
|
|
4706
|
+
const sender = await client.signer.getAddress();
|
|
4707
|
+
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
4708
|
+
const operatorTip = p.operatorTip ?? 0n;
|
|
4709
|
+
const refundRecipient = p.refundRecipient ?? sender;
|
|
4710
|
+
const resolvedToken = await tokens.resolve(p.token, { chain: "l1" });
|
|
4711
|
+
const baseTokenAssetId = resolvedToken.baseTokenAssetId;
|
|
4712
|
+
const baseTokenL1 = await tokens.l1TokenFromAssetId(baseTokenAssetId);
|
|
4713
|
+
const baseIsEth = resolvedToken.isChainEthBased;
|
|
4714
|
+
const route = (() => {
|
|
4715
|
+
if (resolvedToken.kind === "eth") {
|
|
4716
|
+
return baseIsEth ? "eth-base" : "eth-nonbase";
|
|
4717
|
+
}
|
|
4718
|
+
if (resolvedToken.kind === "base") {
|
|
4719
|
+
return baseIsEth ? "eth-base" : "erc20-base";
|
|
4720
|
+
}
|
|
4721
|
+
return "erc20-nonbase";
|
|
4722
|
+
})();
|
|
4723
|
+
return {
|
|
4724
|
+
client,
|
|
4725
|
+
tokens,
|
|
4726
|
+
contracts,
|
|
4727
|
+
resolvedToken,
|
|
4728
|
+
baseTokenAssetId,
|
|
4729
|
+
baseTokenL1,
|
|
4730
|
+
baseIsEth,
|
|
4731
|
+
l1AssetRouter,
|
|
4732
|
+
route,
|
|
4733
|
+
bridgehub,
|
|
4734
|
+
chainIdL2: BigInt(chainId),
|
|
4735
|
+
sender,
|
|
4736
|
+
gasOverrides: p.l1TxOverrides ? toGasOverrides(p.l1TxOverrides) : void 0,
|
|
4737
|
+
l2GasLimit: p.l2GasLimit,
|
|
4738
|
+
gasPerPubdata,
|
|
4739
|
+
operatorTip,
|
|
4740
|
+
refundRecipient
|
|
4741
|
+
};
|
|
4742
|
+
}
|
|
4743
|
+
function encodeNativeTokenVaultTransferData(amount, receiver, token) {
|
|
4744
|
+
return new ethers.AbiCoder().encode(["uint256", "address", "address"], [amount, receiver, token]);
|
|
4745
|
+
}
|
|
4746
|
+
function encodeSecondBridgeDataV1(assetId, transferData) {
|
|
4747
|
+
const abi2 = new ethers.AbiCoder();
|
|
4748
|
+
const data = abi2.encode(["bytes32", "bytes"], [assetId, transferData]);
|
|
4749
|
+
return ethers.ethers.concat(["0x01", data]);
|
|
4750
|
+
}
|
|
4751
|
+
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
4752
|
+
return ethers.AbiCoder.defaultAbiCoder().encode(
|
|
4753
|
+
["address", "uint256", "address"],
|
|
4754
|
+
[token, amount, l2Receiver]
|
|
4755
|
+
);
|
|
4756
|
+
}
|
|
4757
|
+
function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
4758
|
+
return encodeSecondBridgeArgs(token, amount, l2Receiver);
|
|
4759
|
+
}
|
|
4760
|
+
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
4761
|
+
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
4762
|
+
}
|
|
4763
|
+
function buildDirectRequestStruct(args) {
|
|
4764
|
+
return {
|
|
4765
|
+
chainId: args.chainId,
|
|
4766
|
+
l2Contract: args.l2Contract,
|
|
4767
|
+
mintValue: args.mintValue,
|
|
4768
|
+
l2Value: args.l2Value,
|
|
4769
|
+
l2Calldata: "0x",
|
|
4770
|
+
l2GasLimit: args.l2GasLimit,
|
|
4771
|
+
l2GasPerPubdataByteLimit: args.gasPerPubdata,
|
|
4772
|
+
factoryDeps: [],
|
|
4773
|
+
refundRecipient: args.refundRecipient
|
|
4774
|
+
};
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4777
|
+
// src/core/resources/deposits/gas.ts
|
|
4778
|
+
function makeGasQuote(p) {
|
|
4779
|
+
const maxPriorityFeePerGas = p.maxPriorityFeePerGas ?? 0n;
|
|
4780
|
+
return {
|
|
4781
|
+
gasLimit: p.gasLimit,
|
|
4782
|
+
maxFeePerGas: p.maxFeePerGas,
|
|
4783
|
+
maxPriorityFeePerGas,
|
|
4784
|
+
gasPerPubdata: p.gasPerPubdata,
|
|
4785
|
+
maxCost: p.gasLimit * p.maxFeePerGas
|
|
4786
|
+
};
|
|
4787
|
+
}
|
|
4788
|
+
async function fetchFees(estimator) {
|
|
4789
|
+
try {
|
|
4790
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
4791
|
+
if (fees.maxFeePerGas != null) {
|
|
4792
|
+
return {
|
|
4793
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
4794
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? 0n
|
|
4795
|
+
};
|
|
4796
|
+
}
|
|
4797
|
+
if (fees.gasPrice != null) {
|
|
4798
|
+
return {
|
|
4799
|
+
maxFeePerGas: fees.gasPrice,
|
|
4800
|
+
maxPriorityFeePerGas: 0n
|
|
4801
|
+
};
|
|
4802
|
+
}
|
|
4803
|
+
} catch {
|
|
4804
|
+
}
|
|
4805
|
+
try {
|
|
4806
|
+
const gp = await estimator.getGasPrice();
|
|
4807
|
+
return { maxFeePerGas: gp, maxPriorityFeePerGas: 0n };
|
|
4808
|
+
} catch {
|
|
4809
|
+
return { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n };
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
async function quoteL1Gas(input) {
|
|
4813
|
+
const { estimator, tx, overrides, fallbackGasLimit } = input;
|
|
4814
|
+
let market;
|
|
4815
|
+
const getMarket = async () => {
|
|
4816
|
+
if (market) return market;
|
|
4817
|
+
market = await fetchFees(estimator);
|
|
4818
|
+
return market;
|
|
4819
|
+
};
|
|
4820
|
+
const maxFeePerGas = overrides?.maxFeePerGas ?? (tx.maxFeePerGas != null ? BigInt(tx.maxFeePerGas) : (await getMarket()).maxFeePerGas);
|
|
4821
|
+
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? (tx.maxPriorityFeePerGas != null ? BigInt(tx.maxPriorityFeePerGas) : (await getMarket()).maxPriorityFeePerGas);
|
|
4822
|
+
const explicitGasLimit = overrides?.gasLimit ?? (tx.gasLimit != null ? BigInt(tx.gasLimit) : void 0);
|
|
4823
|
+
if (explicitGasLimit != null) {
|
|
4824
|
+
return makeGasQuote({ gasLimit: explicitGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
4825
|
+
}
|
|
4826
|
+
try {
|
|
4827
|
+
const est = await estimator.estimateGas(tx);
|
|
4828
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
4829
|
+
return makeGasQuote({ gasLimit: buffered, maxFeePerGas, maxPriorityFeePerGas });
|
|
4830
|
+
} catch (err) {
|
|
4831
|
+
if (fallbackGasLimit != null) {
|
|
4832
|
+
return makeGasQuote({ gasLimit: fallbackGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
4833
|
+
}
|
|
4834
|
+
console.warn("L1 gas estimation failed", err);
|
|
4835
|
+
return void 0;
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
async function quoteL2Gas(input) {
|
|
4839
|
+
const { estimator, route, tx, gasPerPubdata, l2GasLimit, overrideGasLimit, stateOverrides } = input;
|
|
4840
|
+
const market = await fetchFees(estimator);
|
|
4841
|
+
const maxFeePerGas = market.maxFeePerGas || market.maxPriorityFeePerGas || 0n;
|
|
4842
|
+
const txGasLimit = tx?.gasLimit != null ? BigInt(tx.gasLimit) : void 0;
|
|
4843
|
+
const explicit = overrideGasLimit ?? txGasLimit;
|
|
4844
|
+
if (explicit != null) {
|
|
4845
|
+
return makeGasQuote({
|
|
4846
|
+
gasLimit: explicit,
|
|
4847
|
+
maxFeePerGas,
|
|
4848
|
+
gasPerPubdata
|
|
4849
|
+
});
|
|
4850
|
+
}
|
|
4851
|
+
if (!tx) {
|
|
4852
|
+
return makeGasQuote({
|
|
4853
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
4854
|
+
maxFeePerGas,
|
|
4855
|
+
gasPerPubdata
|
|
4856
|
+
});
|
|
4857
|
+
}
|
|
4858
|
+
try {
|
|
4859
|
+
const execEstimate = await estimator.estimateGas(tx, stateOverrides);
|
|
4860
|
+
const memoryBytes = route === "erc20-nonbase" ? 500n : DEFAULT_ABI_BYTES;
|
|
4861
|
+
const pubdataBytes = route === "erc20-nonbase" ? 200n : DEFAULT_PUBDATA_BYTES;
|
|
4862
|
+
const pp = gasPerPubdata ?? 800n;
|
|
4863
|
+
const memoryOverhead = memoryBytes * TX_MEMORY_OVERHEAD_GAS;
|
|
4864
|
+
const pubdataOverhead = pubdataBytes * pp;
|
|
4865
|
+
let total = BigInt(execEstimate) + TX_OVERHEAD_GAS + memoryOverhead + pubdataOverhead;
|
|
4866
|
+
total = total * (100n + BUFFER) / 100n;
|
|
4867
|
+
return makeGasQuote({
|
|
4868
|
+
gasLimit: total,
|
|
4869
|
+
maxFeePerGas,
|
|
4870
|
+
gasPerPubdata: pp
|
|
4871
|
+
});
|
|
4872
|
+
} catch (err) {
|
|
4873
|
+
console.warn("L2 gas estimation failed", err);
|
|
4874
|
+
return makeGasQuote({
|
|
4875
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
4876
|
+
maxFeePerGas,
|
|
4877
|
+
gasPerPubdata
|
|
4878
|
+
});
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
async function quoteL2BaseCost(input) {
|
|
4882
|
+
const { estimator, encode: encode2, bridgehub, chainIdL2, l2GasLimit, gasPerPubdata } = input;
|
|
4883
|
+
const market = await fetchFees(estimator);
|
|
4884
|
+
const l1GasPrice = market.maxFeePerGas || market.maxPriorityFeePerGas || 0n;
|
|
4885
|
+
if (l1GasPrice === 0n) {
|
|
4886
|
+
throw new Error("Could not fetch L1 gas price for Bridgehub base cost calculation.");
|
|
4887
|
+
}
|
|
4888
|
+
const data = encode2(IBridgehub_default, "l2TransactionBaseCost", [
|
|
4889
|
+
chainIdL2,
|
|
4890
|
+
l1GasPrice,
|
|
4891
|
+
l2GasLimit,
|
|
4892
|
+
gasPerPubdata
|
|
4893
|
+
]);
|
|
4894
|
+
const raw = await estimator.call({
|
|
4895
|
+
to: bridgehub,
|
|
4896
|
+
data
|
|
4897
|
+
});
|
|
4898
|
+
return BigInt(raw);
|
|
4899
|
+
}
|
|
4900
|
+
|
|
4901
|
+
// src/adapters/ethers/estimator.ts
|
|
4902
|
+
function toCoreTx(tx) {
|
|
4903
|
+
return {
|
|
4904
|
+
to: tx.to,
|
|
4905
|
+
from: tx.from,
|
|
4906
|
+
data: tx.data,
|
|
4907
|
+
value: tx.value ? BigInt(tx.value) : void 0,
|
|
4908
|
+
gasLimit: tx.gasLimit ? BigInt(tx.gasLimit) : void 0,
|
|
4909
|
+
maxFeePerGas: tx.maxFeePerGas ? BigInt(tx.maxFeePerGas) : void 0,
|
|
3775
4910
|
maxPriorityFeePerGas: tx.maxPriorityFeePerGas ? BigInt(tx.maxPriorityFeePerGas) : void 0
|
|
3776
4911
|
};
|
|
3777
4912
|
}
|
|
@@ -3853,15 +4988,15 @@ function createErrorOps(decodeRevert2) {
|
|
|
3853
4988
|
throw toZKsyncError2(kind, { resource, operation, context: opts?.ctx ?? {}, message }, e);
|
|
3854
4989
|
}
|
|
3855
4990
|
}
|
|
3856
|
-
function
|
|
4991
|
+
function wrap6(operation, fn, opts) {
|
|
3857
4992
|
return run("INTERNAL", operation, fn, opts);
|
|
3858
4993
|
}
|
|
3859
4994
|
function wrapAs9(kind, operation, fn, opts) {
|
|
3860
4995
|
return run(kind, operation, fn, opts);
|
|
3861
4996
|
}
|
|
3862
|
-
async function
|
|
4997
|
+
async function toResult3(operation, fn, opts) {
|
|
3863
4998
|
try {
|
|
3864
|
-
const value = await
|
|
4999
|
+
const value = await wrap6(operation, fn, opts);
|
|
3865
5000
|
return { ok: true, value };
|
|
3866
5001
|
} catch (e) {
|
|
3867
5002
|
const shaped = isZKsyncError(e) ? e : toZKsyncError2(
|
|
@@ -3877,7 +5012,7 @@ function createErrorOps(decodeRevert2) {
|
|
|
3877
5012
|
return { ok: false, error: shaped };
|
|
3878
5013
|
}
|
|
3879
5014
|
}
|
|
3880
|
-
return { wrap:
|
|
5015
|
+
return { wrap: wrap6, wrapAs: wrapAs9, toResult: toResult3 };
|
|
3881
5016
|
}
|
|
3882
5017
|
return { toZKsyncError: toZKsyncError2, createErrorHandlers: createErrorHandlers2 };
|
|
3883
5018
|
}
|
|
@@ -4208,6 +5343,11 @@ function routeEthDirect() {
|
|
|
4208
5343
|
}
|
|
4209
5344
|
};
|
|
4210
5345
|
}
|
|
5346
|
+
|
|
5347
|
+
// src/core/types/primitives.ts
|
|
5348
|
+
var ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
5349
|
+
|
|
5350
|
+
// src/adapters/ethers/resources/deposits/routes/erc20-nonbase.ts
|
|
4211
5351
|
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
4212
5352
|
function routeErc20NonBase() {
|
|
4213
5353
|
return {
|
|
@@ -4910,6 +6050,18 @@ function createContractsResource(client) {
|
|
|
4910
6050
|
const { l2BaseTokenSystem: l2BaseTokenSystem2 } = await instances();
|
|
4911
6051
|
return l2BaseTokenSystem2;
|
|
4912
6052
|
}
|
|
6053
|
+
async function interopCenter() {
|
|
6054
|
+
const { interopCenter: interopCenter2 } = await instances();
|
|
6055
|
+
return interopCenter2;
|
|
6056
|
+
}
|
|
6057
|
+
async function interopHandler() {
|
|
6058
|
+
const { interopHandler: interopHandler2 } = await instances();
|
|
6059
|
+
return interopHandler2;
|
|
6060
|
+
}
|
|
6061
|
+
async function l2MessageVerification() {
|
|
6062
|
+
const { l2MessageVerification: l2MessageVerification2 } = await instances();
|
|
6063
|
+
return l2MessageVerification2;
|
|
6064
|
+
}
|
|
4913
6065
|
return {
|
|
4914
6066
|
addresses,
|
|
4915
6067
|
instances,
|
|
@@ -4919,7 +6071,10 @@ function createContractsResource(client) {
|
|
|
4919
6071
|
l1Nullifier,
|
|
4920
6072
|
l2AssetRouter,
|
|
4921
6073
|
l2NativeTokenVault,
|
|
4922
|
-
l2BaseTokenSystem
|
|
6074
|
+
l2BaseTokenSystem,
|
|
6075
|
+
interopCenter,
|
|
6076
|
+
interopHandler,
|
|
6077
|
+
l2MessageVerification
|
|
4923
6078
|
};
|
|
4924
6079
|
}
|
|
4925
6080
|
|
|
@@ -4984,7 +6139,13 @@ function createDepositsResource(client, tokens, contracts) {
|
|
|
4984
6139
|
const stepHashes = {};
|
|
4985
6140
|
const managed = new ethers.NonceManager(client.signer);
|
|
4986
6141
|
const from = await managed.getAddress();
|
|
4987
|
-
let next
|
|
6142
|
+
let next;
|
|
6143
|
+
if (typeof p.l1TxOverrides?.nonce === "number") {
|
|
6144
|
+
next = p.l1TxOverrides.nonce;
|
|
6145
|
+
} else {
|
|
6146
|
+
const blockTag = p.l1TxOverrides?.nonce ?? "latest";
|
|
6147
|
+
next = await client.l1.getTransactionCount(from, blockTag);
|
|
6148
|
+
}
|
|
4988
6149
|
for (const step of plan.steps) {
|
|
4989
6150
|
if (step.kind === "approve") {
|
|
4990
6151
|
try {
|
|
@@ -5092,14 +6253,14 @@ function createDepositsResource(client, tokens, contracts) {
|
|
|
5092
6253
|
if (!l1Rcpt) return { phase: "L1_PENDING", l1TxHash };
|
|
5093
6254
|
let l2TxHash;
|
|
5094
6255
|
try {
|
|
5095
|
-
l2TxHash =
|
|
6256
|
+
l2TxHash = getL2TransactionHashFromLogs(l1Rcpt.logs) ?? void 0;
|
|
5096
6257
|
} catch (e) {
|
|
5097
6258
|
throw toZKsyncError(
|
|
5098
6259
|
"INTERNAL",
|
|
5099
6260
|
{
|
|
5100
6261
|
resource: "deposits",
|
|
5101
|
-
operation: "deposits.status.
|
|
5102
|
-
context: { where: "
|
|
6262
|
+
operation: "deposits.status.getL2TransactionHashFromLogs",
|
|
6263
|
+
context: { where: "getL2TransactionHashFromLogs", l1TxHash },
|
|
5103
6264
|
message: "Failed to derive L2 transaction hash from L1 logs."
|
|
5104
6265
|
},
|
|
5105
6266
|
e
|
|
@@ -5249,7 +6410,7 @@ async function commonCtx2(p, client, tokens, contracts) {
|
|
|
5249
6410
|
l2NativeTokenVault,
|
|
5250
6411
|
l2BaseTokenSystem,
|
|
5251
6412
|
baseIsEth,
|
|
5252
|
-
gasOverrides: p.l2TxOverrides
|
|
6413
|
+
gasOverrides: p.l2TxOverrides ? toGasOverrides(p.l2TxOverrides) : void 0
|
|
5253
6414
|
};
|
|
5254
6415
|
}
|
|
5255
6416
|
|
|
@@ -5341,806 +6502,2083 @@ function buildFeeBreakdown2(p) {
|
|
|
5341
6502
|
};
|
|
5342
6503
|
}
|
|
5343
6504
|
|
|
5344
|
-
// src/adapters/ethers/resources/withdrawals/routes/eth.ts
|
|
5345
|
-
var { wrapAs: wrapAs6 } = createErrorHandlers("withdrawals");
|
|
5346
|
-
function routeEthBase() {
|
|
6505
|
+
// src/adapters/ethers/resources/withdrawals/routes/eth.ts
|
|
6506
|
+
var { wrapAs: wrapAs6 } = createErrorHandlers("withdrawals");
|
|
6507
|
+
function routeEthBase() {
|
|
6508
|
+
return {
|
|
6509
|
+
async build(p, ctx) {
|
|
6510
|
+
const steps = [];
|
|
6511
|
+
const base = await ctx.contracts.l2BaseTokenSystem();
|
|
6512
|
+
const data = await wrapAs6(
|
|
6513
|
+
"INTERNAL",
|
|
6514
|
+
OP_WITHDRAWALS.eth.encodeWithdraw,
|
|
6515
|
+
() => Promise.resolve(base.interface.encodeFunctionData("withdraw", [p.to ?? ctx.sender])),
|
|
6516
|
+
{
|
|
6517
|
+
ctx: { where: "L2BaseToken.withdraw", to: p.to ?? ctx.sender },
|
|
6518
|
+
message: "Failed to encode ETH withdraw calldata."
|
|
6519
|
+
}
|
|
6520
|
+
);
|
|
6521
|
+
const tx = {
|
|
6522
|
+
to: L2_BASE_TOKEN_ADDRESS,
|
|
6523
|
+
data,
|
|
6524
|
+
from: ctx.sender,
|
|
6525
|
+
value: p.amount
|
|
6526
|
+
};
|
|
6527
|
+
const gas = await quoteL2Gas4({ ctx, tx });
|
|
6528
|
+
if (gas) {
|
|
6529
|
+
tx.gasLimit = gas.gasLimit;
|
|
6530
|
+
tx.maxFeePerGas = gas.maxFeePerGas;
|
|
6531
|
+
tx.maxPriorityFeePerGas = gas.maxPriorityFeePerGas;
|
|
6532
|
+
}
|
|
6533
|
+
const fees = buildFeeBreakdown2({
|
|
6534
|
+
feeToken: L2_BASE_TOKEN_ADDRESS,
|
|
6535
|
+
l2Gas: gas
|
|
6536
|
+
});
|
|
6537
|
+
steps.push({
|
|
6538
|
+
key: "l2-base-token:withdraw",
|
|
6539
|
+
kind: "l2-base-token:withdraw",
|
|
6540
|
+
description: "Withdraw ETH via L2 Base Token System",
|
|
6541
|
+
tx
|
|
6542
|
+
});
|
|
6543
|
+
return { steps, approvals: [], fees };
|
|
6544
|
+
}
|
|
6545
|
+
};
|
|
6546
|
+
}
|
|
6547
|
+
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
6548
|
+
var SIG = {
|
|
6549
|
+
withdraw: "withdraw(bytes32,bytes)"
|
|
6550
|
+
};
|
|
6551
|
+
function routeErc20NonBase2() {
|
|
6552
|
+
return {
|
|
6553
|
+
async build(p, ctx) {
|
|
6554
|
+
const steps = [];
|
|
6555
|
+
const approvals = [];
|
|
6556
|
+
const erc20 = new ethers.Contract(p.token, IERC20_default, ctx.client.getL2Signer());
|
|
6557
|
+
const current = await wrapAs7(
|
|
6558
|
+
"CONTRACT",
|
|
6559
|
+
OP_WITHDRAWALS.erc20.allowance,
|
|
6560
|
+
() => erc20.allowance(ctx.sender, ctx.l2NativeTokenVault),
|
|
6561
|
+
{
|
|
6562
|
+
ctx: {
|
|
6563
|
+
where: "erc20.allowance",
|
|
6564
|
+
chain: "L2",
|
|
6565
|
+
token: p.token,
|
|
6566
|
+
spender: ctx.l2NativeTokenVault
|
|
6567
|
+
},
|
|
6568
|
+
message: "Failed to read L2 ERC-20 allowance."
|
|
6569
|
+
}
|
|
6570
|
+
);
|
|
6571
|
+
if (current < p.amount) {
|
|
6572
|
+
approvals.push({ token: p.token, spender: ctx.l2NativeTokenVault, amount: p.amount });
|
|
6573
|
+
const data = erc20.interface.encodeFunctionData("approve", [
|
|
6574
|
+
ctx.l2NativeTokenVault,
|
|
6575
|
+
p.amount
|
|
6576
|
+
]);
|
|
6577
|
+
const approveTx = {
|
|
6578
|
+
to: p.token,
|
|
6579
|
+
data,
|
|
6580
|
+
from: ctx.sender
|
|
6581
|
+
};
|
|
6582
|
+
const approveGas = await quoteL2Gas4({ ctx, tx: approveTx });
|
|
6583
|
+
if (approveGas) {
|
|
6584
|
+
approveTx.gasLimit = approveGas.gasLimit;
|
|
6585
|
+
approveTx.maxFeePerGas = approveGas.maxFeePerGas;
|
|
6586
|
+
approveTx.maxPriorityFeePerGas = approveGas.maxPriorityFeePerGas;
|
|
6587
|
+
}
|
|
6588
|
+
steps.push({
|
|
6589
|
+
key: `approve:l2:${p.token}:${ctx.l2NativeTokenVault}`,
|
|
6590
|
+
kind: "approve:l2",
|
|
6591
|
+
description: `Approve ${p.amount} to NativeTokenVault`,
|
|
6592
|
+
tx: approveTx
|
|
6593
|
+
});
|
|
6594
|
+
}
|
|
6595
|
+
const assetId = await wrapAs7(
|
|
6596
|
+
"CONTRACT",
|
|
6597
|
+
OP_WITHDRAWALS.erc20.ensureRegistered,
|
|
6598
|
+
async () => {
|
|
6599
|
+
const ntv = await ctx.contracts.l2NativeTokenVault();
|
|
6600
|
+
const ensured = await ntv.getFunction("ensureTokenIsRegistered").staticCall(p.token);
|
|
6601
|
+
return ensured;
|
|
6602
|
+
},
|
|
6603
|
+
{
|
|
6604
|
+
ctx: { where: "L2NativeTokenVault.ensureTokenIsRegistered", token: p.token },
|
|
6605
|
+
message: "Failed to ensure token is registered in L2NativeTokenVault."
|
|
6606
|
+
}
|
|
6607
|
+
);
|
|
6608
|
+
const assetData = await wrapAs7(
|
|
6609
|
+
"INTERNAL",
|
|
6610
|
+
OP_WITHDRAWALS.erc20.encodeAssetData,
|
|
6611
|
+
() => Promise.resolve(
|
|
6612
|
+
encodeNativeTokenVaultTransferData(p.amount, p.to ?? ctx.sender, p.token)
|
|
6613
|
+
),
|
|
6614
|
+
{
|
|
6615
|
+
ctx: { where: "AbiCoder.encode", token: p.token, to: p.to ?? ctx.sender },
|
|
6616
|
+
message: "Failed to encode burn/withdraw asset data."
|
|
6617
|
+
}
|
|
6618
|
+
);
|
|
6619
|
+
const l2ar = await ctx.contracts.l2AssetRouter();
|
|
6620
|
+
const dataWithdraw = await wrapAs7(
|
|
6621
|
+
"INTERNAL",
|
|
6622
|
+
OP_WITHDRAWALS.erc20.encodeWithdraw,
|
|
6623
|
+
() => Promise.resolve(l2ar.interface.encodeFunctionData(SIG.withdraw, [assetId, assetData])),
|
|
6624
|
+
{
|
|
6625
|
+
ctx: { where: "L2AssetRouter.withdraw", assetId },
|
|
6626
|
+
message: "Failed to encode withdraw calldata."
|
|
6627
|
+
}
|
|
6628
|
+
);
|
|
6629
|
+
const withdrawTx = {
|
|
6630
|
+
to: ctx.l2AssetRouter,
|
|
6631
|
+
data: dataWithdraw,
|
|
6632
|
+
from: ctx.sender
|
|
6633
|
+
};
|
|
6634
|
+
const withdrawGas = current >= p.amount ? await quoteL2Gas4({ ctx, tx: withdrawTx }) : void 0;
|
|
6635
|
+
if (withdrawGas) {
|
|
6636
|
+
withdrawTx.gasLimit = withdrawGas.gasLimit;
|
|
6637
|
+
withdrawTx.maxFeePerGas = withdrawGas.maxFeePerGas;
|
|
6638
|
+
withdrawTx.maxPriorityFeePerGas = withdrawGas.maxPriorityFeePerGas;
|
|
6639
|
+
}
|
|
6640
|
+
steps.push({
|
|
6641
|
+
key: "l2-asset-router:withdraw",
|
|
6642
|
+
kind: "l2-asset-router:withdraw",
|
|
6643
|
+
description: "Burn on L2 & send L2\u2192L1 message",
|
|
6644
|
+
tx: withdrawTx
|
|
6645
|
+
});
|
|
6646
|
+
const fees = buildFeeBreakdown2({
|
|
6647
|
+
feeToken: ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2),
|
|
6648
|
+
l2Gas: withdrawGas
|
|
6649
|
+
});
|
|
6650
|
+
return { steps, approvals, fees };
|
|
6651
|
+
}
|
|
6652
|
+
};
|
|
6653
|
+
}
|
|
6654
|
+
|
|
6655
|
+
// src/core/utils/events.ts
|
|
6656
|
+
function extractPreferAddress(opts) {
|
|
6657
|
+
const preferAddr = typeof opts?.prefer === "object" ? opts.prefer.address : opts?.prefer === "assetRouter" ? L2_ASSET_ROUTER_ADDRESS : L1_MESSENGER_ADDRESS;
|
|
6658
|
+
return (preferAddr || L1_MESSENGER_ADDRESS).toLowerCase();
|
|
6659
|
+
}
|
|
6660
|
+
function findL1MessageSentLog(receipt, opts) {
|
|
6661
|
+
const index = opts?.index ?? 0;
|
|
6662
|
+
const preferAddr = extractPreferAddress(opts);
|
|
6663
|
+
const matches = receipt.logs.filter((lg) => {
|
|
6664
|
+
const t0 = (lg.topics?.[0] ?? "").toLowerCase();
|
|
6665
|
+
return t0 === TOPIC_L1_MESSAGE_SENT_NEW || t0 === TOPIC_L1_MESSAGE_SENT_LEG;
|
|
6666
|
+
});
|
|
6667
|
+
if (!matches.length) {
|
|
6668
|
+
throw new Error("No L1MessageSent event found in L2 receipt logs.");
|
|
6669
|
+
}
|
|
6670
|
+
const preferred = matches.find((lg) => (lg.address ?? "").toLowerCase() === preferAddr);
|
|
6671
|
+
const chosen = preferred ?? matches[index] ?? matches[0];
|
|
6672
|
+
if (!chosen) {
|
|
6673
|
+
throw new Error("No suitable L1MessageSent event found.");
|
|
6674
|
+
}
|
|
6675
|
+
return chosen;
|
|
6676
|
+
}
|
|
6677
|
+
function isL1MessageSentLog(log, opts) {
|
|
6678
|
+
const topic = log.topics[0].toLowerCase();
|
|
6679
|
+
const preferAddr = extractPreferAddress(opts);
|
|
6680
|
+
return log.address.toLowerCase() === preferAddr && (topic === TOPIC_L1_MESSAGE_SENT_LEG.toLowerCase() || topic === TOPIC_L1_MESSAGE_SENT_NEW.toLowerCase());
|
|
6681
|
+
}
|
|
6682
|
+
|
|
6683
|
+
// src/core/resources/withdrawals/logs.ts
|
|
6684
|
+
function messengerLogIndex(raw, opts) {
|
|
6685
|
+
const index = opts?.index;
|
|
6686
|
+
const messenger = (opts?.messenger).toLowerCase();
|
|
6687
|
+
const arr = Array.isArray(raw?.l2ToL1Logs) ? raw.l2ToL1Logs : [];
|
|
6688
|
+
const hits = arr.map((lg, i) => ({ i, lg })).filter(({ lg }) => (lg?.sender ?? "").toLowerCase() === messenger);
|
|
6689
|
+
if (!hits.length) {
|
|
6690
|
+
throw new Error("No L2->L1 messenger logs found in receipt.");
|
|
6691
|
+
}
|
|
6692
|
+
return (hits[index] ?? hits[0]).i;
|
|
6693
|
+
}
|
|
6694
|
+
|
|
6695
|
+
// src/adapters/ethers/resources/withdrawals/services/finalization.ts
|
|
6696
|
+
var { wrapAs: wrapAs8 } = createErrorHandlers("withdrawals");
|
|
6697
|
+
var IL1NullifierMini = [
|
|
6698
|
+
"function isWithdrawalFinalized(uint256,uint256,uint256) view returns (bool)"
|
|
6699
|
+
];
|
|
6700
|
+
function createFinalizationServices(client) {
|
|
6701
|
+
const { l1, l2, signer } = client;
|
|
5347
6702
|
return {
|
|
5348
|
-
async
|
|
5349
|
-
const
|
|
5350
|
-
|
|
5351
|
-
|
|
6703
|
+
async fetchFinalizeDepositParams(l2TxHash) {
|
|
6704
|
+
const parsed = await wrapAs8(
|
|
6705
|
+
"RPC",
|
|
6706
|
+
OP_WITHDRAWALS.finalize.fetchParams.receipt,
|
|
6707
|
+
() => client.zks.getReceiptWithL2ToL1(l2TxHash),
|
|
6708
|
+
{
|
|
6709
|
+
ctx: { where: "getReceiptWithL2ToL1", l2TxHash },
|
|
6710
|
+
message: "Failed to fetch L2 receipt (with L2\u2192L1 logs)."
|
|
6711
|
+
}
|
|
6712
|
+
);
|
|
6713
|
+
if (!parsed) {
|
|
6714
|
+
throw createError("STATE", {
|
|
6715
|
+
resource: "withdrawals",
|
|
6716
|
+
operation: OP_WITHDRAWALS.finalize.fetchParams.receipt,
|
|
6717
|
+
message: "L2 receipt not found.",
|
|
6718
|
+
context: { l2TxHash }
|
|
6719
|
+
});
|
|
6720
|
+
}
|
|
6721
|
+
const ev = await wrapAs8(
|
|
5352
6722
|
"INTERNAL",
|
|
5353
|
-
OP_WITHDRAWALS.
|
|
5354
|
-
|
|
6723
|
+
OP_WITHDRAWALS.finalize.fetchParams.findMessage,
|
|
6724
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
6725
|
+
() => Promise.resolve(findL1MessageSentLog(parsed, { index: 0 })),
|
|
5355
6726
|
{
|
|
5356
|
-
ctx: {
|
|
5357
|
-
message: "Failed to
|
|
6727
|
+
ctx: { l2TxHash, index: 0 },
|
|
6728
|
+
message: "Failed to locate L1MessageSent event in L2 receipt."
|
|
5358
6729
|
}
|
|
5359
6730
|
);
|
|
5360
|
-
const
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
6731
|
+
const message = await wrapAs8(
|
|
6732
|
+
"INTERNAL",
|
|
6733
|
+
OP_WITHDRAWALS.finalize.fetchParams.decodeMessage,
|
|
6734
|
+
() => Promise.resolve(ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ev.data)[0]),
|
|
6735
|
+
{
|
|
6736
|
+
ctx: { where: "decode L1MessageSent", data: ev.data },
|
|
6737
|
+
message: "Failed to decode withdrawal message."
|
|
6738
|
+
}
|
|
6739
|
+
);
|
|
6740
|
+
const raw = await wrapAs8(
|
|
6741
|
+
"RPC",
|
|
6742
|
+
OP_WITHDRAWALS.finalize.fetchParams.rawReceipt,
|
|
6743
|
+
() => client.zks.getReceiptWithL2ToL1(l2TxHash),
|
|
6744
|
+
{
|
|
6745
|
+
ctx: { where: "getReceiptWithL2ToL1 (raw)", l2TxHash },
|
|
6746
|
+
message: "Failed to fetch raw L2 receipt."
|
|
6747
|
+
}
|
|
6748
|
+
);
|
|
6749
|
+
if (!raw) {
|
|
6750
|
+
throw createError("STATE", {
|
|
6751
|
+
resource: "withdrawals",
|
|
6752
|
+
operation: OP_WITHDRAWALS.finalize.fetchParams.rawReceipt,
|
|
6753
|
+
message: "Raw L2 receipt not found.",
|
|
6754
|
+
context: { l2TxHash }
|
|
6755
|
+
});
|
|
6756
|
+
}
|
|
6757
|
+
const idx = await wrapAs8(
|
|
6758
|
+
"INTERNAL",
|
|
6759
|
+
OP_WITHDRAWALS.finalize.fetchParams.messengerIndex,
|
|
6760
|
+
() => Promise.resolve(messengerLogIndex(raw, { index: 0, messenger: L1_MESSENGER_ADDRESS })),
|
|
6761
|
+
{
|
|
6762
|
+
ctx: { where: "derive messenger log index", l2TxHash, receipt: raw },
|
|
6763
|
+
message: "Failed to derive messenger log index."
|
|
6764
|
+
}
|
|
6765
|
+
);
|
|
6766
|
+
const proof = await wrapAs8(
|
|
6767
|
+
"RPC",
|
|
6768
|
+
OP_WITHDRAWALS.finalize.fetchParams.proof,
|
|
6769
|
+
() => client.zks.getL2ToL1LogProof(l2TxHash, idx),
|
|
6770
|
+
{
|
|
6771
|
+
ctx: { where: "get L2\u2192L1 log proof", l2TxHash, messengerLogIndex: idx },
|
|
6772
|
+
message: "Failed to fetch L2\u2192L1 log proof."
|
|
6773
|
+
}
|
|
6774
|
+
);
|
|
6775
|
+
const { chainId } = await wrapAs8(
|
|
6776
|
+
"RPC",
|
|
6777
|
+
OP_WITHDRAWALS.finalize.fetchParams.network,
|
|
6778
|
+
() => l2.getNetwork(),
|
|
6779
|
+
{
|
|
6780
|
+
ctx: { where: "l2.getNetwork" },
|
|
6781
|
+
message: "Failed to read L2 network."
|
|
6782
|
+
}
|
|
6783
|
+
);
|
|
6784
|
+
const txIndex = Number(parsed.transactionIndex ?? 0);
|
|
6785
|
+
const params = {
|
|
6786
|
+
chainId: BigInt(chainId),
|
|
6787
|
+
l2BatchNumber: proof.batchNumber,
|
|
6788
|
+
l2MessageIndex: proof.id,
|
|
6789
|
+
l2Sender: L2_ASSET_ROUTER_ADDRESS,
|
|
6790
|
+
l2TxNumberInBatch: txIndex,
|
|
6791
|
+
message,
|
|
6792
|
+
merkleProof: proof.proof
|
|
5365
6793
|
};
|
|
5366
|
-
const
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
6794
|
+
const { l1Nullifier } = await client.ensureAddresses();
|
|
6795
|
+
return { params, nullifier: l1Nullifier };
|
|
6796
|
+
},
|
|
6797
|
+
async simulateFinalizeReadiness(params) {
|
|
6798
|
+
const { l1Nullifier } = await client.ensureAddresses();
|
|
6799
|
+
const done = await (async () => {
|
|
6800
|
+
try {
|
|
6801
|
+
const cMini = new ethers.Contract(l1Nullifier, IL1NullifierMini, l1);
|
|
6802
|
+
const isFinalized = await wrapAs8(
|
|
6803
|
+
"RPC",
|
|
6804
|
+
OP_WITHDRAWALS.finalize.readiness.isFinalized,
|
|
6805
|
+
() => cMini.isWithdrawalFinalized(
|
|
6806
|
+
params.chainId,
|
|
6807
|
+
params.l2BatchNumber,
|
|
6808
|
+
params.l2MessageIndex
|
|
6809
|
+
),
|
|
6810
|
+
{
|
|
6811
|
+
ctx: { where: "isWithdrawalFinalized", params },
|
|
6812
|
+
message: "Failed to read finalization status."
|
|
6813
|
+
}
|
|
6814
|
+
);
|
|
6815
|
+
return Boolean(isFinalized);
|
|
6816
|
+
} catch {
|
|
6817
|
+
return false;
|
|
6818
|
+
}
|
|
6819
|
+
})();
|
|
6820
|
+
if (done) return { kind: "FINALIZED" };
|
|
6821
|
+
const c = new ethers.Contract(l1Nullifier, IL1Nullifier_default, l1);
|
|
6822
|
+
try {
|
|
6823
|
+
await c.finalizeDeposit.staticCall(params);
|
|
6824
|
+
return { kind: "READY" };
|
|
6825
|
+
} catch (e) {
|
|
6826
|
+
return classifyReadinessFromRevert(e);
|
|
6827
|
+
}
|
|
6828
|
+
},
|
|
6829
|
+
async isWithdrawalFinalized(key) {
|
|
6830
|
+
const { l1Nullifier } = await client.ensureAddresses();
|
|
6831
|
+
const c = new ethers.Contract(l1Nullifier, IL1NullifierMini, l1);
|
|
6832
|
+
return await wrapAs8(
|
|
6833
|
+
"RPC",
|
|
6834
|
+
OP_WITHDRAWALS.finalize.isFinalized,
|
|
6835
|
+
() => c.isWithdrawalFinalized(key.chainIdL2, key.l2BatchNumber, key.l2MessageIndex),
|
|
6836
|
+
{
|
|
6837
|
+
ctx: { where: "isWithdrawalFinalized", key },
|
|
6838
|
+
message: "Failed to read finalization status."
|
|
6839
|
+
}
|
|
6840
|
+
);
|
|
6841
|
+
},
|
|
6842
|
+
async estimateFinalization(params) {
|
|
6843
|
+
const { l1Nullifier } = await client.ensureAddresses();
|
|
6844
|
+
const signer2 = client.getL1Signer();
|
|
6845
|
+
const c = new ethers.Contract(l1Nullifier, IL1Nullifier_default, signer2);
|
|
6846
|
+
const gasLimit = await wrapAs8(
|
|
6847
|
+
"RPC",
|
|
6848
|
+
OP_WITHDRAWALS.finalize.estimate,
|
|
6849
|
+
() => c.finalizeDeposit.estimateGas(params),
|
|
6850
|
+
{
|
|
6851
|
+
ctx: {
|
|
6852
|
+
where: "estimateGas(finalizeDeposit)",
|
|
6853
|
+
chainIdL2: params.chainId,
|
|
6854
|
+
l2BatchNumber: params.l2BatchNumber,
|
|
6855
|
+
l2MessageIndex: params.l2MessageIndex,
|
|
6856
|
+
l1Nullifier
|
|
6857
|
+
},
|
|
6858
|
+
message: "Failed to estimate gas for finalizeDeposit."
|
|
6859
|
+
}
|
|
6860
|
+
);
|
|
6861
|
+
const feeData = await wrapAs8("RPC", OP_WITHDRAWALS.finalize.estimate, () => l1.getFeeData(), {
|
|
6862
|
+
ctx: { where: "l1.getFeeData" },
|
|
6863
|
+
message: "Failed to estimate fee data for finalizeDeposit."
|
|
6864
|
+
});
|
|
6865
|
+
const maxFeePerGas = feeData.maxFeePerGas ?? feeData.gasPrice ?? // legacy-style gas price if present
|
|
6866
|
+
(() => {
|
|
6867
|
+
throw createError("RPC", {
|
|
6868
|
+
resource: "withdrawals",
|
|
6869
|
+
operation: OP_WITHDRAWALS.finalize.estimate,
|
|
6870
|
+
message: "Provider did not return gas price or EIP-1559 fields.",
|
|
6871
|
+
context: { feeData }
|
|
6872
|
+
});
|
|
6873
|
+
})();
|
|
6874
|
+
const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? 0n;
|
|
6875
|
+
return {
|
|
6876
|
+
gasLimit,
|
|
6877
|
+
maxFeePerGas,
|
|
6878
|
+
maxPriorityFeePerGas
|
|
6879
|
+
};
|
|
6880
|
+
},
|
|
6881
|
+
async finalizeDeposit(params) {
|
|
6882
|
+
const { l1Nullifier } = await client.ensureAddresses();
|
|
6883
|
+
const c = new ethers.Contract(l1Nullifier, IL1Nullifier_default, signer);
|
|
6884
|
+
try {
|
|
6885
|
+
const receipt = await c.finalizeDeposit(params);
|
|
6886
|
+
const hash = receipt.hash;
|
|
6887
|
+
return {
|
|
6888
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
6889
|
+
hash,
|
|
6890
|
+
wait: async () => {
|
|
6891
|
+
try {
|
|
6892
|
+
return await receipt.wait();
|
|
6893
|
+
} catch (e) {
|
|
6894
|
+
throw toZKsyncError(
|
|
6895
|
+
"EXECUTION",
|
|
6896
|
+
{
|
|
6897
|
+
resource: "withdrawals",
|
|
6898
|
+
operation: OP_WITHDRAWALS.finalize.wait,
|
|
6899
|
+
message: "Failed while waiting for finalizeDeposit transaction.",
|
|
6900
|
+
context: { txHash: hash }
|
|
6901
|
+
},
|
|
6902
|
+
e
|
|
6903
|
+
);
|
|
6904
|
+
}
|
|
6905
|
+
}
|
|
6906
|
+
};
|
|
6907
|
+
} catch (e) {
|
|
6908
|
+
throw toZKsyncError(
|
|
6909
|
+
"EXECUTION",
|
|
6910
|
+
{
|
|
6911
|
+
resource: "withdrawals",
|
|
6912
|
+
operation: OP_WITHDRAWALS.finalize.send,
|
|
6913
|
+
message: "Failed to send finalizeDeposit transaction.",
|
|
6914
|
+
context: {
|
|
6915
|
+
chainIdL2: params.chainId,
|
|
6916
|
+
l2BatchNumber: params.l2BatchNumber,
|
|
6917
|
+
l2MessageIndex: params.l2MessageIndex,
|
|
6918
|
+
l1Nullifier
|
|
6919
|
+
}
|
|
6920
|
+
},
|
|
6921
|
+
e
|
|
6922
|
+
);
|
|
5371
6923
|
}
|
|
5372
|
-
const fees = buildFeeBreakdown2({
|
|
5373
|
-
feeToken: L2_BASE_TOKEN_ADDRESS,
|
|
5374
|
-
l2Gas: gas
|
|
5375
|
-
});
|
|
5376
|
-
steps.push({
|
|
5377
|
-
key: "l2-base-token:withdraw",
|
|
5378
|
-
kind: "l2-base-token:withdraw",
|
|
5379
|
-
description: "Withdraw ETH via L2 Base Token System",
|
|
5380
|
-
tx
|
|
5381
|
-
});
|
|
5382
|
-
return { steps, approvals: [], fees };
|
|
5383
6924
|
}
|
|
5384
6925
|
};
|
|
5385
6926
|
}
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
6927
|
+
|
|
6928
|
+
// src/adapters/ethers/resources/withdrawals/index.ts
|
|
6929
|
+
var ROUTES2 = {
|
|
6930
|
+
base: routeEthBase(),
|
|
6931
|
+
// BaseTokenSystem.withdraw, chain base = ETH
|
|
6932
|
+
"erc20-nonbase": routeErc20NonBase2()
|
|
6933
|
+
// AssetRouter.withdraw for non-base ERC-20s
|
|
5389
6934
|
};
|
|
5390
|
-
function
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
6935
|
+
function createWithdrawalsResource(client, tokens, contracts) {
|
|
6936
|
+
const svc = createFinalizationServices(client);
|
|
6937
|
+
const { wrap: wrap6, toResult: toResult3 } = createErrorHandlers("withdrawals");
|
|
6938
|
+
const tokensResource = tokens ?? createTokensResource(client);
|
|
6939
|
+
const contractsResource = contracts ?? createContractsResource(client);
|
|
6940
|
+
async function buildPlan(p) {
|
|
6941
|
+
const ctx = await commonCtx2(p, client, tokensResource, contractsResource);
|
|
6942
|
+
await ROUTES2[ctx.route].preflight?.(p, ctx);
|
|
6943
|
+
const { steps, approvals, fees } = await ROUTES2[ctx.route].build(p, ctx);
|
|
6944
|
+
return {
|
|
6945
|
+
route: ctx.route,
|
|
6946
|
+
summary: {
|
|
6947
|
+
route: ctx.route,
|
|
6948
|
+
approvalsNeeded: approvals,
|
|
6949
|
+
amounts: {
|
|
6950
|
+
transfer: { token: p.token, amount: p.amount }
|
|
6951
|
+
},
|
|
6952
|
+
fees
|
|
6953
|
+
},
|
|
6954
|
+
steps
|
|
6955
|
+
};
|
|
6956
|
+
}
|
|
6957
|
+
const finalizeCache = /* @__PURE__ */ new Map();
|
|
6958
|
+
const quote = (p) => wrap6(
|
|
6959
|
+
OP_WITHDRAWALS.quote,
|
|
6960
|
+
async () => {
|
|
6961
|
+
const plan = await buildPlan(p);
|
|
6962
|
+
return plan.summary;
|
|
6963
|
+
},
|
|
6964
|
+
{
|
|
6965
|
+
message: "Internal error while preparing a withdrawal quote.",
|
|
6966
|
+
ctx: { token: p.token, where: "withdrawals.quote" }
|
|
6967
|
+
}
|
|
6968
|
+
);
|
|
6969
|
+
const tryQuote = (p) => toResult3(
|
|
6970
|
+
OP_WITHDRAWALS.tryQuote,
|
|
6971
|
+
async () => {
|
|
6972
|
+
const plan = await buildPlan(p);
|
|
6973
|
+
return plan.summary;
|
|
6974
|
+
},
|
|
6975
|
+
{
|
|
6976
|
+
message: "Internal error while preparing a withdrawal quote.",
|
|
6977
|
+
ctx: { token: p.token, where: "withdrawals.tryQuote" }
|
|
6978
|
+
}
|
|
6979
|
+
);
|
|
6980
|
+
const prepare = (p) => wrap6(OP_WITHDRAWALS.prepare, () => buildPlan(p), {
|
|
6981
|
+
message: "Internal error while preparing a withdrawal plan.",
|
|
6982
|
+
ctx: { token: p.token, where: "withdrawals.prepare" }
|
|
6983
|
+
});
|
|
6984
|
+
const tryPrepare = (p) => toResult3(OP_WITHDRAWALS.tryPrepare, () => buildPlan(p), {
|
|
6985
|
+
message: "Internal error while preparing a withdrawal plan.",
|
|
6986
|
+
ctx: { token: p.token, where: "withdrawals.tryPrepare" }
|
|
6987
|
+
});
|
|
6988
|
+
const create = (p) => wrap6(
|
|
6989
|
+
OP_WITHDRAWALS.create,
|
|
6990
|
+
async () => {
|
|
6991
|
+
const plan = await prepare(p);
|
|
6992
|
+
const stepHashes = {};
|
|
6993
|
+
const managed = new ethers.NonceManager(client.getL2Signer());
|
|
6994
|
+
const from = await managed.getAddress();
|
|
6995
|
+
let next;
|
|
6996
|
+
if (typeof p.l2TxOverrides?.nonce === "number") {
|
|
6997
|
+
next = p.l2TxOverrides.nonce;
|
|
6998
|
+
} else {
|
|
6999
|
+
const blockTag = p.l2TxOverrides?.nonce ?? "pending";
|
|
7000
|
+
next = await client.l2.getTransactionCount(from, blockTag);
|
|
7001
|
+
}
|
|
7002
|
+
for (const step of plan.steps) {
|
|
7003
|
+
step.tx.nonce = next++;
|
|
7004
|
+
if (p.l2TxOverrides) {
|
|
7005
|
+
const overrides = p.l2TxOverrides;
|
|
7006
|
+
if (overrides.gasLimit != null) step.tx.gasLimit = overrides.gasLimit;
|
|
7007
|
+
if (overrides.maxFeePerGas != null) step.tx.maxFeePerGas = overrides.maxFeePerGas;
|
|
7008
|
+
if (overrides.maxPriorityFeePerGas != null) {
|
|
7009
|
+
step.tx.maxPriorityFeePerGas = overrides.maxPriorityFeePerGas;
|
|
7010
|
+
}
|
|
7011
|
+
}
|
|
7012
|
+
if (!step.tx.gasLimit) {
|
|
7013
|
+
try {
|
|
7014
|
+
const est = await client.l2.estimateGas(step.tx);
|
|
7015
|
+
step.tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
7016
|
+
} catch {
|
|
7017
|
+
}
|
|
7018
|
+
}
|
|
7019
|
+
let hash;
|
|
7020
|
+
try {
|
|
7021
|
+
const sent = await managed.sendTransaction(step.tx);
|
|
7022
|
+
hash = sent.hash;
|
|
7023
|
+
stepHashes[step.key] = hash;
|
|
7024
|
+
const rcpt = await sent.wait();
|
|
7025
|
+
if (rcpt?.status === 0) {
|
|
7026
|
+
throw createError("EXECUTION", {
|
|
7027
|
+
resource: "withdrawals",
|
|
7028
|
+
operation: "withdrawals.create.sendTransaction",
|
|
7029
|
+
message: "Withdrawal transaction reverted on L2 during a step.",
|
|
7030
|
+
context: { step: step.key, txHash: hash, nonce: Number(step.tx.nonce ?? -1) }
|
|
7031
|
+
});
|
|
7032
|
+
}
|
|
7033
|
+
} catch (e) {
|
|
7034
|
+
throw toZKsyncError(
|
|
7035
|
+
"EXECUTION",
|
|
7036
|
+
{
|
|
7037
|
+
resource: "withdrawals",
|
|
7038
|
+
operation: "withdrawals.create.sendTransaction",
|
|
7039
|
+
message: "Failed to send or confirm a withdrawal transaction step.",
|
|
7040
|
+
context: { step: step.key, txHash: hash, nonce: Number(step.tx.nonce ?? -1) }
|
|
7041
|
+
},
|
|
7042
|
+
e
|
|
7043
|
+
);
|
|
7044
|
+
}
|
|
7045
|
+
}
|
|
7046
|
+
const keys = Object.keys(stepHashes);
|
|
7047
|
+
const l2TxHash = stepHashes[keys[keys.length - 1]];
|
|
7048
|
+
return { kind: "withdrawal", l2TxHash, stepHashes, plan };
|
|
7049
|
+
},
|
|
7050
|
+
{
|
|
7051
|
+
message: "Internal error while creating withdrawal transactions.",
|
|
7052
|
+
ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.create" }
|
|
7053
|
+
}
|
|
7054
|
+
);
|
|
7055
|
+
const tryCreate = (p) => toResult3(OP_WITHDRAWALS.tryCreate, () => create(p), {
|
|
7056
|
+
message: "Internal error while creating withdrawal transactions.",
|
|
7057
|
+
ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.tryCreate" }
|
|
7058
|
+
});
|
|
7059
|
+
const status = (h) => wrap6(
|
|
7060
|
+
OP_WITHDRAWALS.status,
|
|
7061
|
+
async () => {
|
|
7062
|
+
const l2TxHash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
|
|
7063
|
+
if (!l2TxHash || l2TxHash === "0x") {
|
|
7064
|
+
return { phase: "UNKNOWN", l2TxHash: "0x" };
|
|
7065
|
+
}
|
|
7066
|
+
let l2Rcpt;
|
|
7067
|
+
try {
|
|
7068
|
+
l2Rcpt = await client.l2.getTransactionReceipt(l2TxHash);
|
|
7069
|
+
} catch (e) {
|
|
7070
|
+
if (isReceiptNotFound(e)) {
|
|
7071
|
+
return { phase: "L2_PENDING", l2TxHash };
|
|
7072
|
+
}
|
|
7073
|
+
throw toZKsyncError(
|
|
7074
|
+
"RPC",
|
|
7075
|
+
{
|
|
7076
|
+
resource: "withdrawals",
|
|
7077
|
+
operation: "withdrawals.status.getTransactionReceipt",
|
|
7078
|
+
message: "Failed to fetch L2 transaction receipt.",
|
|
7079
|
+
context: { l2TxHash, where: "l2.getTransactionReceipt" }
|
|
5406
7080
|
},
|
|
5407
|
-
|
|
7081
|
+
e
|
|
7082
|
+
);
|
|
7083
|
+
}
|
|
7084
|
+
if (!l2Rcpt) return { phase: "L2_PENDING", l2TxHash };
|
|
7085
|
+
let pack;
|
|
7086
|
+
try {
|
|
7087
|
+
pack = await svc.fetchFinalizeDepositParams(l2TxHash);
|
|
7088
|
+
} catch {
|
|
7089
|
+
return { phase: "PENDING", l2TxHash };
|
|
7090
|
+
}
|
|
7091
|
+
const key = {
|
|
7092
|
+
chainIdL2: pack.params.chainId,
|
|
7093
|
+
l2BatchNumber: pack.params.l2BatchNumber,
|
|
7094
|
+
l2MessageIndex: pack.params.l2MessageIndex
|
|
7095
|
+
};
|
|
7096
|
+
try {
|
|
7097
|
+
const done = await svc.isWithdrawalFinalized(key);
|
|
7098
|
+
if (done) return { phase: "FINALIZED", l2TxHash, key };
|
|
7099
|
+
} catch {
|
|
7100
|
+
}
|
|
7101
|
+
const readiness = await svc.simulateFinalizeReadiness(pack.params);
|
|
7102
|
+
if (readiness.kind === "FINALIZED") return { phase: "FINALIZED", l2TxHash, key };
|
|
7103
|
+
if (readiness.kind === "READY") return { phase: "READY_TO_FINALIZE", l2TxHash, key };
|
|
7104
|
+
return { phase: "PENDING", l2TxHash, key };
|
|
7105
|
+
},
|
|
7106
|
+
{
|
|
7107
|
+
message: "Internal error while checking withdrawal status.",
|
|
7108
|
+
ctx: { where: "withdrawals.status", l2TxHash: typeof h === "string" ? h : h.l2TxHash }
|
|
7109
|
+
}
|
|
7110
|
+
);
|
|
7111
|
+
const wait = (h, opts = {
|
|
7112
|
+
for: "l2",
|
|
7113
|
+
pollMs: 5500
|
|
7114
|
+
}) => wrap6(
|
|
7115
|
+
OP_WITHDRAWALS.wait,
|
|
7116
|
+
async () => {
|
|
7117
|
+
const l2Hash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
|
|
7118
|
+
if (!l2Hash || l2Hash === "0x") return null;
|
|
7119
|
+
if (opts.for === "l2") {
|
|
7120
|
+
let rcpt;
|
|
7121
|
+
try {
|
|
7122
|
+
rcpt = await client.l2.waitForTransaction(l2Hash);
|
|
7123
|
+
} catch (e) {
|
|
7124
|
+
throw toZKsyncError(
|
|
7125
|
+
"RPC",
|
|
7126
|
+
{
|
|
7127
|
+
resource: "withdrawals",
|
|
7128
|
+
operation: "withdrawals.wait.l2.waitForTransaction",
|
|
7129
|
+
message: "Failed while waiting for L2 transaction.",
|
|
7130
|
+
context: { l2TxHash: l2Hash }
|
|
7131
|
+
},
|
|
7132
|
+
e
|
|
7133
|
+
);
|
|
5408
7134
|
}
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
const
|
|
5422
|
-
if (
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
7135
|
+
if (!rcpt) return null;
|
|
7136
|
+
try {
|
|
7137
|
+
const raw = await client.zks.getReceiptWithL2ToL1(l2Hash);
|
|
7138
|
+
rcpt.l2ToL1Logs = raw?.l2ToL1Logs ?? [];
|
|
7139
|
+
} catch {
|
|
7140
|
+
rcpt.l2ToL1Logs = rcpt.l2ToL1Logs ?? [];
|
|
7141
|
+
}
|
|
7142
|
+
return rcpt;
|
|
7143
|
+
}
|
|
7144
|
+
const poll = Math.max(1e3, opts.pollMs ?? 2500);
|
|
7145
|
+
const deadline = opts.timeoutMs ? Date.now() + opts.timeoutMs : void 0;
|
|
7146
|
+
while (true) {
|
|
7147
|
+
const s = await status(l2Hash);
|
|
7148
|
+
if (opts.for === "ready") {
|
|
7149
|
+
if (s.phase === "READY_TO_FINALIZE" || s.phase === "FINALIZED") return null;
|
|
7150
|
+
} else {
|
|
7151
|
+
if (s.phase === "FINALIZED") {
|
|
7152
|
+
const l1Hash = finalizeCache.get(l2Hash);
|
|
7153
|
+
if (l1Hash) {
|
|
7154
|
+
try {
|
|
7155
|
+
const l1Rcpt = await client.l1.getTransactionReceipt(l1Hash);
|
|
7156
|
+
if (l1Rcpt) {
|
|
7157
|
+
finalizeCache.delete(l2Hash);
|
|
7158
|
+
return l1Rcpt;
|
|
7159
|
+
}
|
|
7160
|
+
} catch {
|
|
7161
|
+
}
|
|
7162
|
+
}
|
|
7163
|
+
return null;
|
|
7164
|
+
}
|
|
5426
7165
|
}
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
kind: "approve:l2",
|
|
5430
|
-
description: `Approve ${p.amount} to NativeTokenVault`,
|
|
5431
|
-
tx: approveTx
|
|
5432
|
-
});
|
|
7166
|
+
if (deadline && Date.now() > deadline) return null;
|
|
7167
|
+
await new Promise((r) => setTimeout(r, poll));
|
|
5433
7168
|
}
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
7169
|
+
},
|
|
7170
|
+
{
|
|
7171
|
+
message: "Internal error while waiting for withdrawal.",
|
|
7172
|
+
ctx: {
|
|
7173
|
+
where: "withdrawals.wait",
|
|
7174
|
+
l2TxHash: typeof h === "string" ? h : h.l2TxHash,
|
|
7175
|
+
for: opts.for
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
);
|
|
7179
|
+
const finalize = (l2TxHash) => wrap6(
|
|
7180
|
+
OP_WITHDRAWALS.finalize.send,
|
|
7181
|
+
async () => {
|
|
7182
|
+
const pack = await (async () => {
|
|
7183
|
+
try {
|
|
7184
|
+
return await svc.fetchFinalizeDepositParams(l2TxHash);
|
|
7185
|
+
} catch (e) {
|
|
7186
|
+
throw createError("STATE", {
|
|
7187
|
+
resource: "withdrawals",
|
|
7188
|
+
operation: OP_WITHDRAWALS.finalize.fetchParams.receipt,
|
|
7189
|
+
message: "Withdrawal not ready: finalize params unavailable.",
|
|
7190
|
+
context: { l2TxHash },
|
|
7191
|
+
cause: e
|
|
7192
|
+
});
|
|
5445
7193
|
}
|
|
5446
|
-
);
|
|
5447
|
-
const
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
7194
|
+
})();
|
|
7195
|
+
const { params } = pack;
|
|
7196
|
+
const key = {
|
|
7197
|
+
chainIdL2: params.chainId,
|
|
7198
|
+
l2BatchNumber: params.l2BatchNumber,
|
|
7199
|
+
l2MessageIndex: params.l2MessageIndex
|
|
7200
|
+
};
|
|
7201
|
+
try {
|
|
7202
|
+
const done = await svc.isWithdrawalFinalized(key);
|
|
7203
|
+
if (done) {
|
|
7204
|
+
const statusNow = await status(l2TxHash);
|
|
7205
|
+
return { status: statusNow };
|
|
5456
7206
|
}
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
const
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
7207
|
+
} catch {
|
|
7208
|
+
}
|
|
7209
|
+
const readiness = await svc.simulateFinalizeReadiness(params);
|
|
7210
|
+
if (readiness.kind === "FINALIZED") {
|
|
7211
|
+
const statusNow = await status(l2TxHash);
|
|
7212
|
+
return { status: statusNow };
|
|
7213
|
+
}
|
|
7214
|
+
if (readiness.kind === "NOT_READY") {
|
|
7215
|
+
throw createError("STATE", {
|
|
7216
|
+
resource: "withdrawals",
|
|
7217
|
+
operation: OP_WITHDRAWALS.finalize.readiness.simulate,
|
|
7218
|
+
message: "Withdrawal not ready to finalize.",
|
|
7219
|
+
context: readiness
|
|
7220
|
+
});
|
|
7221
|
+
}
|
|
7222
|
+
try {
|
|
7223
|
+
const tx = await svc.finalizeDeposit(params);
|
|
7224
|
+
finalizeCache.set(l2TxHash, tx.hash);
|
|
7225
|
+
const rcpt = await tx.wait();
|
|
7226
|
+
const statusNow = await status(l2TxHash);
|
|
7227
|
+
return { status: statusNow, receipt: rcpt };
|
|
7228
|
+
} catch (e) {
|
|
7229
|
+
const statusNow = await status(l2TxHash);
|
|
7230
|
+
if (statusNow.phase === "FINALIZED") return { status: statusNow };
|
|
7231
|
+
try {
|
|
7232
|
+
const again = await svc.simulateFinalizeReadiness(params);
|
|
7233
|
+
if (again.kind === "NOT_READY") {
|
|
7234
|
+
throw createError("STATE", {
|
|
7235
|
+
resource: "withdrawals",
|
|
7236
|
+
operation: OP_WITHDRAWALS.finalize.readiness.simulate,
|
|
7237
|
+
message: "Withdrawal not ready to finalize.",
|
|
7238
|
+
context: again
|
|
7239
|
+
});
|
|
7240
|
+
}
|
|
7241
|
+
} catch {
|
|
5466
7242
|
}
|
|
5467
|
-
|
|
5468
|
-
const withdrawTx = {
|
|
5469
|
-
to: ctx.l2AssetRouter,
|
|
5470
|
-
data: dataWithdraw,
|
|
5471
|
-
from: ctx.sender
|
|
5472
|
-
};
|
|
5473
|
-
const withdrawGas = current >= p.amount ? await quoteL2Gas4({ ctx, tx: withdrawTx }) : void 0;
|
|
5474
|
-
if (withdrawGas) {
|
|
5475
|
-
withdrawTx.gasLimit = withdrawGas.gasLimit;
|
|
5476
|
-
withdrawTx.maxFeePerGas = withdrawGas.maxFeePerGas;
|
|
5477
|
-
withdrawTx.maxPriorityFeePerGas = withdrawGas.maxPriorityFeePerGas;
|
|
7243
|
+
throw e;
|
|
5478
7244
|
}
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
7245
|
+
},
|
|
7246
|
+
{
|
|
7247
|
+
message: "Internal error while attempting to finalize withdrawal.",
|
|
7248
|
+
ctx: { l2TxHash, where: "withdrawals.finalize" }
|
|
7249
|
+
}
|
|
7250
|
+
);
|
|
7251
|
+
const tryFinalize = (l2TxHash) => toResult3("withdrawals.tryFinalize", () => finalize(l2TxHash), {
|
|
7252
|
+
message: "Internal error while attempting to tryFinalize withdrawal.",
|
|
7253
|
+
ctx: { l2TxHash, where: "withdrawals.tryFinalize" }
|
|
7254
|
+
});
|
|
7255
|
+
const tryWait = (h, opts) => toResult3(
|
|
7256
|
+
OP_WITHDRAWALS.tryWait,
|
|
7257
|
+
async () => {
|
|
7258
|
+
const v = await wait(h, opts);
|
|
7259
|
+
if (v) return v;
|
|
7260
|
+
throw createError("STATE", {
|
|
7261
|
+
resource: "withdrawals",
|
|
7262
|
+
operation: "withdrawals.tryWait",
|
|
7263
|
+
message: opts.for === "l2" ? "No L2 receipt yet; the withdrawal has not executed on L2." : "No L1 receipt yet; the withdrawal has not been included on L1.",
|
|
7264
|
+
context: {
|
|
7265
|
+
for: opts.for,
|
|
7266
|
+
l2TxHash: typeof h === "string" ? h : "l2TxHash" in h ? h.l2TxHash : void 0,
|
|
7267
|
+
where: "withdrawals.tryWait"
|
|
7268
|
+
}
|
|
5488
7269
|
});
|
|
5489
|
-
|
|
7270
|
+
},
|
|
7271
|
+
{
|
|
7272
|
+
message: "Internal error while waiting for withdrawal.",
|
|
7273
|
+
ctx: { input: h, for: opts?.for, where: "withdrawals.tryWait" }
|
|
5490
7274
|
}
|
|
7275
|
+
);
|
|
7276
|
+
return {
|
|
7277
|
+
quote,
|
|
7278
|
+
tryQuote,
|
|
7279
|
+
prepare,
|
|
7280
|
+
tryPrepare,
|
|
7281
|
+
create,
|
|
7282
|
+
tryCreate,
|
|
7283
|
+
status,
|
|
7284
|
+
wait,
|
|
7285
|
+
finalize,
|
|
7286
|
+
tryFinalize,
|
|
7287
|
+
tryWait
|
|
5491
7288
|
};
|
|
5492
7289
|
}
|
|
5493
7290
|
|
|
5494
|
-
// src/core/
|
|
5495
|
-
function
|
|
5496
|
-
const
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
const matches = receipt.logs.filter((lg) => {
|
|
5503
|
-
const t0 = (lg.topics?.[0] ?? "").toLowerCase();
|
|
5504
|
-
return t0 === TOPIC_L1_MESSAGE_SENT_NEW || t0 === TOPIC_L1_MESSAGE_SENT_LEG;
|
|
5505
|
-
});
|
|
5506
|
-
if (!matches.length) {
|
|
5507
|
-
throw new Error("No L1MessageSent event found in L2 receipt logs.");
|
|
5508
|
-
}
|
|
5509
|
-
const preferred = matches.find((lg) => (lg.address ?? "").toLowerCase() === preferAddr);
|
|
5510
|
-
const chosen = preferred ?? matches[index] ?? matches[0];
|
|
5511
|
-
if (!chosen) {
|
|
5512
|
-
throw new Error("No suitable L1MessageSent event found.");
|
|
5513
|
-
}
|
|
5514
|
-
return chosen;
|
|
7291
|
+
// src/core/resources/interop/attributes/call.ts
|
|
7292
|
+
function createCallAttributes(codec) {
|
|
7293
|
+
const indirectCall = (messageValue) => codec.encode("indirectCall", [messageValue]);
|
|
7294
|
+
const interopCallValue = (bridgedAmount) => codec.encode("interopCallValue", [bridgedAmount]);
|
|
7295
|
+
return {
|
|
7296
|
+
indirectCall,
|
|
7297
|
+
interopCallValue
|
|
7298
|
+
};
|
|
5515
7299
|
}
|
|
5516
7300
|
|
|
5517
|
-
// src/core/resources/
|
|
5518
|
-
function
|
|
5519
|
-
const
|
|
5520
|
-
const
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
}
|
|
5526
|
-
return (hits[index] ?? hits[0]).i;
|
|
7301
|
+
// src/core/resources/interop/attributes/bundle.ts
|
|
7302
|
+
function createBundleAttributes(codec) {
|
|
7303
|
+
const executionAddress = (executor) => codec.encode("executionAddress", [executor]);
|
|
7304
|
+
const unbundlerAddress = (addr) => codec.encode("unbundlerAddress", [addr]);
|
|
7305
|
+
return {
|
|
7306
|
+
executionAddress,
|
|
7307
|
+
unbundlerAddress
|
|
7308
|
+
};
|
|
5527
7309
|
}
|
|
5528
7310
|
|
|
5529
|
-
// src/
|
|
5530
|
-
|
|
5531
|
-
var IL1NullifierMini = [
|
|
5532
|
-
"function isWithdrawalFinalized(uint256,uint256,uint256) view returns (bool)"
|
|
5533
|
-
];
|
|
5534
|
-
function createFinalizationServices(client) {
|
|
5535
|
-
const { l1, l2, signer } = client;
|
|
7311
|
+
// src/core/resources/interop/attributes/resource.ts
|
|
7312
|
+
function createAttributesResource(codec) {
|
|
5536
7313
|
return {
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
7314
|
+
call: createCallAttributes(codec),
|
|
7315
|
+
bundle: createBundleAttributes(codec)
|
|
7316
|
+
};
|
|
7317
|
+
}
|
|
7318
|
+
|
|
7319
|
+
// src/adapters/ethers/resources/interop/attributes/resource.ts
|
|
7320
|
+
function getInteropAttributes(params, ctx) {
|
|
7321
|
+
const bundleAttributes = [];
|
|
7322
|
+
if (params.execution?.only) {
|
|
7323
|
+
bundleAttributes.push(ctx.attributes.bundle.executionAddress(params.execution.only));
|
|
7324
|
+
}
|
|
7325
|
+
if (params.unbundling?.by) {
|
|
7326
|
+
bundleAttributes.push(ctx.attributes.bundle.unbundlerAddress(params.unbundling.by));
|
|
7327
|
+
}
|
|
7328
|
+
const callAttributes = params.actions.map((action) => {
|
|
7329
|
+
switch (action.type) {
|
|
7330
|
+
case "sendNative": {
|
|
7331
|
+
const baseMatches = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
7332
|
+
if (baseMatches) {
|
|
7333
|
+
return [ctx.attributes.call.interopCallValue(action.amount)];
|
|
5545
7334
|
}
|
|
5546
|
-
|
|
5547
|
-
if (!parsed) {
|
|
5548
|
-
throw createError("STATE", {
|
|
5549
|
-
resource: "withdrawals",
|
|
5550
|
-
operation: OP_WITHDRAWALS.finalize.fetchParams.receipt,
|
|
5551
|
-
message: "L2 receipt not found.",
|
|
5552
|
-
context: { l2TxHash }
|
|
5553
|
-
});
|
|
7335
|
+
return [ctx.attributes.call.indirectCall(action.amount)];
|
|
5554
7336
|
}
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
7337
|
+
case "call":
|
|
7338
|
+
if (action.value && action.value > 0n) {
|
|
7339
|
+
return [ctx.attributes.call.interopCallValue(action.value)];
|
|
7340
|
+
}
|
|
7341
|
+
return [];
|
|
7342
|
+
case "sendErc20":
|
|
7343
|
+
return [ctx.attributes.call.indirectCall(0n)];
|
|
7344
|
+
default:
|
|
7345
|
+
assertNever(action);
|
|
7346
|
+
}
|
|
7347
|
+
});
|
|
7348
|
+
return { bundleAttributes, callAttributes };
|
|
7349
|
+
}
|
|
7350
|
+
function createEthersAttributesResource(opts = {}) {
|
|
7351
|
+
const iface = opts.iface ?? new ethers.Interface(IERC7786Attributes_default);
|
|
7352
|
+
const encode2 = (fn, args) => iface.encodeFunctionData(fn, args);
|
|
7353
|
+
return createAttributesResource({ encode: encode2 });
|
|
7354
|
+
}
|
|
7355
|
+
|
|
7356
|
+
// src/core/types/flows/interop.ts
|
|
7357
|
+
function isInteropExpectedRoot(obj) {
|
|
7358
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
7359
|
+
const root = obj;
|
|
7360
|
+
return isBigint(root.rootChainId) && isBigint(root.batchNumber) && isHash(root.expectedRoot);
|
|
7361
|
+
}
|
|
7362
|
+
function isInteropMessageProof(obj) {
|
|
7363
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
7364
|
+
const proof = obj;
|
|
7365
|
+
return isBigint(proof.chainId) && isBigint(proof.l1BatchNumber) && isBigint(proof.l2MessageIndex) && typeof proof.message === "object" && proof.message !== null && isNumber(proof.message.txNumberInBatch) && isAddress(proof.message.sender) && isHash(proof.message.data) && isHash66Array(proof.proof);
|
|
7366
|
+
}
|
|
7367
|
+
function isInteropFinalizationInfo(obj) {
|
|
7368
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
7369
|
+
const info = obj;
|
|
7370
|
+
return isHash66(info.l2SrcTxHash) && isHash66(info.bundleHash) && isBigint(info.dstChainId) && isHash(info.encodedData) && isInteropExpectedRoot(info.expectedRoot) && isInteropMessageProof(info.proof);
|
|
7371
|
+
}
|
|
7372
|
+
|
|
7373
|
+
// src/core/resources/interop/route.ts
|
|
7374
|
+
function sumActionMsgValue(actions) {
|
|
7375
|
+
let sum = 0n;
|
|
7376
|
+
for (const a of actions) {
|
|
7377
|
+
if (a.type === "sendNative") sum += a.amount;
|
|
7378
|
+
else if (a.type === "call" && a.value) sum += a.value;
|
|
7379
|
+
}
|
|
7380
|
+
return sum;
|
|
7381
|
+
}
|
|
7382
|
+
function sumErc20Amounts(actions) {
|
|
7383
|
+
let sum = 0n;
|
|
7384
|
+
for (const a of actions) if (a.type === "sendErc20") sum += a.amount;
|
|
7385
|
+
return sum;
|
|
7386
|
+
}
|
|
7387
|
+
function pickInteropRoute(args) {
|
|
7388
|
+
const hasErc20 = args.actions.some((a) => a.type === "sendErc20");
|
|
7389
|
+
const baseMatches = args.ctx.baseTokenSrc.toLowerCase() === args.ctx.baseTokenDst.toLowerCase();
|
|
7390
|
+
if (hasErc20) return "indirect";
|
|
7391
|
+
if (!baseMatches) return "indirect";
|
|
7392
|
+
return "direct";
|
|
7393
|
+
}
|
|
7394
|
+
|
|
7395
|
+
// src/core/resources/interop/plan.ts
|
|
7396
|
+
function preflightDirect(params, ctx) {
|
|
7397
|
+
if (!params.actions?.length) {
|
|
7398
|
+
throw new Error('route "direct" requires at least one action.');
|
|
7399
|
+
}
|
|
7400
|
+
const baseMatch = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
7401
|
+
if (!baseMatch) {
|
|
7402
|
+
throw new Error('route "direct" requires matching base tokens between source and destination.');
|
|
7403
|
+
}
|
|
7404
|
+
for (const action of params.actions) {
|
|
7405
|
+
switch (action.type) {
|
|
7406
|
+
case "sendNative":
|
|
7407
|
+
if (action.amount < 0n) {
|
|
7408
|
+
throw new Error("sendNative.amount must be >= 0.");
|
|
5563
7409
|
}
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
() => Promise.resolve(ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ev.data)[0]),
|
|
5569
|
-
{
|
|
5570
|
-
ctx: { where: "decode L1MessageSent", data: ev.data },
|
|
5571
|
-
message: "Failed to decode withdrawal message."
|
|
7410
|
+
break;
|
|
7411
|
+
case "call":
|
|
7412
|
+
if (action.value != null && action.value < 0n) {
|
|
7413
|
+
throw new Error("call.value must be >= 0 when provided.");
|
|
5572
7414
|
}
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
7415
|
+
break;
|
|
7416
|
+
default:
|
|
7417
|
+
throw new Error(
|
|
7418
|
+
`route "direct" does not support ${action.type} actions; use the indirect route.`
|
|
7419
|
+
);
|
|
7420
|
+
}
|
|
7421
|
+
}
|
|
7422
|
+
}
|
|
7423
|
+
function buildDirectBundle(params, ctx, attrs) {
|
|
7424
|
+
const totalActionValue = sumActionMsgValue(params.actions);
|
|
7425
|
+
const starters = params.actions.map((action, index) => {
|
|
7426
|
+
const to = ctx.codec.formatAddress(action.to);
|
|
7427
|
+
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
7428
|
+
switch (action.type) {
|
|
7429
|
+
case "sendNative":
|
|
7430
|
+
return [to, "0x", callAttributes];
|
|
7431
|
+
case "call":
|
|
7432
|
+
return [to, action.data ?? "0x", callAttributes];
|
|
7433
|
+
default:
|
|
7434
|
+
throw new Error(`buildDirectBundle: unsupported action type "${action.type}".`);
|
|
7435
|
+
}
|
|
7436
|
+
});
|
|
7437
|
+
return {
|
|
7438
|
+
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
7439
|
+
starters,
|
|
7440
|
+
bundleAttributes: attrs.bundleAttributes,
|
|
7441
|
+
approvals: [],
|
|
7442
|
+
quoteExtras: {
|
|
7443
|
+
totalActionValue,
|
|
7444
|
+
bridgedTokenTotal: 0n
|
|
7445
|
+
}
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
function preflightIndirect(params, ctx) {
|
|
7449
|
+
if (!params.actions?.length) {
|
|
7450
|
+
throw new Error('route "indirect" requires at least one action.');
|
|
7451
|
+
}
|
|
7452
|
+
const hasErc20 = params.actions.some((a) => a.type === "sendErc20");
|
|
7453
|
+
const baseMatches = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
7454
|
+
if (!hasErc20 && baseMatches) {
|
|
7455
|
+
throw new Error(
|
|
7456
|
+
'route "indirect" requires ERC-20 actions or mismatched base tokens; use the direct route instead.'
|
|
7457
|
+
);
|
|
7458
|
+
}
|
|
7459
|
+
for (const action of params.actions) {
|
|
7460
|
+
switch (action.type) {
|
|
7461
|
+
case "sendNative":
|
|
7462
|
+
if (action.amount < 0n) {
|
|
7463
|
+
throw new Error("sendNative.amount must be >= 0.");
|
|
5581
7464
|
}
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
operation: OP_WITHDRAWALS.finalize.fetchParams.rawReceipt,
|
|
5587
|
-
message: "Raw L2 receipt not found.",
|
|
5588
|
-
context: { l2TxHash }
|
|
5589
|
-
});
|
|
5590
|
-
}
|
|
5591
|
-
const idx = await wrapAs8(
|
|
5592
|
-
"INTERNAL",
|
|
5593
|
-
OP_WITHDRAWALS.finalize.fetchParams.messengerIndex,
|
|
5594
|
-
() => Promise.resolve(messengerLogIndex(raw, { index: 0, messenger: L1_MESSENGER_ADDRESS })),
|
|
5595
|
-
{
|
|
5596
|
-
ctx: { where: "derive messenger log index", l2TxHash, receipt: raw },
|
|
5597
|
-
message: "Failed to derive messenger log index."
|
|
7465
|
+
break;
|
|
7466
|
+
case "sendErc20":
|
|
7467
|
+
if (action.amount < 0n) {
|
|
7468
|
+
throw new Error("sendErc20.amount must be >= 0.");
|
|
5598
7469
|
}
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
7470
|
+
break;
|
|
7471
|
+
case "call":
|
|
7472
|
+
if (action.value != null) {
|
|
7473
|
+
if (action.value < 0n) {
|
|
7474
|
+
throw new Error("call.value must be >= 0 when provided.");
|
|
7475
|
+
}
|
|
7476
|
+
if (action.value > 0n && !baseMatches) {
|
|
7477
|
+
throw new Error("indirect route does not support call.value when base tokens differ.");
|
|
7478
|
+
}
|
|
5607
7479
|
}
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
7480
|
+
break;
|
|
7481
|
+
default:
|
|
7482
|
+
assertNever(action);
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7485
|
+
}
|
|
7486
|
+
function buildIndirectBundle(params, ctx, attrs, starterData) {
|
|
7487
|
+
const totalActionValue = sumActionMsgValue(params.actions);
|
|
7488
|
+
const bridgedTokenTotal = sumErc20Amounts(params.actions);
|
|
7489
|
+
const approvalMap = /* @__PURE__ */ new Map();
|
|
7490
|
+
for (const action of params.actions) {
|
|
7491
|
+
if (action.type !== "sendErc20") continue;
|
|
7492
|
+
const key = action.token.toLowerCase();
|
|
7493
|
+
const existing = approvalMap.get(key);
|
|
7494
|
+
if (existing) {
|
|
7495
|
+
existing.amount += action.amount;
|
|
7496
|
+
} else {
|
|
7497
|
+
approvalMap.set(key, {
|
|
7498
|
+
token: action.token,
|
|
7499
|
+
spender: ctx.l2NativeTokenVault,
|
|
7500
|
+
amount: action.amount
|
|
7501
|
+
});
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
const approvals = Array.from(approvalMap.values());
|
|
7505
|
+
const starters = params.actions.map((action, index) => {
|
|
7506
|
+
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
7507
|
+
if (starterData[index]?.assetRouterPayload) {
|
|
7508
|
+
const l2AssetRouter = ctx.codec.formatAddress(ctx.l2AssetRouter);
|
|
7509
|
+
return [l2AssetRouter, starterData[index].assetRouterPayload, callAttributes];
|
|
7510
|
+
}
|
|
7511
|
+
const directTo = ctx.codec.formatAddress(action.to);
|
|
7512
|
+
switch (action.type) {
|
|
7513
|
+
case "sendNative":
|
|
7514
|
+
return [directTo, "0x", callAttributes];
|
|
7515
|
+
case "call":
|
|
7516
|
+
return [directTo, action.data ?? "0x", callAttributes];
|
|
7517
|
+
case "sendErc20":
|
|
7518
|
+
throw new Error("buildIndirectBundle: missing assetRouterPayload for sendErc20 action.");
|
|
7519
|
+
default:
|
|
7520
|
+
return assertNever(action);
|
|
7521
|
+
}
|
|
7522
|
+
});
|
|
7523
|
+
return {
|
|
7524
|
+
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
7525
|
+
starters,
|
|
7526
|
+
bundleAttributes: attrs.bundleAttributes,
|
|
7527
|
+
approvals,
|
|
7528
|
+
quoteExtras: {
|
|
7529
|
+
totalActionValue,
|
|
7530
|
+
bridgedTokenTotal
|
|
7531
|
+
}
|
|
7532
|
+
};
|
|
7533
|
+
}
|
|
7534
|
+
var PREFIX_EVM_CHAIN = ethers.getBytes("0x00010000");
|
|
7535
|
+
var PREFIX_EVM_ADDRESS = ethers.getBytes("0x000100000014");
|
|
7536
|
+
function formatInteropEvmChain(chainId) {
|
|
7537
|
+
const chainRef = ethers.toBeArray(chainId);
|
|
7538
|
+
const chainRefLength = ethers.getBytes(ethers.toBeHex(chainRef.length, 1));
|
|
7539
|
+
const payload = ethers.concat([PREFIX_EVM_CHAIN, chainRefLength, chainRef, new Uint8Array([0])]);
|
|
7540
|
+
return ethers.hexlify(payload);
|
|
7541
|
+
}
|
|
7542
|
+
function formatInteropEvmAddress(address) {
|
|
7543
|
+
const normalized = ethers.getAddress(address);
|
|
7544
|
+
const addrBytes = ethers.getBytes(normalized);
|
|
7545
|
+
const payload = ethers.concat([PREFIX_EVM_ADDRESS, addrBytes]);
|
|
7546
|
+
return ethers.hexlify(payload);
|
|
7547
|
+
}
|
|
7548
|
+
var interopCodec = {
|
|
7549
|
+
formatChain: formatInteropEvmChain,
|
|
7550
|
+
formatAddress: formatInteropEvmAddress
|
|
7551
|
+
};
|
|
7552
|
+
function getErc20Tokens(params) {
|
|
7553
|
+
const erc20Tokens = /* @__PURE__ */ new Map();
|
|
7554
|
+
for (const action of params.actions) {
|
|
7555
|
+
if (action.type !== "sendErc20") continue;
|
|
7556
|
+
erc20Tokens.set(action.token.toLowerCase(), action.token);
|
|
7557
|
+
}
|
|
7558
|
+
return Array.from(erc20Tokens.values());
|
|
7559
|
+
}
|
|
7560
|
+
function buildEnsureTokenSteps(erc20Tokens, ctx) {
|
|
7561
|
+
if (erc20Tokens.length === 0) return [];
|
|
7562
|
+
const ntv = new ethers.Contract(ctx.l2NativeTokenVault, L2NativeTokenVault_default, ctx.client.l2);
|
|
7563
|
+
return erc20Tokens.map((token) => ({
|
|
7564
|
+
key: `ensure-token:${token.toLowerCase()}`,
|
|
7565
|
+
kind: "interop.ntv.ensure-token",
|
|
7566
|
+
description: `Ensure ${token} is registered in the native token vault`,
|
|
7567
|
+
tx: {
|
|
7568
|
+
to: ctx.l2NativeTokenVault,
|
|
7569
|
+
data: ntv.interface.encodeFunctionData("ensureTokenIsRegistered", [token]),
|
|
7570
|
+
...ctx.gasOverrides
|
|
7571
|
+
}
|
|
7572
|
+
}));
|
|
7573
|
+
}
|
|
7574
|
+
async function resolveErc20AssetIds(erc20Tokens, ctx) {
|
|
7575
|
+
const assetIds = /* @__PURE__ */ new Map();
|
|
7576
|
+
if (erc20Tokens.length === 0) return assetIds;
|
|
7577
|
+
const ntv = new ethers.Contract(ctx.l2NativeTokenVault, L2NativeTokenVault_default, ctx.client.getL2Signer());
|
|
7578
|
+
for (const token of erc20Tokens) {
|
|
7579
|
+
const assetId = await ntv.getFunction("ensureTokenIsRegistered").staticCall(token);
|
|
7580
|
+
assetIds.set(token.toLowerCase(), assetId);
|
|
7581
|
+
}
|
|
7582
|
+
return assetIds;
|
|
7583
|
+
}
|
|
7584
|
+
|
|
7585
|
+
// src/adapters/ethers/resources/interop/services/starter-data.ts
|
|
7586
|
+
async function getStarterData(params, ctx, erc20AssetIds) {
|
|
7587
|
+
const starterData = [];
|
|
7588
|
+
for (const action of params.actions) {
|
|
7589
|
+
switch (action.type) {
|
|
7590
|
+
case "sendErc20": {
|
|
7591
|
+
const assetId = erc20AssetIds.get(action.token.toLowerCase());
|
|
7592
|
+
if (!assetId) {
|
|
7593
|
+
throw new Error(`Missing precomputed assetId for token ${action.token}.`);
|
|
5616
7594
|
}
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
7595
|
+
const transferData = encodeNativeTokenVaultTransferData(
|
|
7596
|
+
action.amount,
|
|
7597
|
+
action.to,
|
|
7598
|
+
action.token
|
|
7599
|
+
);
|
|
7600
|
+
const assetRouterPayload = encodeSecondBridgeDataV1(assetId, transferData);
|
|
7601
|
+
starterData.push({ assetRouterPayload });
|
|
7602
|
+
break;
|
|
7603
|
+
}
|
|
7604
|
+
case "sendNative":
|
|
7605
|
+
if (!ctx.baseTokens.matches) {
|
|
7606
|
+
const assetId = await ctx.tokens.baseTokenAssetId();
|
|
7607
|
+
const transferData = encodeNativeTokenVaultTransferData(
|
|
7608
|
+
action.amount,
|
|
7609
|
+
action.to,
|
|
7610
|
+
ctx.baseTokens.src
|
|
7611
|
+
);
|
|
7612
|
+
const assetRouterPayload = encodeSecondBridgeDataV1(assetId, transferData);
|
|
7613
|
+
starterData.push({ assetRouterPayload });
|
|
7614
|
+
} else {
|
|
7615
|
+
starterData.push({});
|
|
5635
7616
|
}
|
|
5636
|
-
|
|
5637
|
-
|
|
7617
|
+
break;
|
|
7618
|
+
case "call":
|
|
7619
|
+
starterData.push({});
|
|
7620
|
+
break;
|
|
7621
|
+
default:
|
|
7622
|
+
assertNever(action);
|
|
7623
|
+
}
|
|
7624
|
+
}
|
|
7625
|
+
return starterData;
|
|
7626
|
+
}
|
|
7627
|
+
|
|
7628
|
+
// src/adapters/ethers/resources/interop/routes/indirect.ts
|
|
7629
|
+
function routeIndirect() {
|
|
7630
|
+
return {
|
|
7631
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
7632
|
+
async preflight(params, ctx) {
|
|
7633
|
+
preflightIndirect(params, {
|
|
7634
|
+
dstChainId: ctx.dstChainId,
|
|
7635
|
+
baseTokens: ctx.baseTokens,
|
|
7636
|
+
l2AssetRouter: ctx.l2AssetRouter,
|
|
7637
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault});
|
|
5638
7638
|
},
|
|
5639
|
-
async
|
|
5640
|
-
const
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
7639
|
+
async build(params, ctx) {
|
|
7640
|
+
const steps = [];
|
|
7641
|
+
const erc20Tokens = getErc20Tokens(params);
|
|
7642
|
+
const erc20AssetIds = await resolveErc20AssetIds(erc20Tokens, ctx);
|
|
7643
|
+
const attributes = getInteropAttributes(params, ctx);
|
|
7644
|
+
const starterData = await getStarterData(params, ctx, erc20AssetIds);
|
|
7645
|
+
const bundle = buildIndirectBundle(
|
|
7646
|
+
params,
|
|
5644
7647
|
{
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
7648
|
+
dstChainId: ctx.dstChainId,
|
|
7649
|
+
baseTokens: ctx.baseTokens,
|
|
7650
|
+
l2AssetRouter: ctx.l2AssetRouter,
|
|
7651
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault,
|
|
7652
|
+
codec: interopCodec
|
|
7653
|
+
},
|
|
7654
|
+
attributes,
|
|
7655
|
+
starterData
|
|
5648
7656
|
);
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
7657
|
+
steps.push(...buildEnsureTokenSteps(erc20Tokens, ctx));
|
|
7658
|
+
for (const approval of bundle.approvals) {
|
|
7659
|
+
const erc20 = new ethers.Contract(approval.token, IERC20_default, ctx.client.l2);
|
|
7660
|
+
const currentAllowance = await erc20.allowance(
|
|
7661
|
+
ctx.sender,
|
|
7662
|
+
ctx.l2NativeTokenVault
|
|
7663
|
+
);
|
|
7664
|
+
if (currentAllowance < approval.amount) {
|
|
7665
|
+
const approveData = erc20.interface.encodeFunctionData("approve", [
|
|
7666
|
+
ctx.l2NativeTokenVault,
|
|
7667
|
+
approval.amount
|
|
7668
|
+
]);
|
|
7669
|
+
steps.push({
|
|
7670
|
+
key: `approve:${approval.token}:${ctx.l2NativeTokenVault}`,
|
|
7671
|
+
kind: "approve",
|
|
7672
|
+
description: `Approve ${ctx.l2NativeTokenVault} to spend ${approval.amount} of ${approval.token}`,
|
|
7673
|
+
tx: {
|
|
7674
|
+
to: approval.token,
|
|
7675
|
+
data: approveData,
|
|
7676
|
+
...ctx.gasOverrides
|
|
5663
7677
|
}
|
|
5664
|
-
);
|
|
5665
|
-
return Boolean(isFinalized);
|
|
5666
|
-
} catch {
|
|
5667
|
-
return false;
|
|
7678
|
+
});
|
|
5668
7679
|
}
|
|
5669
|
-
})();
|
|
5670
|
-
if (done) return { kind: "FINALIZED" };
|
|
5671
|
-
const c = new ethers.Contract(l1Nullifier, IL1Nullifier_default, l1);
|
|
5672
|
-
try {
|
|
5673
|
-
await c.finalizeDeposit.staticCall(params);
|
|
5674
|
-
return { kind: "READY" };
|
|
5675
|
-
} catch (e) {
|
|
5676
|
-
return classifyReadinessFromRevert(e);
|
|
5677
7680
|
}
|
|
7681
|
+
const data = ctx.ifaces.interopCenter.encodeFunctionData("sendBundle", [
|
|
7682
|
+
bundle.dstChain,
|
|
7683
|
+
bundle.starters,
|
|
7684
|
+
bundle.bundleAttributes
|
|
7685
|
+
]);
|
|
7686
|
+
steps.push({
|
|
7687
|
+
key: "sendBundle",
|
|
7688
|
+
kind: "interop.center",
|
|
7689
|
+
description: "Send interop bundle (indirect route)",
|
|
7690
|
+
tx: {
|
|
7691
|
+
to: ctx.interopCenter,
|
|
7692
|
+
data,
|
|
7693
|
+
value: bundle.quoteExtras.totalActionValue,
|
|
7694
|
+
...ctx.gasOverrides
|
|
7695
|
+
}
|
|
7696
|
+
});
|
|
7697
|
+
return {
|
|
7698
|
+
steps,
|
|
7699
|
+
approvals: bundle.approvals,
|
|
7700
|
+
quoteExtras: bundle.quoteExtras
|
|
7701
|
+
};
|
|
7702
|
+
}
|
|
7703
|
+
};
|
|
7704
|
+
}
|
|
7705
|
+
|
|
7706
|
+
// src/adapters/ethers/resources/interop/routes/direct.ts
|
|
7707
|
+
function routeDirect() {
|
|
7708
|
+
return {
|
|
7709
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
7710
|
+
async preflight(params, ctx) {
|
|
7711
|
+
preflightDirect(params, {
|
|
7712
|
+
dstChainId: ctx.dstChainId,
|
|
7713
|
+
baseTokens: ctx.baseTokens,
|
|
7714
|
+
l2AssetRouter: ctx.l2AssetRouter,
|
|
7715
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault});
|
|
5678
7716
|
},
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
7717
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
7718
|
+
async build(params, ctx) {
|
|
7719
|
+
const steps = [];
|
|
7720
|
+
const attrs = getInteropAttributes(params, ctx);
|
|
7721
|
+
const built = buildDirectBundle(
|
|
7722
|
+
params,
|
|
5684
7723
|
{
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
7724
|
+
dstChainId: ctx.dstChainId,
|
|
7725
|
+
baseTokens: ctx.baseTokens,
|
|
7726
|
+
l2AssetRouter: ctx.l2AssetRouter,
|
|
7727
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault,
|
|
7728
|
+
codec: interopCodec
|
|
7729
|
+
},
|
|
7730
|
+
attrs
|
|
5688
7731
|
);
|
|
5689
|
-
const
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
7732
|
+
const data = ctx.ifaces.interopCenter.encodeFunctionData("sendBundle", [
|
|
7733
|
+
built.dstChain,
|
|
7734
|
+
built.starters,
|
|
7735
|
+
built.bundleAttributes
|
|
7736
|
+
]);
|
|
7737
|
+
steps.push({
|
|
7738
|
+
key: "sendBundle",
|
|
7739
|
+
kind: "interop.center",
|
|
7740
|
+
description: `Send interop bundle (direct route; ${params.actions.length} actions)`,
|
|
7741
|
+
// In direct route, msg.value equals the total forwarded value across
|
|
7742
|
+
// all calls (sendNative.amount + call.value).
|
|
7743
|
+
tx: {
|
|
7744
|
+
to: ctx.interopCenter,
|
|
7745
|
+
data,
|
|
7746
|
+
value: built.quoteExtras.totalActionValue,
|
|
7747
|
+
...ctx.gasOverrides
|
|
5697
7748
|
}
|
|
5698
|
-
);
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
7749
|
+
});
|
|
7750
|
+
return {
|
|
7751
|
+
steps,
|
|
7752
|
+
approvals: built.approvals,
|
|
7753
|
+
quoteExtras: built.quoteExtras
|
|
7754
|
+
};
|
|
7755
|
+
}
|
|
7756
|
+
};
|
|
7757
|
+
}
|
|
7758
|
+
var MIN_INTEROP_PROTOCOL = 31;
|
|
7759
|
+
async function assertInteropProtocolVersion(client, srcChainId, dstChainId) {
|
|
7760
|
+
const [srcProtocolVersion, dstProtocolVersion] = await Promise.all([
|
|
7761
|
+
client.getProtocolVersion(srcChainId),
|
|
7762
|
+
client.getProtocolVersion(dstChainId)
|
|
7763
|
+
]);
|
|
7764
|
+
const assertProtocolVersion = (chainId, protocolVersion) => {
|
|
7765
|
+
if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
|
|
7766
|
+
throw createError("VALIDATION", {
|
|
7767
|
+
resource: "interop",
|
|
7768
|
+
operation: OP_INTEROP.context.protocolVersion,
|
|
7769
|
+
message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
|
|
7770
|
+
context: {
|
|
7771
|
+
chainId,
|
|
7772
|
+
requiredMinor: MIN_INTEROP_PROTOCOL,
|
|
7773
|
+
semver: protocolVersion
|
|
5708
7774
|
}
|
|
5709
|
-
);
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
7775
|
+
});
|
|
7776
|
+
}
|
|
7777
|
+
};
|
|
7778
|
+
assertProtocolVersion(srcChainId, srcProtocolVersion);
|
|
7779
|
+
assertProtocolVersion(dstChainId, dstProtocolVersion);
|
|
7780
|
+
}
|
|
7781
|
+
async function commonCtx3(dstProvider, params, client, tokens, contracts, attributes) {
|
|
7782
|
+
const sender = await client.signer.getAddress();
|
|
7783
|
+
const chainId = (await client.l2.getNetwork()).chainId;
|
|
7784
|
+
const dstChainId = (await dstProvider.getNetwork()).chainId;
|
|
7785
|
+
const {
|
|
7786
|
+
bridgehub,
|
|
7787
|
+
l2AssetRouter,
|
|
7788
|
+
l2NativeTokenVault,
|
|
7789
|
+
interopCenter,
|
|
7790
|
+
interopHandler,
|
|
7791
|
+
l2MessageVerification
|
|
7792
|
+
} = await contracts.addresses();
|
|
7793
|
+
await assertInteropProtocolVersion(client, chainId, dstChainId);
|
|
7794
|
+
const [srcBaseToken, dstBaseToken] = await Promise.all([
|
|
7795
|
+
client.baseToken(chainId),
|
|
7796
|
+
client.baseToken(dstChainId)
|
|
7797
|
+
]);
|
|
7798
|
+
const interopCenterIface = new ethers.Interface(InteropCenter_default);
|
|
7799
|
+
const interopHandlerIface = new ethers.Interface(IInteropHandler_default);
|
|
7800
|
+
const baseMatches = srcBaseToken.toLowerCase() === dstBaseToken.toLowerCase();
|
|
7801
|
+
return {
|
|
7802
|
+
client,
|
|
7803
|
+
tokens,
|
|
7804
|
+
contracts,
|
|
7805
|
+
sender,
|
|
7806
|
+
chainIdL2: chainId,
|
|
7807
|
+
chainId,
|
|
7808
|
+
bridgehub,
|
|
7809
|
+
dstChainId,
|
|
7810
|
+
dstProvider,
|
|
7811
|
+
interopCenter,
|
|
7812
|
+
interopHandler,
|
|
7813
|
+
l2MessageVerification,
|
|
7814
|
+
l2AssetRouter,
|
|
7815
|
+
l2NativeTokenVault,
|
|
7816
|
+
baseTokens: { src: srcBaseToken, dst: dstBaseToken, matches: baseMatches },
|
|
7817
|
+
ifaces: { interopCenter: interopCenterIface, interopHandler: interopHandlerIface },
|
|
7818
|
+
attributes,
|
|
7819
|
+
gasOverrides: params.txOverrides ? toGasOverrides(params.txOverrides) : void 0
|
|
7820
|
+
};
|
|
7821
|
+
}
|
|
7822
|
+
function getTopics() {
|
|
7823
|
+
const centerIface = new ethers.Interface(InteropCenter_default);
|
|
7824
|
+
const handlerIface = new ethers.Interface(IInteropHandler_default);
|
|
7825
|
+
const topics = {
|
|
7826
|
+
interopBundleSent: centerIface.getEvent("InteropBundleSent").topicHash,
|
|
7827
|
+
bundleVerified: handlerIface.getEvent("BundleVerified").topicHash,
|
|
7828
|
+
bundleExecuted: handlerIface.getEvent("BundleExecuted").topicHash,
|
|
7829
|
+
bundleUnbundled: handlerIface.getEvent("BundleUnbundled").topicHash
|
|
7830
|
+
};
|
|
7831
|
+
return { topics, centerIface };
|
|
7832
|
+
}
|
|
7833
|
+
var { wrap: wrap2 } = createErrorHandlers("interop");
|
|
7834
|
+
var DEFAULT_BLOCKS_RANGE_SIZE = 1e4;
|
|
7835
|
+
var DEFAULT_MAX_BLOCKS_BACK = 2e4;
|
|
7836
|
+
var SAFE_BLOCKS_RANGE_SIZE = 1e3;
|
|
7837
|
+
function parseMaxBlockRangeLimit(error) {
|
|
7838
|
+
if (!ethers.isError(error, "UNKNOWN_ERROR")) return null;
|
|
7839
|
+
if (!error.error || typeof error.error !== "object") return null;
|
|
7840
|
+
const match = /query exceeds max block range\s+(\d+)/i.exec(error.error?.message);
|
|
7841
|
+
if (!match) return null;
|
|
7842
|
+
const limit = Number.parseInt(match[1], 10);
|
|
7843
|
+
return Number.isInteger(limit) && limit > 0 ? limit : null;
|
|
7844
|
+
}
|
|
7845
|
+
async function getTxReceipt(provider, txHash) {
|
|
7846
|
+
const receipt = await wrap2(
|
|
7847
|
+
OP_INTEROP.svc.status.sourceReceipt,
|
|
7848
|
+
() => provider.getTransactionReceipt(txHash),
|
|
7849
|
+
{
|
|
7850
|
+
ctx: { where: "l2.getTransactionReceipt", l2SrcTxHash: txHash },
|
|
7851
|
+
message: "Failed to fetch source L2 receipt for interop tx."
|
|
7852
|
+
}
|
|
7853
|
+
);
|
|
7854
|
+
if (!receipt) return null;
|
|
7855
|
+
return {
|
|
7856
|
+
logs: receipt.logs.map((log) => ({
|
|
7857
|
+
address: log.address,
|
|
7858
|
+
topics: log.topics,
|
|
7859
|
+
data: log.data,
|
|
7860
|
+
transactionHash: log.transactionHash
|
|
7861
|
+
}))
|
|
7862
|
+
};
|
|
7863
|
+
}
|
|
7864
|
+
async function getLogs(provider, address, topics, opts) {
|
|
7865
|
+
const maxBlocksBack = opts?.maxBlocksBack ?? DEFAULT_MAX_BLOCKS_BACK;
|
|
7866
|
+
const initialChunkSize = opts?.logChunkSize ?? DEFAULT_BLOCKS_RANGE_SIZE;
|
|
7867
|
+
return await wrap2(
|
|
7868
|
+
OP_INTEROP.svc.status.dstLogs,
|
|
7869
|
+
async () => {
|
|
7870
|
+
const currentBlock = await provider.getBlockNumber();
|
|
7871
|
+
const minBlock = Math.max(0, currentBlock - maxBlocksBack);
|
|
7872
|
+
let toBlock = currentBlock;
|
|
7873
|
+
let chunkSize = initialChunkSize;
|
|
7874
|
+
while (toBlock >= minBlock) {
|
|
7875
|
+
const fromBlock = Math.max(minBlock, toBlock - chunkSize + 1);
|
|
7876
|
+
try {
|
|
7877
|
+
const rawLogs = await provider.getLogs({
|
|
7878
|
+
address,
|
|
7879
|
+
topics,
|
|
7880
|
+
fromBlock,
|
|
7881
|
+
toBlock
|
|
7882
|
+
});
|
|
7883
|
+
if (rawLogs.length > 0) {
|
|
7884
|
+
return rawLogs.map((log) => ({
|
|
7885
|
+
address: log.address,
|
|
7886
|
+
topics: log.topics,
|
|
7887
|
+
data: log.data,
|
|
7888
|
+
transactionHash: log.transactionHash
|
|
7889
|
+
}));
|
|
7890
|
+
}
|
|
7891
|
+
toBlock = fromBlock - 1;
|
|
7892
|
+
} catch (error) {
|
|
7893
|
+
const serverLimit = parseMaxBlockRangeLimit(error);
|
|
7894
|
+
if (serverLimit == null) {
|
|
7895
|
+
if (chunkSize > SAFE_BLOCKS_RANGE_SIZE) {
|
|
7896
|
+
chunkSize = SAFE_BLOCKS_RANGE_SIZE;
|
|
7897
|
+
} else {
|
|
7898
|
+
throw error;
|
|
7899
|
+
}
|
|
7900
|
+
} else {
|
|
7901
|
+
chunkSize = Math.min(chunkSize, serverLimit);
|
|
7902
|
+
}
|
|
5725
7903
|
}
|
|
7904
|
+
}
|
|
7905
|
+
return [];
|
|
7906
|
+
},
|
|
7907
|
+
{
|
|
7908
|
+
ctx: { address, maxBlocksBack, logChunkSize: initialChunkSize },
|
|
7909
|
+
message: "Failed to query destination bundle lifecycle logs."
|
|
7910
|
+
}
|
|
7911
|
+
);
|
|
7912
|
+
}
|
|
7913
|
+
async function getInteropRoot(provider, rootChainId, batchNumber) {
|
|
7914
|
+
return await wrap2(
|
|
7915
|
+
OP_INTEROP.svc.status.getRoot,
|
|
7916
|
+
async () => {
|
|
7917
|
+
const rootStorage = new ethers.Contract(
|
|
7918
|
+
L2_INTEROP_ROOT_STORAGE_ADDRESS,
|
|
7919
|
+
InteropRootStorage_default,
|
|
7920
|
+
provider
|
|
5726
7921
|
);
|
|
5727
|
-
|
|
5728
|
-
ctx: { where: "l1.getFeeData" },
|
|
5729
|
-
message: "Failed to estimate fee data for finalizeDeposit."
|
|
5730
|
-
});
|
|
5731
|
-
const maxFeePerGas = feeData.maxFeePerGas ?? feeData.gasPrice ?? // legacy-style gas price if present
|
|
5732
|
-
(() => {
|
|
5733
|
-
throw createError("RPC", {
|
|
5734
|
-
resource: "withdrawals",
|
|
5735
|
-
operation: OP_WITHDRAWALS.finalize.estimate,
|
|
5736
|
-
message: "Provider did not return gas price or EIP-1559 fields.",
|
|
5737
|
-
context: { feeData }
|
|
5738
|
-
});
|
|
5739
|
-
})();
|
|
5740
|
-
const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? 0n;
|
|
5741
|
-
return {
|
|
5742
|
-
gasLimit,
|
|
5743
|
-
maxFeePerGas,
|
|
5744
|
-
maxPriorityFeePerGas
|
|
5745
|
-
};
|
|
7922
|
+
return await rootStorage.interopRoots(rootChainId, batchNumber);
|
|
5746
7923
|
},
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
7924
|
+
{
|
|
7925
|
+
ctx: { rootChainId, batchNumber },
|
|
7926
|
+
message: "Failed to get interop root from the destination chain."
|
|
7927
|
+
}
|
|
7928
|
+
);
|
|
7929
|
+
}
|
|
7930
|
+
|
|
7931
|
+
// src/adapters/ethers/resources/interop/services/finalization/bundle.ts
|
|
7932
|
+
var { wrap: wrap3 } = createErrorHandlers("interop");
|
|
7933
|
+
async function getBundleStatus(client, dstProvider, topics, bundleHash, opts) {
|
|
7934
|
+
const { interopHandler } = await client.ensureAddresses();
|
|
7935
|
+
const bundleLogs = await getLogs(dstProvider, interopHandler, [null, bundleHash], opts);
|
|
7936
|
+
const findLastByTopic = (eventTopic) => bundleLogs.findLast((log) => log.topics[0].toLowerCase() === eventTopic.toLowerCase());
|
|
7937
|
+
const lifecycleChecks = [
|
|
7938
|
+
{ phase: "UNBUNDLED", topic: topics.bundleUnbundled, includeTxHash: true },
|
|
7939
|
+
{ phase: "EXECUTED", topic: topics.bundleExecuted, includeTxHash: true },
|
|
7940
|
+
{ phase: "VERIFIED", topic: topics.bundleVerified }
|
|
7941
|
+
];
|
|
7942
|
+
for (const check of lifecycleChecks) {
|
|
7943
|
+
const match = findLastByTopic(check.topic);
|
|
7944
|
+
if (!match) continue;
|
|
7945
|
+
if (check.includeTxHash) {
|
|
7946
|
+
return { phase: check.phase, dstExecTxHash: match.transactionHash };
|
|
7947
|
+
}
|
|
7948
|
+
return { phase: check.phase };
|
|
7949
|
+
}
|
|
7950
|
+
return { phase: "SENT" };
|
|
7951
|
+
}
|
|
7952
|
+
async function executeBundle(client, dstProvider, info, opts) {
|
|
7953
|
+
const { topics } = getTopics();
|
|
7954
|
+
const { bundleHash, encodedData, proof } = info;
|
|
7955
|
+
const dstStatus = await getBundleStatus(client, dstProvider, topics, bundleHash, opts);
|
|
7956
|
+
if (["EXECUTED", "UNBUNDLED"].includes(dstStatus.phase)) {
|
|
7957
|
+
throw createError("STATE", {
|
|
7958
|
+
resource: "interop",
|
|
7959
|
+
operation: OP_INTEROP.finalize,
|
|
7960
|
+
message: `Interop bundle has already been ${dstStatus.phase.toLowerCase()}.`,
|
|
7961
|
+
context: { bundleHash }
|
|
7962
|
+
});
|
|
7963
|
+
}
|
|
7964
|
+
const signer = await wrap3(OP_INTEROP.exec.sendStep, () => client.signerFor(dstProvider), {
|
|
7965
|
+
message: "Failed to resolve destination signer."
|
|
7966
|
+
});
|
|
7967
|
+
const { interopHandler } = await client.ensureAddresses();
|
|
7968
|
+
const handler = new ethers.Contract(interopHandler, IInteropHandler_default, signer);
|
|
7969
|
+
try {
|
|
7970
|
+
const txResponse = await handler.executeBundle(encodedData, proof);
|
|
7971
|
+
const hash = txResponse.hash;
|
|
7972
|
+
return {
|
|
7973
|
+
hash,
|
|
7974
|
+
wait: async () => {
|
|
7975
|
+
try {
|
|
7976
|
+
const receipt = await txResponse.wait();
|
|
7977
|
+
if (!receipt || receipt.status !== 1) {
|
|
7978
|
+
throw createError("EXECUTION", {
|
|
7979
|
+
resource: "interop",
|
|
7980
|
+
operation: OP_INTEROP.exec.waitStep,
|
|
7981
|
+
message: "Interop bundle execution reverted on destination.",
|
|
7982
|
+
context: { txHash: hash }
|
|
7983
|
+
});
|
|
7984
|
+
}
|
|
7985
|
+
return receipt;
|
|
7986
|
+
} catch (e) {
|
|
7987
|
+
if (isZKsyncError(e)) throw e;
|
|
7988
|
+
throw toZKsyncError(
|
|
7989
|
+
"EXECUTION",
|
|
7990
|
+
{
|
|
7991
|
+
resource: "interop",
|
|
7992
|
+
operation: OP_INTEROP.exec.waitStep,
|
|
7993
|
+
message: "Failed while waiting for executeBundle transaction on destination.",
|
|
7994
|
+
context: { txHash: hash }
|
|
7995
|
+
},
|
|
7996
|
+
e
|
|
7997
|
+
);
|
|
5755
7998
|
}
|
|
5756
|
-
|
|
5757
|
-
|
|
7999
|
+
}
|
|
8000
|
+
};
|
|
8001
|
+
} catch (e) {
|
|
8002
|
+
throw toZKsyncError(
|
|
8003
|
+
"EXECUTION",
|
|
8004
|
+
{
|
|
8005
|
+
resource: "interop",
|
|
8006
|
+
operation: OP_INTEROP.exec.sendStep,
|
|
8007
|
+
message: "Failed to send executeBundle transaction on destination chain."
|
|
8008
|
+
},
|
|
8009
|
+
e
|
|
8010
|
+
);
|
|
8011
|
+
}
|
|
8012
|
+
}
|
|
8013
|
+
|
|
8014
|
+
// src/core/resources/interop/finalization.ts
|
|
8015
|
+
var DEFAULT_POLL_MS = 1e3;
|
|
8016
|
+
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
8017
|
+
function resolveIdsFromWaitable(input) {
|
|
8018
|
+
if (typeof input === "string") {
|
|
8019
|
+
return { l2SrcTxHash: input };
|
|
8020
|
+
}
|
|
8021
|
+
return {
|
|
8022
|
+
l2SrcTxHash: input.l2SrcTxHash,
|
|
8023
|
+
bundleHash: input.bundleHash,
|
|
8024
|
+
dstExecTxHash: input.dstExecTxHash
|
|
8025
|
+
};
|
|
8026
|
+
}
|
|
8027
|
+
function parseBundleSentFromReceipt(input) {
|
|
8028
|
+
const { receipt, interopCenter, interopBundleSentTopic, decodeInteropBundleSent: decodeInteropBundleSent2 } = input;
|
|
8029
|
+
const bundleSentLog = receipt.logs.find(
|
|
8030
|
+
(log) => log.address.toLowerCase() === interopCenter.toLowerCase() && log.topics[0].toLowerCase() === interopBundleSentTopic.toLowerCase()
|
|
8031
|
+
);
|
|
8032
|
+
if (!bundleSentLog) {
|
|
8033
|
+
throw createError("STATE", {
|
|
8034
|
+
resource: "interop",
|
|
8035
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
8036
|
+
message: "Failed to locate InteropBundleSent event in source receipt.",
|
|
8037
|
+
context: { receipt, interopCenter }
|
|
8038
|
+
});
|
|
8039
|
+
}
|
|
8040
|
+
const decoded = decodeInteropBundleSent2({
|
|
8041
|
+
data: bundleSentLog.data,
|
|
8042
|
+
topics: bundleSentLog.topics
|
|
8043
|
+
});
|
|
8044
|
+
return { bundleHash: decoded.bundleHash, dstChainId: decoded.destinationChainId };
|
|
8045
|
+
}
|
|
8046
|
+
function parseBundleReceiptInfo(params) {
|
|
8047
|
+
const {
|
|
8048
|
+
rawReceipt,
|
|
8049
|
+
interopCenter,
|
|
8050
|
+
interopBundleSentTopic,
|
|
8051
|
+
decodeInteropBundleSent: decodeInteropBundleSent2,
|
|
8052
|
+
decodeL1MessageData: decodeL1MessageData2,
|
|
8053
|
+
l2SrcTxHash
|
|
8054
|
+
} = params;
|
|
8055
|
+
let l2ToL1LogIndex = -1;
|
|
8056
|
+
let l1MessageData = null;
|
|
8057
|
+
let found;
|
|
8058
|
+
for (const log of rawReceipt.logs) {
|
|
8059
|
+
if (isL1MessageSentLog(log)) {
|
|
8060
|
+
l2ToL1LogIndex += 1;
|
|
5758
8061
|
try {
|
|
5759
|
-
|
|
5760
|
-
const hash = receipt.hash;
|
|
5761
|
-
return {
|
|
5762
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
5763
|
-
hash,
|
|
5764
|
-
wait: async () => {
|
|
5765
|
-
try {
|
|
5766
|
-
return await receipt.wait();
|
|
5767
|
-
} catch (e) {
|
|
5768
|
-
throw toZKsyncError(
|
|
5769
|
-
"EXECUTION",
|
|
5770
|
-
{
|
|
5771
|
-
resource: "withdrawals",
|
|
5772
|
-
operation: OP_WITHDRAWALS.finalize.wait,
|
|
5773
|
-
message: "Failed while waiting for finalizeDeposit transaction.",
|
|
5774
|
-
context: { txHash: hash }
|
|
5775
|
-
},
|
|
5776
|
-
e
|
|
5777
|
-
);
|
|
5778
|
-
}
|
|
5779
|
-
}
|
|
5780
|
-
};
|
|
8062
|
+
l1MessageData = decodeL1MessageData2(log);
|
|
5781
8063
|
} catch (e) {
|
|
5782
|
-
throw
|
|
5783
|
-
"
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
chainIdL2: params.chainId,
|
|
5790
|
-
l2BatchNumber: params.l2BatchNumber,
|
|
5791
|
-
l2MessageIndex: params.l2MessageIndex,
|
|
5792
|
-
l1Nullifier
|
|
5793
|
-
}
|
|
5794
|
-
},
|
|
5795
|
-
e
|
|
5796
|
-
);
|
|
8064
|
+
throw createError("STATE", {
|
|
8065
|
+
resource: "interop",
|
|
8066
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
8067
|
+
message: "Failed to decode L1MessageSent log data for interop bundle.",
|
|
8068
|
+
context: { l2SrcTxHash, l2ToL1LogIndex },
|
|
8069
|
+
cause: e
|
|
8070
|
+
});
|
|
5797
8071
|
}
|
|
8072
|
+
continue;
|
|
5798
8073
|
}
|
|
8074
|
+
if (log.address.toLowerCase() !== interopCenter.toLowerCase() || log.topics[0].toLowerCase() !== interopBundleSentTopic.toLowerCase())
|
|
8075
|
+
continue;
|
|
8076
|
+
const decoded = decodeInteropBundleSent2({
|
|
8077
|
+
data: log.data,
|
|
8078
|
+
topics: log.topics
|
|
8079
|
+
});
|
|
8080
|
+
found = {
|
|
8081
|
+
bundleHash: decoded.bundleHash,
|
|
8082
|
+
dstChainId: decoded.destinationChainId,
|
|
8083
|
+
sourceChainId: decoded.sourceChainId
|
|
8084
|
+
};
|
|
8085
|
+
break;
|
|
8086
|
+
}
|
|
8087
|
+
if (!found) {
|
|
8088
|
+
throw createError("STATE", {
|
|
8089
|
+
resource: "interop",
|
|
8090
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
8091
|
+
message: "Failed to locate InteropBundleSent event in source receipt.",
|
|
8092
|
+
context: { l2SrcTxHash, interopCenter }
|
|
8093
|
+
});
|
|
8094
|
+
}
|
|
8095
|
+
if (!l1MessageData) {
|
|
8096
|
+
throw createError("STATE", {
|
|
8097
|
+
resource: "interop",
|
|
8098
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
8099
|
+
message: "Failed to locate L1MessageSent log data for interop bundle.",
|
|
8100
|
+
context: { l2SrcTxHash, interopCenter }
|
|
8101
|
+
});
|
|
8102
|
+
}
|
|
8103
|
+
return {
|
|
8104
|
+
bundleHash: found.bundleHash,
|
|
8105
|
+
dstChainId: found.dstChainId,
|
|
8106
|
+
sourceChainId: found.sourceChainId,
|
|
8107
|
+
l1MessageData,
|
|
8108
|
+
l2ToL1LogIndex,
|
|
8109
|
+
txNumberInBatch: Number(rawReceipt.transactionIndex),
|
|
8110
|
+
rawReceipt
|
|
8111
|
+
};
|
|
8112
|
+
}
|
|
8113
|
+
function getBundleEncodedData(messageData) {
|
|
8114
|
+
const prefix = `0x${messageData.slice(2, 4)}`;
|
|
8115
|
+
if (prefix !== BUNDLE_IDENTIFIER) {
|
|
8116
|
+
throw createError("STATE", {
|
|
8117
|
+
resource: "interop",
|
|
8118
|
+
operation: OP_INTEROP.wait,
|
|
8119
|
+
message: "Unexpected bundle prefix in L1MessageSent data.",
|
|
8120
|
+
context: { prefix, expected: BUNDLE_IDENTIFIER }
|
|
8121
|
+
});
|
|
8122
|
+
}
|
|
8123
|
+
return `0x${messageData.slice(4)}`;
|
|
8124
|
+
}
|
|
8125
|
+
function buildFinalizationInfo(ids, bundleInfo, proof, messageData) {
|
|
8126
|
+
const expectedRoot = {
|
|
8127
|
+
rootChainId: bundleInfo.sourceChainId,
|
|
8128
|
+
batchNumber: proof.batchNumber,
|
|
8129
|
+
expectedRoot: proof.root
|
|
8130
|
+
};
|
|
8131
|
+
const messageProof = {
|
|
8132
|
+
chainId: bundleInfo.sourceChainId,
|
|
8133
|
+
l1BatchNumber: proof.batchNumber,
|
|
8134
|
+
l2MessageIndex: proof.id,
|
|
8135
|
+
message: {
|
|
8136
|
+
txNumberInBatch: bundleInfo.txNumberInBatch,
|
|
8137
|
+
sender: L2_INTEROP_CENTER_ADDRESS,
|
|
8138
|
+
data: messageData
|
|
8139
|
+
},
|
|
8140
|
+
proof: proof.proof
|
|
8141
|
+
};
|
|
8142
|
+
return {
|
|
8143
|
+
l2SrcTxHash: ids.l2SrcTxHash,
|
|
8144
|
+
bundleHash: bundleInfo.bundleHash,
|
|
8145
|
+
dstChainId: bundleInfo.dstChainId,
|
|
8146
|
+
expectedRoot,
|
|
8147
|
+
proof: messageProof,
|
|
8148
|
+
encodedData: getBundleEncodedData(messageData)
|
|
8149
|
+
};
|
|
8150
|
+
}
|
|
8151
|
+
function decodeInteropBundleSent(centerIface, log) {
|
|
8152
|
+
const decoded = centerIface.decodeEventLog(
|
|
8153
|
+
"InteropBundleSent",
|
|
8154
|
+
log.data,
|
|
8155
|
+
log.topics
|
|
8156
|
+
);
|
|
8157
|
+
return {
|
|
8158
|
+
bundleHash: decoded.interopBundleHash,
|
|
8159
|
+
sourceChainId: decoded.interopBundle.sourceChainId,
|
|
8160
|
+
destinationChainId: decoded.interopBundle.destinationChainId
|
|
5799
8161
|
};
|
|
5800
8162
|
}
|
|
8163
|
+
function decodeL1MessageData(log) {
|
|
8164
|
+
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], log.data);
|
|
8165
|
+
return decoded[0];
|
|
8166
|
+
}
|
|
5801
8167
|
|
|
5802
|
-
// src/adapters/ethers/resources/
|
|
5803
|
-
var
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
};
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
8168
|
+
// src/adapters/ethers/resources/interop/services/finalization/polling.ts
|
|
8169
|
+
var { wrap: wrap4 } = createErrorHandlers("interop");
|
|
8170
|
+
function isProofNotReadyError(error) {
|
|
8171
|
+
return isZKsyncError(error, {
|
|
8172
|
+
operation: "zksrpc.getL2ToL1LogProof",
|
|
8173
|
+
messageIncludes: "proof not yet available"
|
|
8174
|
+
});
|
|
8175
|
+
}
|
|
8176
|
+
function shouldRetryRootFetch(error) {
|
|
8177
|
+
if (!isZKsyncError(error)) return false;
|
|
8178
|
+
return error.envelope.operation === OP_INTEROP.svc.status.getRoot;
|
|
8179
|
+
}
|
|
8180
|
+
async function waitForProof(client, l2SrcTxHash, logIndex, blockNumber, pollMs, deadline) {
|
|
8181
|
+
while (true) {
|
|
8182
|
+
if (Date.now() > deadline) {
|
|
8183
|
+
throw createError("TIMEOUT", {
|
|
8184
|
+
resource: "interop",
|
|
8185
|
+
operation: OP_INTEROP.svc.wait.timeout,
|
|
8186
|
+
message: "Timed out waiting for block to be finalized.",
|
|
8187
|
+
context: { l2SrcTxHash, logIndex, blockNumber }
|
|
8188
|
+
});
|
|
8189
|
+
}
|
|
8190
|
+
const finalizedBlock = await client.l2.getBlock("finalized");
|
|
8191
|
+
if (finalizedBlock && BigInt(finalizedBlock.number) >= blockNumber) {
|
|
8192
|
+
break;
|
|
8193
|
+
}
|
|
8194
|
+
await sleep(pollMs);
|
|
8195
|
+
}
|
|
8196
|
+
while (true) {
|
|
8197
|
+
if (Date.now() > deadline) {
|
|
8198
|
+
throw createError("TIMEOUT", {
|
|
8199
|
+
resource: "interop",
|
|
8200
|
+
operation: OP_INTEROP.svc.wait.timeout,
|
|
8201
|
+
message: "Timed out waiting for L2->L1 log proof to become available.",
|
|
8202
|
+
context: { l2SrcTxHash, logIndex }
|
|
8203
|
+
});
|
|
8204
|
+
}
|
|
8205
|
+
try {
|
|
8206
|
+
return await client.zks.getL2ToL1LogProof(l2SrcTxHash, logIndex);
|
|
8207
|
+
} catch (error) {
|
|
8208
|
+
if (!isProofNotReadyError(error)) throw error;
|
|
8209
|
+
}
|
|
8210
|
+
await sleep(pollMs);
|
|
8211
|
+
}
|
|
8212
|
+
}
|
|
8213
|
+
async function waitForRoot(provider, expectedRoot, pollMs, deadline) {
|
|
8214
|
+
while (true) {
|
|
8215
|
+
if (Date.now() > deadline) {
|
|
8216
|
+
throw createError("TIMEOUT", {
|
|
8217
|
+
resource: "interop",
|
|
8218
|
+
operation: OP_INTEROP.svc.wait.timeout,
|
|
8219
|
+
message: "Timed out waiting for interop root to become available.",
|
|
8220
|
+
context: { expectedRoot }
|
|
8221
|
+
});
|
|
8222
|
+
}
|
|
8223
|
+
let interopRoot = null;
|
|
8224
|
+
try {
|
|
8225
|
+
const root = await getInteropRoot(
|
|
8226
|
+
provider,
|
|
8227
|
+
expectedRoot.rootChainId,
|
|
8228
|
+
expectedRoot.batchNumber
|
|
8229
|
+
);
|
|
8230
|
+
if (root !== ZERO_HASH) {
|
|
8231
|
+
interopRoot = root;
|
|
8232
|
+
}
|
|
8233
|
+
} catch (error) {
|
|
8234
|
+
if (!shouldRetryRootFetch(error)) throw error;
|
|
8235
|
+
interopRoot = null;
|
|
8236
|
+
}
|
|
8237
|
+
if (interopRoot) {
|
|
8238
|
+
if (interopRoot.toLowerCase() === expectedRoot.expectedRoot.toLowerCase()) {
|
|
8239
|
+
return;
|
|
8240
|
+
}
|
|
8241
|
+
throw createError("STATE", {
|
|
8242
|
+
resource: "interop",
|
|
8243
|
+
operation: OP_INTEROP.wait,
|
|
8244
|
+
message: "Interop root mismatch.",
|
|
8245
|
+
context: {
|
|
8246
|
+
expected: expectedRoot.expectedRoot,
|
|
8247
|
+
got: interopRoot
|
|
8248
|
+
}
|
|
8249
|
+
});
|
|
8250
|
+
}
|
|
8251
|
+
await sleep(pollMs);
|
|
8252
|
+
}
|
|
8253
|
+
}
|
|
8254
|
+
async function waitForTxReceipt(client, txHash, pollMs, deadline) {
|
|
8255
|
+
while (true) {
|
|
8256
|
+
if (Date.now() > deadline) {
|
|
8257
|
+
throw createError("TIMEOUT", {
|
|
8258
|
+
resource: "interop",
|
|
8259
|
+
operation: OP_INTEROP.svc.wait.timeout,
|
|
8260
|
+
message: "Timed out waiting for source receipt to be available.",
|
|
8261
|
+
context: { txHash }
|
|
8262
|
+
});
|
|
8263
|
+
}
|
|
8264
|
+
const receipt = await wrap4(
|
|
8265
|
+
OP_INTEROP.svc.status.sourceReceipt,
|
|
8266
|
+
() => client.zks.getReceiptWithL2ToL1(txHash),
|
|
8267
|
+
{
|
|
8268
|
+
ctx: { where: "zks.getReceiptWithL2ToL1", txHash },
|
|
8269
|
+
message: "Failed to fetch source L2 receipt (with L2->L1 logs) for interop tx."
|
|
8270
|
+
}
|
|
8271
|
+
);
|
|
8272
|
+
if (receipt) {
|
|
8273
|
+
return receipt;
|
|
8274
|
+
}
|
|
8275
|
+
await sleep(pollMs);
|
|
8276
|
+
}
|
|
8277
|
+
}
|
|
8278
|
+
async function waitForFinalization(client, dstProvider, input, opts) {
|
|
8279
|
+
const { topics, centerIface } = getTopics();
|
|
8280
|
+
const pollMs = opts?.pollMs ?? DEFAULT_POLL_MS;
|
|
8281
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
8282
|
+
const deadline = Date.now() + timeoutMs;
|
|
8283
|
+
const ids = resolveIdsFromWaitable(input);
|
|
8284
|
+
if (!ids.l2SrcTxHash) {
|
|
8285
|
+
throw createError("STATE", {
|
|
8286
|
+
resource: "interop",
|
|
8287
|
+
operation: OP_INTEROP.svc.status.sourceReceipt,
|
|
8288
|
+
message: "Cannot wait for interop finalization: missing l2SrcTxHash.",
|
|
8289
|
+
context: { input }
|
|
8290
|
+
});
|
|
8291
|
+
}
|
|
8292
|
+
const { interopCenter } = await client.ensureAddresses();
|
|
8293
|
+
let bundleInfo = null;
|
|
8294
|
+
while (!bundleInfo) {
|
|
8295
|
+
if (Date.now() > deadline) {
|
|
8296
|
+
throw createError("TIMEOUT", {
|
|
8297
|
+
resource: "interop",
|
|
8298
|
+
operation: OP_INTEROP.svc.wait.timeout,
|
|
8299
|
+
message: "Timed out waiting for source receipt to be available.",
|
|
8300
|
+
context: { l2SrcTxHash: ids.l2SrcTxHash }
|
|
8301
|
+
});
|
|
8302
|
+
}
|
|
8303
|
+
const txReceipt = await waitForTxReceipt(client, ids.l2SrcTxHash, pollMs, deadline);
|
|
8304
|
+
bundleInfo = parseBundleReceiptInfo({
|
|
8305
|
+
rawReceipt: txReceipt,
|
|
8306
|
+
interopCenter,
|
|
8307
|
+
interopBundleSentTopic: topics.interopBundleSent,
|
|
8308
|
+
decodeInteropBundleSent: (log) => decodeInteropBundleSent(centerIface, log),
|
|
8309
|
+
decodeL1MessageData,
|
|
8310
|
+
l2SrcTxHash: ids.l2SrcTxHash
|
|
8311
|
+
});
|
|
8312
|
+
}
|
|
8313
|
+
const proof = await waitForProof(
|
|
8314
|
+
client,
|
|
8315
|
+
ids.l2SrcTxHash,
|
|
8316
|
+
bundleInfo.l2ToL1LogIndex,
|
|
8317
|
+
BigInt(bundleInfo.rawReceipt.blockNumber),
|
|
8318
|
+
pollMs,
|
|
8319
|
+
deadline
|
|
8320
|
+
);
|
|
8321
|
+
const finalizationInfo = buildFinalizationInfo(
|
|
8322
|
+
{ l2SrcTxHash: ids.l2SrcTxHash, bundleHash: ids.bundleHash },
|
|
8323
|
+
bundleInfo,
|
|
8324
|
+
proof,
|
|
8325
|
+
bundleInfo.l1MessageData
|
|
8326
|
+
);
|
|
8327
|
+
await waitForRoot(dstProvider, finalizationInfo.expectedRoot, pollMs, deadline);
|
|
8328
|
+
return finalizationInfo;
|
|
8329
|
+
}
|
|
8330
|
+
|
|
8331
|
+
// src/adapters/ethers/resources/interop/services/finalization/status.ts
|
|
8332
|
+
async function getStatus(client, dstProvider, input, opts) {
|
|
8333
|
+
const { topics, centerIface } = getTopics();
|
|
8334
|
+
const baseIds = resolveIdsFromWaitable(input);
|
|
8335
|
+
const enrichedIds = await (async () => {
|
|
8336
|
+
if (baseIds.bundleHash) return baseIds;
|
|
8337
|
+
if (!baseIds.l2SrcTxHash) return baseIds;
|
|
8338
|
+
const { interopCenter } = await client.ensureAddresses();
|
|
8339
|
+
const receipt = await getTxReceipt(client.l2, baseIds.l2SrcTxHash);
|
|
8340
|
+
if (!receipt) return baseIds;
|
|
8341
|
+
const { bundleHash } = parseBundleSentFromReceipt({
|
|
8342
|
+
receipt: { logs: receipt.logs },
|
|
8343
|
+
interopCenter,
|
|
8344
|
+
interopBundleSentTopic: topics.interopBundleSent,
|
|
8345
|
+
decodeInteropBundleSent: (log) => decodeInteropBundleSent(centerIface, log)
|
|
8346
|
+
});
|
|
8347
|
+
return { ...baseIds, bundleHash };
|
|
8348
|
+
})();
|
|
8349
|
+
if (!enrichedIds.bundleHash) {
|
|
8350
|
+
const phase = enrichedIds.l2SrcTxHash ? "SENT" : "UNKNOWN";
|
|
5818
8351
|
return {
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
amounts: {
|
|
5824
|
-
transfer: { token: p.token, amount: p.amount }
|
|
5825
|
-
},
|
|
5826
|
-
fees
|
|
5827
|
-
},
|
|
5828
|
-
steps
|
|
8352
|
+
phase,
|
|
8353
|
+
l2SrcTxHash: enrichedIds.l2SrcTxHash,
|
|
8354
|
+
bundleHash: enrichedIds.bundleHash,
|
|
8355
|
+
dstExecTxHash: enrichedIds.dstExecTxHash
|
|
5829
8356
|
};
|
|
5830
8357
|
}
|
|
5831
|
-
const
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
8358
|
+
const dstInfo = await getBundleStatus(client, dstProvider, topics, enrichedIds.bundleHash, opts);
|
|
8359
|
+
return {
|
|
8360
|
+
phase: dstInfo.phase,
|
|
8361
|
+
l2SrcTxHash: enrichedIds.l2SrcTxHash,
|
|
8362
|
+
bundleHash: enrichedIds.bundleHash,
|
|
8363
|
+
dstExecTxHash: dstInfo.dstExecTxHash ?? enrichedIds.dstExecTxHash
|
|
8364
|
+
};
|
|
8365
|
+
}
|
|
8366
|
+
|
|
8367
|
+
// src/adapters/ethers/resources/interop/services/finalization/index.ts
|
|
8368
|
+
function createInteropFinalizationServices(client) {
|
|
8369
|
+
return {
|
|
8370
|
+
status(dstProvider, input, opts) {
|
|
8371
|
+
return getStatus(client, dstProvider, input, opts);
|
|
5837
8372
|
},
|
|
5838
|
-
{
|
|
5839
|
-
|
|
5840
|
-
ctx: { token: p.token, where: "withdrawals.quote" }
|
|
5841
|
-
}
|
|
5842
|
-
);
|
|
5843
|
-
const tryQuote = (p) => toResult2(
|
|
5844
|
-
OP_WITHDRAWALS.tryQuote,
|
|
5845
|
-
async () => {
|
|
5846
|
-
const plan = await buildPlan(p);
|
|
5847
|
-
return plan.summary;
|
|
8373
|
+
wait(dstProvider, input, opts) {
|
|
8374
|
+
return waitForFinalization(client, dstProvider, input, opts);
|
|
5848
8375
|
},
|
|
5849
|
-
{
|
|
5850
|
-
|
|
5851
|
-
|
|
8376
|
+
async finalize(dstProvider, info, opts) {
|
|
8377
|
+
const execResult = await executeBundle(client, dstProvider, info, opts);
|
|
8378
|
+
await execResult.wait();
|
|
8379
|
+
return {
|
|
8380
|
+
bundleHash: info.bundleHash,
|
|
8381
|
+
dstExecTxHash: execResult.hash
|
|
8382
|
+
};
|
|
5852
8383
|
}
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
8384
|
+
};
|
|
8385
|
+
}
|
|
8386
|
+
function resolveDstProvider(dstChain) {
|
|
8387
|
+
return typeof dstChain === "string" ? new ethers.JsonRpcProvider(dstChain) : dstChain;
|
|
8388
|
+
}
|
|
8389
|
+
function resolveWaitableInput(waitableInput) {
|
|
8390
|
+
const input = waitableInput;
|
|
8391
|
+
return {
|
|
8392
|
+
dstProvider: resolveDstProvider(waitableInput.dstChain),
|
|
8393
|
+
waitable: input.waitable ? input.waitable : waitableInput
|
|
8394
|
+
};
|
|
8395
|
+
}
|
|
8396
|
+
|
|
8397
|
+
// src/adapters/ethers/resources/interop/index.ts
|
|
8398
|
+
var { wrap: wrap5, toResult: toResult2 } = createErrorHandlers("interop");
|
|
8399
|
+
var ROUTES3 = {
|
|
8400
|
+
direct: routeDirect(),
|
|
8401
|
+
indirect: routeIndirect()
|
|
8402
|
+
};
|
|
8403
|
+
function createInteropResource(client, tokens, contracts, attributes) {
|
|
8404
|
+
const svc = createInteropFinalizationServices(client);
|
|
8405
|
+
const tokensResource = createTokensResource(client);
|
|
8406
|
+
const contractsResource = createContractsResource(client);
|
|
8407
|
+
const attributesResource = createEthersAttributesResource();
|
|
8408
|
+
async function buildPlanWithCtx(dstProvider, params) {
|
|
8409
|
+
const ctx = await commonCtx3(
|
|
8410
|
+
dstProvider,
|
|
8411
|
+
params,
|
|
8412
|
+
client,
|
|
8413
|
+
tokensResource,
|
|
8414
|
+
contractsResource,
|
|
8415
|
+
attributesResource
|
|
8416
|
+
);
|
|
8417
|
+
const route = pickInteropRoute({
|
|
8418
|
+
actions: params.actions,
|
|
8419
|
+
ctx: {
|
|
8420
|
+
sender: ctx.sender,
|
|
8421
|
+
srcChainId: ctx.chainId,
|
|
8422
|
+
dstChainId: ctx.dstChainId,
|
|
8423
|
+
baseTokenSrc: ctx.baseTokens.src,
|
|
8424
|
+
baseTokenDst: ctx.baseTokens.dst
|
|
8425
|
+
}
|
|
8426
|
+
});
|
|
8427
|
+
await wrap5(OP_INTEROP.routes[route].preflight, () => ROUTES3[route].preflight?.(params, ctx), {
|
|
8428
|
+
message: "Interop preflight failed.",
|
|
8429
|
+
ctx: { where: `routes.${route}.preflight` }
|
|
8430
|
+
});
|
|
8431
|
+
const { steps, approvals, quoteExtras } = await wrap5(
|
|
8432
|
+
OP_INTEROP.routes[route].build,
|
|
8433
|
+
() => ROUTES3[route].build(params, ctx),
|
|
8434
|
+
{
|
|
8435
|
+
message: "Failed to build interop route plan.",
|
|
8436
|
+
ctx: { where: `routes.${route}.build` }
|
|
8437
|
+
}
|
|
8438
|
+
);
|
|
8439
|
+
const summary = {
|
|
8440
|
+
route,
|
|
8441
|
+
approvalsNeeded: approvals,
|
|
8442
|
+
totalActionValue: quoteExtras.totalActionValue,
|
|
8443
|
+
bridgedTokenTotal: quoteExtras.bridgedTokenTotal
|
|
8444
|
+
};
|
|
8445
|
+
return { plan: { route, summary, steps }, ctx };
|
|
8446
|
+
}
|
|
8447
|
+
async function buildPlan(dstProvider, params) {
|
|
8448
|
+
const { plan } = await buildPlanWithCtx(dstProvider, params);
|
|
8449
|
+
return plan;
|
|
8450
|
+
}
|
|
8451
|
+
const quote = (params) => wrap5(OP_INTEROP.quote, async () => {
|
|
8452
|
+
const plan = await buildPlan(resolveDstProvider(params.dstChain), params);
|
|
8453
|
+
return plan.summary;
|
|
5857
8454
|
});
|
|
5858
|
-
const
|
|
5859
|
-
|
|
5860
|
-
|
|
8455
|
+
const tryQuote = (params) => toResult2(OP_INTEROP.tryQuote, () => quote(params));
|
|
8456
|
+
const prepare = (params) => wrap5(OP_INTEROP.prepare, () => buildPlan(resolveDstProvider(params.dstChain), params), {
|
|
8457
|
+
message: "Internal error while preparing an interop plan.",
|
|
8458
|
+
ctx: { where: "interop.prepare" }
|
|
5861
8459
|
});
|
|
5862
|
-
const
|
|
5863
|
-
|
|
8460
|
+
const tryPrepare = (params) => toResult2(OP_INTEROP.tryPrepare, () => prepare(params));
|
|
8461
|
+
const create = (params) => wrap5(
|
|
8462
|
+
OP_INTEROP.create,
|
|
5864
8463
|
async () => {
|
|
5865
|
-
const plan = await
|
|
8464
|
+
const { plan, ctx } = await buildPlanWithCtx(resolveDstProvider(params.dstChain), params);
|
|
8465
|
+
const signer = ctx.client.signerFor(ctx.client.l2);
|
|
8466
|
+
const srcProvider = ctx.client.l2;
|
|
8467
|
+
const from = await signer.getAddress();
|
|
8468
|
+
let next;
|
|
8469
|
+
if (typeof params.txOverrides?.nonce === "number") {
|
|
8470
|
+
next = params.txOverrides.nonce;
|
|
8471
|
+
} else {
|
|
8472
|
+
const blockTag = params.txOverrides?.nonce ?? "pending";
|
|
8473
|
+
next = await srcProvider.getTransactionCount(from, blockTag);
|
|
8474
|
+
}
|
|
5866
8475
|
const stepHashes = {};
|
|
5867
|
-
const managed = new ethers.NonceManager(client.getL2Signer());
|
|
5868
|
-
const from = await managed.getAddress();
|
|
5869
|
-
let next = await client.l2.getTransactionCount(from, "pending");
|
|
5870
8476
|
for (const step of plan.steps) {
|
|
5871
8477
|
step.tx.nonce = next++;
|
|
5872
|
-
if (
|
|
5873
|
-
|
|
5874
|
-
if (overrides.gasLimit != null) step.tx.gasLimit = overrides.gasLimit;
|
|
5875
|
-
if (overrides.maxFeePerGas != null) step.tx.maxFeePerGas = overrides.maxFeePerGas;
|
|
5876
|
-
if (overrides.maxPriorityFeePerGas != null) {
|
|
5877
|
-
step.tx.maxPriorityFeePerGas = overrides.maxPriorityFeePerGas;
|
|
5878
|
-
}
|
|
8478
|
+
if (!step.tx.chainId) {
|
|
8479
|
+
step.tx.chainId = Number(ctx.chainId);
|
|
5879
8480
|
}
|
|
5880
8481
|
if (!step.tx.gasLimit) {
|
|
5881
8482
|
try {
|
|
5882
|
-
const est = await
|
|
8483
|
+
const est = await srcProvider.estimateGas({
|
|
8484
|
+
...step.tx,
|
|
8485
|
+
from
|
|
8486
|
+
});
|
|
5883
8487
|
step.tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
5884
8488
|
} catch {
|
|
5885
8489
|
}
|
|
5886
8490
|
}
|
|
5887
8491
|
let hash;
|
|
5888
8492
|
try {
|
|
5889
|
-
const sent = await
|
|
8493
|
+
const sent = await signer.sendTransaction(step.tx);
|
|
5890
8494
|
hash = sent.hash;
|
|
5891
8495
|
stepHashes[step.key] = hash;
|
|
5892
8496
|
const rcpt = await sent.wait();
|
|
5893
8497
|
if (rcpt?.status === 0) {
|
|
5894
8498
|
throw createError("EXECUTION", {
|
|
5895
|
-
resource: "
|
|
5896
|
-
operation: "
|
|
5897
|
-
message: "
|
|
5898
|
-
context: { step: step.key, txHash: hash
|
|
8499
|
+
resource: "interop",
|
|
8500
|
+
operation: "interop.create.sendTransaction",
|
|
8501
|
+
message: "Interop transaction reverted on source L2.",
|
|
8502
|
+
context: { step: step.key, txHash: hash }
|
|
5899
8503
|
});
|
|
5900
8504
|
}
|
|
5901
8505
|
} catch (e) {
|
|
5902
|
-
throw
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
8506
|
+
if (isZKsyncError(e)) throw e;
|
|
8507
|
+
throw createError("EXECUTION", {
|
|
8508
|
+
resource: "interop",
|
|
8509
|
+
operation: "interop.create.sendTransaction",
|
|
8510
|
+
message: "Failed to send or confirm an interop transaction step.",
|
|
8511
|
+
context: {
|
|
8512
|
+
step: step.key,
|
|
8513
|
+
txHash: hash,
|
|
8514
|
+
nonce: Number(step.tx.nonce ?? -1)
|
|
5909
8515
|
},
|
|
5910
|
-
e
|
|
5911
|
-
);
|
|
5912
|
-
}
|
|
5913
|
-
}
|
|
5914
|
-
const keys = Object.keys(stepHashes);
|
|
5915
|
-
const l2TxHash = stepHashes[keys[keys.length - 1]];
|
|
5916
|
-
return { kind: "withdrawal", l2TxHash, stepHashes, plan };
|
|
5917
|
-
},
|
|
5918
|
-
{
|
|
5919
|
-
message: "Internal error while creating withdrawal transactions.",
|
|
5920
|
-
ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.create" }
|
|
5921
|
-
}
|
|
5922
|
-
);
|
|
5923
|
-
const tryCreate = (p) => toResult2(OP_WITHDRAWALS.tryCreate, () => create(p), {
|
|
5924
|
-
message: "Internal error while creating withdrawal transactions.",
|
|
5925
|
-
ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.tryCreate" }
|
|
5926
|
-
});
|
|
5927
|
-
const status = (h) => wrap2(
|
|
5928
|
-
OP_WITHDRAWALS.status,
|
|
5929
|
-
async () => {
|
|
5930
|
-
const l2TxHash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
|
|
5931
|
-
if (!l2TxHash || l2TxHash === "0x") {
|
|
5932
|
-
return { phase: "UNKNOWN", l2TxHash: "0x" };
|
|
5933
|
-
}
|
|
5934
|
-
let l2Rcpt;
|
|
5935
|
-
try {
|
|
5936
|
-
l2Rcpt = await client.l2.getTransactionReceipt(l2TxHash);
|
|
5937
|
-
} catch (e) {
|
|
5938
|
-
if (isReceiptNotFound(e)) {
|
|
5939
|
-
return { phase: "L2_PENDING", l2TxHash };
|
|
8516
|
+
cause: e
|
|
8517
|
+
});
|
|
5940
8518
|
}
|
|
5941
|
-
throw toZKsyncError(
|
|
5942
|
-
"RPC",
|
|
5943
|
-
{
|
|
5944
|
-
resource: "withdrawals",
|
|
5945
|
-
operation: "withdrawals.status.getTransactionReceipt",
|
|
5946
|
-
message: "Failed to fetch L2 transaction receipt.",
|
|
5947
|
-
context: { l2TxHash, where: "l2.getTransactionReceipt" }
|
|
5948
|
-
},
|
|
5949
|
-
e
|
|
5950
|
-
);
|
|
5951
|
-
}
|
|
5952
|
-
if (!l2Rcpt) return { phase: "L2_PENDING", l2TxHash };
|
|
5953
|
-
let pack;
|
|
5954
|
-
try {
|
|
5955
|
-
pack = await svc.fetchFinalizeDepositParams(l2TxHash);
|
|
5956
|
-
} catch {
|
|
5957
|
-
return { phase: "PENDING", l2TxHash };
|
|
5958
8519
|
}
|
|
5959
|
-
const
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
8520
|
+
const last = Object.values(stepHashes).pop();
|
|
8521
|
+
return {
|
|
8522
|
+
kind: "interop",
|
|
8523
|
+
dstChain: params.dstChain,
|
|
8524
|
+
stepHashes,
|
|
8525
|
+
plan,
|
|
8526
|
+
l2SrcTxHash: last ?? "0x"
|
|
5963
8527
|
};
|
|
5964
|
-
try {
|
|
5965
|
-
const done = await svc.isWithdrawalFinalized(key);
|
|
5966
|
-
if (done) return { phase: "FINALIZED", l2TxHash, key };
|
|
5967
|
-
} catch {
|
|
5968
|
-
}
|
|
5969
|
-
const readiness = await svc.simulateFinalizeReadiness(pack.params);
|
|
5970
|
-
if (readiness.kind === "FINALIZED") return { phase: "FINALIZED", l2TxHash, key };
|
|
5971
|
-
if (readiness.kind === "READY") return { phase: "READY_TO_FINALIZE", l2TxHash, key };
|
|
5972
|
-
return { phase: "PENDING", l2TxHash, key };
|
|
5973
8528
|
},
|
|
5974
8529
|
{
|
|
5975
|
-
message: "Internal error while
|
|
5976
|
-
ctx: { where: "
|
|
8530
|
+
message: "Internal error while creating interop bundle.",
|
|
8531
|
+
ctx: { where: "interop.create" }
|
|
5977
8532
|
}
|
|
5978
8533
|
);
|
|
5979
|
-
const
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
context: { l2TxHash: l2Hash }
|
|
5999
|
-
},
|
|
6000
|
-
e
|
|
6001
|
-
);
|
|
6002
|
-
}
|
|
6003
|
-
if (!rcpt) return null;
|
|
6004
|
-
try {
|
|
6005
|
-
const raw = await client.zks.getReceiptWithL2ToL1(l2Hash);
|
|
6006
|
-
rcpt.l2ToL1Logs = raw?.l2ToL1Logs ?? [];
|
|
6007
|
-
} catch {
|
|
6008
|
-
rcpt.l2ToL1Logs = rcpt.l2ToL1Logs ?? [];
|
|
6009
|
-
}
|
|
6010
|
-
return rcpt;
|
|
6011
|
-
}
|
|
6012
|
-
const poll = Math.max(1e3, opts.pollMs ?? 2500);
|
|
6013
|
-
const deadline = opts.timeoutMs ? Date.now() + opts.timeoutMs : void 0;
|
|
6014
|
-
while (true) {
|
|
6015
|
-
const s = await status(l2Hash);
|
|
6016
|
-
if (opts.for === "ready") {
|
|
6017
|
-
if (s.phase === "READY_TO_FINALIZE" || s.phase === "FINALIZED") return null;
|
|
6018
|
-
} else {
|
|
6019
|
-
if (s.phase === "FINALIZED") {
|
|
6020
|
-
const l1Hash = finalizeCache.get(l2Hash);
|
|
6021
|
-
if (l1Hash) {
|
|
6022
|
-
try {
|
|
6023
|
-
const l1Rcpt = await client.l1.getTransactionReceipt(l1Hash);
|
|
6024
|
-
if (l1Rcpt) {
|
|
6025
|
-
finalizeCache.delete(l2Hash);
|
|
6026
|
-
return l1Rcpt;
|
|
6027
|
-
}
|
|
6028
|
-
} catch {
|
|
6029
|
-
}
|
|
6030
|
-
}
|
|
6031
|
-
return null;
|
|
6032
|
-
}
|
|
6033
|
-
}
|
|
6034
|
-
if (deadline && Date.now() > deadline) return null;
|
|
6035
|
-
await new Promise((r) => setTimeout(r, poll));
|
|
6036
|
-
}
|
|
6037
|
-
},
|
|
6038
|
-
{
|
|
6039
|
-
message: "Internal error while waiting for withdrawal.",
|
|
6040
|
-
ctx: {
|
|
6041
|
-
where: "withdrawals.wait",
|
|
6042
|
-
l2TxHash: typeof h === "string" ? h : h.l2TxHash,
|
|
6043
|
-
for: opts.for
|
|
8534
|
+
const tryCreate = (params) => toResult2(OP_INTEROP.tryCreate, () => create(params));
|
|
8535
|
+
const status = (h, opts) => {
|
|
8536
|
+
const { dstProvider, waitable } = resolveWaitableInput(h);
|
|
8537
|
+
return wrap5(OP_INTEROP.status, () => svc.status(dstProvider, waitable, opts), {
|
|
8538
|
+
message: "Internal error while checking interop status.",
|
|
8539
|
+
ctx: { where: "interop.status" }
|
|
8540
|
+
});
|
|
8541
|
+
};
|
|
8542
|
+
const wait = (h, opts) => {
|
|
8543
|
+
const { dstProvider, waitable } = resolveWaitableInput(h);
|
|
8544
|
+
return wrap5(
|
|
8545
|
+
OP_INTEROP.wait,
|
|
8546
|
+
async () => {
|
|
8547
|
+
const info = await svc.wait(dstProvider, waitable, opts);
|
|
8548
|
+
return { ...info, dstChain: h.dstChain };
|
|
8549
|
+
},
|
|
8550
|
+
{
|
|
8551
|
+
message: "Internal error while waiting for interop finalization.",
|
|
8552
|
+
ctx: { where: "interop.wait" }
|
|
6044
8553
|
}
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
const
|
|
6048
|
-
|
|
8554
|
+
);
|
|
8555
|
+
};
|
|
8556
|
+
const tryWait = (h, opts) => toResult2(OP_INTEROP.tryWait, () => wait(h, opts));
|
|
8557
|
+
const finalize = (h, opts) => wrap5(
|
|
8558
|
+
OP_INTEROP.finalize,
|
|
6049
8559
|
async () => {
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
return await svc.fetchFinalizeDepositParams(l2TxHash);
|
|
6053
|
-
} catch (e) {
|
|
8560
|
+
if (isInteropFinalizationInfo(h)) {
|
|
8561
|
+
if (h.dstChain == null) {
|
|
6054
8562
|
throw createError("STATE", {
|
|
6055
|
-
resource: "
|
|
6056
|
-
operation:
|
|
6057
|
-
message: "
|
|
6058
|
-
context: {
|
|
6059
|
-
cause: e
|
|
8563
|
+
resource: "interop",
|
|
8564
|
+
operation: OP_INTEROP.finalize,
|
|
8565
|
+
message: "Missing dstChain in interop finalization info.",
|
|
8566
|
+
context: { input: h }
|
|
6060
8567
|
});
|
|
6061
8568
|
}
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
const key = {
|
|
6065
|
-
chainIdL2: params.chainId,
|
|
6066
|
-
l2BatchNumber: params.l2BatchNumber,
|
|
6067
|
-
l2MessageIndex: params.l2MessageIndex
|
|
6068
|
-
};
|
|
6069
|
-
try {
|
|
6070
|
-
const done = await svc.isWithdrawalFinalized(key);
|
|
6071
|
-
if (done) {
|
|
6072
|
-
const statusNow = await status(l2TxHash);
|
|
6073
|
-
return { status: statusNow };
|
|
6074
|
-
}
|
|
6075
|
-
} catch {
|
|
6076
|
-
}
|
|
6077
|
-
const readiness = await svc.simulateFinalizeReadiness(params);
|
|
6078
|
-
if (readiness.kind === "FINALIZED") {
|
|
6079
|
-
const statusNow = await status(l2TxHash);
|
|
6080
|
-
return { status: statusNow };
|
|
6081
|
-
}
|
|
6082
|
-
if (readiness.kind === "NOT_READY") {
|
|
6083
|
-
throw createError("STATE", {
|
|
6084
|
-
resource: "withdrawals",
|
|
6085
|
-
operation: OP_WITHDRAWALS.finalize.readiness.simulate,
|
|
6086
|
-
message: "Withdrawal not ready to finalize.",
|
|
6087
|
-
context: readiness
|
|
6088
|
-
});
|
|
6089
|
-
}
|
|
6090
|
-
try {
|
|
6091
|
-
const tx = await svc.finalizeDeposit(params);
|
|
6092
|
-
finalizeCache.set(l2TxHash, tx.hash);
|
|
6093
|
-
const rcpt = await tx.wait();
|
|
6094
|
-
const statusNow = await status(l2TxHash);
|
|
6095
|
-
return { status: statusNow, receipt: rcpt };
|
|
6096
|
-
} catch (e) {
|
|
6097
|
-
const statusNow = await status(l2TxHash);
|
|
6098
|
-
if (statusNow.phase === "FINALIZED") return { status: statusNow };
|
|
6099
|
-
try {
|
|
6100
|
-
const again = await svc.simulateFinalizeReadiness(params);
|
|
6101
|
-
if (again.kind === "NOT_READY") {
|
|
6102
|
-
throw createError("STATE", {
|
|
6103
|
-
resource: "withdrawals",
|
|
6104
|
-
operation: OP_WITHDRAWALS.finalize.readiness.simulate,
|
|
6105
|
-
message: "Withdrawal not ready to finalize.",
|
|
6106
|
-
context: again
|
|
6107
|
-
});
|
|
6108
|
-
}
|
|
6109
|
-
} catch {
|
|
6110
|
-
}
|
|
6111
|
-
throw e;
|
|
8569
|
+
const dstProvider2 = resolveDstProvider(h.dstChain);
|
|
8570
|
+
return svc.finalize(dstProvider2, h, opts);
|
|
6112
8571
|
}
|
|
8572
|
+
const { dstProvider, waitable } = resolveWaitableInput(h);
|
|
8573
|
+
const info = await svc.wait(dstProvider, waitable);
|
|
8574
|
+
return svc.finalize(dstProvider, info, opts);
|
|
6113
8575
|
},
|
|
6114
8576
|
{
|
|
6115
|
-
message: "
|
|
6116
|
-
ctx: {
|
|
6117
|
-
}
|
|
6118
|
-
);
|
|
6119
|
-
const tryFinalize = (l2TxHash) => toResult2("withdrawals.tryFinalize", () => finalize(l2TxHash), {
|
|
6120
|
-
message: "Internal error while attempting to tryFinalize withdrawal.",
|
|
6121
|
-
ctx: { l2TxHash, where: "withdrawals.tryFinalize" }
|
|
6122
|
-
});
|
|
6123
|
-
const tryWait = (h, opts) => toResult2(
|
|
6124
|
-
OP_WITHDRAWALS.tryWait,
|
|
6125
|
-
async () => {
|
|
6126
|
-
const v = await wait(h, opts);
|
|
6127
|
-
if (v) return v;
|
|
6128
|
-
throw createError("STATE", {
|
|
6129
|
-
resource: "withdrawals",
|
|
6130
|
-
operation: "withdrawals.tryWait",
|
|
6131
|
-
message: opts.for === "l2" ? "No L2 receipt yet; the withdrawal has not executed on L2." : "No L1 receipt yet; the withdrawal has not been included on L1.",
|
|
6132
|
-
context: {
|
|
6133
|
-
for: opts.for,
|
|
6134
|
-
l2TxHash: typeof h === "string" ? h : "l2TxHash" in h ? h.l2TxHash : void 0,
|
|
6135
|
-
where: "withdrawals.tryWait"
|
|
6136
|
-
}
|
|
6137
|
-
});
|
|
6138
|
-
},
|
|
6139
|
-
{
|
|
6140
|
-
message: "Internal error while waiting for withdrawal.",
|
|
6141
|
-
ctx: { input: h, for: opts?.for, where: "withdrawals.tryWait" }
|
|
8577
|
+
message: "Failed to finalize/execute interop bundle on destination.",
|
|
8578
|
+
ctx: { where: "interop.finalize" }
|
|
6142
8579
|
}
|
|
6143
8580
|
);
|
|
8581
|
+
const tryFinalize = (h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(h, opts));
|
|
6144
8582
|
return {
|
|
6145
8583
|
quote,
|
|
6146
8584
|
tryQuote,
|
|
@@ -6150,9 +8588,9 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
6150
8588
|
tryCreate,
|
|
6151
8589
|
status,
|
|
6152
8590
|
wait,
|
|
8591
|
+
tryWait,
|
|
6153
8592
|
finalize,
|
|
6154
|
-
tryFinalize
|
|
6155
|
-
tryWait
|
|
8593
|
+
tryFinalize
|
|
6156
8594
|
};
|
|
6157
8595
|
}
|
|
6158
8596
|
|
|
@@ -6160,11 +8598,13 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
6160
8598
|
function createEthersSdk(client) {
|
|
6161
8599
|
const tokens = createTokensResource(client);
|
|
6162
8600
|
const contracts = createContractsResource(client);
|
|
8601
|
+
const interop = createInteropResource(client);
|
|
6163
8602
|
return {
|
|
6164
8603
|
deposits: createDepositsResource(client, tokens, contracts),
|
|
6165
8604
|
withdrawals: createWithdrawalsResource(client, tokens, contracts),
|
|
6166
8605
|
tokens,
|
|
6167
|
-
contracts
|
|
8606
|
+
contracts,
|
|
8607
|
+
interop
|
|
6168
8608
|
};
|
|
6169
8609
|
}
|
|
6170
8610
|
|