@matterlabs/zksync-js 0.0.13 → 0.0.15

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 (96) hide show
  1. package/dist/adapters/ethers/client.cjs +13 -4
  2. package/dist/adapters/ethers/client.cjs.map +1 -1
  3. package/dist/adapters/ethers/client.d.ts +1 -2
  4. package/dist/adapters/ethers/client.js +6 -6
  5. package/dist/adapters/ethers/index.cjs +607 -259
  6. package/dist/adapters/ethers/index.cjs.map +1 -1
  7. package/dist/adapters/ethers/index.js +9 -9
  8. package/dist/adapters/ethers/resources/deposits/routes/priority.d.ts +12 -0
  9. package/dist/adapters/ethers/resources/deposits/services/gas.d.ts +4 -0
  10. package/dist/adapters/ethers/resources/interop/index.d.ts +14 -14
  11. package/dist/adapters/ethers/resources/interop/resolvers.d.ts +3 -8
  12. package/dist/adapters/ethers/resources/interop/routes/types.d.ts +2 -1
  13. package/dist/adapters/ethers/resources/interop/services/erc20.d.ts +10 -0
  14. package/dist/adapters/ethers/resources/interop/services/fee.d.ts +12 -0
  15. package/dist/adapters/ethers/resources/interop/services/finalization/index.d.ts +1 -1
  16. package/dist/adapters/ethers/resources/interop/services/finalization/polling.d.ts +1 -1
  17. package/dist/adapters/ethers/resources/interop/services/gas.d.ts +12 -0
  18. package/dist/adapters/ethers/resources/interop/types.d.ts +6 -14
  19. package/dist/adapters/ethers/sdk.cjs +1008 -259
  20. package/dist/adapters/ethers/sdk.cjs.map +1 -1
  21. package/dist/adapters/ethers/sdk.d.ts +6 -1
  22. package/dist/adapters/ethers/sdk.js +7 -7
  23. package/dist/adapters/viem/client.cjs +795 -7
  24. package/dist/adapters/viem/client.cjs.map +1 -1
  25. package/dist/adapters/viem/client.d.ts +6 -1
  26. package/dist/adapters/viem/client.js +6 -6
  27. package/dist/adapters/viem/index.cjs +6490 -2799
  28. package/dist/adapters/viem/index.cjs.map +1 -1
  29. package/dist/adapters/viem/index.d.ts +5 -0
  30. package/dist/adapters/viem/index.js +9 -9
  31. package/dist/adapters/viem/resources/deposits/routes/priority.d.ts +13 -0
  32. package/dist/adapters/viem/resources/deposits/services/gas.d.ts +4 -0
  33. package/dist/adapters/viem/resources/interop/address.d.ts +18 -0
  34. package/dist/adapters/viem/resources/interop/attributes/resource.d.ts +6 -0
  35. package/dist/adapters/viem/resources/interop/context.d.ts +31 -0
  36. package/dist/adapters/viem/resources/interop/index.d.ts +62 -0
  37. package/dist/adapters/viem/resources/interop/resolvers.d.ts +4 -0
  38. package/dist/adapters/viem/resources/interop/routes/direct.d.ts +2 -0
  39. package/dist/adapters/viem/resources/interop/routes/indirect.d.ts +2 -0
  40. package/dist/adapters/viem/resources/interop/routes/types.d.ts +23 -0
  41. package/dist/adapters/viem/resources/interop/services/erc20.d.ts +25 -0
  42. package/dist/adapters/viem/resources/interop/services/fee.d.ts +12 -0
  43. package/dist/adapters/viem/resources/interop/services/finalization/bundle.d.ts +15 -0
  44. package/dist/adapters/viem/resources/interop/services/finalization/data-fetchers.d.ts +17 -0
  45. package/dist/adapters/viem/resources/interop/services/finalization/decoders.d.ts +11 -0
  46. package/dist/adapters/viem/resources/interop/services/finalization/index.d.ts +13 -0
  47. package/dist/adapters/viem/resources/interop/services/finalization/polling.d.ts +7 -0
  48. package/dist/adapters/viem/resources/interop/services/finalization/status.d.ts +5 -0
  49. package/dist/adapters/viem/resources/interop/services/finalization/topics.d.ts +4 -0
  50. package/dist/adapters/viem/resources/interop/services/gas.d.ts +12 -0
  51. package/dist/adapters/viem/resources/interop/services/starter-data.d.ts +6 -0
  52. package/dist/adapters/viem/resources/interop/types.d.ts +8 -0
  53. package/dist/adapters/viem/sdk.cjs +6401 -2758
  54. package/dist/adapters/viem/sdk.cjs.map +1 -1
  55. package/dist/adapters/viem/sdk.d.ts +8 -1
  56. package/dist/adapters/viem/sdk.js +7 -7
  57. package/dist/{chunk-E3KP7XCG.js → chunk-3HHUZXSV.js} +1 -1
  58. package/dist/{chunk-EDWBCPO3.js → chunk-4PZCNTQ3.js} +1387 -71
  59. package/dist/{chunk-UDBRUBEK.js → chunk-65HAYKVL.js} +2 -2
  60. package/dist/chunk-BWKWWLY4.js +9 -0
  61. package/dist/{chunk-JHO2UQ5F.js → chunk-HGB3DOV2.js} +445 -554
  62. package/dist/{chunk-HI64OOAR.js → chunk-HVHMLAYH.js} +1 -1
  63. package/dist/{chunk-2RIARDXZ.js → chunk-JHRYNLZG.js} +65 -7
  64. package/dist/{chunk-RI73VJSH.js → chunk-JXR5V5YK.js} +463 -27
  65. package/dist/chunk-K2UVKMLN.js +658 -0
  66. package/dist/{chunk-53MC5BR2.js → chunk-MDPX5LNW.js} +1 -1
  67. package/dist/{chunk-QQ2OR434.js → chunk-MT4X5FEO.js} +18 -2
  68. package/dist/{chunk-R5WRFPK2.js → chunk-MZBKM3GH.js} +4 -4
  69. package/dist/{chunk-5R7L5NM5.js → chunk-YIWXIP2M.js} +10 -2
  70. package/dist/core/constants.cjs +17 -1
  71. package/dist/core/constants.cjs.map +1 -1
  72. package/dist/core/constants.d.ts +9 -1
  73. package/dist/core/constants.js +1 -1
  74. package/dist/core/index.cjs +52 -24
  75. package/dist/core/index.cjs.map +1 -1
  76. package/dist/core/index.js +5 -5
  77. package/dist/core/internal/abis/IERC7786Attributes.d.ts +21 -11
  78. package/dist/core/internal/abis/IInteropCenter.d.ts +4 -0
  79. package/dist/core/resources/deposits/chains.d.ts +1 -0
  80. package/dist/core/resources/deposits/gas.d.ts +7 -0
  81. package/dist/core/resources/deposits/priority.d.ts +41 -0
  82. package/dist/core/resources/interop/attributes/bundle.d.ts +1 -0
  83. package/dist/core/resources/interop/attributes/resource.d.ts +1 -0
  84. package/dist/core/resources/interop/plan.d.ts +11 -3
  85. package/dist/core/resources/interop/protocol.d.ts +3 -0
  86. package/dist/core/rpc/types.d.ts +1 -0
  87. package/dist/core/rpc/zks.d.ts +5 -1
  88. package/dist/core/types/errors.d.ts +5 -0
  89. package/dist/core/types/flows/interop.d.ts +11 -20
  90. package/dist/core/types/primitives.d.ts +2 -0
  91. package/dist/index.cjs +69 -25
  92. package/dist/index.cjs.map +1 -1
  93. package/dist/index.js +5 -5
  94. package/package.json +1 -1
  95. package/dist/chunk-4S4XDA4N.js +0 -415
  96. package/dist/chunk-5L6EYUJB.js +0 -237
@@ -48,7 +48,15 @@ var TX_OVERHEAD_GAS = 10000n;
48
48
  var TX_MEMORY_OVERHEAD_GAS = 10n;
49
49
  var DEFAULT_PUBDATA_BYTES = 155n;
50
50
  var DEFAULT_ABI_BYTES = 400n;
51
- var SAFE_L1_BRIDGE_GAS = 800000n;
51
+ var SAFE_L1_BRIDGE_GAS = 3000000n;
52
+ var L1_TX_INTRINSIC_L2_GAS = 167157n;
53
+ var L1_TX_INTRINSIC_PUBDATA = 88n;
54
+ var L1_TX_MIN_L2_GAS_BASE = 173484n;
55
+ var L1_TX_DELTA_544_ENCODING_BYTES = 1656n;
56
+ var L1_TX_DELTA_FACTORY_DEPS_L2_GAS = 2473n;
57
+ var L1_TX_DELTA_FACTORY_DEPS_PUBDATA = 64n;
58
+ var TX_SLOT_OVERHEAD_L2_GAS = 10000n;
59
+ var PRIORITY_TX_MAX_GAS_LIMIT = 72000000n;
52
60
 
53
61
  // src/core/utils/addr.ts
54
62
  function isAddress(x) {
@@ -413,6 +421,11 @@ var OP_INTEROP = {
413
421
  wait: {
414
422
  poll: "interop.svc.wait:poll",
415
423
  timeout: "interop.svc.wait:timeout"
424
+ },
425
+ fees: {
426
+ zkInteropFee: "interop.svc.fees:zkInteropFee",
427
+ zkToken: "interop.svc.fees:zkToken",
428
+ protocolFee: "interop.svc.fees:protocolFee"
416
429
  }
417
430
  }
418
431
  };
@@ -481,6 +494,7 @@ function normalizeProof(p) {
481
494
  const raw = p ?? {};
482
495
  const idRaw = raw?.id ?? raw?.index;
483
496
  const bnRaw = raw?.batch_number ?? raw?.batchNumber;
497
+ const gwBlockNumberRaw = raw?.gatewayBlockNumber;
484
498
  if (idRaw == null || bnRaw == null) {
485
499
  throw createError("RPC", {
486
500
  resource: "zksrpc",
@@ -501,7 +515,8 @@ function normalizeProof(p) {
501
515
  id: toBig(idRaw),
502
516
  batchNumber: toBig(bnRaw),
503
517
  proof: toHexArray(raw?.proof),
504
- root: raw.root
518
+ root: raw.root,
519
+ gatewayBlockNumber: gwBlockNumberRaw != null ? toBig(gwBlockNumberRaw) : void 0
505
520
  };
506
521
  } catch (e) {
507
522
  if (isZKsyncError(e)) throw e;
@@ -778,13 +793,15 @@ function createZksRpc(transport) {
778
793
  );
779
794
  },
780
795
  // Fetches a proof for an L2→L1 log emitted in the given transaction.
781
- async getL2ToL1LogProof(txHash, index) {
796
+ async getL2ToL1LogProof(txHash, index, proofTarget) {
782
797
  return withRpcOp(
783
798
  "zksrpc.getL2ToL1LogProof",
784
799
  "Failed to fetch L2\u2192L1 log proof.",
785
- { txHash, index },
800
+ { txHash, index, proofTarget },
786
801
  async () => {
787
- const proof = await transport(METHODS.getL2ToL1LogProof, [txHash, index]);
802
+ const params = [txHash, index];
803
+ if (proofTarget != void 0) params.push(proofTarget);
804
+ const proof = await transport(METHODS.getL2ToL1LogProof, params);
788
805
  if (!proof) {
789
806
  throw createError("STATE", {
790
807
  resource: "zksrpc",
@@ -4967,56 +4984,69 @@ var IERC20_default = IERC20ABI;
4967
4984
  // src/core/internal/abis/IERC7786Attributes.ts
4968
4985
  var IERC7786AttributesABI = [
4969
4986
  {
4987
+ type: "function",
4988
+ name: "executionAddress",
4970
4989
  inputs: [
4971
4990
  {
4972
- internalType: "bytes",
4973
4991
  name: "_executionAddress",
4974
- type: "bytes"
4992
+ type: "bytes",
4993
+ internalType: "bytes"
4975
4994
  }
4976
4995
  ],
4977
- name: "executionAddress",
4978
4996
  outputs: [],
4979
- stateMutability: "pure",
4980
- type: "function"
4997
+ stateMutability: "pure"
4981
4998
  },
4982
4999
  {
5000
+ type: "function",
5001
+ name: "indirectCall",
4983
5002
  inputs: [
4984
5003
  {
4985
- internalType: "uint256",
4986
5004
  name: "_indirectCallMessageValue",
4987
- type: "uint256"
5005
+ type: "uint256",
5006
+ internalType: "uint256"
4988
5007
  }
4989
5008
  ],
4990
- name: "indirectCall",
4991
5009
  outputs: [],
4992
- stateMutability: "pure",
4993
- type: "function"
5010
+ stateMutability: "pure"
4994
5011
  },
4995
5012
  {
5013
+ type: "function",
5014
+ name: "interopCallValue",
4996
5015
  inputs: [
4997
5016
  {
4998
- internalType: "uint256",
4999
5017
  name: "_interopCallValue",
5000
- type: "uint256"
5018
+ type: "uint256",
5019
+ internalType: "uint256"
5001
5020
  }
5002
5021
  ],
5003
- name: "interopCallValue",
5004
5022
  outputs: [],
5005
- stateMutability: "pure",
5006
- type: "function"
5023
+ stateMutability: "pure"
5007
5024
  },
5008
5025
  {
5026
+ type: "function",
5027
+ name: "unbundlerAddress",
5009
5028
  inputs: [
5010
5029
  {
5011
- internalType: "bytes",
5012
5030
  name: "_unbundlerAddress",
5013
- type: "bytes"
5031
+ type: "bytes",
5032
+ internalType: "bytes"
5014
5033
  }
5015
5034
  ],
5016
- name: "unbundlerAddress",
5017
5035
  outputs: [],
5018
- stateMutability: "pure",
5019
- type: "function"
5036
+ stateMutability: "pure"
5037
+ },
5038
+ {
5039
+ type: "function",
5040
+ name: "useFixedFee",
5041
+ inputs: [
5042
+ {
5043
+ name: "_useFixed",
5044
+ type: "bool",
5045
+ internalType: "bool"
5046
+ }
5047
+ ],
5048
+ outputs: [],
5049
+ stateMutability: "pure"
5020
5050
  }
5021
5051
  ];
5022
5052
  var IERC7786Attributes_default = IERC7786AttributesABI;
@@ -5864,6 +5894,11 @@ var IInteropCenterABI = [
5864
5894
  type: "uint256",
5865
5895
  internalType: "uint256"
5866
5896
  },
5897
+ {
5898
+ name: "destinationBaseTokenAssetId",
5899
+ type: "bytes32",
5900
+ internalType: "bytes32"
5901
+ },
5867
5902
  {
5868
5903
  name: "interopBundleSalt",
5869
5904
  type: "bytes32",
@@ -7498,7 +7533,7 @@ function createErrorOps(decodeRevert2) {
7498
7533
  throw toZKsyncError2(kind, { resource, operation, context: opts?.ctx ?? {}, message }, e);
7499
7534
  }
7500
7535
  }
7501
- function wrap7(operation, fn, opts) {
7536
+ function wrap8(operation, fn, opts) {
7502
7537
  return run("INTERNAL", operation, fn, opts);
7503
7538
  }
7504
7539
  function wrapAs10(kind, operation, fn, opts) {
@@ -7506,7 +7541,7 @@ function createErrorOps(decodeRevert2) {
7506
7541
  }
7507
7542
  async function toResult3(operation, fn, opts) {
7508
7543
  try {
7509
- const value = await wrap7(operation, fn, opts);
7544
+ const value = await wrap8(operation, fn, opts);
7510
7545
  return { ok: true, value };
7511
7546
  } catch (e) {
7512
7547
  const shaped = isZKsyncError(e) ? e : toZKsyncError2(
@@ -7522,7 +7557,7 @@ function createErrorOps(decodeRevert2) {
7522
7557
  return { ok: false, error: shaped };
7523
7558
  }
7524
7559
  }
7525
- return { wrap: wrap7, wrapAs: wrapAs10, toResult: toResult3 };
7560
+ return { wrap: wrap8, wrapAs: wrapAs10, toResult: toResult3 };
7526
7561
  }
7527
7562
  return { toZKsyncError: toZKsyncError2, createErrorHandlers: createErrorHandlers2 };
7528
7563
  }
@@ -8001,7 +8036,33 @@ function buildDirectRequestStruct(args) {
8001
8036
  };
8002
8037
  }
8003
8038
 
8039
+ // src/core/resources/deposits/chains.ts
8040
+ var ERAVM_CHAIN_IDS = /* @__PURE__ */ new Set([324n, 2741n, 11124n, 300n]);
8041
+ function isEraVmChain(chainIdL2) {
8042
+ return ERAVM_CHAIN_IDS.has(chainIdL2);
8043
+ }
8044
+
8004
8045
  // src/core/resources/deposits/gas.ts
8046
+ var CREATE_REESTIMATE_BUFFER = 15n;
8047
+ var maxBigInt = (a, b) => a > b ? a : b;
8048
+ function applyGasBuffer(gasLimit, bufferPct = BUFFER) {
8049
+ return gasLimit * (100n + bufferPct) / 100n;
8050
+ }
8051
+ function resolveCreateDepositL1GasLimit(input) {
8052
+ const { chainIdL2, stepKey, preparedGasLimit, estimatedGasLimit } = input;
8053
+ if (estimatedGasLimit == null) {
8054
+ return preparedGasLimit;
8055
+ }
8056
+ const isEraVmBridgeStep = isEraVmChain(chainIdL2) && stepKey.startsWith("bridgehub:");
8057
+ const reestimatedGasLimit = applyGasBuffer(
8058
+ estimatedGasLimit,
8059
+ isEraVmBridgeStep ? BUFFER : CREATE_REESTIMATE_BUFFER
8060
+ );
8061
+ if (isEraVmBridgeStep && preparedGasLimit != null) {
8062
+ return maxBigInt(preparedGasLimit, reestimatedGasLimit);
8063
+ }
8064
+ return reestimatedGasLimit;
8065
+ }
8005
8066
  function makeGasQuote(p) {
8006
8067
  const maxPriorityFeePerGas = p.maxPriorityFeePerGas ?? 0n;
8007
8068
  return {
@@ -8052,13 +8113,12 @@ async function quoteL1Gas(input) {
8052
8113
  }
8053
8114
  try {
8054
8115
  const est = await estimator.estimateGas(tx);
8055
- const buffered = BigInt(est) * (100n + BUFFER) / 100n;
8116
+ const buffered = applyGasBuffer(BigInt(est));
8056
8117
  return makeGasQuote({ gasLimit: buffered, maxFeePerGas, maxPriorityFeePerGas });
8057
- } catch (err) {
8118
+ } catch {
8058
8119
  if (fallbackGasLimit != null) {
8059
8120
  return makeGasQuote({ gasLimit: fallbackGasLimit, maxFeePerGas, maxPriorityFeePerGas });
8060
8121
  }
8061
- console.warn("L1 gas estimation failed", err);
8062
8122
  return void 0;
8063
8123
  }
8064
8124
  }
@@ -8090,14 +8150,13 @@ async function quoteL2Gas(input) {
8090
8150
  const memoryOverhead = memoryBytes * TX_MEMORY_OVERHEAD_GAS;
8091
8151
  const pubdataOverhead = pubdataBytes * pp;
8092
8152
  let total = BigInt(execEstimate) + TX_OVERHEAD_GAS + memoryOverhead + pubdataOverhead;
8093
- total = total * (100n + BUFFER) / 100n;
8153
+ total = applyGasBuffer(total);
8094
8154
  return makeGasQuote({
8095
8155
  gasLimit: total,
8096
8156
  maxFeePerGas,
8097
8157
  gasPerPubdata: pp
8098
8158
  });
8099
- } catch (err) {
8100
- console.warn("L2 gas estimation failed", err);
8159
+ } catch {
8101
8160
  return makeGasQuote({
8102
8161
  gasLimit: l2GasLimit ?? 0n,
8103
8162
  maxFeePerGas,
@@ -8260,8 +8319,22 @@ async function determineNonBaseL2Gas(input) {
8260
8319
  try {
8261
8320
  const l2TokenAddress = input.knownL2Token ?? (ctx.tokens ? await ctx.tokens.toL2Address(l1Token) : await (await ctx.contracts.l2NativeTokenVault()).l2TokenAddress(l1Token));
8262
8321
  if (l2TokenAddress === ZERO_L2_TOKEN_ADDRESS) {
8322
+ if (input.undeployedGasLimit != null) {
8323
+ return quoteL2Gas2({
8324
+ ctx,
8325
+ route,
8326
+ overrideGasLimit: input.undeployedGasLimit
8327
+ });
8328
+ }
8263
8329
  return fallbackQuote();
8264
8330
  }
8331
+ if (input.priorityFloorGasLimit != null) {
8332
+ return quoteL2Gas2({
8333
+ ctx,
8334
+ route,
8335
+ overrideGasLimit: input.priorityFloorGasLimit
8336
+ });
8337
+ }
8265
8338
  const modelTx = {
8266
8339
  to: input.modelTx?.to ?? ctx.sender,
8267
8340
  from: input.modelTx?.from ?? ctx.sender,
@@ -8277,8 +8350,7 @@ async function determineNonBaseL2Gas(input) {
8277
8350
  return fallbackQuote();
8278
8351
  }
8279
8352
  return gas;
8280
- } catch (err) {
8281
- console.warn("Failed to determine non-base deposit L2 gas; defaulting to safe gas limit.", err);
8353
+ } catch {
8282
8354
  return fallbackQuote();
8283
8355
  }
8284
8356
  }
@@ -8295,7 +8367,9 @@ async function determineEthNonBaseL2Gas(input) {
8295
8367
  route: "eth-nonbase",
8296
8368
  l1Token: input.ctx.resolvedToken?.l1 ?? FORMAL_ETH_ADDRESS,
8297
8369
  knownL2Token: input.ctx.resolvedToken?.l2,
8298
- modelTx: input.modelTx
8370
+ modelTx: input.modelTx,
8371
+ priorityFloorGasLimit: input.priorityFloorGasLimit,
8372
+ undeployedGasLimit: input.undeployedGasLimit
8299
8373
  });
8300
8374
  }
8301
8375
 
@@ -8327,41 +8401,120 @@ function buildFeeBreakdown(p) {
8327
8401
  };
8328
8402
  }
8329
8403
 
8404
+ // src/core/resources/deposits/priority.ts
8405
+ var PRIORITY_TX_ENCODING_STEP_BYTES = 544n;
8406
+ var DEFAULT_PRIORITY_BODY_GAS_ESTIMATE_MULTIPLIER = 6n;
8407
+ var ERAVM_PRIORITY_L2_GAS_BUFFER = 30n;
8408
+ var maxBigInt2 = (a, b) => a > b ? a : b;
8409
+ var ceilDiv = (a, b) => (a + b - 1n) / b;
8410
+ function derivePriorityTxGasBreakdown(input) {
8411
+ const factoryDepsCount = input.factoryDepsCount ?? 0n;
8412
+ const minBodyGas = maxBigInt2(
8413
+ L1_TX_INTRINSIC_L2_GAS + ceilDiv(
8414
+ input.encodedLength * L1_TX_DELTA_544_ENCODING_BYTES,
8415
+ PRIORITY_TX_ENCODING_STEP_BYTES
8416
+ ) + factoryDepsCount * L1_TX_DELTA_FACTORY_DEPS_L2_GAS,
8417
+ L1_TX_MIN_L2_GAS_BASE
8418
+ ) + L1_TX_INTRINSIC_PUBDATA * input.gasPerPubdata + factoryDepsCount * L1_TX_DELTA_FACTORY_DEPS_PUBDATA * input.gasPerPubdata;
8419
+ const overhead = maxBigInt2(TX_SLOT_OVERHEAD_L2_GAS, TX_MEMORY_OVERHEAD_GAS * input.encodedLength);
8420
+ const derivedBodyGas = minBodyGas;
8421
+ return {
8422
+ encodedLength: input.encodedLength,
8423
+ minBodyGas,
8424
+ overhead,
8425
+ derivedBodyGas,
8426
+ derivedL2GasLimit: derivedBodyGas + overhead,
8427
+ priorityTxMaxGasLimit: PRIORITY_TX_MAX_GAS_LIMIT,
8428
+ priorityTxMaxGasLimitExceeded: derivedBodyGas > PRIORITY_TX_MAX_GAS_LIMIT
8429
+ };
8430
+ }
8431
+ function derivePriorityBodyGasEstimateCap(input) {
8432
+ return input.minBodyGas * (input.multiplier ?? DEFAULT_PRIORITY_BODY_GAS_ESTIMATE_MULTIPLIER);
8433
+ }
8434
+ function applyPriorityL2GasLimitBuffer(input) {
8435
+ if (!isEraVmChain(input.chainIdL2)) {
8436
+ return input.gasLimit;
8437
+ }
8438
+ return input.gasLimit * (100n + ERAVM_PRIORITY_L2_GAS_BUFFER) / 100n;
8439
+ }
8440
+ var EMPTY_BYTES = "0x";
8441
+ var ZERO_RESERVED_WORDS = [0n, 0n, 0n, 0n];
8442
+ var L2_CANONICAL_TRANSACTION_TUPLE = "tuple(uint256 txType,uint256 from,uint256 to,uint256 gasLimit,uint256 gasPerPubdataByteLimit,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 paymaster,uint256 nonce,uint256 value,uint256[4] reserved,bytes data,bytes signature,uint256[] factoryDeps,bytes paymasterInput,bytes reservedDynamic)";
8443
+ function hexByteLength(hex) {
8444
+ return BigInt(Math.max(hex.length - 2, 0) / 2);
8445
+ }
8446
+ function getPriorityTxEncodedLength(input) {
8447
+ const encoded = ethers.AbiCoder.defaultAbiCoder().encode(
8448
+ [L2_CANONICAL_TRANSACTION_TUPLE],
8449
+ [
8450
+ [
8451
+ 0n,
8452
+ BigInt(input.sender),
8453
+ BigInt(input.l2Contract),
8454
+ 0n,
8455
+ input.gasPerPubdata,
8456
+ 0n,
8457
+ 0n,
8458
+ 0n,
8459
+ 0n,
8460
+ input.l2Value,
8461
+ ZERO_RESERVED_WORDS,
8462
+ input.l2Calldata,
8463
+ EMPTY_BYTES,
8464
+ input.factoryDepsHashes ?? [],
8465
+ EMPTY_BYTES,
8466
+ EMPTY_BYTES
8467
+ ]
8468
+ ]
8469
+ );
8470
+ return hexByteLength(encoded);
8471
+ }
8472
+ function getPriorityTxGasBreakdown(input) {
8473
+ return derivePriorityTxGasBreakdown({
8474
+ encodedLength: getPriorityTxEncodedLength(input),
8475
+ gasPerPubdata: input.gasPerPubdata,
8476
+ factoryDepsCount: BigInt(input.factoryDepsHashes?.length ?? 0)
8477
+ });
8478
+ }
8479
+
8330
8480
  // src/adapters/ethers/resources/deposits/routes/eth.ts
8481
+ var EMPTY_BYTES2 = "0x";
8331
8482
  function routeEthDirect() {
8332
8483
  return {
8333
8484
  async build(p, ctx) {
8334
8485
  const bh = await ctx.contracts.bridgehub();
8335
- const l2TxModel = {
8336
- to: p.to ?? ctx.sender,
8337
- from: ctx.sender,
8338
- data: "0x",
8339
- value: 0n
8340
- };
8486
+ const l2Contract = p.to ?? ctx.sender;
8487
+ const l2Value = p.amount;
8488
+ const l2Calldata = EMPTY_BYTES2;
8489
+ const priorityFloorBreakdown = getPriorityTxGasBreakdown({
8490
+ sender: ctx.sender,
8491
+ l2Contract,
8492
+ l2Value,
8493
+ l2Calldata,
8494
+ gasPerPubdata: ctx.gasPerPubdata
8495
+ });
8496
+ const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
8497
+ chainIdL2: ctx.chainIdL2,
8498
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
8499
+ });
8341
8500
  const l2GasParams = await quoteL2Gas2({
8342
8501
  ctx,
8343
8502
  route: "eth-base",
8344
- l2TxForModeling: l2TxModel,
8345
- overrideGasLimit: ctx.l2GasLimit,
8346
- stateOverrides: {
8347
- [ctx.sender]: {
8348
- balance: "0xffffffffffffffffffff"
8349
- }
8350
- }
8503
+ overrideGasLimit: quotedL2GasLimit
8351
8504
  });
8352
8505
  if (!l2GasParams) {
8353
8506
  throw new Error("Failed to estimate L2 gas for deposit.");
8354
8507
  }
8355
8508
  const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
8356
- const mintValue = baseCost + ctx.operatorTip + p.amount;
8509
+ const mintValue = baseCost + ctx.operatorTip + l2Value;
8357
8510
  const req = buildDirectRequestStruct({
8358
8511
  chainId: ctx.chainIdL2,
8359
8512
  mintValue,
8360
8513
  l2GasLimit: l2GasParams.gasLimit,
8361
8514
  gasPerPubdata: ctx.gasPerPubdata,
8362
8515
  refundRecipient: ctx.refundRecipient,
8363
- l2Contract: p.to ?? ctx.sender,
8364
- l2Value: p.amount
8516
+ l2Contract,
8517
+ l2Value
8365
8518
  });
8366
8519
  const data = bh.interface.encodeFunctionData("requestL2TransactionDirect", [req]);
8367
8520
  const l1TxCandidate = {
@@ -8406,6 +8559,56 @@ function routeEthDirect() {
8406
8559
  };
8407
8560
  }
8408
8561
  var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
8562
+ var ZERO_L2_TOKEN_ADDRESS2 = "0x0000000000000000000000000000000000000000";
8563
+ var ZERO_ASSET_ID = "0x0000000000000000000000000000000000000000000000000000000000000000";
8564
+ async function getPriorityGasModel(input) {
8565
+ try {
8566
+ const l1NativeTokenVault = await input.ctx.contracts.l1NativeTokenVault();
8567
+ const l1AssetRouter = await input.ctx.contracts.l1AssetRouter();
8568
+ const { chainId: l1ChainId } = await input.ctx.client.l1.getNetwork();
8569
+ const isFirstBridge = input.ctx.resolvedToken.assetId.toLowerCase() === ZERO_ASSET_ID || input.ctx.resolvedToken.originChainId === 0n;
8570
+ const erc20MetadataOriginChainId = isFirstBridge ? BigInt(l1ChainId) : input.ctx.resolvedToken.originChainId;
8571
+ const erc20Metadata = await l1NativeTokenVault.getERC20Getters(
8572
+ input.token,
8573
+ erc20MetadataOriginChainId
8574
+ );
8575
+ const bridgeMintCalldata = ethers.AbiCoder.defaultAbiCoder().encode(
8576
+ ["address", "address", "address", "uint256", "bytes"],
8577
+ [input.ctx.sender, input.receiver, input.token, input.amount, erc20Metadata]
8578
+ );
8579
+ const l2Calldata = isFirstBridge ? new ethers.Interface(IL2AssetRouter_default).encodeFunctionData(
8580
+ "finalizeDeposit(address,address,address,uint256,bytes)",
8581
+ [input.ctx.sender, input.receiver, input.token, input.amount, erc20Metadata]
8582
+ ) : await (() => {
8583
+ return l1AssetRouter.getDepositCalldata(
8584
+ input.ctx.sender,
8585
+ input.ctx.resolvedToken.assetId,
8586
+ bridgeMintCalldata
8587
+ );
8588
+ })();
8589
+ const priorityFloorBreakdown = getPriorityTxGasBreakdown({
8590
+ sender: input.ctx.l1AssetRouter,
8591
+ l2Contract: L2_ASSET_ROUTER_ADDRESS,
8592
+ l2Value: 0n,
8593
+ l2Calldata,
8594
+ gasPerPubdata: input.ctx.gasPerPubdata
8595
+ });
8596
+ const model = {
8597
+ priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
8598
+ chainIdL2: input.ctx.chainIdL2,
8599
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
8600
+ })
8601
+ };
8602
+ if (isFirstBridge || input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS2) {
8603
+ model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
8604
+ minBodyGas: priorityFloorBreakdown.minBodyGas
8605
+ }) + priorityFloorBreakdown.overhead;
8606
+ }
8607
+ return model;
8608
+ } catch {
8609
+ return {};
8610
+ }
8611
+ }
8409
8612
  function routeErc20NonBase() {
8410
8613
  return {
8411
8614
  async preflight(p, ctx) {
@@ -8426,11 +8629,29 @@ function routeErc20NonBase() {
8426
8629
  const l1Signer = ctx.client.getL1Signer();
8427
8630
  const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
8428
8631
  const baseIsEth = ctx.baseIsEth ?? isETH(baseToken);
8632
+ const receiver = p.to ?? ctx.sender;
8633
+ const secondBridgeCalldata = await wrapAs3(
8634
+ "INTERNAL",
8635
+ OP_DEPOSITS.nonbase.encodeCalldata,
8636
+ () => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, receiver)),
8637
+ {
8638
+ ctx: { where: "encodeSecondBridgeErc20Args" },
8639
+ message: "Failed to encode bridging calldata."
8640
+ }
8641
+ );
8642
+ const priorityGasModel = await getPriorityGasModel({
8643
+ ctx,
8644
+ token: p.token,
8645
+ amount: p.amount,
8646
+ receiver
8647
+ });
8429
8648
  const l2GasParams = await determineErc20L2Gas({
8430
8649
  ctx,
8431
8650
  l1Token: p.token,
8651
+ priorityFloorGasLimit: priorityGasModel.priorityFloorGasLimit,
8652
+ undeployedGasLimit: priorityGasModel.undeployedGasLimit,
8432
8653
  modelTx: {
8433
- to: p.to ?? ctx.sender,
8654
+ to: receiver,
8434
8655
  from: ctx.sender,
8435
8656
  data: "0x",
8436
8657
  value: 0n
@@ -8492,15 +8713,6 @@ function routeErc20NonBase() {
8492
8713
  });
8493
8714
  }
8494
8715
  }
8495
- const secondBridgeCalldata = await wrapAs3(
8496
- "INTERNAL",
8497
- OP_DEPOSITS.nonbase.encodeCalldata,
8498
- () => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, p.to ?? ctx.sender)),
8499
- {
8500
- ctx: { where: "encodeSecondBridgeErc20Args" },
8501
- message: "Failed to encode bridging calldata."
8502
- }
8503
- );
8504
8716
  const requestStruct = {
8505
8717
  chainId: ctx.chainIdL2,
8506
8718
  mintValue,
@@ -8557,7 +8769,71 @@ function routeErc20NonBase() {
8557
8769
  }
8558
8770
  };
8559
8771
  }
8772
+
8773
+ // src/core/codec/ntv.ts
8774
+ function createNTVCodec(deps) {
8775
+ function encodeAssetId(originChainId, ntvAddress, tokenAddress) {
8776
+ const encoded = deps.encode(
8777
+ ["uint256", "address", "address"],
8778
+ [originChainId, ntvAddress, tokenAddress]
8779
+ );
8780
+ return deps.keccak256(encoded);
8781
+ }
8782
+ return {
8783
+ encodeAssetId
8784
+ };
8785
+ }
8786
+
8787
+ // src/adapters/ethers/resources/deposits/routes/eth-nonbase.ts
8560
8788
  var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
8789
+ var ZERO_L2_TOKEN_ADDRESS3 = "0x0000000000000000000000000000000000000000";
8790
+ var ZERO_ASSET_ID2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
8791
+ var ntvCodec = createNTVCodec({
8792
+ encode: (types, values) => ethers.AbiCoder.defaultAbiCoder().encode(types, values),
8793
+ keccak256: (data) => ethers.keccak256(data)
8794
+ });
8795
+ async function getPriorityGasModel2(input) {
8796
+ try {
8797
+ const l1AssetRouter = await input.ctx.contracts.l1AssetRouter();
8798
+ const l1NativeTokenVault = await input.ctx.contracts.l1NativeTokenVault();
8799
+ const originChainId = input.ctx.resolvedToken.originChainId !== 0n ? input.ctx.resolvedToken.originChainId : BigInt((await input.ctx.client.l1.getNetwork()).chainId);
8800
+ const resolvedAssetId = input.ctx.resolvedToken.assetId.toLowerCase() === ZERO_ASSET_ID2 ? ntvCodec.encodeAssetId(originChainId, L2_NATIVE_TOKEN_VAULT_ADDRESS, ETH_ADDRESS) : input.ctx.resolvedToken.assetId;
8801
+ const erc20Metadata = await l1NativeTokenVault.getERC20Getters(
8802
+ ETH_ADDRESS,
8803
+ originChainId
8804
+ );
8805
+ const bridgeMintCalldata = ethers.AbiCoder.defaultAbiCoder().encode(
8806
+ ["address", "address", "address", "uint256", "bytes"],
8807
+ [input.ctx.sender, input.receiver, ETH_ADDRESS, input.amount, erc20Metadata]
8808
+ );
8809
+ const l2Calldata = await l1AssetRouter.getDepositCalldata(
8810
+ input.ctx.sender,
8811
+ resolvedAssetId,
8812
+ bridgeMintCalldata
8813
+ );
8814
+ const priorityFloorBreakdown = getPriorityTxGasBreakdown({
8815
+ sender: input.ctx.l1AssetRouter,
8816
+ l2Contract: L2_ASSET_ROUTER_ADDRESS,
8817
+ l2Value: 0n,
8818
+ l2Calldata,
8819
+ gasPerPubdata: input.ctx.gasPerPubdata
8820
+ });
8821
+ const model = {
8822
+ priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
8823
+ chainIdL2: input.ctx.chainIdL2,
8824
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
8825
+ })
8826
+ };
8827
+ if (input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS3) {
8828
+ model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
8829
+ minBodyGas: priorityFloorBreakdown.minBodyGas
8830
+ }) + priorityFloorBreakdown.overhead;
8831
+ }
8832
+ return model;
8833
+ } catch {
8834
+ return {};
8835
+ }
8836
+ }
8561
8837
  function routeEthNonBase() {
8562
8838
  return {
8563
8839
  async preflight(p, ctx) {
@@ -8606,15 +8882,23 @@ function routeEthNonBase() {
8606
8882
  async build(p, ctx) {
8607
8883
  const l1Signer = ctx.client.getL1Signer();
8608
8884
  const baseToken = ctx.baseTokenL1;
8885
+ const receiver = p.to ?? ctx.sender;
8886
+ const priorityGasModel = await getPriorityGasModel2({
8887
+ ctx,
8888
+ amount: p.amount,
8889
+ receiver
8890
+ });
8609
8891
  const l2TxModel = {
8610
- to: p.to ?? ctx.sender,
8892
+ to: receiver,
8611
8893
  from: ctx.sender,
8612
8894
  data: "0x",
8613
8895
  value: 0n
8614
8896
  };
8615
8897
  const l2GasParams = await determineEthNonBaseL2Gas({
8616
8898
  ctx,
8617
- modelTx: l2TxModel
8899
+ modelTx: l2TxModel,
8900
+ priorityFloorGasLimit: priorityGasModel.priorityFloorGasLimit,
8901
+ undeployedGasLimit: priorityGasModel.undeployedGasLimit
8618
8902
  });
8619
8903
  if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
8620
8904
  const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
@@ -8648,12 +8932,12 @@ function routeEthNonBase() {
8648
8932
  const secondBridgeCalldata = await wrapAs4(
8649
8933
  "INTERNAL",
8650
8934
  OP_DEPOSITS.ethNonBase.encodeCalldata,
8651
- () => Promise.resolve(encodeSecondBridgeEthArgs(p.amount, p.to ?? ctx.sender)),
8935
+ () => Promise.resolve(encodeSecondBridgeEthArgs(p.amount, receiver)),
8652
8936
  {
8653
8937
  ctx: {
8654
8938
  where: "encodeSecondBridgeEthArgs",
8655
8939
  amount: p.amount.toString(),
8656
- to: p.to ?? ctx.sender
8940
+ to: receiver
8657
8941
  }
8658
8942
  }
8659
8943
  );
@@ -8714,6 +8998,7 @@ function routeEthNonBase() {
8714
8998
  };
8715
8999
  }
8716
9000
  var { wrapAs: wrapAs5 } = createErrorHandlers("deposits");
9001
+ var EMPTY_BYTES3 = "0x";
8717
9002
  function routeErc20Base() {
8718
9003
  return {
8719
9004
  async preflight(p, ctx) {
@@ -8744,17 +9029,24 @@ function routeErc20Base() {
8744
9029
  async build(p, ctx) {
8745
9030
  const l1Signer = ctx.client.getL1Signer();
8746
9031
  const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
8747
- const l2TxModel = {
8748
- to: p.to ?? ctx.sender,
8749
- from: ctx.sender,
8750
- data: "0x",
8751
- value: 0n
8752
- };
9032
+ const l2Contract = p.to ?? ctx.sender;
9033
+ const l2Value = p.amount;
9034
+ const l2Calldata = EMPTY_BYTES3;
9035
+ const priorityFloorBreakdown = getPriorityTxGasBreakdown({
9036
+ sender: ctx.sender,
9037
+ l2Contract,
9038
+ l2Value,
9039
+ l2Calldata,
9040
+ gasPerPubdata: ctx.gasPerPubdata
9041
+ });
9042
+ const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
9043
+ chainIdL2: ctx.chainIdL2,
9044
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
9045
+ });
8753
9046
  const l2GasParams = await quoteL2Gas2({
8754
9047
  ctx,
8755
9048
  route: "erc20-base",
8756
- l2TxForModeling: l2TxModel,
8757
- overrideGasLimit: ctx.l2GasLimit
9049
+ overrideGasLimit: quotedL2GasLimit
8758
9050
  });
8759
9051
  if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
8760
9052
  const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
@@ -8793,8 +9085,8 @@ function routeErc20Base() {
8793
9085
  l2GasLimit: l2GasParams.gasLimit,
8794
9086
  gasPerPubdata: ctx.gasPerPubdata,
8795
9087
  refundRecipient: ctx.refundRecipient,
8796
- l2Contract: p.to ?? ctx.sender,
8797
- l2Value: p.amount
9088
+ l2Contract,
9089
+ l2Value
8798
9090
  });
8799
9091
  const bridgehub = await ctx.contracts.bridgehub();
8800
9092
  const data = bridgehub.interface.encodeFunctionData("requestL2TransactionDirect", [
@@ -8841,25 +9133,9 @@ function routeErc20Base() {
8841
9133
  }
8842
9134
  };
8843
9135
  }
8844
-
8845
- // src/core/codec/ntv.ts
8846
- function createNTVCodec(deps) {
8847
- function encodeAssetId(originChainId, ntvAddress, tokenAddress) {
8848
- const encoded = deps.encode(
8849
- ["uint256", "address", "address"],
8850
- [originChainId, ntvAddress, tokenAddress]
8851
- );
8852
- return deps.keccak256(encoded);
8853
- }
8854
- return {
8855
- encodeAssetId
8856
- };
8857
- }
8858
-
8859
- // src/adapters/ethers/resources/tokens/tokens.ts
8860
9136
  var { wrapAs: wrapAs6 } = createErrorHandlers("tokens");
8861
9137
  var abi = ethers.AbiCoder.defaultAbiCoder();
8862
- var ntvCodec = createNTVCodec({
9138
+ var ntvCodec2 = createNTVCodec({
8863
9139
  encode: (types, values) => abi.encode(types, values),
8864
9140
  keccak256: (data) => ethers.ethers.keccak256(data)
8865
9141
  });
@@ -8978,7 +9254,7 @@ function createTokensResource(client) {
8978
9254
  return wrapAs6("CONTRACT", "tokens.isChainEthBased", async () => {
8979
9255
  const baseAssetId = await getBaseTokenAssetId();
8980
9256
  const l1ChainId = await getL1ChainId();
8981
- const ethAssetId = ntvCodec.encodeAssetId(
9257
+ const ethAssetId = ntvCodec2.encodeAssetId(
8982
9258
  l1ChainId,
8983
9259
  L2_NATIVE_TOKEN_VAULT_ADDRESS,
8984
9260
  ETH_ADDRESS
@@ -9192,6 +9468,8 @@ function createDepositsResource(client, tokens, contracts) {
9192
9468
  async () => {
9193
9469
  const plan = await prepare(p);
9194
9470
  const stepHashes = {};
9471
+ const { chainId } = await client.l2.getNetwork();
9472
+ const chainIdL2 = BigInt(chainId);
9195
9473
  const managed = new ethers.NonceManager(client.signer);
9196
9474
  const from = await managed.getAddress();
9197
9475
  let next;
@@ -9237,8 +9515,14 @@ function createDepositsResource(client, tokens, contracts) {
9237
9515
  }
9238
9516
  if (!p.l1TxOverrides?.gasLimit) {
9239
9517
  try {
9518
+ const preparedGasLimit = step.tx.gasLimit != null ? BigInt(step.tx.gasLimit.toString()) : void 0;
9240
9519
  const est = await client.l1.estimateGas(step.tx);
9241
- step.tx.gasLimit = BigInt(est) * 115n / 100n;
9520
+ step.tx.gasLimit = resolveCreateDepositL1GasLimit({
9521
+ chainIdL2,
9522
+ stepKey: step.key,
9523
+ preparedGasLimit,
9524
+ estimatedGasLimit: BigInt(est)
9525
+ });
9242
9526
  } catch {
9243
9527
  }
9244
9528
  }
@@ -9989,7 +10273,7 @@ var ROUTES2 = {
9989
10273
  };
9990
10274
  function createWithdrawalsResource(client, tokens, contracts) {
9991
10275
  const svc = createFinalizationServices(client);
9992
- const { wrap: wrap7, toResult: toResult3 } = createErrorHandlers("withdrawals");
10276
+ const { wrap: wrap8, toResult: toResult3 } = createErrorHandlers("withdrawals");
9993
10277
  const tokensResource = tokens ?? createTokensResource(client);
9994
10278
  const contractsResource = contracts ?? createContractsResource(client);
9995
10279
  async function buildPlan(p) {
@@ -10010,7 +10294,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
10010
10294
  };
10011
10295
  }
10012
10296
  const finalizeCache = /* @__PURE__ */ new Map();
10013
- const quote = (p) => wrap7(
10297
+ const quote = (p) => wrap8(
10014
10298
  OP_WITHDRAWALS.quote,
10015
10299
  async () => {
10016
10300
  const plan = await buildPlan(p);
@@ -10032,7 +10316,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
10032
10316
  ctx: { token: p.token, where: "withdrawals.tryQuote" }
10033
10317
  }
10034
10318
  );
10035
- const prepare = (p) => wrap7(OP_WITHDRAWALS.prepare, () => buildPlan(p), {
10319
+ const prepare = (p) => wrap8(OP_WITHDRAWALS.prepare, () => buildPlan(p), {
10036
10320
  message: "Internal error while preparing a withdrawal plan.",
10037
10321
  ctx: { token: p.token, where: "withdrawals.prepare" }
10038
10322
  });
@@ -10040,7 +10324,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
10040
10324
  message: "Internal error while preparing a withdrawal plan.",
10041
10325
  ctx: { token: p.token, where: "withdrawals.tryPrepare" }
10042
10326
  });
10043
- const create = (p) => wrap7(
10327
+ const create = (p) => wrap8(
10044
10328
  OP_WITHDRAWALS.create,
10045
10329
  async () => {
10046
10330
  const plan = await prepare(p);
@@ -10111,7 +10395,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
10111
10395
  message: "Internal error while creating withdrawal transactions.",
10112
10396
  ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.tryCreate" }
10113
10397
  });
10114
- const status = (h) => wrap7(
10398
+ const status = (h) => wrap8(
10115
10399
  OP_WITHDRAWALS.status,
10116
10400
  async () => {
10117
10401
  const l2TxHash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
@@ -10166,7 +10450,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
10166
10450
  const wait = (h, opts = {
10167
10451
  for: "l2",
10168
10452
  pollMs: 5500
10169
- }) => wrap7(
10453
+ }) => wrap8(
10170
10454
  OP_WITHDRAWALS.wait,
10171
10455
  async () => {
10172
10456
  const l2Hash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
@@ -10231,7 +10515,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
10231
10515
  }
10232
10516
  }
10233
10517
  );
10234
- const finalize = (l2TxHash) => wrap7(
10518
+ const finalize = (l2TxHash) => wrap8(
10235
10519
  OP_WITHDRAWALS.finalize.send,
10236
10520
  async () => {
10237
10521
  const pack = await (async () => {
@@ -10357,9 +10641,11 @@ function createCallAttributes(codec) {
10357
10641
  function createBundleAttributes(codec) {
10358
10642
  const executionAddress = (executor) => codec.encode("executionAddress", [executor]);
10359
10643
  const unbundlerAddress = (addr) => codec.encode("unbundlerAddress", [addr]);
10644
+ const useFixedFee = (enabled) => codec.encode("useFixedFee", [enabled]);
10360
10645
  return {
10361
10646
  executionAddress,
10362
- unbundlerAddress
10647
+ unbundlerAddress,
10648
+ useFixedFee
10363
10649
  };
10364
10650
  }
10365
10651
 
@@ -10380,6 +10666,7 @@ function getInteropAttributes(params, ctx) {
10380
10666
  if (params.unbundling?.by) {
10381
10667
  bundleAttributes.push(ctx.attributes.bundle.unbundlerAddress(params.unbundling.by));
10382
10668
  }
10669
+ bundleAttributes.push(ctx.attributes.bundle.useFixedFee(params.fee?.useFixed ?? false));
10383
10670
  const callAttributes = params.actions.map((action) => {
10384
10671
  switch (action.type) {
10385
10672
  case "sendNative": {
@@ -10409,11 +10696,6 @@ function createEthersAttributesResource(opts = {}) {
10409
10696
  }
10410
10697
 
10411
10698
  // src/core/types/flows/interop.ts
10412
- function isInteropExpectedRoot(obj) {
10413
- if (typeof obj !== "object" || obj === null) return false;
10414
- const root = obj;
10415
- return isBigint(root.rootChainId) && isBigint(root.batchNumber) && isHash(root.expectedRoot);
10416
- }
10417
10699
  function isInteropMessageProof(obj) {
10418
10700
  if (typeof obj !== "object" || obj === null) return false;
10419
10701
  const proof = obj;
@@ -10422,7 +10704,7 @@ function isInteropMessageProof(obj) {
10422
10704
  function isInteropFinalizationInfo(obj) {
10423
10705
  if (typeof obj !== "object" || obj === null) return false;
10424
10706
  const info = obj;
10425
- return isHash66(info.l2SrcTxHash) && isHash66(info.bundleHash) && isBigint(info.dstChainId) && isHash(info.encodedData) && isInteropExpectedRoot(info.expectedRoot) && isInteropMessageProof(info.proof);
10707
+ return isHash66(info.l2SrcTxHash) && isHash66(info.bundleHash) && isBigint(info.dstChainId) && isHash(info.encodedData) && isInteropMessageProof(info.proof);
10426
10708
  }
10427
10709
 
10428
10710
  // src/core/resources/interop/route.ts
@@ -10475,7 +10757,7 @@ function preflightDirect(params, ctx) {
10475
10757
  }
10476
10758
  }
10477
10759
  }
10478
- function buildDirectBundle(params, ctx, attrs) {
10760
+ function buildDirectBundle(params, ctx, attrs, interopFeeInfo) {
10479
10761
  const totalActionValue = sumActionMsgValue(params.actions);
10480
10762
  const starters = params.actions.map((action, index) => {
10481
10763
  const to = ctx.codec.formatAddress(action.to);
@@ -10493,7 +10775,8 @@ function buildDirectBundle(params, ctx, attrs) {
10493
10775
  dstChain: ctx.codec.formatChain(ctx.dstChainId),
10494
10776
  starters,
10495
10777
  bundleAttributes: attrs.bundleAttributes,
10496
- approvals: [],
10778
+ approvals: interopFeeInfo.approval ? [interopFeeInfo.approval] : [],
10779
+ interopFee: interopFeeInfo.fee,
10497
10780
  quoteExtras: {
10498
10781
  totalActionValue,
10499
10782
  bridgedTokenTotal: 0n
@@ -10538,7 +10821,7 @@ function preflightIndirect(params, ctx) {
10538
10821
  }
10539
10822
  }
10540
10823
  }
10541
- function buildIndirectBundle(params, ctx, attrs, starterData) {
10824
+ function buildIndirectBundle(params, ctx, attrs, starterData, interopFeeInfo) {
10542
10825
  const totalActionValue = sumActionMsgValue(params.actions);
10543
10826
  const bridgedTokenTotal = sumErc20Amounts(params.actions);
10544
10827
  const approvalMap = /* @__PURE__ */ new Map();
@@ -10557,6 +10840,7 @@ function buildIndirectBundle(params, ctx, attrs, starterData) {
10557
10840
  }
10558
10841
  }
10559
10842
  const approvals = Array.from(approvalMap.values());
10843
+ if (interopFeeInfo.approval) approvals.push(interopFeeInfo.approval);
10560
10844
  const starters = params.actions.map((action, index) => {
10561
10845
  const callAttributes = attrs.callAttributes[index] ?? [];
10562
10846
  if (starterData[index]?.assetRouterPayload) {
@@ -10580,6 +10864,7 @@ function buildIndirectBundle(params, ctx, attrs, starterData) {
10580
10864
  starters,
10581
10865
  bundleAttributes: attrs.bundleAttributes,
10582
10866
  approvals,
10867
+ interopFee: interopFeeInfo.fee,
10583
10868
  quoteExtras: {
10584
10869
  totalActionValue,
10585
10870
  bridgedTokenTotal
@@ -10626,6 +10911,29 @@ function buildEnsureTokenSteps(erc20Tokens, ctx) {
10626
10911
  }
10627
10912
  }));
10628
10913
  }
10914
+ async function buildApproveSteps(approvals, ctx) {
10915
+ const steps = [];
10916
+ for (const approval of approvals) {
10917
+ const erc20 = new ethers.Contract(approval.token, IERC20_default, ctx.client.l2);
10918
+ const currentAllowance = await erc20.allowance(ctx.sender, approval.spender);
10919
+ if (currentAllowance < approval.amount) {
10920
+ steps.push({
10921
+ key: `approve:${approval.token}:${approval.spender}`,
10922
+ kind: "approve",
10923
+ description: `Approve ${approval.spender} to spend ${approval.amount} of ${approval.token}`,
10924
+ tx: {
10925
+ to: approval.token,
10926
+ data: erc20.interface.encodeFunctionData("approve", [
10927
+ approval.spender,
10928
+ approval.amount
10929
+ ]),
10930
+ ...ctx.gasOverrides
10931
+ }
10932
+ });
10933
+ }
10934
+ }
10935
+ return steps;
10936
+ }
10629
10937
  async function resolveErc20AssetIds(erc20Tokens, ctx) {
10630
10938
  const assetIds = /* @__PURE__ */ new Map();
10631
10939
  if (erc20Tokens.length === 0) return assetIds;
@@ -10679,6 +10987,44 @@ async function getStarterData(params, ctx, erc20AssetIds) {
10679
10987
  }
10680
10988
  return starterData;
10681
10989
  }
10990
+ var { wrap: wrap3 } = createErrorHandlers("interop");
10991
+ async function buildFeeInfo(params, ctx, numStarters) {
10992
+ const useFixed = params.fee?.useFixed ?? false;
10993
+ const interopCenter = new ethers.Contract(ctx.interopCenter, IInteropCenter_default, ctx.client.l2);
10994
+ if (useFixed) {
10995
+ const zkFeePerCall = await wrap3(
10996
+ OP_INTEROP.svc.fees.zkInteropFee,
10997
+ () => interopCenter.ZK_INTEROP_FEE(),
10998
+ { message: "Failed to fetch ZK interop fee from InteropCenter." }
10999
+ );
11000
+ const zkFeeTotal = zkFeePerCall * BigInt(numStarters);
11001
+ const zkTokenAddress = await wrap3(
11002
+ OP_INTEROP.svc.fees.zkToken,
11003
+ () => interopCenter.zkToken(),
11004
+ { message: "Failed to fetch ZK token address from InteropCenter." }
11005
+ );
11006
+ const approval = {
11007
+ token: zkTokenAddress,
11008
+ spender: ctx.interopCenter,
11009
+ amount: zkFeeTotal
11010
+ };
11011
+ return {
11012
+ approval,
11013
+ fee: { token: zkTokenAddress, amount: zkFeeTotal }
11014
+ };
11015
+ } else {
11016
+ const protocolFeePerCall = await wrap3(
11017
+ OP_INTEROP.svc.fees.protocolFee,
11018
+ () => interopCenter.interopProtocolFee(),
11019
+ { message: "Failed to fetch interop protocol fee from InteropCenter." }
11020
+ );
11021
+ const totalFee = protocolFeePerCall * BigInt(numStarters);
11022
+ return {
11023
+ approval: null,
11024
+ fee: { token: ctx.baseTokens.src, amount: totalFee }
11025
+ };
11026
+ }
11027
+ }
10682
11028
 
10683
11029
  // src/adapters/ethers/resources/interop/routes/indirect.ts
10684
11030
  function routeIndirect() {
@@ -10694,7 +11040,10 @@ function routeIndirect() {
10694
11040
  async build(params, ctx) {
10695
11041
  const steps = [];
10696
11042
  const erc20Tokens = getErc20Tokens(params);
10697
- const erc20AssetIds = await resolveErc20AssetIds(erc20Tokens, ctx);
11043
+ const [erc20AssetIds, feeInfo] = await Promise.all([
11044
+ resolveErc20AssetIds(erc20Tokens, ctx),
11045
+ buildFeeInfo(params, ctx, params.actions.length)
11046
+ ]);
10698
11047
  const attributes = getInteropAttributes(params, ctx);
10699
11048
  const starterData = await getStarterData(params, ctx, erc20AssetIds);
10700
11049
  const bundle = buildIndirectBundle(
@@ -10707,32 +11056,11 @@ function routeIndirect() {
10707
11056
  codec: interopCodec
10708
11057
  },
10709
11058
  attributes,
10710
- starterData
11059
+ starterData,
11060
+ feeInfo
10711
11061
  );
10712
11062
  steps.push(...buildEnsureTokenSteps(erc20Tokens, ctx));
10713
- for (const approval of bundle.approvals) {
10714
- const erc20 = new ethers.Contract(approval.token, IERC20_default, ctx.client.l2);
10715
- const currentAllowance = await erc20.allowance(
10716
- ctx.sender,
10717
- ctx.l2NativeTokenVault
10718
- );
10719
- if (currentAllowance < approval.amount) {
10720
- const approveData = erc20.interface.encodeFunctionData("approve", [
10721
- ctx.l2NativeTokenVault,
10722
- approval.amount
10723
- ]);
10724
- steps.push({
10725
- key: `approve:${approval.token}:${ctx.l2NativeTokenVault}`,
10726
- kind: "approve",
10727
- description: `Approve ${ctx.l2NativeTokenVault} to spend ${approval.amount} of ${approval.token}`,
10728
- tx: {
10729
- to: approval.token,
10730
- data: approveData,
10731
- ...ctx.gasOverrides
10732
- }
10733
- });
10734
- }
10735
- }
11063
+ steps.push(...await buildApproveSteps(bundle.approvals, ctx));
10736
11064
  const data = ctx.ifaces.interopCenter.encodeFunctionData("sendBundle", [
10737
11065
  bundle.dstChain,
10738
11066
  bundle.starters,
@@ -10745,14 +11073,15 @@ function routeIndirect() {
10745
11073
  tx: {
10746
11074
  to: ctx.interopCenter,
10747
11075
  data,
10748
- value: bundle.quoteExtras.totalActionValue,
11076
+ value: bundle.quoteExtras.totalActionValue + feeInfo.fee.amount,
10749
11077
  ...ctx.gasOverrides
10750
11078
  }
10751
11079
  });
10752
11080
  return {
10753
11081
  steps,
10754
11082
  approvals: bundle.approvals,
10755
- quoteExtras: bundle.quoteExtras
11083
+ quoteExtras: bundle.quoteExtras,
11084
+ interopFee: feeInfo.fee
10756
11085
  };
10757
11086
  }
10758
11087
  };
@@ -10769,10 +11098,10 @@ function routeDirect() {
10769
11098
  l2AssetRouter: ctx.l2AssetRouter,
10770
11099
  l2NativeTokenVault: ctx.l2NativeTokenVault});
10771
11100
  },
10772
- // eslint-disable-next-line @typescript-eslint/require-await
10773
11101
  async build(params, ctx) {
10774
11102
  const steps = [];
10775
11103
  const attrs = getInteropAttributes(params, ctx);
11104
+ const feeInfo = await buildFeeInfo(params, ctx, params.actions.length);
10776
11105
  const built = buildDirectBundle(
10777
11106
  params,
10778
11107
  {
@@ -10782,8 +11111,10 @@ function routeDirect() {
10782
11111
  l2NativeTokenVault: ctx.l2NativeTokenVault,
10783
11112
  codec: interopCodec
10784
11113
  },
10785
- attrs
11114
+ attrs,
11115
+ feeInfo
10786
11116
  );
11117
+ steps.push(...await buildApproveSteps(built.approvals, ctx));
10787
11118
  const data = ctx.ifaces.interopCenter.encodeFunctionData("sendBundle", [
10788
11119
  built.dstChain,
10789
11120
  built.starters,
@@ -10793,43 +11124,47 @@ function routeDirect() {
10793
11124
  key: "sendBundle",
10794
11125
  kind: "interop.center",
10795
11126
  description: `Send interop bundle (direct route; ${params.actions.length} actions)`,
10796
- // In direct route, msg.value equals the total forwarded value across
10797
- // all calls (sendNative.amount + call.value).
11127
+ // msg.value = forwarded action value + protocol fee.
10798
11128
  tx: {
10799
11129
  to: ctx.interopCenter,
10800
11130
  data,
10801
- value: built.quoteExtras.totalActionValue,
11131
+ value: built.quoteExtras.totalActionValue + feeInfo.fee.amount,
10802
11132
  ...ctx.gasOverrides
10803
11133
  }
10804
11134
  });
10805
11135
  return {
10806
11136
  steps,
10807
11137
  approvals: built.approvals,
10808
- quoteExtras: built.quoteExtras
11138
+ quoteExtras: built.quoteExtras,
11139
+ interopFee: feeInfo.fee
10809
11140
  };
10810
11141
  }
10811
11142
  };
10812
11143
  }
11144
+
11145
+ // src/core/resources/interop/protocol.ts
10813
11146
  var MIN_INTEROP_PROTOCOL = 31;
11147
+ function assertProtocolVersion(chainId, protocolVersion) {
11148
+ if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
11149
+ throw createError("VALIDATION", {
11150
+ resource: "interop",
11151
+ operation: OP_INTEROP.context.protocolVersion,
11152
+ message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
11153
+ context: {
11154
+ chainId,
11155
+ requiredMinor: MIN_INTEROP_PROTOCOL,
11156
+ semver: protocolVersion
11157
+ }
11158
+ });
11159
+ }
11160
+ }
11161
+
11162
+ // src/adapters/ethers/resources/interop/context.ts
10814
11163
  async function assertInteropProtocolVersion(client, srcChainId, dstChainId) {
10815
11164
  const [srcProtocolVersion, dstProtocolVersion] = await Promise.all([
10816
11165
  client.getProtocolVersion(srcChainId),
10817
11166
  client.getProtocolVersion(dstChainId)
10818
11167
  ]);
10819
- const assertProtocolVersion = (chainId, protocolVersion) => {
10820
- if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
10821
- throw createError("VALIDATION", {
10822
- resource: "interop",
10823
- operation: OP_INTEROP.context.protocolVersion,
10824
- message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
10825
- context: {
10826
- chainId,
10827
- requiredMinor: MIN_INTEROP_PROTOCOL,
10828
- semver: protocolVersion
10829
- }
10830
- });
10831
- }
10832
- };
10833
11168
  assertProtocolVersion(srcChainId, srcProtocolVersion);
10834
11169
  assertProtocolVersion(dstChainId, dstProtocolVersion);
10835
11170
  }
@@ -10885,7 +11220,7 @@ function getTopics() {
10885
11220
  };
10886
11221
  return { topics, centerIface };
10887
11222
  }
10888
- var { wrap: wrap3 } = createErrorHandlers("interop");
11223
+ var { wrap: wrap4 } = createErrorHandlers("interop");
10889
11224
  var DEFAULT_BLOCKS_RANGE_SIZE = 1e4;
10890
11225
  var DEFAULT_MAX_BLOCKS_BACK = 2e4;
10891
11226
  var SAFE_BLOCKS_RANGE_SIZE = 1e3;
@@ -10898,9 +11233,16 @@ function parseMaxBlockRangeLimit(error) {
10898
11233
  return Number.isInteger(limit) && limit > 0 ? limit : null;
10899
11234
  }
10900
11235
  async function getTxReceipt(provider, txHash) {
10901
- const receipt = await wrap3(
11236
+ const receipt = await wrap4(
10902
11237
  OP_INTEROP.svc.status.sourceReceipt,
10903
- () => provider.getTransactionReceipt(txHash),
11238
+ async () => {
11239
+ try {
11240
+ return await provider.getTransactionReceipt(txHash);
11241
+ } catch (error) {
11242
+ if (isReceiptNotFound(error)) return null;
11243
+ throw error;
11244
+ }
11245
+ },
10904
11246
  {
10905
11247
  ctx: { where: "l2.getTransactionReceipt", l2SrcTxHash: txHash },
10906
11248
  message: "Failed to fetch source L2 receipt for interop tx."
@@ -10919,7 +11261,7 @@ async function getTxReceipt(provider, txHash) {
10919
11261
  async function getLogs(provider, address, topics, opts) {
10920
11262
  const maxBlocksBack = opts?.maxBlocksBack ?? DEFAULT_MAX_BLOCKS_BACK;
10921
11263
  const initialChunkSize = opts?.logChunkSize ?? DEFAULT_BLOCKS_RANGE_SIZE;
10922
- return await wrap3(
11264
+ return await wrap4(
10923
11265
  OP_INTEROP.svc.status.dstLogs,
10924
11266
  async () => {
10925
11267
  const currentBlock = await provider.getBlockNumber();
@@ -10966,7 +11308,7 @@ async function getLogs(provider, address, topics, opts) {
10966
11308
  );
10967
11309
  }
10968
11310
  async function getInteropRoot(provider, rootChainId, batchNumber) {
10969
- return await wrap3(
11311
+ return await wrap4(
10970
11312
  OP_INTEROP.svc.status.getRoot,
10971
11313
  async () => {
10972
11314
  const rootStorage = new ethers.Contract(
@@ -10984,7 +11326,7 @@ async function getInteropRoot(provider, rootChainId, batchNumber) {
10984
11326
  }
10985
11327
 
10986
11328
  // src/adapters/ethers/resources/interop/services/finalization/bundle.ts
10987
- var { wrap: wrap4 } = createErrorHandlers("interop");
11329
+ var { wrap: wrap5 } = createErrorHandlers("interop");
10988
11330
  async function getBundleStatus(client, dstProvider, topics, bundleHash, opts) {
10989
11331
  const { interopHandler } = await client.ensureAddresses();
10990
11332
  const bundleLogs = await getLogs(dstProvider, interopHandler, [null, bundleHash], opts);
@@ -11016,7 +11358,7 @@ async function executeBundle(client, dstProvider, info, opts) {
11016
11358
  context: { bundleHash }
11017
11359
  });
11018
11360
  }
11019
- const signer = await wrap4(OP_INTEROP.exec.sendStep, () => client.signerFor(dstProvider), {
11361
+ const signer = await wrap5(OP_INTEROP.exec.sendStep, () => client.signerFor(dstProvider), {
11020
11362
  message: "Failed to resolve destination signer."
11021
11363
  });
11022
11364
  const { interopHandler } = await client.ensureAddresses();
@@ -11178,11 +11520,6 @@ function getBundleEncodedData(messageData) {
11178
11520
  return `0x${messageData.slice(4)}`;
11179
11521
  }
11180
11522
  function buildFinalizationInfo(ids, bundleInfo, proof, messageData) {
11181
- const expectedRoot = {
11182
- rootChainId: bundleInfo.sourceChainId,
11183
- batchNumber: proof.batchNumber,
11184
- expectedRoot: proof.root
11185
- };
11186
11523
  const messageProof = {
11187
11524
  chainId: bundleInfo.sourceChainId,
11188
11525
  l1BatchNumber: proof.batchNumber,
@@ -11198,7 +11535,6 @@ function buildFinalizationInfo(ids, bundleInfo, proof, messageData) {
11198
11535
  l2SrcTxHash: ids.l2SrcTxHash,
11199
11536
  bundleHash: bundleInfo.bundleHash,
11200
11537
  dstChainId: bundleInfo.dstChainId,
11201
- expectedRoot,
11202
11538
  proof: messageProof,
11203
11539
  encodedData: getBundleEncodedData(messageData)
11204
11540
  };
@@ -11221,7 +11557,7 @@ function decodeL1MessageData(log) {
11221
11557
  }
11222
11558
 
11223
11559
  // src/adapters/ethers/resources/interop/services/finalization/polling.ts
11224
- var { wrap: wrap5 } = createErrorHandlers("interop");
11560
+ var { wrap: wrap6 } = createErrorHandlers("interop");
11225
11561
  function isProofNotReadyError(error) {
11226
11562
  return isZKsyncError(error, {
11227
11563
  operation: "zksrpc.getL2ToL1LogProof",
@@ -11258,30 +11594,26 @@ async function waitForProof(client, l2SrcTxHash, logIndex, blockNumber, pollMs,
11258
11594
  });
11259
11595
  }
11260
11596
  try {
11261
- return await client.zks.getL2ToL1LogProof(l2SrcTxHash, logIndex);
11597
+ return await client.zks.getL2ToL1LogProof(l2SrcTxHash, logIndex, "messageRoot" /* MessageRoot */);
11262
11598
  } catch (error) {
11263
11599
  if (!isProofNotReadyError(error)) throw error;
11264
11600
  }
11265
11601
  await sleep(pollMs);
11266
11602
  }
11267
11603
  }
11268
- async function waitForRoot(provider, expectedRoot, pollMs, deadline) {
11604
+ async function waitForRoot(provider, chainId, batchNumber, pollMs, deadline) {
11269
11605
  while (true) {
11270
11606
  if (Date.now() > deadline) {
11271
11607
  throw createError("TIMEOUT", {
11272
11608
  resource: "interop",
11273
11609
  operation: OP_INTEROP.svc.wait.timeout,
11274
11610
  message: "Timed out waiting for interop root to become available.",
11275
- context: { expectedRoot }
11611
+ context: { chainId, batchNumber }
11276
11612
  });
11277
11613
  }
11278
11614
  let interopRoot = null;
11279
11615
  try {
11280
- const root = await getInteropRoot(
11281
- provider,
11282
- expectedRoot.rootChainId,
11283
- expectedRoot.batchNumber
11284
- );
11616
+ const root = await getInteropRoot(provider, chainId, batchNumber);
11285
11617
  if (root !== ZERO_HASH) {
11286
11618
  interopRoot = root;
11287
11619
  }
@@ -11290,18 +11622,7 @@ async function waitForRoot(provider, expectedRoot, pollMs, deadline) {
11290
11622
  interopRoot = null;
11291
11623
  }
11292
11624
  if (interopRoot) {
11293
- if (interopRoot.toLowerCase() === expectedRoot.expectedRoot.toLowerCase()) {
11294
- return;
11295
- }
11296
- throw createError("STATE", {
11297
- resource: "interop",
11298
- operation: OP_INTEROP.wait,
11299
- message: "Interop root mismatch.",
11300
- context: {
11301
- expected: expectedRoot.expectedRoot,
11302
- got: interopRoot
11303
- }
11304
- });
11625
+ return interopRoot;
11305
11626
  }
11306
11627
  await sleep(pollMs);
11307
11628
  }
@@ -11316,7 +11637,7 @@ async function waitForTxReceipt(client, txHash, pollMs, deadline) {
11316
11637
  context: { txHash }
11317
11638
  });
11318
11639
  }
11319
- const receipt = await wrap5(
11640
+ const receipt = await wrap6(
11320
11641
  OP_INTEROP.svc.status.sourceReceipt,
11321
11642
  () => client.zks.getReceiptWithL2ToL1(txHash),
11322
11643
  {
@@ -11330,7 +11651,7 @@ async function waitForTxReceipt(client, txHash, pollMs, deadline) {
11330
11651
  await sleep(pollMs);
11331
11652
  }
11332
11653
  }
11333
- async function waitForFinalization(client, dstProvider, input, opts) {
11654
+ async function waitForFinalization(client, dstProvider, gwProvider, input, opts) {
11334
11655
  const { topics, centerIface } = getTopics();
11335
11656
  const pollMs = opts?.pollMs ?? DEFAULT_POLL_MS;
11336
11657
  const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
@@ -11379,7 +11700,16 @@ async function waitForFinalization(client, dstProvider, input, opts) {
11379
11700
  proof,
11380
11701
  bundleInfo.l1MessageData
11381
11702
  );
11382
- await waitForRoot(dstProvider, finalizationInfo.expectedRoot, pollMs, deadline);
11703
+ if (proof.gatewayBlockNumber == null) {
11704
+ throw createError("STATE", {
11705
+ resource: "interop",
11706
+ operation: OP_INTEROP.svc.wait.timeout,
11707
+ message: "Proof missing gatewayBlockNumber required for interop finalization.",
11708
+ context: { l2SrcTxHash: ids.l2SrcTxHash }
11709
+ });
11710
+ }
11711
+ const { chainId: gwChainId } = await gwProvider.getNetwork();
11712
+ await waitForRoot(dstProvider, gwChainId, proof.gatewayBlockNumber, pollMs, deadline);
11383
11713
  return finalizationInfo;
11384
11714
  }
11385
11715
 
@@ -11425,8 +11755,8 @@ function createInteropFinalizationServices(client) {
11425
11755
  status(dstProvider, input, opts) {
11426
11756
  return getStatus(client, dstProvider, input, opts);
11427
11757
  },
11428
- wait(dstProvider, input, opts) {
11429
- return waitForFinalization(client, dstProvider, input, opts);
11758
+ wait(dstProvider, gwProvider, input, opts) {
11759
+ return waitForFinalization(client, dstProvider, gwProvider, input, opts);
11430
11760
  },
11431
11761
  async finalize(dstProvider, info, opts) {
11432
11762
  const execResult = await executeBundle(client, dstProvider, info, opts);
@@ -11438,24 +11768,56 @@ function createInteropFinalizationServices(client) {
11438
11768
  }
11439
11769
  };
11440
11770
  }
11441
- function resolveDstProvider(dstChain) {
11442
- return typeof dstChain === "string" ? new ethers.JsonRpcProvider(dstChain) : dstChain;
11771
+ function resolveChainRef(ref) {
11772
+ return typeof ref === "string" ? new ethers.JsonRpcProvider(ref) : ref;
11443
11773
  }
11444
- function resolveWaitableInput(waitableInput) {
11445
- const input = waitableInput;
11446
- return {
11447
- dstProvider: resolveDstProvider(waitableInput.dstChain),
11448
- waitable: input.waitable ? input.waitable : waitableInput
11449
- };
11774
+
11775
+ // src/adapters/ethers/resources/interop/services/gas.ts
11776
+ async function quoteStepsL2Fee(steps, ctx) {
11777
+ if (steps.length === 0) return 0n;
11778
+ const estimator = ethersToGasEstimator(ctx.client.l2);
11779
+ let maxFeePerGas;
11780
+ try {
11781
+ const fees = await estimator.estimateFeesPerGas();
11782
+ maxFeePerGas = fees.maxFeePerGas ?? fees.gasPrice ?? await estimator.getGasPrice();
11783
+ } catch {
11784
+ return void 0;
11785
+ }
11786
+ let total = 0n;
11787
+ for (const step of steps) {
11788
+ try {
11789
+ const coreTx = toCoreTx({ ...step.tx, from: ctx.sender });
11790
+ const est = await estimator.estimateGas(coreTx);
11791
+ const buffered = BigInt(est) * (100n + BUFFER) / 100n;
11792
+ total += buffered * maxFeePerGas;
11793
+ } catch {
11794
+ return void 0;
11795
+ }
11796
+ }
11797
+ return total;
11450
11798
  }
11451
11799
 
11452
11800
  // src/adapters/ethers/resources/interop/index.ts
11453
- var { wrap: wrap6, toResult: toResult2 } = createErrorHandlers("interop");
11801
+ var { wrap: wrap7, toResult: toResult2 } = createErrorHandlers("interop");
11454
11802
  var ROUTES3 = {
11455
11803
  direct: routeDirect(),
11456
11804
  indirect: routeIndirect()
11457
11805
  };
11458
- function createInteropResource(client, tokens, contracts, attributes) {
11806
+ function createInteropResource(client, config, tokens, contracts, attributes) {
11807
+ let gwProviderCache;
11808
+ function requireConfig() {
11809
+ if (!config)
11810
+ throw createError("STATE", {
11811
+ resource: "interop",
11812
+ operation: "interop.init",
11813
+ message: "Interop is not configured. Pass gwChain in createEthersSdk options."
11814
+ });
11815
+ return config;
11816
+ }
11817
+ function getGwProvider() {
11818
+ if (!gwProviderCache) gwProviderCache = resolveChainRef(requireConfig().gwChain);
11819
+ return gwProviderCache;
11820
+ }
11459
11821
  const svc = createInteropFinalizationServices(client);
11460
11822
  const tokensResource = tokens ?? createTokensResource(client);
11461
11823
  const contractsResource = contracts ?? createContractsResource(client);
@@ -11479,11 +11841,11 @@ function createInteropResource(client, tokens, contracts, attributes) {
11479
11841
  baseTokenDst: ctx.baseTokens.dst
11480
11842
  }
11481
11843
  });
11482
- await wrap6(OP_INTEROP.routes[route].preflight, () => ROUTES3[route].preflight?.(params, ctx), {
11844
+ await wrap7(OP_INTEROP.routes[route].preflight, () => ROUTES3[route].preflight?.(params, ctx), {
11483
11845
  message: "Interop preflight failed.",
11484
11846
  ctx: { where: `routes.${route}.preflight` }
11485
11847
  });
11486
- const { steps, approvals, quoteExtras } = await wrap6(
11848
+ const { steps, approvals, quoteExtras, interopFee } = await wrap7(
11487
11849
  OP_INTEROP.routes[route].build,
11488
11850
  () => ROUTES3[route].build(params, ctx),
11489
11851
  {
@@ -11491,11 +11853,14 @@ function createInteropResource(client, tokens, contracts, attributes) {
11491
11853
  ctx: { where: `routes.${route}.build` }
11492
11854
  }
11493
11855
  );
11856
+ const l2Fee = await quoteStepsL2Fee(steps, ctx).catch(() => void 0);
11494
11857
  const summary = {
11495
11858
  route,
11496
11859
  approvalsNeeded: approvals,
11497
11860
  totalActionValue: quoteExtras.totalActionValue,
11498
- bridgedTokenTotal: quoteExtras.bridgedTokenTotal
11861
+ bridgedTokenTotal: quoteExtras.bridgedTokenTotal,
11862
+ interopFee,
11863
+ l2Fee
11499
11864
  };
11500
11865
  return { plan: { route, summary, steps }, ctx };
11501
11866
  }
@@ -11503,20 +11868,23 @@ function createInteropResource(client, tokens, contracts, attributes) {
11503
11868
  const { plan } = await buildPlanWithCtx(dstProvider, params);
11504
11869
  return plan;
11505
11870
  }
11506
- const quote = (params) => wrap6(OP_INTEROP.quote, async () => {
11507
- const plan = await buildPlan(resolveDstProvider(params.dstChain), params);
11871
+ const quote = (dstChain, params) => wrap7(OP_INTEROP.quote, async () => {
11872
+ const plan = await buildPlan(resolveChainRef(dstChain), params);
11508
11873
  return plan.summary;
11509
11874
  });
11510
- const tryQuote = (params) => toResult2(OP_INTEROP.tryQuote, () => quote(params));
11511
- const prepare = (params) => wrap6(OP_INTEROP.prepare, () => buildPlan(resolveDstProvider(params.dstChain), params), {
11875
+ const tryQuote = (dstChain, params) => toResult2(OP_INTEROP.tryQuote, () => quote(dstChain, params));
11876
+ const prepare = (dstChain, params) => wrap7(OP_INTEROP.prepare, () => buildPlan(resolveChainRef(dstChain), params), {
11512
11877
  message: "Internal error while preparing an interop plan.",
11513
11878
  ctx: { where: "interop.prepare" }
11514
11879
  });
11515
- const tryPrepare = (params) => toResult2(OP_INTEROP.tryPrepare, () => prepare(params));
11516
- const create = (params) => wrap6(
11880
+ const tryPrepare = (dstChain, params) => toResult2(
11881
+ OP_INTEROP.tryPrepare,
11882
+ () => prepare(dstChain, params)
11883
+ );
11884
+ const create = (dstChain, params) => wrap7(
11517
11885
  OP_INTEROP.create,
11518
11886
  async () => {
11519
- const { plan, ctx } = await buildPlanWithCtx(resolveDstProvider(params.dstChain), params);
11887
+ const { plan, ctx } = await buildPlanWithCtx(resolveChainRef(dstChain), params);
11520
11888
  const signer = ctx.client.signerFor(ctx.client.l2);
11521
11889
  const srcProvider = ctx.client.l2;
11522
11890
  const from = await signer.getAddress();
@@ -11578,7 +11946,6 @@ function createInteropResource(client, tokens, contracts, attributes) {
11578
11946
  const last = Object.values(stepHashes).pop();
11579
11947
  return {
11580
11948
  kind: "interop",
11581
- dstChain: params.dstChain,
11582
11949
  stepHashes,
11583
11950
  plan,
11584
11951
  l2SrcTxHash: last ?? "0x"
@@ -11589,46 +11956,27 @@ function createInteropResource(client, tokens, contracts, attributes) {
11589
11956
  ctx: { where: "interop.create" }
11590
11957
  }
11591
11958
  );
11592
- const tryCreate = (params) => toResult2(OP_INTEROP.tryCreate, () => create(params));
11593
- const status = (h, opts) => {
11594
- const { dstProvider, waitable } = resolveWaitableInput(h);
11595
- return wrap6(OP_INTEROP.status, () => svc.status(dstProvider, waitable, opts), {
11596
- message: "Internal error while checking interop status.",
11597
- ctx: { where: "interop.status" }
11598
- });
11599
- };
11600
- const wait = (h, opts) => {
11601
- const { dstProvider, waitable } = resolveWaitableInput(h);
11602
- return wrap6(
11603
- OP_INTEROP.wait,
11604
- async () => {
11605
- const info = await svc.wait(dstProvider, waitable, opts);
11606
- return { ...info, dstChain: h.dstChain };
11607
- },
11608
- {
11609
- message: "Internal error while waiting for interop finalization.",
11610
- ctx: { where: "interop.wait" }
11611
- }
11612
- );
11613
- };
11614
- const tryWait = (h, opts) => toResult2(OP_INTEROP.tryWait, () => wait(h, opts));
11615
- const finalize = (h, opts) => wrap6(
11959
+ const tryCreate = (dstChain, params) => toResult2(
11960
+ OP_INTEROP.tryCreate,
11961
+ () => create(dstChain, params)
11962
+ );
11963
+ const status = (dstChain, h, opts) => wrap7(OP_INTEROP.status, () => svc.status(resolveChainRef(dstChain), h, opts), {
11964
+ message: "Internal error while checking interop status.",
11965
+ ctx: { where: "interop.status" }
11966
+ });
11967
+ const wait = (dstChain, h, opts) => wrap7(OP_INTEROP.wait, () => svc.wait(resolveChainRef(dstChain), getGwProvider(), h, opts), {
11968
+ message: "Internal error while waiting for interop finalization.",
11969
+ ctx: { where: "interop.wait" }
11970
+ });
11971
+ const tryWait = (dstChain, h, opts) => toResult2(OP_INTEROP.tryWait, () => wait(dstChain, h, opts));
11972
+ const finalize = (dstChain, h, opts) => wrap7(
11616
11973
  OP_INTEROP.finalize,
11617
11974
  async () => {
11975
+ const dstProvider = resolveChainRef(dstChain);
11618
11976
  if (isInteropFinalizationInfo(h)) {
11619
- if (h.dstChain == null) {
11620
- throw createError("STATE", {
11621
- resource: "interop",
11622
- operation: OP_INTEROP.finalize,
11623
- message: "Missing dstChain in interop finalization info.",
11624
- context: { input: h }
11625
- });
11626
- }
11627
- const dstProvider2 = resolveDstProvider(h.dstChain);
11628
- return svc.finalize(dstProvider2, h, opts);
11977
+ return svc.finalize(dstProvider, h, opts);
11629
11978
  }
11630
- const { dstProvider, waitable } = resolveWaitableInput(h);
11631
- const info = await svc.wait(dstProvider, waitable);
11979
+ const info = await svc.wait(dstProvider, getGwProvider(), h);
11632
11980
  return svc.finalize(dstProvider, info, opts);
11633
11981
  },
11634
11982
  {
@@ -11636,7 +11984,7 @@ function createInteropResource(client, tokens, contracts, attributes) {
11636
11984
  ctx: { where: "interop.finalize" }
11637
11985
  }
11638
11986
  );
11639
- const tryFinalize = (h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(h, opts));
11987
+ const tryFinalize = (dstChain, h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(dstChain, h, opts));
11640
11988
  return {
11641
11989
  quote,
11642
11990
  tryQuote,
@@ -11653,10 +12001,10 @@ function createInteropResource(client, tokens, contracts, attributes) {
11653
12001
  }
11654
12002
 
11655
12003
  // src/adapters/ethers/sdk.ts
11656
- function createEthersSdk(client) {
12004
+ function createEthersSdk(client, options) {
11657
12005
  const tokens = createTokensResource(client);
11658
12006
  const contracts = createContractsResource(client);
11659
- const interop = createInteropResource(client);
12007
+ const interop = createInteropResource(client, options?.interop, tokens, contracts);
11660
12008
  return {
11661
12009
  deposits: createDepositsResource(client, tokens, contracts),
11662
12010
  withdrawals: createWithdrawalsResource(client, tokens, contracts),