@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,10 +1,9 @@
1
- export { createEthersClient as createClient, createEthersClient } from '../../chunk-7CAVFIMW.js';
2
- export { buildDirectRequestStruct, createDepositsResource, createEthersSdk, createFinalizationServices, createInteropFinalizationServices, createInteropResource, createTokensResource, createWithdrawalsResource, encodeNativeTokenVaultTransferData, encodeSecondBridgeArgs, encodeSecondBridgeDataV1, encodeSecondBridgeErc20Args, encodeSecondBridgeEthArgs, getL2TransactionHashFromLogs } from '../../chunk-XKRNLFET.js';
3
- export { classifyReadinessFromRevert, createErrorHandlers, decodeRevert, registerErrorAbi, toZKsyncError } from '../../chunk-5RRJDPAJ.js';
4
- import '../../chunk-EOBXYHTZ.js';
1
+ export { createEthersClient as createClient, createEthersClient } from '../../chunk-24TE2NNJ.js';
2
+ export { buildDirectRequestStruct, createDepositsResource, createEthersSdk, createFinalizationServices, createInteropFinalizationServices, createInteropResource, createTokensResource, createWithdrawalsResource, encodeNativeTokenVaultTransferData, encodeSecondBridgeArgs, encodeSecondBridgeDataV1, encodeSecondBridgeErc20Args, encodeSecondBridgeEthArgs, getL2TransactionHashFromLogs } from '../../chunk-5HG2DUYW.js';
3
+ export { classifyReadinessFromRevert, createErrorHandlers, decodeRevert, registerErrorAbi, toZKsyncError } from '../../chunk-NJK325XV.js';
4
+ import '../../chunk-NLUCYVMX.js';
5
5
  import '../../chunk-3HHUZXSV.js';
6
6
  import '../../chunk-BWKWWLY4.js';
7
- import '../../chunk-HP3EWKJL.js';
8
- import '../../chunk-DYJKK5FW.js';
9
- import '../../chunk-JY62QO3W.js';
7
+ import '../../chunk-JSBMIT4S.js';
8
+ import '../../chunk-UEKFQAOS.js';
10
9
  import '../../chunk-MT4X5FEO.js';
@@ -1,4 +1,5 @@
1
1
  import type { EthersClient } from '../../client';
2
+ import type { Hex } from '../../../../core/types/primitives';
2
3
  import type { AttributesResource } from '../../../../core/resources/interop/attributes/resource';
3
4
  import type { InteropRoute, InteropPlan, InteropQuote, InteropStatus, InteropFinalizationResult, InteropParams, InteropHandle, InteropWaitable, InteropFinalizationInfo } from '../../../../core/types/flows/interop';
4
5
  import type { ContractsResource } from '../contracts';
@@ -6,7 +7,7 @@ import type { TokensResource } from '../../../../core/types/flows/token';
6
7
  import type { InteropRouteStrategy } from './routes/types';
7
8
  import type { TransactionRequest } from 'ethers';
8
9
  import { createInteropFinalizationServices, type InteropFinalizationServices } from './services/finalization';
9
- import type { LogsQueryOptions } from './services/finalization/data-fetchers';
10
+ import { type LogsQueryOptions } from './services/finalization/data-fetchers';
10
11
  import type { ChainRef, InteropConfig } from './types';
11
12
  export declare const ROUTES: Record<InteropRoute, InteropRouteStrategy>;
12
13
  export interface InteropResource {
@@ -57,6 +58,8 @@ export interface InteropResource {
57
58
  ok: false;
58
59
  error: unknown;
59
60
  }>;
61
+ getInteropRoot(dstChain: ChainRef, rootChainId: bigint, batchNumber: bigint): Promise<Hex>;
62
+ verifyBundle(dstChain: ChainRef, h: InteropWaitable | InteropFinalizationInfo): Promise<InteropFinalizationResult>;
60
63
  }
61
64
  export declare function createInteropResource(client: EthersClient, config?: InteropConfig, tokens?: TokensResource, contracts?: ContractsResource, attributes?: AttributesResource): InteropResource;
62
65
  export { createInteropFinalizationServices };
@@ -13,3 +13,7 @@ export declare function executeBundle(client: EthersClient, dstProvider: Abstrac
13
13
  hash: Hex;
14
14
  wait: () => Promise<TransactionReceipt>;
15
15
  }>;
16
+ export declare function verifyBundle(client: EthersClient, dstProvider: AbstractProvider, info: InteropFinalizationInfo): Promise<{
17
+ hash: Hex;
18
+ wait: () => Promise<TransactionReceipt>;
19
+ }>;
@@ -0,0 +1,12 @@
1
+ import type { TransactionRequest } from 'ethers';
2
+ import type { BuildCtx } from '../context';
3
+ /**
4
+ * Estimates the combined L2 gas cost for all steps in an interop plan.
5
+ *
6
+ * Fetches gas price once, then estimates gas for each step using ctx.sender as the
7
+ * from address. Applies the standard buffer and sums gasLimit × maxFeePerGas across
8
+ * all steps. Returns undefined if estimation fails for any step.
9
+ */
10
+ export declare function quoteStepsL2Fee(steps: Array<{
11
+ tx: TransactionRequest;
12
+ }>, ctx: BuildCtx): Promise<bigint | undefined>;
@@ -377,6 +377,7 @@ var OP_INTEROP = {
377
377
  tryWait: "interop.tryWait",
378
378
  finalize: "interop.finalize",
379
379
  tryFinalize: "interop.tryFinalize",
380
+ verify: "interop.verify",
380
381
  context: {
381
382
  chainTypeManager: "interop.chainTypeManager",
382
383
  protocolVersion: "interop.protocolVersion"
@@ -5930,7 +5931,33 @@ function buildDirectRequestStruct(args) {
5930
5931
  };
5931
5932
  }
5932
5933
 
5934
+ // src/core/resources/deposits/chains.ts
5935
+ var ERAVM_CHAIN_IDS = /* @__PURE__ */ new Set([324n, 2741n, 11124n, 300n]);
5936
+ function isEraVmChain(chainIdL2) {
5937
+ return ERAVM_CHAIN_IDS.has(chainIdL2);
5938
+ }
5939
+
5933
5940
  // src/core/resources/deposits/gas.ts
5941
+ var CREATE_REESTIMATE_BUFFER = 15n;
5942
+ var maxBigInt = (a, b) => a > b ? a : b;
5943
+ function applyGasBuffer(gasLimit, bufferPct = BUFFER) {
5944
+ return gasLimit * (100n + bufferPct) / 100n;
5945
+ }
5946
+ function resolveCreateDepositL1GasLimit(input) {
5947
+ const { chainIdL2, stepKey, preparedGasLimit, estimatedGasLimit } = input;
5948
+ if (estimatedGasLimit == null) {
5949
+ return preparedGasLimit;
5950
+ }
5951
+ const isEraVmBridgeStep = isEraVmChain(chainIdL2) && stepKey.startsWith("bridgehub:");
5952
+ const reestimatedGasLimit = applyGasBuffer(
5953
+ estimatedGasLimit,
5954
+ isEraVmBridgeStep ? BUFFER : CREATE_REESTIMATE_BUFFER
5955
+ );
5956
+ if (isEraVmBridgeStep && preparedGasLimit != null) {
5957
+ return maxBigInt(preparedGasLimit, reestimatedGasLimit);
5958
+ }
5959
+ return reestimatedGasLimit;
5960
+ }
5934
5961
  function makeGasQuote(p) {
5935
5962
  const maxPriorityFeePerGas = p.maxPriorityFeePerGas ?? 0n;
5936
5963
  return {
@@ -5981,7 +6008,7 @@ async function quoteL1Gas(input) {
5981
6008
  }
5982
6009
  try {
5983
6010
  const est = await estimator.estimateGas(tx);
5984
- const buffered = BigInt(est) * (100n + BUFFER) / 100n;
6011
+ const buffered = applyGasBuffer(BigInt(est));
5985
6012
  return makeGasQuote({ gasLimit: buffered, maxFeePerGas, maxPriorityFeePerGas });
5986
6013
  } catch {
5987
6014
  if (fallbackGasLimit != null) {
@@ -6018,7 +6045,7 @@ async function quoteL2Gas(input) {
6018
6045
  const memoryOverhead = memoryBytes * TX_MEMORY_OVERHEAD_GAS;
6019
6046
  const pubdataOverhead = pubdataBytes * pp;
6020
6047
  let total = BigInt(execEstimate) + TX_OVERHEAD_GAS + memoryOverhead + pubdataOverhead;
6021
- total = total * (100n + BUFFER) / 100n;
6048
+ total = applyGasBuffer(total);
6022
6049
  return makeGasQuote({
6023
6050
  gasLimit: total,
6024
6051
  maxFeePerGas,
@@ -6455,18 +6482,19 @@ function buildFeeBreakdown(p) {
6455
6482
  // src/core/resources/deposits/priority.ts
6456
6483
  var PRIORITY_TX_ENCODING_STEP_BYTES = 544n;
6457
6484
  var DEFAULT_PRIORITY_BODY_GAS_ESTIMATE_MULTIPLIER = 6n;
6458
- var maxBigInt = (a, b) => a > b ? a : b;
6485
+ var ERAVM_PRIORITY_L2_GAS_BUFFER = 30n;
6486
+ var maxBigInt2 = (a, b) => a > b ? a : b;
6459
6487
  var ceilDiv = (a, b) => (a + b - 1n) / b;
6460
6488
  function derivePriorityTxGasBreakdown(input) {
6461
6489
  const factoryDepsCount = input.factoryDepsCount ?? 0n;
6462
- const minBodyGas = maxBigInt(
6490
+ const minBodyGas = maxBigInt2(
6463
6491
  L1_TX_INTRINSIC_L2_GAS + ceilDiv(
6464
6492
  input.encodedLength * L1_TX_DELTA_544_ENCODING_BYTES,
6465
6493
  PRIORITY_TX_ENCODING_STEP_BYTES
6466
6494
  ) + factoryDepsCount * L1_TX_DELTA_FACTORY_DEPS_L2_GAS,
6467
6495
  L1_TX_MIN_L2_GAS_BASE
6468
6496
  ) + L1_TX_INTRINSIC_PUBDATA * input.gasPerPubdata + factoryDepsCount * L1_TX_DELTA_FACTORY_DEPS_PUBDATA * input.gasPerPubdata;
6469
- const overhead = maxBigInt(TX_SLOT_OVERHEAD_L2_GAS, TX_MEMORY_OVERHEAD_GAS * input.encodedLength);
6497
+ const overhead = maxBigInt2(TX_SLOT_OVERHEAD_L2_GAS, TX_MEMORY_OVERHEAD_GAS * input.encodedLength);
6470
6498
  const derivedBodyGas = minBodyGas;
6471
6499
  return {
6472
6500
  encodedLength: input.encodedLength,
@@ -6481,8 +6509,12 @@ function derivePriorityTxGasBreakdown(input) {
6481
6509
  function derivePriorityBodyGasEstimateCap(input) {
6482
6510
  return input.minBodyGas * (input.multiplier ?? DEFAULT_PRIORITY_BODY_GAS_ESTIMATE_MULTIPLIER);
6483
6511
  }
6484
-
6485
- // src/adapters/ethers/resources/deposits/routes/priority.ts
6512
+ function applyPriorityL2GasLimitBuffer(input) {
6513
+ if (!isEraVmChain(input.chainIdL2)) {
6514
+ return input.gasLimit;
6515
+ }
6516
+ return input.gasLimit * (100n + ERAVM_PRIORITY_L2_GAS_BUFFER) / 100n;
6517
+ }
6486
6518
  var EMPTY_BYTES = "0x";
6487
6519
  var ZERO_RESERVED_WORDS = [0n, 0n, 0n, 0n];
6488
6520
  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)";
@@ -6539,7 +6571,10 @@ function routeEthDirect() {
6539
6571
  l2Calldata,
6540
6572
  gasPerPubdata: ctx.gasPerPubdata
6541
6573
  });
6542
- const quotedL2GasLimit = ctx.l2GasLimit ?? priorityFloorBreakdown.derivedL2GasLimit;
6574
+ const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
6575
+ chainIdL2: ctx.chainIdL2,
6576
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
6577
+ });
6543
6578
  const l2GasParams = await quoteL2Gas2({
6544
6579
  ctx,
6545
6580
  route: "eth-base",
@@ -6642,7 +6677,10 @@ async function getPriorityGasModel(input) {
6642
6677
  gasPerPubdata: input.ctx.gasPerPubdata
6643
6678
  });
6644
6679
  const model = {
6645
- priorityFloorGasLimit: priorityFloorBreakdown.derivedL2GasLimit
6680
+ priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
6681
+ chainIdL2: input.ctx.chainIdL2,
6682
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
6683
+ })
6646
6684
  };
6647
6685
  if (isFirstBridge || input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS2) {
6648
6686
  model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
@@ -6864,7 +6902,10 @@ async function getPriorityGasModel2(input) {
6864
6902
  gasPerPubdata: input.ctx.gasPerPubdata
6865
6903
  });
6866
6904
  const model = {
6867
- priorityFloorGasLimit: priorityFloorBreakdown.derivedL2GasLimit
6905
+ priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
6906
+ chainIdL2: input.ctx.chainIdL2,
6907
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
6908
+ })
6868
6909
  };
6869
6910
  if (input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS3) {
6870
6911
  model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
@@ -6986,7 +7027,7 @@ function routeEthNonBase() {
6986
7027
  const requestStruct = {
6987
7028
  chainId: ctx.chainIdL2,
6988
7029
  mintValue,
6989
- l2Value: p.amount,
7030
+ l2Value: 0n,
6990
7031
  l2GasLimit: l2GasParams.gasLimit,
6991
7032
  l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
6992
7033
  refundRecipient: ctx.refundRecipient,
@@ -6994,6 +7035,7 @@ function routeEthNonBase() {
6994
7035
  secondBridgeValue: p.amount,
6995
7036
  secondBridgeCalldata
6996
7037
  };
7038
+ const bridgehubValue = p.amount;
6997
7039
  const bridgehub = await ctx.contracts.bridgehub();
6998
7040
  const data = bridgehub.interface.encodeFunctionData("requestL2TransactionTwoBridges", [
6999
7041
  requestStruct
@@ -7001,8 +7043,7 @@ function routeEthNonBase() {
7001
7043
  const l1TxCandidate = {
7002
7044
  to: ctx.bridgehub,
7003
7045
  data,
7004
- value: p.amount,
7005
- // base ≠ ETH ⇒ msg.value == secondBridgeValue
7046
+ value: bridgehubValue,
7006
7047
  from: ctx.sender,
7007
7048
  ...ctx.gasOverrides
7008
7049
  };
@@ -7081,7 +7122,10 @@ function routeErc20Base() {
7081
7122
  l2Calldata,
7082
7123
  gasPerPubdata: ctx.gasPerPubdata
7083
7124
  });
7084
- const quotedL2GasLimit = ctx.l2GasLimit ?? priorityFloorBreakdown.derivedL2GasLimit;
7125
+ const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
7126
+ chainIdL2: ctx.chainIdL2,
7127
+ gasLimit: priorityFloorBreakdown.derivedL2GasLimit
7128
+ });
7085
7129
  const l2GasParams = await quoteL2Gas2({
7086
7130
  ctx,
7087
7131
  route: "erc20-base",
@@ -7507,6 +7551,8 @@ function createDepositsResource(client, tokens, contracts) {
7507
7551
  async () => {
7508
7552
  const plan = await prepare(p);
7509
7553
  const stepHashes = {};
7554
+ const { chainId } = await client.l2.getNetwork();
7555
+ const chainIdL2 = BigInt(chainId);
7510
7556
  const managed = new ethers.NonceManager(client.signer);
7511
7557
  const from = await managed.getAddress();
7512
7558
  let next;
@@ -7552,8 +7598,14 @@ function createDepositsResource(client, tokens, contracts) {
7552
7598
  }
7553
7599
  if (!p.l1TxOverrides?.gasLimit) {
7554
7600
  try {
7601
+ const preparedGasLimit = step.tx.gasLimit != null ? BigInt(step.tx.gasLimit.toString()) : void 0;
7555
7602
  const est = await client.l1.estimateGas(step.tx);
7556
- step.tx.gasLimit = BigInt(est) * 115n / 100n;
7603
+ step.tx.gasLimit = resolveCreateDepositL1GasLimit({
7604
+ chainIdL2,
7605
+ stepKey: step.key,
7606
+ preparedGasLimit,
7607
+ estimatedGasLimit: BigInt(est)
7608
+ });
7557
7609
  } catch {
7558
7610
  }
7559
7611
  }
@@ -9172,26 +9224,30 @@ function routeDirect() {
9172
9224
  }
9173
9225
  };
9174
9226
  }
9227
+
9228
+ // src/core/resources/interop/protocol.ts
9175
9229
  var MIN_INTEROP_PROTOCOL = 31;
9230
+ function assertProtocolVersion(chainId, protocolVersion) {
9231
+ if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
9232
+ throw createError("VALIDATION", {
9233
+ resource: "interop",
9234
+ operation: OP_INTEROP.context.protocolVersion,
9235
+ message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
9236
+ context: {
9237
+ chainId,
9238
+ requiredMinor: MIN_INTEROP_PROTOCOL,
9239
+ semver: protocolVersion
9240
+ }
9241
+ });
9242
+ }
9243
+ }
9244
+
9245
+ // src/adapters/ethers/resources/interop/context.ts
9176
9246
  async function assertInteropProtocolVersion(client, srcChainId, dstChainId) {
9177
9247
  const [srcProtocolVersion, dstProtocolVersion] = await Promise.all([
9178
9248
  client.getProtocolVersion(srcChainId),
9179
9249
  client.getProtocolVersion(dstChainId)
9180
9250
  ]);
9181
- const assertProtocolVersion = (chainId, protocolVersion) => {
9182
- if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
9183
- throw createError("VALIDATION", {
9184
- resource: "interop",
9185
- operation: OP_INTEROP.context.protocolVersion,
9186
- message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
9187
- context: {
9188
- chainId,
9189
- requiredMinor: MIN_INTEROP_PROTOCOL,
9190
- semver: protocolVersion
9191
- }
9192
- });
9193
- }
9194
- };
9195
9251
  assertProtocolVersion(srcChainId, srcProtocolVersion);
9196
9252
  assertProtocolVersion(dstChainId, dstProtocolVersion);
9197
9253
  }
@@ -9262,7 +9318,14 @@ function parseMaxBlockRangeLimit(error) {
9262
9318
  async function getTxReceipt(provider, txHash) {
9263
9319
  const receipt = await wrap3(
9264
9320
  OP_INTEROP.svc.status.sourceReceipt,
9265
- () => provider.getTransactionReceipt(txHash),
9321
+ async () => {
9322
+ try {
9323
+ return await provider.getTransactionReceipt(txHash);
9324
+ } catch (error) {
9325
+ if (isReceiptNotFound(error)) return null;
9326
+ throw error;
9327
+ }
9328
+ },
9266
9329
  {
9267
9330
  ctx: { where: "l2.getTransactionReceipt", l2SrcTxHash: txHash },
9268
9331
  message: "Failed to fetch source L2 receipt for interop tx."
@@ -9427,6 +9490,60 @@ async function executeBundle(client, dstProvider, info, opts) {
9427
9490
  );
9428
9491
  }
9429
9492
  }
9493
+ async function verifyBundle(client, dstProvider, info) {
9494
+ const signer = await wrap4(OP_INTEROP.verify, () => client.signerFor(dstProvider), {
9495
+ message: "Failed to resolve destination signer for verifyBundle."
9496
+ });
9497
+ const { interopHandler } = await client.ensureAddresses();
9498
+ const handler = new ethers.Contract(interopHandler, IInteropHandler_default, signer);
9499
+ try {
9500
+ const txResponse = await handler.verifyBundle(
9501
+ info.encodedData,
9502
+ info.proof
9503
+ );
9504
+ const hash = txResponse.hash;
9505
+ return {
9506
+ hash,
9507
+ wait: async () => {
9508
+ try {
9509
+ const receipt = await txResponse.wait();
9510
+ if (!receipt || receipt.status !== 1) {
9511
+ throw createError("EXECUTION", {
9512
+ resource: "interop",
9513
+ operation: OP_INTEROP.verify,
9514
+ message: "Interop bundle verification reverted on destination.",
9515
+ context: { txHash: hash }
9516
+ });
9517
+ }
9518
+ return receipt;
9519
+ } catch (e) {
9520
+ if (isZKsyncError(e)) throw e;
9521
+ throw toZKsyncError(
9522
+ "EXECUTION",
9523
+ {
9524
+ resource: "interop",
9525
+ operation: OP_INTEROP.verify,
9526
+ message: "Failed while waiting for verifyBundle transaction on destination.",
9527
+ context: { txHash: hash }
9528
+ },
9529
+ e
9530
+ );
9531
+ }
9532
+ }
9533
+ };
9534
+ } catch (e) {
9535
+ if (isZKsyncError(e)) throw e;
9536
+ throw toZKsyncError(
9537
+ "EXECUTION",
9538
+ {
9539
+ resource: "interop",
9540
+ operation: OP_INTEROP.verify,
9541
+ message: "Failed to send verifyBundle transaction on destination chain."
9542
+ },
9543
+ e
9544
+ );
9545
+ }
9546
+ }
9430
9547
 
9431
9548
  // src/core/resources/interop/finalization.ts
9432
9549
  var DEFAULT_POLL_MS = 1e3;
@@ -9792,6 +9909,31 @@ function resolveChainRef(ref) {
9792
9909
  return typeof ref === "string" ? new ethers.JsonRpcProvider(ref) : ref;
9793
9910
  }
9794
9911
 
9912
+ // src/adapters/ethers/resources/interop/services/gas.ts
9913
+ async function quoteStepsL2Fee(steps, ctx) {
9914
+ if (steps.length === 0) return 0n;
9915
+ const estimator = ethersToGasEstimator(ctx.client.l2);
9916
+ let maxFeePerGas;
9917
+ try {
9918
+ const fees = await estimator.estimateFeesPerGas();
9919
+ maxFeePerGas = fees.maxFeePerGas ?? fees.gasPrice ?? await estimator.getGasPrice();
9920
+ } catch {
9921
+ return void 0;
9922
+ }
9923
+ let total = 0n;
9924
+ for (const step of steps) {
9925
+ try {
9926
+ const coreTx = toCoreTx({ ...step.tx, from: ctx.sender });
9927
+ const est = await estimator.estimateGas(coreTx);
9928
+ const buffered = BigInt(est) * (100n + BUFFER) / 100n;
9929
+ total += buffered * maxFeePerGas;
9930
+ } catch {
9931
+ return void 0;
9932
+ }
9933
+ }
9934
+ return total;
9935
+ }
9936
+
9795
9937
  // src/adapters/ethers/resources/interop/index.ts
9796
9938
  var { wrap: wrap6, toResult: toResult2 } = createErrorHandlers("interop");
9797
9939
  var ROUTES3 = {
@@ -9848,12 +9990,14 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
9848
9990
  ctx: { where: `routes.${route}.build` }
9849
9991
  }
9850
9992
  );
9993
+ const l2Fee = await quoteStepsL2Fee(steps, ctx).catch(() => void 0);
9851
9994
  const summary = {
9852
9995
  route,
9853
9996
  approvalsNeeded: approvals,
9854
9997
  totalActionValue: quoteExtras.totalActionValue,
9855
9998
  bridgedTokenTotal: quoteExtras.bridgedTokenTotal,
9856
- interopFee
9999
+ interopFee,
10000
+ l2Fee
9857
10001
  };
9858
10002
  return { plan: { route, summary, steps }, ctx };
9859
10003
  }
@@ -9978,6 +10122,28 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
9978
10122
  }
9979
10123
  );
9980
10124
  const tryFinalize = (dstChain, h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(dstChain, h, opts));
10125
+ const interopGetRoot = (dstChain, rootChainId, batchNumber) => wrap6(
10126
+ OP_INTEROP.svc.status.getRoot,
10127
+ () => getInteropRoot(resolveChainRef(dstChain), rootChainId, batchNumber),
10128
+ {
10129
+ message: "Failed to get interop root from the destination chain.",
10130
+ ctx: { where: "interop.getInteropRoot" }
10131
+ }
10132
+ );
10133
+ const verifyBundle2 = (dstChain, h) => wrap6(
10134
+ OP_INTEROP.verify,
10135
+ async () => {
10136
+ const dstProvider = resolveChainRef(dstChain);
10137
+ const info = isInteropFinalizationInfo(h) ? h : await svc.wait(dstProvider, getGwProvider(), h);
10138
+ const result = await verifyBundle(client, dstProvider, info);
10139
+ await result.wait();
10140
+ return { bundleHash: info.bundleHash, dstExecTxHash: result.hash };
10141
+ },
10142
+ {
10143
+ message: "Failed to verify interop bundle on destination.",
10144
+ ctx: { where: "interop.verifyBundle" }
10145
+ }
10146
+ );
9981
10147
  return {
9982
10148
  quote,
9983
10149
  tryQuote,
@@ -9989,7 +10155,9 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
9989
10155
  wait,
9990
10156
  tryWait,
9991
10157
  finalize,
9992
- tryFinalize
10158
+ tryFinalize,
10159
+ getInteropRoot: interopGetRoot,
10160
+ verifyBundle: verifyBundle2
9993
10161
  };
9994
10162
  }
9995
10163