@matterlabs/zksync-js 0.0.14 → 0.0.16

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.
Files changed (66) hide show
  1. package/dist/adapters/ethers/client.cjs.map +1 -1
  2. package/dist/adapters/ethers/client.d.ts +1 -2
  3. package/dist/adapters/ethers/client.js +4 -5
  4. package/dist/adapters/ethers/index.cjs +200 -32
  5. package/dist/adapters/ethers/index.cjs.map +1 -1
  6. package/dist/adapters/ethers/index.js +6 -7
  7. package/dist/adapters/ethers/resources/interop/index.d.ts +4 -1
  8. package/dist/adapters/ethers/resources/interop/services/finalization/bundle.d.ts +4 -0
  9. package/dist/adapters/ethers/resources/interop/services/gas.d.ts +12 -0
  10. package/dist/adapters/ethers/sdk.cjs +200 -32
  11. package/dist/adapters/ethers/sdk.cjs.map +1 -1
  12. package/dist/adapters/ethers/sdk.js +5 -6
  13. package/dist/adapters/viem/client.cjs +787 -3
  14. package/dist/adapters/viem/client.cjs.map +1 -1
  15. package/dist/adapters/viem/client.d.ts +6 -1
  16. package/dist/adapters/viem/client.js +4 -5
  17. package/dist/adapters/viem/index.cjs +6502 -2966
  18. package/dist/adapters/viem/index.cjs.map +1 -1
  19. package/dist/adapters/viem/index.d.ts +5 -0
  20. package/dist/adapters/viem/index.js +6 -7
  21. package/dist/adapters/viem/resources/interop/address.d.ts +18 -0
  22. package/dist/adapters/viem/resources/interop/attributes/resource.d.ts +6 -0
  23. package/dist/adapters/viem/resources/interop/context.d.ts +31 -0
  24. package/dist/adapters/viem/resources/interop/index.d.ts +65 -0
  25. package/dist/adapters/viem/resources/interop/resolvers.d.ts +4 -0
  26. package/dist/adapters/viem/resources/interop/routes/direct.d.ts +2 -0
  27. package/dist/adapters/viem/resources/interop/routes/indirect.d.ts +2 -0
  28. package/dist/adapters/viem/resources/interop/routes/types.d.ts +23 -0
  29. package/dist/adapters/viem/resources/interop/services/erc20.d.ts +25 -0
  30. package/dist/adapters/viem/resources/interop/services/fee.d.ts +12 -0
  31. package/dist/adapters/viem/resources/interop/services/finalization/bundle.d.ts +19 -0
  32. package/dist/adapters/viem/resources/interop/services/finalization/data-fetchers.d.ts +17 -0
  33. package/dist/adapters/viem/resources/interop/services/finalization/decoders.d.ts +11 -0
  34. package/dist/adapters/viem/resources/interop/services/finalization/index.d.ts +13 -0
  35. package/dist/adapters/viem/resources/interop/services/finalization/polling.d.ts +7 -0
  36. package/dist/adapters/viem/resources/interop/services/finalization/status.d.ts +5 -0
  37. package/dist/adapters/viem/resources/interop/services/finalization/topics.d.ts +4 -0
  38. package/dist/adapters/viem/resources/interop/services/gas.d.ts +12 -0
  39. package/dist/adapters/viem/resources/interop/services/starter-data.d.ts +6 -0
  40. package/dist/adapters/viem/resources/interop/types.d.ts +8 -0
  41. package/dist/adapters/viem/sdk.cjs +6665 -3173
  42. package/dist/adapters/viem/sdk.cjs.map +1 -1
  43. package/dist/adapters/viem/sdk.d.ts +8 -1
  44. package/dist/adapters/viem/sdk.js +5 -5
  45. package/dist/{chunk-7CAVFIMW.js → chunk-24TE2NNJ.js} +2 -3
  46. package/dist/{chunk-75IOOODG.js → chunk-3KH5PCD6.js} +1233 -31
  47. package/dist/{chunk-XKRNLFET.js → chunk-5HG2DUYW.js} +150 -375
  48. package/dist/{chunk-OTXPSNNC.js → chunk-CK5UFAZK.js} +64 -7
  49. package/dist/{chunk-HP3EWKJL.js → chunk-JSBMIT4S.js} +1 -1
  50. package/dist/{chunk-5RRJDPAJ.js → chunk-NJK325XV.js} +2 -2
  51. package/dist/chunk-NLUCYVMX.js +658 -0
  52. package/dist/{chunk-XDRCN4FC.js → chunk-SBGBYZJM.js} +10 -2
  53. package/dist/{chunk-J47RI3G7.js → chunk-TYYUG5GA.js} +1 -1
  54. package/dist/{chunk-JY62QO3W.js → chunk-UEKFQAOS.js} +420 -6
  55. package/dist/core/index.js +2 -3
  56. package/dist/core/resources/deposits/chains.d.ts +1 -0
  57. package/dist/core/resources/deposits/gas.d.ts +7 -0
  58. package/dist/core/resources/deposits/priority.d.ts +4 -0
  59. package/dist/core/resources/interop/protocol.d.ts +3 -0
  60. package/dist/core/types/errors.d.ts +1 -0
  61. package/dist/core/types/flows/interop.d.ts +0 -2
  62. package/dist/core/types/primitives.d.ts +2 -0
  63. package/dist/index.js +2 -3
  64. package/package.json +1 -1
  65. package/dist/chunk-DYJKK5FW.js +0 -417
  66. package/dist/chunk-EOBXYHTZ.js +0 -265
@@ -1,9 +1,9 @@
1
- import { createErrorHandlers, toZKsyncError, classifyReadinessFromRevert } from './chunk-5RRJDPAJ.js';
2
- import { createNTVCodec, toGasOverrides, buildFeeBreakdown, derivePriorityTxGasBreakdown, quoteL2Gas, quoteL2BaseCost, quoteL1Gas, derivePriorityBodyGasEstimateCap, quoteL2Gas2 } from './chunk-EOBXYHTZ.js';
3
- import { findL1MessageSentLog, messengerLogIndex, isL1MessageSentLog, pickWithdrawRoute } from './chunk-3HHUZXSV.js';
4
- import { isHash66, IL1Nullifier_default, OP_WITHDRAWALS, createError, normalizeL1Token, isAddressEq, hexEq, OP_DEPOSITS, IERC20_default, isZKsyncError, isReceiptNotFound, OP_INTEROP, IInteropHandler_default, IERC7786Attributes_default, isBigint, isHash, IInteropCenter_default, sleep, isETH, normalizeAddrEq, isNumber, isAddress, isHash66Array, IInteropRootStorage_default, IL2AssetRouter_default, L2NativeTokenVault_default, assertNever } from './chunk-JY62QO3W.js';
5
- import { ETH_ADDRESS, TOPIC_CANONICAL_ASSIGNED, TOPIC_CANONICAL_SUCCESS, L1_MESSENGER_ADDRESS, L2_BASE_TOKEN_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, L2_INTEROP_CENTER_ADDRESS, BUNDLE_IDENTIFIER, L2_INTEROP_ROOT_STORAGE_ADDRESS, SAFE_L1_BRIDGE_GAS, L2_ASSET_ROUTER_ADDRESS, FORMAL_ETH_ADDRESS } from './chunk-MT4X5FEO.js';
6
- import { Interface, keccak256, AbiCoder, ethers, getBytes, Contract, NonceManager, JsonRpcProvider, isError, getAddress, concat, hexlify, toBeArray, toBeHex } from 'ethers';
1
+ import { createErrorHandlers, toZKsyncError, classifyReadinessFromRevert } from './chunk-NJK325XV.js';
2
+ import { createNTVCodec, resolveCreateDepositL1GasLimit, isInteropFinalizationInfo, DEFAULT_POLL_MS, DEFAULT_TIMEOUT_MS, resolveIdsFromWaitable, parseBundleReceiptInfo, buildFinalizationInfo, parseBundleSentFromReceipt, createAttributesResource, pickInteropRoute, ZERO_HASH, toGasOverrides, applyPriorityL2GasLimitBuffer, buildFeeBreakdown, buildIndirectBundle, preflightIndirect, buildDirectBundle, preflightDirect, derivePriorityTxGasBreakdown, quoteL2Gas, quoteL2BaseCost, quoteL1Gas, derivePriorityBodyGasEstimateCap, quoteL2Gas2, assertProtocolVersion } from './chunk-NLUCYVMX.js';
3
+ import { findL1MessageSentLog, messengerLogIndex, pickWithdrawRoute } from './chunk-3HHUZXSV.js';
4
+ import { isHash66, IL1Nullifier_default, OP_WITHDRAWALS, createError, normalizeL1Token, isAddressEq, hexEq, OP_DEPOSITS, IERC20_default, isZKsyncError, isReceiptNotFound, OP_INTEROP, IInteropHandler_default, IERC7786Attributes_default, IInteropRootStorage_default, IInteropCenter_default, sleep, isETH, normalizeAddrEq, IL2AssetRouter_default, L2NativeTokenVault_default, assertNever } from './chunk-UEKFQAOS.js';
5
+ import { ETH_ADDRESS, TOPIC_CANONICAL_ASSIGNED, TOPIC_CANONICAL_SUCCESS, L1_MESSENGER_ADDRESS, L2_BASE_TOKEN_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, L2_INTEROP_ROOT_STORAGE_ADDRESS, BUFFER, SAFE_L1_BRIDGE_GAS, L2_ASSET_ROUTER_ADDRESS, FORMAL_ETH_ADDRESS } from './chunk-MT4X5FEO.js';
6
+ import { Interface, keccak256, AbiCoder, ethers, getBytes, Contract, NonceManager, JsonRpcProvider, getAddress, concat, hexlify, toBeArray, toBeHex, isError } from 'ethers';
7
7
 
8
8
  var I_BRIDGEHUB = new Interface([
9
9
  "event NewPriorityRequest(uint256 indexed chainId, address indexed sender, bytes32 txHash, uint256 txId, bytes data)"
@@ -388,7 +388,10 @@ function routeEthDirect() {
388
388
  l2Calldata,
389
389
  gasPerPubdata: ctx.gasPerPubdata
390
390
  });
391
- const quotedL2GasLimit = ctx.l2GasLimit ?? priorityFloorBreakdown.derivedL2GasLimit;
391
+ const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
392
+ chainIdL2: ctx.chainIdL2,
393
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
394
+ });
392
395
  const l2GasParams = await quoteL2Gas3({
393
396
  ctx,
394
397
  route: "eth-base",
@@ -450,11 +453,6 @@ function routeEthDirect() {
450
453
  }
451
454
  };
452
455
  }
453
-
454
- // src/core/types/primitives.ts
455
- var ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
456
-
457
- // src/adapters/ethers/resources/deposits/routes/erc20-nonbase.ts
458
456
  var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
459
457
  var ZERO_L2_TOKEN_ADDRESS2 = "0x0000000000000000000000000000000000000000";
460
458
  var ZERO_ASSET_ID = "0x0000000000000000000000000000000000000000000000000000000000000000";
@@ -491,7 +489,10 @@ async function getPriorityGasModel(input) {
491
489
  gasPerPubdata: input.ctx.gasPerPubdata
492
490
  });
493
491
  const model = {
494
- priorityFloorGasLimit: priorityFloorBreakdown.derivedL2GasLimit
492
+ priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
493
+ chainIdL2: input.ctx.chainIdL2,
494
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
495
+ })
495
496
  };
496
497
  if (isFirstBridge || input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS2) {
497
498
  model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
@@ -697,7 +698,10 @@ async function getPriorityGasModel2(input) {
697
698
  gasPerPubdata: input.ctx.gasPerPubdata
698
699
  });
699
700
  const model = {
700
- priorityFloorGasLimit: priorityFloorBreakdown.derivedL2GasLimit
701
+ priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
702
+ chainIdL2: input.ctx.chainIdL2,
703
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
704
+ })
701
705
  };
702
706
  if (input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS3) {
703
707
  model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
@@ -819,7 +823,7 @@ function routeEthNonBase() {
819
823
  const requestStruct = {
820
824
  chainId: ctx.chainIdL2,
821
825
  mintValue,
822
- l2Value: p.amount,
826
+ l2Value: 0n,
823
827
  l2GasLimit: l2GasParams.gasLimit,
824
828
  l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
825
829
  refundRecipient: ctx.refundRecipient,
@@ -827,6 +831,7 @@ function routeEthNonBase() {
827
831
  secondBridgeValue: p.amount,
828
832
  secondBridgeCalldata
829
833
  };
834
+ const bridgehubValue = p.amount;
830
835
  const bridgehub = await ctx.contracts.bridgehub();
831
836
  const data = bridgehub.interface.encodeFunctionData("requestL2TransactionTwoBridges", [
832
837
  requestStruct
@@ -834,8 +839,7 @@ function routeEthNonBase() {
834
839
  const l1TxCandidate = {
835
840
  to: ctx.bridgehub,
836
841
  data,
837
- value: p.amount,
838
- // base ≠ ETH ⇒ msg.value == secondBridgeValue
842
+ value: bridgehubValue,
839
843
  from: ctx.sender,
840
844
  ...ctx.gasOverrides
841
845
  };
@@ -914,7 +918,10 @@ function routeErc20Base() {
914
918
  l2Calldata,
915
919
  gasPerPubdata: ctx.gasPerPubdata
916
920
  });
917
- const quotedL2GasLimit = ctx.l2GasLimit ?? priorityFloorBreakdown.derivedL2GasLimit;
921
+ const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
922
+ chainIdL2: ctx.chainIdL2,
923
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
924
+ });
918
925
  const l2GasParams = await quoteL2Gas3({
919
926
  ctx,
920
927
  route: "erc20-base",
@@ -1340,6 +1347,8 @@ function createDepositsResource(client, tokens, contracts) {
1340
1347
  async () => {
1341
1348
  const plan = await prepare(p);
1342
1349
  const stepHashes = {};
1350
+ const { chainId } = await client.l2.getNetwork();
1351
+ const chainIdL2 = BigInt(chainId);
1343
1352
  const managed = new NonceManager(client.signer);
1344
1353
  const from = await managed.getAddress();
1345
1354
  let next;
@@ -1385,8 +1394,14 @@ function createDepositsResource(client, tokens, contracts) {
1385
1394
  }
1386
1395
  if (!p.l1TxOverrides?.gasLimit) {
1387
1396
  try {
1397
+ const preparedGasLimit = step.tx.gasLimit != null ? BigInt(step.tx.gasLimit.toString()) : void 0;
1388
1398
  const est = await client.l1.estimateGas(step.tx);
1389
- step.tx.gasLimit = BigInt(est) * 115n / 100n;
1399
+ step.tx.gasLimit = resolveCreateDepositL1GasLimit({
1400
+ chainIdL2,
1401
+ stepKey: step.key,
1402
+ preparedGasLimit,
1403
+ estimatedGasLimit: BigInt(est)
1404
+ });
1390
1405
  } catch {
1391
1406
  }
1392
1407
  }
@@ -2374,38 +2389,6 @@ function createWithdrawalsResource(client, tokens, contracts) {
2374
2389
  tryWait
2375
2390
  };
2376
2391
  }
2377
-
2378
- // src/core/resources/interop/attributes/call.ts
2379
- function createCallAttributes(codec) {
2380
- const indirectCall = (messageValue) => codec.encode("indirectCall", [messageValue]);
2381
- const interopCallValue = (bridgedAmount) => codec.encode("interopCallValue", [bridgedAmount]);
2382
- return {
2383
- indirectCall,
2384
- interopCallValue
2385
- };
2386
- }
2387
-
2388
- // src/core/resources/interop/attributes/bundle.ts
2389
- function createBundleAttributes(codec) {
2390
- const executionAddress = (executor) => codec.encode("executionAddress", [executor]);
2391
- const unbundlerAddress = (addr) => codec.encode("unbundlerAddress", [addr]);
2392
- const useFixedFee = (enabled) => codec.encode("useFixedFee", [enabled]);
2393
- return {
2394
- executionAddress,
2395
- unbundlerAddress,
2396
- useFixedFee
2397
- };
2398
- }
2399
-
2400
- // src/core/resources/interop/attributes/resource.ts
2401
- function createAttributesResource(codec) {
2402
- return {
2403
- call: createCallAttributes(codec),
2404
- bundle: createBundleAttributes(codec)
2405
- };
2406
- }
2407
-
2408
- // src/adapters/ethers/resources/interop/attributes/resource.ts
2409
2392
  function getInteropAttributes(params, ctx) {
2410
2393
  const bundleAttributes = [];
2411
2394
  if (params.execution?.only) {
@@ -2442,183 +2425,6 @@ function createEthersAttributesResource(opts = {}) {
2442
2425
  const encode2 = (fn, args) => iface.encodeFunctionData(fn, args);
2443
2426
  return createAttributesResource({ encode: encode2 });
2444
2427
  }
2445
-
2446
- // src/core/types/flows/interop.ts
2447
- function isInteropMessageProof(obj) {
2448
- if (typeof obj !== "object" || obj === null) return false;
2449
- const proof = obj;
2450
- 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);
2451
- }
2452
- function isInteropFinalizationInfo(obj) {
2453
- if (typeof obj !== "object" || obj === null) return false;
2454
- const info = obj;
2455
- return isHash66(info.l2SrcTxHash) && isHash66(info.bundleHash) && isBigint(info.dstChainId) && isHash(info.encodedData) && isInteropMessageProof(info.proof);
2456
- }
2457
-
2458
- // src/core/resources/interop/route.ts
2459
- function sumActionMsgValue(actions) {
2460
- let sum = 0n;
2461
- for (const a of actions) {
2462
- if (a.type === "sendNative") sum += a.amount;
2463
- else if (a.type === "call" && a.value) sum += a.value;
2464
- }
2465
- return sum;
2466
- }
2467
- function sumErc20Amounts(actions) {
2468
- let sum = 0n;
2469
- for (const a of actions) if (a.type === "sendErc20") sum += a.amount;
2470
- return sum;
2471
- }
2472
- function pickInteropRoute(args) {
2473
- const hasErc20 = args.actions.some((a) => a.type === "sendErc20");
2474
- const baseMatches = args.ctx.baseTokenSrc.toLowerCase() === args.ctx.baseTokenDst.toLowerCase();
2475
- if (hasErc20) return "indirect";
2476
- if (!baseMatches) return "indirect";
2477
- return "direct";
2478
- }
2479
-
2480
- // src/core/resources/interop/plan.ts
2481
- function preflightDirect(params, ctx) {
2482
- if (!params.actions?.length) {
2483
- throw new Error('route "direct" requires at least one action.');
2484
- }
2485
- const baseMatch = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
2486
- if (!baseMatch) {
2487
- throw new Error('route "direct" requires matching base tokens between source and destination.');
2488
- }
2489
- for (const action of params.actions) {
2490
- switch (action.type) {
2491
- case "sendNative":
2492
- if (action.amount < 0n) {
2493
- throw new Error("sendNative.amount must be >= 0.");
2494
- }
2495
- break;
2496
- case "call":
2497
- if (action.value != null && action.value < 0n) {
2498
- throw new Error("call.value must be >= 0 when provided.");
2499
- }
2500
- break;
2501
- default:
2502
- throw new Error(
2503
- `route "direct" does not support ${action.type} actions; use the indirect route.`
2504
- );
2505
- }
2506
- }
2507
- }
2508
- function buildDirectBundle(params, ctx, attrs, interopFeeInfo) {
2509
- const totalActionValue = sumActionMsgValue(params.actions);
2510
- const starters = params.actions.map((action, index) => {
2511
- const to = ctx.codec.formatAddress(action.to);
2512
- const callAttributes = attrs.callAttributes[index] ?? [];
2513
- switch (action.type) {
2514
- case "sendNative":
2515
- return [to, "0x", callAttributes];
2516
- case "call":
2517
- return [to, action.data ?? "0x", callAttributes];
2518
- default:
2519
- throw new Error(`buildDirectBundle: unsupported action type "${action.type}".`);
2520
- }
2521
- });
2522
- return {
2523
- dstChain: ctx.codec.formatChain(ctx.dstChainId),
2524
- starters,
2525
- bundleAttributes: attrs.bundleAttributes,
2526
- approvals: interopFeeInfo.approval ? [interopFeeInfo.approval] : [],
2527
- interopFee: interopFeeInfo.fee,
2528
- quoteExtras: {
2529
- totalActionValue,
2530
- bridgedTokenTotal: 0n
2531
- }
2532
- };
2533
- }
2534
- function preflightIndirect(params, ctx) {
2535
- if (!params.actions?.length) {
2536
- throw new Error('route "indirect" requires at least one action.');
2537
- }
2538
- const hasErc20 = params.actions.some((a) => a.type === "sendErc20");
2539
- const baseMatches = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
2540
- if (!hasErc20 && baseMatches) {
2541
- throw new Error(
2542
- 'route "indirect" requires ERC-20 actions or mismatched base tokens; use the direct route instead.'
2543
- );
2544
- }
2545
- for (const action of params.actions) {
2546
- switch (action.type) {
2547
- case "sendNative":
2548
- if (action.amount < 0n) {
2549
- throw new Error("sendNative.amount must be >= 0.");
2550
- }
2551
- break;
2552
- case "sendErc20":
2553
- if (action.amount < 0n) {
2554
- throw new Error("sendErc20.amount must be >= 0.");
2555
- }
2556
- break;
2557
- case "call":
2558
- if (action.value != null) {
2559
- if (action.value < 0n) {
2560
- throw new Error("call.value must be >= 0 when provided.");
2561
- }
2562
- if (action.value > 0n && !baseMatches) {
2563
- throw new Error("indirect route does not support call.value when base tokens differ.");
2564
- }
2565
- }
2566
- break;
2567
- default:
2568
- assertNever(action);
2569
- }
2570
- }
2571
- }
2572
- function buildIndirectBundle(params, ctx, attrs, starterData, interopFeeInfo) {
2573
- const totalActionValue = sumActionMsgValue(params.actions);
2574
- const bridgedTokenTotal = sumErc20Amounts(params.actions);
2575
- const approvalMap = /* @__PURE__ */ new Map();
2576
- for (const action of params.actions) {
2577
- if (action.type !== "sendErc20") continue;
2578
- const key = action.token.toLowerCase();
2579
- const existing = approvalMap.get(key);
2580
- if (existing) {
2581
- existing.amount += action.amount;
2582
- } else {
2583
- approvalMap.set(key, {
2584
- token: action.token,
2585
- spender: ctx.l2NativeTokenVault,
2586
- amount: action.amount
2587
- });
2588
- }
2589
- }
2590
- const approvals = Array.from(approvalMap.values());
2591
- if (interopFeeInfo.approval) approvals.push(interopFeeInfo.approval);
2592
- const starters = params.actions.map((action, index) => {
2593
- const callAttributes = attrs.callAttributes[index] ?? [];
2594
- if (starterData[index]?.assetRouterPayload) {
2595
- const l2AssetRouter = ctx.codec.formatAddress(ctx.l2AssetRouter);
2596
- return [l2AssetRouter, starterData[index].assetRouterPayload, callAttributes];
2597
- }
2598
- const directTo = ctx.codec.formatAddress(action.to);
2599
- switch (action.type) {
2600
- case "sendNative":
2601
- return [directTo, "0x", callAttributes];
2602
- case "call":
2603
- return [directTo, action.data ?? "0x", callAttributes];
2604
- case "sendErc20":
2605
- throw new Error("buildIndirectBundle: missing assetRouterPayload for sendErc20 action.");
2606
- default:
2607
- return assertNever(action);
2608
- }
2609
- });
2610
- return {
2611
- dstChain: ctx.codec.formatChain(ctx.dstChainId),
2612
- starters,
2613
- bundleAttributes: attrs.bundleAttributes,
2614
- approvals,
2615
- interopFee: interopFeeInfo.fee,
2616
- quoteExtras: {
2617
- totalActionValue,
2618
- bridgedTokenTotal
2619
- }
2620
- };
2621
- }
2622
2428
  var PREFIX_EVM_CHAIN = getBytes("0x00010000");
2623
2429
  var PREFIX_EVM_ADDRESS = getBytes("0x000100000014");
2624
2430
  function formatInteropEvmChain(chainId) {
@@ -2783,7 +2589,9 @@ function routeIndirect() {
2783
2589
  dstChainId: ctx.dstChainId,
2784
2590
  baseTokens: ctx.baseTokens,
2785
2591
  l2AssetRouter: ctx.l2AssetRouter,
2786
- l2NativeTokenVault: ctx.l2NativeTokenVault});
2592
+ l2NativeTokenVault: ctx.l2NativeTokenVault,
2593
+ codec: interopCodec
2594
+ });
2787
2595
  },
2788
2596
  async build(params, ctx) {
2789
2597
  const steps = [];
@@ -2844,7 +2652,9 @@ function routeDirect() {
2844
2652
  dstChainId: ctx.dstChainId,
2845
2653
  baseTokens: ctx.baseTokens,
2846
2654
  l2AssetRouter: ctx.l2AssetRouter,
2847
- l2NativeTokenVault: ctx.l2NativeTokenVault});
2655
+ l2NativeTokenVault: ctx.l2NativeTokenVault,
2656
+ codec: interopCodec
2657
+ });
2848
2658
  },
2849
2659
  async build(params, ctx) {
2850
2660
  const steps = [];
@@ -2889,26 +2699,11 @@ function routeDirect() {
2889
2699
  }
2890
2700
  };
2891
2701
  }
2892
- var MIN_INTEROP_PROTOCOL = 31;
2893
2702
  async function assertInteropProtocolVersion(client, srcChainId, dstChainId) {
2894
2703
  const [srcProtocolVersion, dstProtocolVersion] = await Promise.all([
2895
2704
  client.getProtocolVersion(srcChainId),
2896
2705
  client.getProtocolVersion(dstChainId)
2897
2706
  ]);
2898
- const assertProtocolVersion = (chainId, protocolVersion) => {
2899
- if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
2900
- throw createError("VALIDATION", {
2901
- resource: "interop",
2902
- operation: OP_INTEROP.context.protocolVersion,
2903
- message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
2904
- context: {
2905
- chainId,
2906
- requiredMinor: MIN_INTEROP_PROTOCOL,
2907
- semver: protocolVersion
2908
- }
2909
- });
2910
- }
2911
- };
2912
2707
  assertProtocolVersion(srcChainId, srcProtocolVersion);
2913
2708
  assertProtocolVersion(dstChainId, dstProtocolVersion);
2914
2709
  }
@@ -2979,7 +2774,14 @@ function parseMaxBlockRangeLimit(error) {
2979
2774
  async function getTxReceipt(provider, txHash) {
2980
2775
  const receipt = await wrap3(
2981
2776
  OP_INTEROP.svc.status.sourceReceipt,
2982
- () => provider.getTransactionReceipt(txHash),
2777
+ async () => {
2778
+ try {
2779
+ return await provider.getTransactionReceipt(txHash);
2780
+ } catch (error) {
2781
+ if (isReceiptNotFound(error)) return null;
2782
+ throw error;
2783
+ }
2784
+ },
2983
2785
  {
2984
2786
  ctx: { where: "l2.getTransactionReceipt", l2SrcTxHash: txHash },
2985
2787
  message: "Failed to fetch source L2 receipt for interop tx."
@@ -3144,137 +2946,59 @@ async function executeBundle(client, dstProvider, info, opts) {
3144
2946
  );
3145
2947
  }
3146
2948
  }
3147
-
3148
- // src/core/resources/interop/finalization.ts
3149
- var DEFAULT_POLL_MS = 1e3;
3150
- var DEFAULT_TIMEOUT_MS = 3e5;
3151
- function resolveIdsFromWaitable(input) {
3152
- if (typeof input === "string") {
3153
- return { l2SrcTxHash: input };
3154
- }
3155
- return {
3156
- l2SrcTxHash: input.l2SrcTxHash,
3157
- bundleHash: input.bundleHash,
3158
- dstExecTxHash: input.dstExecTxHash
3159
- };
3160
- }
3161
- function parseBundleSentFromReceipt(input) {
3162
- const { receipt, interopCenter, interopBundleSentTopic, decodeInteropBundleSent: decodeInteropBundleSent2 } = input;
3163
- const bundleSentLog = receipt.logs.find(
3164
- (log) => log.address.toLowerCase() === interopCenter.toLowerCase() && log.topics[0].toLowerCase() === interopBundleSentTopic.toLowerCase()
3165
- );
3166
- if (!bundleSentLog) {
3167
- throw createError("STATE", {
3168
- resource: "interop",
3169
- operation: OP_INTEROP.svc.status.parseSentLog,
3170
- message: "Failed to locate InteropBundleSent event in source receipt.",
3171
- context: { receipt, interopCenter }
3172
- });
3173
- }
3174
- const decoded = decodeInteropBundleSent2({
3175
- data: bundleSentLog.data,
3176
- topics: bundleSentLog.topics
2949
+ async function verifyBundle(client, dstProvider, info) {
2950
+ const signer = await wrap4(OP_INTEROP.verify, () => client.signerFor(dstProvider), {
2951
+ message: "Failed to resolve destination signer for verifyBundle."
3177
2952
  });
3178
- return { bundleHash: decoded.bundleHash, dstChainId: decoded.destinationChainId };
3179
- }
3180
- function parseBundleReceiptInfo(params) {
3181
- const {
3182
- rawReceipt,
3183
- interopCenter,
3184
- interopBundleSentTopic,
3185
- decodeInteropBundleSent: decodeInteropBundleSent2,
3186
- decodeL1MessageData: decodeL1MessageData2,
3187
- l2SrcTxHash
3188
- } = params;
3189
- let l2ToL1LogIndex = -1;
3190
- let l1MessageData = null;
3191
- let found;
3192
- for (const log of rawReceipt.logs) {
3193
- if (isL1MessageSentLog(log)) {
3194
- l2ToL1LogIndex += 1;
3195
- try {
3196
- l1MessageData = decodeL1MessageData2(log);
3197
- } catch (e) {
3198
- throw createError("STATE", {
3199
- resource: "interop",
3200
- operation: OP_INTEROP.svc.status.parseSentLog,
3201
- message: "Failed to decode L1MessageSent log data for interop bundle.",
3202
- context: { l2SrcTxHash, l2ToL1LogIndex },
3203
- cause: e
3204
- });
2953
+ const { interopHandler } = await client.ensureAddresses();
2954
+ const handler = new Contract(interopHandler, IInteropHandler_default, signer);
2955
+ try {
2956
+ const txResponse = await handler.verifyBundle(
2957
+ info.encodedData,
2958
+ info.proof
2959
+ );
2960
+ const hash = txResponse.hash;
2961
+ return {
2962
+ hash,
2963
+ wait: async () => {
2964
+ try {
2965
+ const receipt = await txResponse.wait();
2966
+ if (!receipt || receipt.status !== 1) {
2967
+ throw createError("EXECUTION", {
2968
+ resource: "interop",
2969
+ operation: OP_INTEROP.verify,
2970
+ message: "Interop bundle verification reverted on destination.",
2971
+ context: { txHash: hash }
2972
+ });
2973
+ }
2974
+ return receipt;
2975
+ } catch (e) {
2976
+ if (isZKsyncError(e)) throw e;
2977
+ throw toZKsyncError(
2978
+ "EXECUTION",
2979
+ {
2980
+ resource: "interop",
2981
+ operation: OP_INTEROP.verify,
2982
+ message: "Failed while waiting for verifyBundle transaction on destination.",
2983
+ context: { txHash: hash }
2984
+ },
2985
+ e
2986
+ );
2987
+ }
3205
2988
  }
3206
- continue;
3207
- }
3208
- if (log.address.toLowerCase() !== interopCenter.toLowerCase() || log.topics[0].toLowerCase() !== interopBundleSentTopic.toLowerCase())
3209
- continue;
3210
- const decoded = decodeInteropBundleSent2({
3211
- data: log.data,
3212
- topics: log.topics
3213
- });
3214
- found = {
3215
- bundleHash: decoded.bundleHash,
3216
- dstChainId: decoded.destinationChainId,
3217
- sourceChainId: decoded.sourceChainId
3218
2989
  };
3219
- break;
3220
- }
3221
- if (!found) {
3222
- throw createError("STATE", {
3223
- resource: "interop",
3224
- operation: OP_INTEROP.svc.status.parseSentLog,
3225
- message: "Failed to locate InteropBundleSent event in source receipt.",
3226
- context: { l2SrcTxHash, interopCenter }
3227
- });
3228
- }
3229
- if (!l1MessageData) {
3230
- throw createError("STATE", {
3231
- resource: "interop",
3232
- operation: OP_INTEROP.svc.status.parseSentLog,
3233
- message: "Failed to locate L1MessageSent log data for interop bundle.",
3234
- context: { l2SrcTxHash, interopCenter }
3235
- });
2990
+ } catch (e) {
2991
+ if (isZKsyncError(e)) throw e;
2992
+ throw toZKsyncError(
2993
+ "EXECUTION",
2994
+ {
2995
+ resource: "interop",
2996
+ operation: OP_INTEROP.verify,
2997
+ message: "Failed to send verifyBundle transaction on destination chain."
2998
+ },
2999
+ e
3000
+ );
3236
3001
  }
3237
- return {
3238
- bundleHash: found.bundleHash,
3239
- dstChainId: found.dstChainId,
3240
- sourceChainId: found.sourceChainId,
3241
- l1MessageData,
3242
- l2ToL1LogIndex,
3243
- txNumberInBatch: Number(rawReceipt.transactionIndex),
3244
- rawReceipt
3245
- };
3246
- }
3247
- function getBundleEncodedData(messageData) {
3248
- const prefix = `0x${messageData.slice(2, 4)}`;
3249
- if (prefix !== BUNDLE_IDENTIFIER) {
3250
- throw createError("STATE", {
3251
- resource: "interop",
3252
- operation: OP_INTEROP.wait,
3253
- message: "Unexpected bundle prefix in L1MessageSent data.",
3254
- context: { prefix, expected: BUNDLE_IDENTIFIER }
3255
- });
3256
- }
3257
- return `0x${messageData.slice(4)}`;
3258
- }
3259
- function buildFinalizationInfo(ids, bundleInfo, proof, messageData) {
3260
- const messageProof = {
3261
- chainId: bundleInfo.sourceChainId,
3262
- l1BatchNumber: proof.batchNumber,
3263
- l2MessageIndex: proof.id,
3264
- message: {
3265
- txNumberInBatch: bundleInfo.txNumberInBatch,
3266
- sender: L2_INTEROP_CENTER_ADDRESS,
3267
- data: messageData
3268
- },
3269
- proof: proof.proof
3270
- };
3271
- return {
3272
- l2SrcTxHash: ids.l2SrcTxHash,
3273
- bundleHash: bundleInfo.bundleHash,
3274
- dstChainId: bundleInfo.dstChainId,
3275
- proof: messageProof,
3276
- encodedData: getBundleEncodedData(messageData)
3277
- };
3278
3002
  }
3279
3003
  function decodeInteropBundleSent(centerIface, log) {
3280
3004
  const decoded = centerIface.decodeEventLog(
@@ -3509,6 +3233,31 @@ function resolveChainRef(ref) {
3509
3233
  return typeof ref === "string" ? new JsonRpcProvider(ref) : ref;
3510
3234
  }
3511
3235
 
3236
+ // src/adapters/ethers/resources/interop/services/gas.ts
3237
+ async function quoteStepsL2Fee(steps, ctx) {
3238
+ if (steps.length === 0) return 0n;
3239
+ const estimator = ethersToGasEstimator(ctx.client.l2);
3240
+ let maxFeePerGas;
3241
+ try {
3242
+ const fees = await estimator.estimateFeesPerGas();
3243
+ maxFeePerGas = fees.maxFeePerGas ?? fees.gasPrice ?? await estimator.getGasPrice();
3244
+ } catch {
3245
+ return void 0;
3246
+ }
3247
+ let total = 0n;
3248
+ for (const step of steps) {
3249
+ try {
3250
+ const coreTx = toCoreTx({ ...step.tx, from: ctx.sender });
3251
+ const est = await estimator.estimateGas(coreTx);
3252
+ const buffered = BigInt(est) * (100n + BUFFER) / 100n;
3253
+ total += buffered * maxFeePerGas;
3254
+ } catch {
3255
+ return void 0;
3256
+ }
3257
+ }
3258
+ return total;
3259
+ }
3260
+
3512
3261
  // src/adapters/ethers/resources/interop/index.ts
3513
3262
  var { wrap: wrap6, toResult: toResult2 } = createErrorHandlers("interop");
3514
3263
  var ROUTES3 = {
@@ -3565,12 +3314,14 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
3565
3314
  ctx: { where: `routes.${route}.build` }
3566
3315
  }
3567
3316
  );
3317
+ const l2Fee = await quoteStepsL2Fee(steps, ctx).catch(() => void 0);
3568
3318
  const summary = {
3569
3319
  route,
3570
3320
  approvalsNeeded: approvals,
3571
3321
  totalActionValue: quoteExtras.totalActionValue,
3572
3322
  bridgedTokenTotal: quoteExtras.bridgedTokenTotal,
3573
- interopFee
3323
+ interopFee,
3324
+ l2Fee
3574
3325
  };
3575
3326
  return { plan: { route, summary, steps }, ctx };
3576
3327
  }
@@ -3695,6 +3446,28 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
3695
3446
  }
3696
3447
  );
3697
3448
  const tryFinalize = (dstChain, h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(dstChain, h, opts));
3449
+ const interopGetRoot = (dstChain, rootChainId, batchNumber) => wrap6(
3450
+ OP_INTEROP.svc.status.getRoot,
3451
+ () => getInteropRoot(resolveChainRef(dstChain), rootChainId, batchNumber),
3452
+ {
3453
+ message: "Failed to get interop root from the destination chain.",
3454
+ ctx: { where: "interop.getInteropRoot" }
3455
+ }
3456
+ );
3457
+ const verifyBundle2 = (dstChain, h) => wrap6(
3458
+ OP_INTEROP.verify,
3459
+ async () => {
3460
+ const dstProvider = resolveChainRef(dstChain);
3461
+ const info = isInteropFinalizationInfo(h) ? h : await svc.wait(dstProvider, getGwProvider(), h);
3462
+ const result = await verifyBundle(client, dstProvider, info);
3463
+ await result.wait();
3464
+ return { bundleHash: info.bundleHash, dstExecTxHash: result.hash };
3465
+ },
3466
+ {
3467
+ message: "Failed to verify interop bundle on destination.",
3468
+ ctx: { where: "interop.verifyBundle" }
3469
+ }
3470
+ );
3698
3471
  return {
3699
3472
  quote,
3700
3473
  tryQuote,
@@ -3706,7 +3479,9 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
3706
3479
  wait,
3707
3480
  tryWait,
3708
3481
  finalize,
3709
- tryFinalize
3482
+ tryFinalize,
3483
+ getInteropRoot: interopGetRoot,
3484
+ verifyBundle: verifyBundle2
3710
3485
  };
3711
3486
  }
3712
3487