@matterlabs/zksync-js 0.0.1

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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/dist/adapters/ethers/client.cjs +4548 -0
  4. package/dist/adapters/ethers/client.cjs.map +1 -0
  5. package/dist/adapters/ethers/client.d.ts +61 -0
  6. package/dist/adapters/ethers/client.js +5 -0
  7. package/dist/adapters/ethers/errors/error-ops.d.ts +20 -0
  8. package/dist/adapters/ethers/errors/revert.d.ts +28 -0
  9. package/dist/adapters/ethers/index.cjs +7537 -0
  10. package/dist/adapters/ethers/index.cjs.map +1 -0
  11. package/dist/adapters/ethers/index.d.ts +12 -0
  12. package/dist/adapters/ethers/index.js +8 -0
  13. package/dist/adapters/ethers/resources/deposits/context.d.ts +27 -0
  14. package/dist/adapters/ethers/resources/deposits/index.d.ts +46 -0
  15. package/dist/adapters/ethers/resources/deposits/routes/erc20-base.d.ts +2 -0
  16. package/dist/adapters/ethers/resources/deposits/routes/erc20-nonbase.d.ts +2 -0
  17. package/dist/adapters/ethers/resources/deposits/routes/eth-nonbase.d.ts +2 -0
  18. package/dist/adapters/ethers/resources/deposits/routes/eth.d.ts +2 -0
  19. package/dist/adapters/ethers/resources/deposits/routes/types.d.ts +10 -0
  20. package/dist/adapters/ethers/resources/deposits/services/verification.d.ts +9 -0
  21. package/dist/adapters/ethers/resources/token-info.d.ts +31 -0
  22. package/dist/adapters/ethers/resources/utils.d.ts +39 -0
  23. package/dist/adapters/ethers/resources/withdrawals/context.d.ts +19 -0
  24. package/dist/adapters/ethers/resources/withdrawals/index.d.ts +56 -0
  25. package/dist/adapters/ethers/resources/withdrawals/routes/erc20-nonbase.d.ts +2 -0
  26. package/dist/adapters/ethers/resources/withdrawals/routes/eth-nonbase.d.ts +2 -0
  27. package/dist/adapters/ethers/resources/withdrawals/routes/eth.d.ts +2 -0
  28. package/dist/adapters/ethers/resources/withdrawals/routes/types.d.ts +18 -0
  29. package/dist/adapters/ethers/resources/withdrawals/services/finalization.d.ts +33 -0
  30. package/dist/adapters/ethers/rpc.d.ts +4 -0
  31. package/dist/adapters/ethers/sdk.cjs +6245 -0
  32. package/dist/adapters/ethers/sdk.cjs.map +1 -0
  33. package/dist/adapters/ethers/sdk.d.ts +29 -0
  34. package/dist/adapters/ethers/sdk.js +6 -0
  35. package/dist/adapters/ethers/typechain/IAssetRouterBase.d.ts +198 -0
  36. package/dist/adapters/ethers/typechain/IBridgehub.d.ts +731 -0
  37. package/dist/adapters/ethers/typechain/IERC20.d.ts +108 -0
  38. package/dist/adapters/ethers/typechain/IL1AssetRouter.d.ts +570 -0
  39. package/dist/adapters/ethers/typechain/IL1NativeTokenVault.d.ts +154 -0
  40. package/dist/adapters/ethers/typechain/IL1Nullifier.d.ts +305 -0
  41. package/dist/adapters/ethers/typechain/IL2AssetRouter.d.ts +288 -0
  42. package/dist/adapters/ethers/typechain/IL2NativeTokenVault.d.ts +380 -0
  43. package/dist/adapters/ethers/typechain/common.d.ts +46 -0
  44. package/dist/adapters/ethers/typechain/factories/IAssetRouterBase__factory.d.ts +203 -0
  45. package/dist/adapters/ethers/typechain/factories/IBridgehub__factory.d.ts +998 -0
  46. package/dist/adapters/ethers/typechain/factories/IERC20__factory.d.ts +177 -0
  47. package/dist/adapters/ethers/typechain/factories/IL1AssetRouter__factory.d.ts +666 -0
  48. package/dist/adapters/ethers/typechain/factories/IL1NativeTokenVault__factory.d.ts +234 -0
  49. package/dist/adapters/ethers/typechain/factories/IL1Nullifier__factory.d.ts +382 -0
  50. package/dist/adapters/ethers/typechain/factories/IL2AssetRouter__factory.d.ts +327 -0
  51. package/dist/adapters/ethers/typechain/factories/IL2NativeTokenVault__factory.d.ts +696 -0
  52. package/dist/adapters/ethers/typechain/factories/index.d.ts +8 -0
  53. package/dist/adapters/ethers/typechain/index.d.ts +17 -0
  54. package/dist/adapters/viem/client.cjs +4534 -0
  55. package/dist/adapters/viem/client.cjs.map +1 -0
  56. package/dist/adapters/viem/client.d.ts +44 -0
  57. package/dist/adapters/viem/client.js +5 -0
  58. package/dist/adapters/viem/errors/error-ops.d.ts +20 -0
  59. package/dist/adapters/viem/errors/revert.d.ts +25 -0
  60. package/dist/adapters/viem/index.cjs +7772 -0
  61. package/dist/adapters/viem/index.cjs.map +1 -0
  62. package/dist/adapters/viem/index.d.ts +11 -0
  63. package/dist/adapters/viem/index.js +8 -0
  64. package/dist/adapters/viem/resources/deposits/context.d.ts +27 -0
  65. package/dist/adapters/viem/resources/deposits/index.d.ts +46 -0
  66. package/dist/adapters/viem/resources/deposits/routes/erc20-base.d.ts +2 -0
  67. package/dist/adapters/viem/resources/deposits/routes/erc20-nonbase.d.ts +2 -0
  68. package/dist/adapters/viem/resources/deposits/routes/eth-nonbase.d.ts +2 -0
  69. package/dist/adapters/viem/resources/deposits/routes/eth.d.ts +2 -0
  70. package/dist/adapters/viem/resources/deposits/routes/types.d.ts +20 -0
  71. package/dist/adapters/viem/resources/deposits/services/verification.d.ts +7 -0
  72. package/dist/adapters/viem/resources/token-info.d.ts +34 -0
  73. package/dist/adapters/viem/resources/utils.d.ts +42 -0
  74. package/dist/adapters/viem/resources/withdrawals/context.d.ts +22 -0
  75. package/dist/adapters/viem/resources/withdrawals/index.d.ts +56 -0
  76. package/dist/adapters/viem/resources/withdrawals/routes/erc20-nonbase.d.ts +2 -0
  77. package/dist/adapters/viem/resources/withdrawals/routes/eth-nonbase.d.ts +2 -0
  78. package/dist/adapters/viem/resources/withdrawals/routes/eth.d.ts +2 -0
  79. package/dist/adapters/viem/resources/withdrawals/routes/types.d.ts +19 -0
  80. package/dist/adapters/viem/resources/withdrawals/services/finalization.d.ts +33 -0
  81. package/dist/adapters/viem/rpc.d.ts +2 -0
  82. package/dist/adapters/viem/sdk.cjs +6481 -0
  83. package/dist/adapters/viem/sdk.cjs.map +1 -0
  84. package/dist/adapters/viem/sdk.d.ts +32 -0
  85. package/dist/adapters/viem/sdk.js +6 -0
  86. package/dist/chunk-263G6636.js +36 -0
  87. package/dist/chunk-3LALBFFE.js +138 -0
  88. package/dist/chunk-4HLJJKIY.js +262 -0
  89. package/dist/chunk-6GCT6TLS.js +45 -0
  90. package/dist/chunk-7M4V3FMT.js +2444 -0
  91. package/dist/chunk-B77GWPO5.js +339 -0
  92. package/dist/chunk-BD2LUO5T.js +123 -0
  93. package/dist/chunk-CGO27P7F.js +2187 -0
  94. package/dist/chunk-DI2CJDPZ.js +76 -0
  95. package/dist/chunk-Y75OMFK6.js +4489 -0
  96. package/dist/core/constants.cjs +39 -0
  97. package/dist/core/constants.cjs.map +1 -0
  98. package/dist/core/constants.d.ts +36 -0
  99. package/dist/core/constants.js +1 -0
  100. package/dist/core/errors/factory.d.ts +10 -0
  101. package/dist/core/errors/formatter.d.ts +2 -0
  102. package/dist/core/errors/rpc.d.ts +4 -0
  103. package/dist/core/errors/withdrawal-revert-map.d.ts +3 -0
  104. package/dist/core/index.cjs +552 -0
  105. package/dist/core/index.cjs.map +1 -0
  106. package/dist/core/index.d.ts +18 -0
  107. package/dist/core/index.js +4 -0
  108. package/dist/core/internal/abi-registry.d.ts +9 -0
  109. package/dist/core/internal/abis/IAssetRouterBase.d.ts +198 -0
  110. package/dist/core/internal/abis/IBaseToken.d.ts +162 -0
  111. package/dist/core/internal/abis/IBridgehub.d.ts +994 -0
  112. package/dist/core/internal/abis/IERC20.d.ts +224 -0
  113. package/dist/core/internal/abis/IL1AssetRouter.d.ts +661 -0
  114. package/dist/core/internal/abis/IL1Nullifier.d.ts +377 -0
  115. package/dist/core/internal/abis/IL2AssetRouter.d.ts +690 -0
  116. package/dist/core/internal/abis/L1NativeTokenVault.d.ts +719 -0
  117. package/dist/core/internal/abis/L2NativeTokenVault.d.ts +735 -0
  118. package/dist/core/internal/abis/Mailbox.d.ts +779 -0
  119. package/dist/core/resources/deposits/route.d.ts +6 -0
  120. package/dist/core/resources/withdrawals/events.d.ts +9 -0
  121. package/dist/core/resources/withdrawals/logs.d.ts +5 -0
  122. package/dist/core/resources/withdrawals/route.d.ts +6 -0
  123. package/dist/core/rpc/transport.d.ts +10 -0
  124. package/dist/core/rpc/types.d.ts +40 -0
  125. package/dist/core/rpc/zks.d.ts +12 -0
  126. package/dist/core/types/errors.d.ts +177 -0
  127. package/dist/core/types/flows/base.d.ts +51 -0
  128. package/dist/core/types/flows/deposits.d.ts +43 -0
  129. package/dist/core/types/flows/route.d.ts +12 -0
  130. package/dist/core/types/flows/withdrawals.d.ts +83 -0
  131. package/dist/core/types/index.d.ts +2 -0
  132. package/dist/core/types/primitives.d.ts +3 -0
  133. package/dist/core/utils/addr.d.ts +5 -0
  134. package/dist/core/utils/gas.d.ts +13 -0
  135. package/dist/index.cjs +571 -0
  136. package/dist/index.cjs.map +1 -0
  137. package/dist/index.d.ts +18 -0
  138. package/dist/index.js +4 -0
  139. package/package.json +177 -0
@@ -0,0 +1,2444 @@
1
+ import { assertNoLegacyGas, assertPriorityFeeBounds, REVERT_TO_READINESS } from './chunk-263G6636.js';
2
+ import { findL1MessageSentLog, messengerLogIndex, isAddressEq, isHash66, pickDepositRoute, isETH, normalizeAddrEq, pickWithdrawRoute } from './chunk-DI2CJDPZ.js';
3
+ import { IL1Nullifier_default, IERC20_default, L1NativeTokenVault_default, L2NativeTokenVault_default, Mailbox_default, IBridgehub_default, IL2AssetRouter_default, IBaseToken_default } from './chunk-Y75OMFK6.js';
4
+ import { isZKsyncError, createError, shapeCause, OP_WITHDRAWALS, OP_DEPOSITS, isReceiptNotFound } from './chunk-B77GWPO5.js';
5
+ import { ETH_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, L1_FEE_ESTIMATION_COEF_NUMERATOR, L1_FEE_ESTIMATION_COEF_DENOMINATOR, L1_MESSENGER_ADDRESS, L2_ASSET_ROUTER_ADDRESS, FORMAL_ETH_ADDRESS, L2_BASE_TOKEN_ADDRESS, TOPIC_CANONICAL_ASSIGNED, TOPIC_CANONICAL_SUCCESS } from './chunk-6GCT6TLS.js';
6
+ import { encodeAbiParameters, keccak256, concat, decodeErrorResult, decodeAbiParameters, decodeEventLog } from 'viem';
7
+
8
+ function encodeNativeTokenVaultAssetId(chainId, address) {
9
+ const encoded = encodeAbiParameters(
10
+ [
11
+ { type: "uint256", name: "originChainId" },
12
+ { type: "address", name: "ntv" },
13
+ { type: "address", name: "token" }
14
+ ],
15
+ [chainId, L2_NATIVE_TOKEN_VAULT_ADDRESS, address]
16
+ );
17
+ return keccak256(encoded);
18
+ }
19
+ function encodeNativeTokenVaultTransferData(amount, receiver, token) {
20
+ return encodeAbiParameters(
21
+ [
22
+ { type: "uint256", name: "amount" },
23
+ { type: "address", name: "receiver" },
24
+ { type: "address", name: "token" }
25
+ ],
26
+ [amount, receiver, token]
27
+ );
28
+ }
29
+ function encodeSecondBridgeDataV1(assetId, transferData) {
30
+ const data = encodeAbiParameters(
31
+ [
32
+ { type: "bytes32", name: "assetId" },
33
+ { type: "bytes", name: "transferData" }
34
+ ],
35
+ [assetId, transferData]
36
+ );
37
+ return concat(["0x01", data]);
38
+ }
39
+ var encodeNTVAssetId = encodeNativeTokenVaultAssetId;
40
+ var encodeNTVTransferData = encodeNativeTokenVaultTransferData;
41
+ function scaleGasLimit(gasLimit) {
42
+ return gasLimit * BigInt(L1_FEE_ESTIMATION_COEF_NUMERATOR) / BigInt(L1_FEE_ESTIMATION_COEF_DENOMINATOR);
43
+ }
44
+ async function checkBaseCost(baseCost, value) {
45
+ const resolved = await value;
46
+ if (baseCost > resolved) {
47
+ throw new Error(
48
+ `The base cost of performing the priority operation is higher than the provided value parameter for the transaction: baseCost: ${String(baseCost)}, provided value: ${String(resolved)}!`
49
+ );
50
+ }
51
+ }
52
+ async function getFeeOverrides(client, overrides) {
53
+ assertNoLegacyGas(overrides);
54
+ let maxFeePerGasFromProvider;
55
+ let maxPriorityFromProvider;
56
+ let gasPriceFromProvider;
57
+ try {
58
+ const fees = await client.l1.estimateFeesPerGas();
59
+ const { maxFeePerGas: maxFeePerGas2, maxPriorityFeePerGas: maxPriorityFeePerGas2 } = fees;
60
+ if (maxFeePerGas2 != null && maxPriorityFeePerGas2 != null) {
61
+ maxFeePerGasFromProvider = maxFeePerGas2;
62
+ maxPriorityFromProvider = maxPriorityFeePerGas2;
63
+ gasPriceFromProvider = fees.gasPrice ?? maxFeePerGas2;
64
+ } else if (fees.gasPrice != null) {
65
+ gasPriceFromProvider = fees.gasPrice;
66
+ }
67
+ } catch {
68
+ }
69
+ if (gasPriceFromProvider == null) {
70
+ try {
71
+ gasPriceFromProvider = await client.l1.getGasPrice();
72
+ } catch {
73
+ }
74
+ }
75
+ const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider;
76
+ if (maxFeePerGas == null) {
77
+ throw new Error("L1 provider returned no gas price data");
78
+ }
79
+ const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
80
+ assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
81
+ const gasPriceForBaseCost = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider ?? maxFeePerGas;
82
+ return {
83
+ gasLimit: overrides?.gasLimit,
84
+ maxFeePerGas,
85
+ maxPriorityFeePerGas,
86
+ gasPriceForBaseCost
87
+ };
88
+ }
89
+ async function getL2FeeOverrides(client, overrides) {
90
+ assertNoLegacyGas(overrides);
91
+ let maxFeePerGasFromProvider;
92
+ let maxPriorityFromProvider;
93
+ let gasPriceFromProvider;
94
+ try {
95
+ const fees = await client.l2.estimateFeesPerGas();
96
+ if (fees?.maxFeePerGas != null && fees.maxPriorityFeePerGas != null) {
97
+ maxFeePerGasFromProvider = fees.maxFeePerGas;
98
+ maxPriorityFromProvider = fees.maxPriorityFeePerGas;
99
+ gasPriceFromProvider = fees.gasPrice ?? fees.maxFeePerGas;
100
+ } else if (fees?.gasPrice != null) {
101
+ gasPriceFromProvider = fees.gasPrice;
102
+ }
103
+ } catch {
104
+ }
105
+ if (gasPriceFromProvider == null) {
106
+ try {
107
+ gasPriceFromProvider = await client.l2.getGasPrice();
108
+ } catch {
109
+ }
110
+ }
111
+ const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider;
112
+ if (maxFeePerGas == null) {
113
+ throw new Error("provider returned no gas price data");
114
+ }
115
+ const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
116
+ assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
117
+ return {
118
+ gasLimit: overrides?.gasLimit,
119
+ maxFeePerGas,
120
+ maxPriorityFeePerGas
121
+ };
122
+ }
123
+ function buildViemFeeOverrides(fees) {
124
+ return {
125
+ maxFeePerGas: fees.maxFeePerGas,
126
+ maxPriorityFeePerGas: fees.maxPriorityFeePerGas,
127
+ gas: fees.gasLimit
128
+ };
129
+ }
130
+ async function getGasPriceWei(client) {
131
+ try {
132
+ const gp = await client.l1.getGasPrice();
133
+ if (gp != null) return gp;
134
+ } catch {
135
+ }
136
+ try {
137
+ const fees = await client.l1.estimateFeesPerGas();
138
+ if (fees?.maxFeePerGas != null) return fees.maxFeePerGas;
139
+ } catch {
140
+ }
141
+ throw new Error("provider returned no gas price data");
142
+ }
143
+ function buildDirectRequestStruct(args) {
144
+ return {
145
+ chainId: args.chainId,
146
+ l2Contract: args.l2Contract,
147
+ mintValue: args.mintValue,
148
+ l2Value: args.l2Value,
149
+ l2Calldata: "0x",
150
+ l2GasLimit: args.l2GasLimit,
151
+ l2GasPerPubdataByteLimit: args.gasPerPubdata,
152
+ factoryDeps: [],
153
+ refundRecipient: args.refundRecipient
154
+ };
155
+ }
156
+ function encodeSecondBridgeArgs(token, amount, l2Receiver) {
157
+ return encodeAbiParameters(
158
+ [
159
+ { type: "address", name: "token" },
160
+ { type: "uint256", name: "amount" },
161
+ { type: "address", name: "l2Receiver" }
162
+ ],
163
+ [token, amount, l2Receiver]
164
+ );
165
+ }
166
+ function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
167
+ return encodeSecondBridgeArgs(token, amount, l2Receiver);
168
+ }
169
+ function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
170
+ return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
171
+ }
172
+
173
+ // src/adapters/viem/resources/deposits/context.ts
174
+ async function commonCtx(p, client) {
175
+ const { bridgehub, l1AssetRouter } = await client.ensureAddresses();
176
+ const chainId = await client.l2.getChainId();
177
+ const sender = client.account.address;
178
+ const fee = await getFeeOverrides(client, p.l1TxOverrides);
179
+ const l2GasLimit = p.l2GasLimit ?? 300000n;
180
+ const gasPerPubdata = p.gasPerPubdata ?? 800n;
181
+ const operatorTip = p.operatorTip ?? 0n;
182
+ const refundRecipient = p.refundRecipient ?? sender;
183
+ const route = await pickDepositRoute(client, BigInt(chainId), p.token);
184
+ return {
185
+ client,
186
+ l1AssetRouter,
187
+ route,
188
+ bridgehub,
189
+ chainIdL2: BigInt(chainId),
190
+ sender,
191
+ fee,
192
+ l2GasLimit,
193
+ gasPerPubdata,
194
+ operatorTip,
195
+ refundRecipient
196
+ };
197
+ }
198
+ var ERROR_ABIS = [];
199
+ var ABI_ERROR_STRING = [
200
+ { type: "error", name: "Error", inputs: [{ name: "message", type: "string" }] }
201
+ ];
202
+ var ABI_PANIC = [
203
+ { type: "error", name: "Panic", inputs: [{ name: "code", type: "uint256" }] }
204
+ ];
205
+ (function bootstrapDefaultAbis() {
206
+ try {
207
+ ERROR_ABIS.push({ name: "IL1Nullifier", abi: IL1Nullifier_default });
208
+ } catch {
209
+ }
210
+ try {
211
+ ERROR_ABIS.push({ name: "IERC20", abi: IERC20_default });
212
+ } catch {
213
+ }
214
+ try {
215
+ ERROR_ABIS.push({ name: "IL1NativeTokenVault", abi: L1NativeTokenVault_default });
216
+ } catch {
217
+ }
218
+ try {
219
+ ERROR_ABIS.push({ name: "IL2NativeTokenVault", abi: L2NativeTokenVault_default });
220
+ } catch {
221
+ }
222
+ try {
223
+ ERROR_ABIS.push({ name: "Mailbox", abi: Mailbox_default });
224
+ } catch {
225
+ }
226
+ })();
227
+ function registerErrorAbi(name, abi) {
228
+ const i = ERROR_ABIS.findIndex((x) => x.name === name);
229
+ const entry = { name, abi };
230
+ if (i >= 0) ERROR_ABIS[i] = entry;
231
+ else ERROR_ABIS.push(entry);
232
+ }
233
+ function extractRevertData(e) {
234
+ const candidates = [
235
+ e?.data?.data,
236
+ e?.error?.data,
237
+ e?.data,
238
+ e?.error?.error?.data,
239
+ e?.info?.error?.data,
240
+ e?.cause?.data,
241
+ e?.cause?.cause?.data,
242
+ e?.details
243
+ ];
244
+ for (const c of candidates) {
245
+ if (typeof c === "string" && c.startsWith("0x") && c.length >= 10) {
246
+ return c;
247
+ }
248
+ }
249
+ return void 0;
250
+ }
251
+ function decodeRevert(e) {
252
+ const data = extractRevertData(e);
253
+ if (!data) return;
254
+ const selector = `0x${data.slice(2, 10)}`;
255
+ try {
256
+ const parsed = decodeErrorResult({ abi: ABI_ERROR_STRING, data });
257
+ if (parsed?.errorName === "Error") {
258
+ return { selector, name: parsed.errorName, args: parsed.args ? [...parsed.args] : void 0 };
259
+ }
260
+ } catch {
261
+ }
262
+ try {
263
+ const parsed = decodeErrorResult({ abi: ABI_PANIC, data });
264
+ if (parsed?.errorName === "Panic") {
265
+ return { selector, name: parsed.errorName, args: parsed.args ? [...parsed.args] : void 0 };
266
+ }
267
+ } catch {
268
+ }
269
+ for (const { name, abi } of ERROR_ABIS) {
270
+ try {
271
+ const parsed = decodeErrorResult({ abi, data });
272
+ if (parsed && parsed.errorName) {
273
+ return {
274
+ selector,
275
+ name: parsed.errorName,
276
+ args: parsed.args ? [...parsed.args] : void 0,
277
+ contract: name
278
+ };
279
+ }
280
+ } catch {
281
+ }
282
+ }
283
+ return { selector };
284
+ }
285
+ function classifyReadinessFromRevert(e) {
286
+ const r = decodeRevert(e);
287
+ const name = r?.name;
288
+ if (name && REVERT_TO_READINESS[name]) return REVERT_TO_READINESS[name];
289
+ const msg = (() => {
290
+ if (typeof e !== "object" || e === null) return "";
291
+ const obj = e;
292
+ const maybe = obj["shortMessage"] ?? obj["message"];
293
+ return typeof maybe === "string" ? maybe : "";
294
+ })();
295
+ const lower = msg.toLowerCase();
296
+ if (lower.includes("paused")) return { kind: "NOT_READY", reason: "paused" };
297
+ if (name || r?.selector) {
298
+ return { kind: "UNFINALIZABLE", reason: "unsupported", detail: name ?? r?.selector };
299
+ }
300
+ return { kind: "NOT_READY", reason: "unknown", detail: lower || void 0 };
301
+ }
302
+
303
+ // src/adapters/viem/errors/error-ops.ts
304
+ function toZKsyncError(type, base, err) {
305
+ if (isZKsyncError(err)) return err;
306
+ const revert = decodeRevert(err);
307
+ return createError(type, { ...base, ...revert ? { revert } : {}, cause: shapeCause(err) });
308
+ }
309
+ function resolveMessage(op, msg) {
310
+ if (!msg) return `Error during ${op}.`;
311
+ return typeof msg === "function" ? msg() : msg;
312
+ }
313
+ function createErrorHandlers(resource) {
314
+ async function run(kind, operation, fn, opts) {
315
+ try {
316
+ return await fn();
317
+ } catch (e) {
318
+ if (isZKsyncError(e)) throw e;
319
+ const message = resolveMessage(operation, opts?.message);
320
+ throw toZKsyncError(kind, { resource, operation, context: opts?.ctx ?? {}, message }, e);
321
+ }
322
+ }
323
+ function wrap2(operation, fn, opts) {
324
+ return run("INTERNAL", operation, fn, opts);
325
+ }
326
+ function wrapAs9(kind, operation, fn, opts) {
327
+ return run(kind, operation, fn, opts);
328
+ }
329
+ async function toResult2(operation, fn, opts) {
330
+ try {
331
+ const value = await wrap2(operation, fn, opts);
332
+ return { ok: true, value };
333
+ } catch (e) {
334
+ const shaped = isZKsyncError(e) ? e : toZKsyncError(
335
+ "INTERNAL",
336
+ {
337
+ resource,
338
+ operation,
339
+ context: opts?.ctx ?? {},
340
+ message: resolveMessage(operation, opts?.message)
341
+ },
342
+ e
343
+ );
344
+ return { ok: false, error: shaped };
345
+ }
346
+ }
347
+ return { wrap: wrap2, wrapAs: wrapAs9, toResult: toResult2 };
348
+ }
349
+
350
+ // src/adapters/viem/resources/deposits/routes/eth.ts
351
+ var { wrapAs } = createErrorHandlers("deposits");
352
+ function routeEthDirect() {
353
+ return {
354
+ async build(p, ctx) {
355
+ const { gasPriceForBaseCost } = ctx.fee;
356
+ const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
357
+ const rawBaseCost = await wrapAs(
358
+ "CONTRACT",
359
+ OP_DEPOSITS.eth.baseCost,
360
+ () => ctx.client.l1.readContract({
361
+ address: ctx.bridgehub,
362
+ abi: IBridgehub_default,
363
+ functionName: "l2TransactionBaseCost",
364
+ args: [ctx.chainIdL2, gasPriceForBaseCost, ctx.l2GasLimit, ctx.gasPerPubdata]
365
+ }),
366
+ {
367
+ ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
368
+ message: "Could not fetch L2 base cost from Bridgehub."
369
+ }
370
+ );
371
+ const baseCost = rawBaseCost;
372
+ const l2Contract = p.to ?? ctx.sender;
373
+ const l2Value = p.amount;
374
+ const mintValue = baseCost + ctx.operatorTip + l2Value;
375
+ const req = buildDirectRequestStruct({
376
+ chainId: ctx.chainIdL2,
377
+ mintValue,
378
+ l2GasLimit: ctx.l2GasLimit,
379
+ gasPerPubdata: ctx.gasPerPubdata,
380
+ refundRecipient: ctx.refundRecipient,
381
+ l2Contract,
382
+ l2Value
383
+ });
384
+ const sim = await wrapAs(
385
+ "RPC",
386
+ OP_DEPOSITS.eth.estGas,
387
+ () => ctx.client.l1.simulateContract({
388
+ address: ctx.bridgehub,
389
+ abi: IBridgehub_default,
390
+ functionName: "requestL2TransactionDirect",
391
+ args: [req],
392
+ value: mintValue,
393
+ account: ctx.client.account
394
+ }),
395
+ {
396
+ ctx: { where: "l1.simulateContract", to: ctx.bridgehub },
397
+ message: "Failed to simulate Bridgehub.requestL2TransactionDirect."
398
+ }
399
+ );
400
+ const resolvedL1GasLimit = sim.request.gas ?? ctx.l2GasLimit;
401
+ const steps = [
402
+ {
403
+ key: "bridgehub:direct",
404
+ kind: "bridgehub:direct",
405
+ description: "Bridge ETH via Bridgehub.requestL2TransactionDirect",
406
+ tx: { ...sim.request, ...txFeeOverrides }
407
+ }
408
+ ];
409
+ return {
410
+ steps,
411
+ approvals: [],
412
+ quoteExtras: { baseCost, mintValue, l1GasLimit: resolvedL1GasLimit }
413
+ };
414
+ }
415
+ };
416
+ }
417
+
418
+ // src/adapters/viem/resources/deposits/routes/erc20-nonbase.ts
419
+ var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
420
+ var BASE_COST_BUFFER_BPS = 100n;
421
+ var BPS = 10000n;
422
+ var withBuffer = (x) => x * (BPS + BASE_COST_BUFFER_BPS) / BPS;
423
+ function routeErc20NonBase() {
424
+ return {
425
+ async preflight(p, ctx) {
426
+ await wrapAs2(
427
+ "VALIDATION",
428
+ OP_DEPOSITS.nonbase.assertNotEthAsset,
429
+ () => {
430
+ if (isETH(p.token)) {
431
+ throw new Error("erc20-nonbase route requires an ERC-20 token (not ETH).");
432
+ }
433
+ },
434
+ { ctx: { token: p.token } }
435
+ );
436
+ const baseToken = await wrapAs2(
437
+ "CONTRACT",
438
+ OP_DEPOSITS.nonbase.baseToken,
439
+ () => ctx.client.l1.readContract({
440
+ address: ctx.bridgehub,
441
+ abi: IBridgehub_default,
442
+ functionName: "baseToken",
443
+ args: [ctx.chainIdL2]
444
+ }),
445
+ { ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 } }
446
+ );
447
+ await wrapAs2(
448
+ "VALIDATION",
449
+ OP_DEPOSITS.nonbase.assertNonBaseToken,
450
+ () => {
451
+ if (normalizeAddrEq(baseToken, p.token)) {
452
+ throw new Error("erc20-nonbase route requires a non-base ERC-20 deposit token.");
453
+ }
454
+ },
455
+ { ctx: { depositToken: p.token, baseToken } }
456
+ );
457
+ return;
458
+ },
459
+ async build(p, ctx) {
460
+ const { gasPriceForBaseCost } = ctx.fee;
461
+ const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
462
+ const baseToken = await wrapAs2(
463
+ "CONTRACT",
464
+ OP_DEPOSITS.nonbase.baseToken,
465
+ () => ctx.client.l1.readContract({
466
+ address: ctx.bridgehub,
467
+ abi: IBridgehub_default,
468
+ functionName: "baseToken",
469
+ args: [ctx.chainIdL2]
470
+ }),
471
+ { ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 } }
472
+ );
473
+ const MIN_L2_GAS_FOR_ERC20 = 2500000n;
474
+ const l2GasLimitUsed = ctx.l2GasLimit && ctx.l2GasLimit > 0n ? ctx.l2GasLimit < MIN_L2_GAS_FOR_ERC20 ? MIN_L2_GAS_FOR_ERC20 : ctx.l2GasLimit : MIN_L2_GAS_FOR_ERC20;
475
+ const rawBaseCost = await wrapAs2(
476
+ "CONTRACT",
477
+ OP_DEPOSITS.nonbase.baseCost,
478
+ () => ctx.client.l1.readContract({
479
+ address: ctx.bridgehub,
480
+ abi: IBridgehub_default,
481
+ functionName: "l2TransactionBaseCost",
482
+ args: [ctx.chainIdL2, gasPriceForBaseCost, l2GasLimitUsed, ctx.gasPerPubdata]
483
+ }),
484
+ { ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 } }
485
+ );
486
+ const baseCost = rawBaseCost;
487
+ const mintValue = withBuffer(baseCost + ctx.operatorTip);
488
+ const approvals = [];
489
+ const steps = [];
490
+ const depositAllowance = await wrapAs2(
491
+ "CONTRACT",
492
+ OP_DEPOSITS.nonbase.allowance,
493
+ () => ctx.client.l1.readContract({
494
+ address: p.token,
495
+ abi: IERC20_default,
496
+ functionName: "allowance",
497
+ args: [ctx.sender, ctx.l1AssetRouter]
498
+ }),
499
+ {
500
+ ctx: { where: "erc20.allowance", token: p.token, spender: ctx.l1AssetRouter },
501
+ message: "Failed to read ERC-20 allowance for deposit token."
502
+ }
503
+ );
504
+ const needsDepositApprove = depositAllowance < p.amount;
505
+ if (needsDepositApprove) {
506
+ const approveDepReq = await wrapAs2(
507
+ "CONTRACT",
508
+ OP_DEPOSITS.nonbase.estGas,
509
+ () => ctx.client.l1.simulateContract({
510
+ address: p.token,
511
+ abi: IERC20_default,
512
+ functionName: "approve",
513
+ args: [ctx.l1AssetRouter, p.amount],
514
+ account: ctx.client.account
515
+ }),
516
+ {
517
+ ctx: { where: "l1.simulateContract", to: p.token },
518
+ message: "Failed to simulate deposit token approve."
519
+ }
520
+ );
521
+ approvals.push({ token: p.token, spender: ctx.l1AssetRouter, amount: p.amount });
522
+ steps.push({
523
+ key: `approve:${p.token}:${ctx.l1AssetRouter}`,
524
+ kind: "approve",
525
+ description: `Approve deposit token for amount`,
526
+ tx: { ...approveDepReq.request, ...txFeeOverrides }
527
+ });
528
+ }
529
+ const baseIsEth = isETH(baseToken);
530
+ let msgValue = 0n;
531
+ if (!baseIsEth) {
532
+ const baseAllowance = await wrapAs2(
533
+ "CONTRACT",
534
+ OP_DEPOSITS.nonbase.allowanceFees,
535
+ () => ctx.client.l1.readContract({
536
+ address: baseToken,
537
+ abi: IERC20_default,
538
+ functionName: "allowance",
539
+ args: [ctx.sender, ctx.l1AssetRouter]
540
+ }),
541
+ {
542
+ ctx: { where: "erc20.allowance", token: baseToken, spender: ctx.l1AssetRouter },
543
+ message: "Failed to read base-token allowance."
544
+ }
545
+ );
546
+ if (baseAllowance < mintValue) {
547
+ const approveBaseReq = await wrapAs2(
548
+ "CONTRACT",
549
+ OP_DEPOSITS.nonbase.estGas,
550
+ () => ctx.client.l1.simulateContract({
551
+ address: baseToken,
552
+ abi: IERC20_default,
553
+ functionName: "approve",
554
+ args: [ctx.l1AssetRouter, mintValue],
555
+ account: ctx.client.account
556
+ }),
557
+ {
558
+ ctx: { where: "l1.simulateContract", to: baseToken },
559
+ message: "Failed to simulate base-token approve."
560
+ }
561
+ );
562
+ approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
563
+ steps.push({
564
+ key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
565
+ kind: "approve",
566
+ description: `Approve base token for mintValue`,
567
+ tx: { ...approveBaseReq.request, ...txFeeOverrides }
568
+ });
569
+ }
570
+ msgValue = 0n;
571
+ } else {
572
+ msgValue = mintValue;
573
+ }
574
+ const secondBridgeCalldata = await wrapAs2(
575
+ "INTERNAL",
576
+ OP_DEPOSITS.nonbase.encodeCalldata,
577
+ () => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, p.to ?? ctx.sender)),
578
+ {
579
+ ctx: {
580
+ where: "encodeSecondBridgeErc20Args",
581
+ token: p.token,
582
+ amount: p.amount.toString()
583
+ }
584
+ }
585
+ );
586
+ const outer = {
587
+ chainId: ctx.chainIdL2,
588
+ mintValue,
589
+ l2Value: 0n,
590
+ l2GasLimit: l2GasLimitUsed,
591
+ l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
592
+ refundRecipient: ctx.refundRecipient,
593
+ secondBridgeAddress: ctx.l1AssetRouter,
594
+ secondBridgeValue: 0n,
595
+ secondBridgeCalldata
596
+ };
597
+ const approvalsNeeded = approvals.length > 0;
598
+ let bridgeTx;
599
+ let resolvedL1GasLimit;
600
+ const gasOverride = txFeeOverrides.gas;
601
+ if (approvalsNeeded) {
602
+ bridgeTx = {
603
+ address: ctx.bridgehub,
604
+ abi: IBridgehub_default,
605
+ functionName: "requestL2TransactionTwoBridges",
606
+ args: [outer],
607
+ value: msgValue,
608
+ account: ctx.client.account,
609
+ ...txFeeOverrides
610
+ };
611
+ resolvedL1GasLimit = gasOverride ?? ctx.l2GasLimit;
612
+ } else {
613
+ const sim = await wrapAs2(
614
+ "CONTRACT",
615
+ OP_DEPOSITS.nonbase.estGas,
616
+ () => ctx.client.l1.simulateContract({
617
+ address: ctx.bridgehub,
618
+ abi: IBridgehub_default,
619
+ functionName: "requestL2TransactionTwoBridges",
620
+ args: [outer],
621
+ value: msgValue,
622
+ account: ctx.client.account
623
+ }),
624
+ {
625
+ ctx: { where: "l1.simulateContract", to: ctx.bridgehub },
626
+ message: "Failed to simulate two-bridges request."
627
+ }
628
+ );
629
+ bridgeTx = { ...sim.request, ...txFeeOverrides };
630
+ resolvedL1GasLimit = sim.request.gas ?? ctx.l2GasLimit;
631
+ }
632
+ steps.push({
633
+ key: "bridgehub:two-bridges:nonbase",
634
+ kind: "bridgehub:two-bridges",
635
+ description: baseIsEth ? "Bridge ERC-20 (fees in ETH) via Bridgehub.requestL2TransactionTwoBridges" : "Bridge ERC-20 (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
636
+ tx: bridgeTx
637
+ });
638
+ return {
639
+ steps,
640
+ approvals,
641
+ quoteExtras: { baseCost, mintValue, l1GasLimit: resolvedL1GasLimit }
642
+ };
643
+ }
644
+ };
645
+ }
646
+
647
+ // src/adapters/viem/resources/deposits/routes/eth-nonbase.ts
648
+ var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
649
+ var BASE_COST_BUFFER_BPS2 = 100n;
650
+ var BPS2 = 10000n;
651
+ var withBuffer2 = (x) => x * (BPS2 + BASE_COST_BUFFER_BPS2) / BPS2;
652
+ function routeEthNonBase() {
653
+ return {
654
+ async preflight(p, ctx) {
655
+ await wrapAs3(
656
+ "VALIDATION",
657
+ OP_DEPOSITS.ethNonBase.assertEthAsset,
658
+ () => {
659
+ if (!isETH(p.token)) {
660
+ throw new Error("eth-nonbase route requires ETH as the deposit asset.");
661
+ }
662
+ },
663
+ { ctx: { token: p.token } }
664
+ );
665
+ const baseToken = await wrapAs3(
666
+ "CONTRACT",
667
+ OP_DEPOSITS.ethNonBase.baseToken,
668
+ () => ctx.client.l1.readContract({
669
+ address: ctx.bridgehub,
670
+ abi: IBridgehub_default,
671
+ functionName: "baseToken",
672
+ args: [ctx.chainIdL2]
673
+ }),
674
+ {
675
+ ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
676
+ message: "Failed to read base token."
677
+ }
678
+ );
679
+ await wrapAs3(
680
+ "VALIDATION",
681
+ OP_DEPOSITS.ethNonBase.assertNonEthBase,
682
+ () => {
683
+ if (isETH(baseToken)) {
684
+ throw new Error("eth-nonbase route requires target chain base token \u2260 ETH.");
685
+ }
686
+ },
687
+ { ctx: { baseToken, chainIdL2: ctx.chainIdL2 } }
688
+ );
689
+ const ethBal = await wrapAs3(
690
+ "RPC",
691
+ OP_DEPOSITS.ethNonBase.ethBalance,
692
+ () => ctx.client.l1.getBalance({ address: ctx.sender }),
693
+ {
694
+ ctx: { where: "l1.getBalance", sender: ctx.sender },
695
+ message: "Failed to read L1 ETH balance."
696
+ }
697
+ );
698
+ await wrapAs3(
699
+ "VALIDATION",
700
+ OP_DEPOSITS.ethNonBase.assertEthBalance,
701
+ () => {
702
+ if (ethBal < p.amount) {
703
+ throw new Error("Insufficient L1 ETH balance to cover deposit amount.");
704
+ }
705
+ },
706
+ { ctx: { required: p.amount.toString(), balance: ethBal.toString() } }
707
+ );
708
+ return;
709
+ },
710
+ async build(p, ctx) {
711
+ const { gasPriceForBaseCost } = ctx.fee;
712
+ const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
713
+ const baseToken = await wrapAs3(
714
+ "CONTRACT",
715
+ OP_DEPOSITS.ethNonBase.baseToken,
716
+ () => ctx.client.l1.readContract({
717
+ address: ctx.bridgehub,
718
+ abi: IBridgehub_default,
719
+ functionName: "baseToken",
720
+ args: [ctx.chainIdL2]
721
+ }),
722
+ {
723
+ ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
724
+ message: "Failed to read base token."
725
+ }
726
+ );
727
+ const rawBaseCost = await wrapAs3(
728
+ "CONTRACT",
729
+ OP_DEPOSITS.ethNonBase.baseCost,
730
+ () => ctx.client.l1.readContract({
731
+ address: ctx.bridgehub,
732
+ abi: IBridgehub_default,
733
+ functionName: "l2TransactionBaseCost",
734
+ args: [ctx.chainIdL2, gasPriceForBaseCost, ctx.l2GasLimit, ctx.gasPerPubdata]
735
+ }),
736
+ {
737
+ ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
738
+ message: "Could not fetch L2 base cost."
739
+ }
740
+ );
741
+ const baseCost = BigInt(rawBaseCost);
742
+ const mintValueRaw = baseCost + ctx.operatorTip;
743
+ const mintValue = withBuffer2(mintValueRaw);
744
+ const approvals = [];
745
+ const steps = [];
746
+ const allowance = await wrapAs3(
747
+ "CONTRACT",
748
+ OP_DEPOSITS.ethNonBase.allowanceBase,
749
+ () => ctx.client.l1.readContract({
750
+ address: baseToken,
751
+ abi: IERC20_default,
752
+ functionName: "allowance",
753
+ args: [ctx.sender, ctx.l1AssetRouter]
754
+ }),
755
+ {
756
+ ctx: { where: "erc20.allowance", token: baseToken, spender: ctx.l1AssetRouter },
757
+ message: "Failed to read base-token allowance."
758
+ }
759
+ );
760
+ const needsApprove = allowance < mintValue;
761
+ if (needsApprove) {
762
+ const approveSim = await wrapAs3(
763
+ "CONTRACT",
764
+ OP_DEPOSITS.ethNonBase.estGas,
765
+ () => ctx.client.l1.simulateContract({
766
+ address: baseToken,
767
+ abi: IERC20_default,
768
+ functionName: "approve",
769
+ args: [ctx.l1AssetRouter, mintValue],
770
+ account: ctx.client.account
771
+ }),
772
+ {
773
+ ctx: { where: "l1.simulateContract", to: baseToken },
774
+ message: "Failed to simulate base-token approve."
775
+ }
776
+ );
777
+ approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
778
+ steps.push({
779
+ key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
780
+ kind: "approve",
781
+ description: `Approve base token for mintValue`,
782
+ tx: { ...approveSim.request }
783
+ });
784
+ }
785
+ const secondBridgeCalldata = await wrapAs3(
786
+ "INTERNAL",
787
+ OP_DEPOSITS.ethNonBase.encodeCalldata,
788
+ () => Promise.resolve(encodeSecondBridgeEthArgs(p.amount, p.to ?? ctx.sender)),
789
+ {
790
+ ctx: {
791
+ where: "encodeSecondBridgeEthArgs",
792
+ amount: p.amount.toString(),
793
+ to: p.to ?? ctx.sender
794
+ },
795
+ message: "Failed to encode ETH bridging calldata."
796
+ }
797
+ );
798
+ const outer = {
799
+ chainId: ctx.chainIdL2,
800
+ mintValue,
801
+ l2Value: 0n,
802
+ l2GasLimit: ctx.l2GasLimit,
803
+ l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
804
+ refundRecipient: ctx.refundRecipient,
805
+ secondBridgeAddress: ctx.l1AssetRouter,
806
+ secondBridgeValue: p.amount,
807
+ secondBridgeCalldata
808
+ };
809
+ let bridgeTx;
810
+ let resolvedL1GasLimit;
811
+ if (needsApprove) {
812
+ bridgeTx = {
813
+ address: ctx.bridgehub,
814
+ abi: IBridgehub_default,
815
+ functionName: "requestL2TransactionTwoBridges",
816
+ args: [outer],
817
+ value: p.amount,
818
+ // base ≠ ETH ⇒ msg.value == secondBridgeValue
819
+ account: ctx.client.account
820
+ };
821
+ resolvedL1GasLimit = ctx.l2GasLimit;
822
+ } else {
823
+ const twoBridgesSim = await wrapAs3(
824
+ "CONTRACT",
825
+ OP_DEPOSITS.ethNonBase.estGas,
826
+ () => ctx.client.l1.simulateContract({
827
+ address: ctx.bridgehub,
828
+ abi: IBridgehub_default,
829
+ functionName: "requestL2TransactionTwoBridges",
830
+ args: [outer],
831
+ value: p.amount,
832
+ // base ≠ ETH ⇒ msg.value == secondBridgeValue
833
+ account: ctx.client.account
834
+ }),
835
+ {
836
+ ctx: { where: "l1.simulateContract", to: ctx.bridgehub },
837
+ message: "Failed to simulate Bridgehub two-bridges request."
838
+ }
839
+ );
840
+ bridgeTx = { ...twoBridgesSim.request, ...txFeeOverrides };
841
+ resolvedL1GasLimit = twoBridgesSim.request.gas ?? ctx.l2GasLimit;
842
+ }
843
+ steps.push({
844
+ key: "bridgehub:two-bridges:eth-nonbase",
845
+ kind: "bridgehub:two-bridges",
846
+ description: "Bridge ETH (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
847
+ tx: bridgeTx
848
+ });
849
+ return {
850
+ steps,
851
+ approvals,
852
+ quoteExtras: { baseCost, mintValue, l1GasLimit: resolvedL1GasLimit }
853
+ };
854
+ }
855
+ };
856
+ }
857
+
858
+ // src/adapters/viem/resources/deposits/routes/erc20-base.ts
859
+ var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
860
+ var BASE_COST_BUFFER_BPS3 = 100n;
861
+ var BPS3 = 10000n;
862
+ var withBuffer3 = (x) => x * (BPS3 + BASE_COST_BUFFER_BPS3) / BPS3;
863
+ function routeErc20Base() {
864
+ return {
865
+ async preflight(p, ctx) {
866
+ await wrapAs4(
867
+ "VALIDATION",
868
+ OP_DEPOSITS.base.assertErc20Asset,
869
+ () => {
870
+ if (isETH(p.token)) {
871
+ throw new Error("erc20-base route requires an ERC-20 token (not ETH).");
872
+ }
873
+ },
874
+ { ctx: { token: p.token } }
875
+ );
876
+ const baseToken = await wrapAs4(
877
+ "CONTRACT",
878
+ OP_DEPOSITS.base.baseToken,
879
+ () => ctx.client.l1.readContract({
880
+ address: ctx.bridgehub,
881
+ abi: IBridgehub_default,
882
+ functionName: "baseToken",
883
+ args: [ctx.chainIdL2]
884
+ }),
885
+ {
886
+ ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
887
+ message: "Failed to read base token."
888
+ }
889
+ );
890
+ await wrapAs4(
891
+ "VALIDATION",
892
+ OP_DEPOSITS.base.assertMatchesBase,
893
+ () => {
894
+ if (!normalizeAddrEq(baseToken, p.token)) {
895
+ throw new Error("Provided token is not the base token for the target chain.");
896
+ }
897
+ },
898
+ { ctx: { baseToken, provided: p.token, chainIdL2: ctx.chainIdL2 } }
899
+ );
900
+ return;
901
+ },
902
+ async build(p, ctx) {
903
+ const { gasPriceForBaseCost } = ctx.fee;
904
+ const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
905
+ const gasOverride = txFeeOverrides.gas;
906
+ const baseToken = await wrapAs4(
907
+ "CONTRACT",
908
+ OP_DEPOSITS.base.baseToken,
909
+ () => ctx.client.l1.readContract({
910
+ address: ctx.bridgehub,
911
+ abi: IBridgehub_default,
912
+ functionName: "baseToken",
913
+ args: [ctx.chainIdL2]
914
+ }),
915
+ {
916
+ ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
917
+ message: "Failed to read base token."
918
+ }
919
+ );
920
+ const rawBaseCost = await wrapAs4(
921
+ "CONTRACT",
922
+ OP_DEPOSITS.base.baseCost,
923
+ () => ctx.client.l1.readContract({
924
+ address: ctx.bridgehub,
925
+ abi: IBridgehub_default,
926
+ functionName: "l2TransactionBaseCost",
927
+ args: [ctx.chainIdL2, gasPriceForBaseCost, ctx.l2GasLimit, ctx.gasPerPubdata]
928
+ }),
929
+ {
930
+ ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
931
+ message: "Could not fetch L2 base cost from Bridgehub."
932
+ }
933
+ );
934
+ const baseCost = rawBaseCost;
935
+ const l2Value = p.amount;
936
+ const rawMintValue = baseCost + ctx.operatorTip + l2Value;
937
+ const mintValue = withBuffer3(rawMintValue);
938
+ const allowance = await wrapAs4(
939
+ "CONTRACT",
940
+ OP_DEPOSITS.base.allowance,
941
+ () => ctx.client.l1.readContract({
942
+ address: baseToken,
943
+ abi: IERC20_default,
944
+ functionName: "allowance",
945
+ args: [ctx.sender, ctx.l1AssetRouter]
946
+ }),
947
+ {
948
+ ctx: { where: "erc20.allowance", token: baseToken, spender: ctx.l1AssetRouter },
949
+ message: "Failed to read base-token allowance."
950
+ }
951
+ );
952
+ const approvals = [];
953
+ const steps = [];
954
+ const needsApprove = allowance < mintValue;
955
+ if (needsApprove) {
956
+ const approveSim = await wrapAs4(
957
+ "CONTRACT",
958
+ OP_DEPOSITS.base.estGas,
959
+ () => ctx.client.l1.simulateContract({
960
+ address: baseToken,
961
+ abi: IERC20_default,
962
+ functionName: "approve",
963
+ args: [ctx.l1AssetRouter, mintValue],
964
+ account: ctx.client.account
965
+ }),
966
+ {
967
+ ctx: { where: "l1.simulateContract", to: baseToken },
968
+ message: "Failed to simulate ERC-20 approve."
969
+ }
970
+ );
971
+ approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
972
+ steps.push({
973
+ key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
974
+ kind: "approve",
975
+ description: "Approve base token for mintValue",
976
+ tx: { ...approveSim.request, ...txFeeOverrides }
977
+ });
978
+ }
979
+ const req = buildDirectRequestStruct({
980
+ chainId: ctx.chainIdL2,
981
+ mintValue,
982
+ l2GasLimit: ctx.l2GasLimit,
983
+ gasPerPubdata: ctx.gasPerPubdata,
984
+ refundRecipient: ctx.refundRecipient,
985
+ l2Contract: p.to ?? ctx.sender,
986
+ l2Value
987
+ });
988
+ let bridgeTx;
989
+ let resolvedL1GasLimit;
990
+ if (needsApprove) {
991
+ bridgeTx = {
992
+ address: ctx.bridgehub,
993
+ abi: IBridgehub_default,
994
+ functionName: "requestL2TransactionDirect",
995
+ args: [req],
996
+ value: 0n,
997
+ // base is ERC-20 ⇒ msg.value MUST be 0
998
+ account: ctx.client.account,
999
+ ...txFeeOverrides
1000
+ };
1001
+ resolvedL1GasLimit = gasOverride ?? ctx.l2GasLimit;
1002
+ } else {
1003
+ const sim = await wrapAs4(
1004
+ "RPC",
1005
+ OP_DEPOSITS.base.estGas,
1006
+ () => ctx.client.l1.simulateContract({
1007
+ address: ctx.bridgehub,
1008
+ abi: IBridgehub_default,
1009
+ functionName: "requestL2TransactionDirect",
1010
+ args: [req],
1011
+ value: 0n,
1012
+ account: ctx.client.account
1013
+ }),
1014
+ {
1015
+ ctx: { where: "l1.simulateContract", to: ctx.bridgehub },
1016
+ message: "Failed to simulate Bridgehub.requestL2TransactionDirect."
1017
+ }
1018
+ );
1019
+ bridgeTx = { ...sim.request, ...txFeeOverrides };
1020
+ resolvedL1GasLimit = sim.request.gas ?? ctx.l2GasLimit;
1021
+ }
1022
+ steps.push({
1023
+ key: "bridgehub:direct:erc20-base",
1024
+ kind: "bridgehub:direct",
1025
+ description: "Bridge base ERC-20 via Bridgehub.requestL2TransactionDirect",
1026
+ tx: bridgeTx
1027
+ });
1028
+ return {
1029
+ steps,
1030
+ approvals,
1031
+ quoteExtras: { baseCost, mintValue, l1GasLimit: resolvedL1GasLimit }
1032
+ };
1033
+ }
1034
+ };
1035
+ }
1036
+ var I_BRIDGEHUB_NEW_PRIORITY_REQUEST = {
1037
+ type: "event",
1038
+ name: "NewPriorityRequest",
1039
+ inputs: [
1040
+ { name: "chainId", type: "uint256", indexed: true },
1041
+ { name: "sender", type: "address", indexed: true },
1042
+ { name: "txHash", type: "bytes32", indexed: false },
1043
+ { name: "txId", type: "uint256", indexed: false },
1044
+ { name: "data", type: "bytes", indexed: false }
1045
+ ]
1046
+ };
1047
+ function extractL2TxHashFromL1Logs(logs) {
1048
+ for (const lg of logs) {
1049
+ try {
1050
+ const parsed = decodeEventLog({
1051
+ abi: [I_BRIDGEHUB_NEW_PRIORITY_REQUEST],
1052
+ data: lg.data,
1053
+ topics: lg.topics,
1054
+ strict: false
1055
+ });
1056
+ if (parsed?.eventName === "NewPriorityRequest") {
1057
+ const h = parsed.args?.txHash;
1058
+ if (h && isHash66(h)) return h;
1059
+ }
1060
+ } catch {
1061
+ }
1062
+ }
1063
+ for (const lg of logs) {
1064
+ const t0 = (lg.topics?.[0] ?? "0x").toLowerCase();
1065
+ if (t0 === TOPIC_CANONICAL_ASSIGNED.toLowerCase()) {
1066
+ const h = lg.topics?.[2];
1067
+ if (h && isHash66(h)) return h;
1068
+ }
1069
+ if (t0 === TOPIC_CANONICAL_SUCCESS.toLowerCase()) {
1070
+ const h = lg.topics?.[3];
1071
+ if (h && isHash66(h)) return h;
1072
+ }
1073
+ }
1074
+ return null;
1075
+ }
1076
+ async function waitForL2ExecutionFromL1Tx(l1, l2, l1TxHash) {
1077
+ const l1Receipt = await l1.waitForTransactionReceipt({ hash: l1TxHash });
1078
+ if (!l1Receipt) throw new Error("No L1 receipt found");
1079
+ const l2TxHash = extractL2TxHashFromL1Logs(l1Receipt.logs);
1080
+ if (!l2TxHash) {
1081
+ throw createError("VERIFICATION", {
1082
+ message: "Failed to extract L2 transaction hash from L1 logs",
1083
+ resource: "deposits",
1084
+ operation: "deposits.wait",
1085
+ context: { l1TxHash, logCount: l1Receipt.logs?.length ?? 0 }
1086
+ });
1087
+ }
1088
+ let l2Receipt = await l2.waitForTransactionReceipt({ hash: l2TxHash }).catch(() => null);
1089
+ if (!l2Receipt) {
1090
+ const maybe = await l2.getTransactionReceipt({ hash: l2TxHash }).catch(() => null);
1091
+ if (!maybe) {
1092
+ throw createError("VERIFICATION", {
1093
+ message: "L2 transaction was not found after waiting for its execution",
1094
+ resource: "deposits",
1095
+ operation: "deposits.wait",
1096
+ context: { l1TxHash, l2TxHash, where: "l2.waitForTransactionReceipt" }
1097
+ });
1098
+ }
1099
+ l2Receipt = maybe;
1100
+ }
1101
+ if (l2Receipt.status !== "success") {
1102
+ throw createError("VERIFICATION", {
1103
+ message: "L2 transaction execution failed",
1104
+ resource: "deposits",
1105
+ operation: "deposits.wait",
1106
+ context: { l1TxHash, l2TxHash, status: l2Receipt.status }
1107
+ });
1108
+ }
1109
+ return { l2Receipt, l2TxHash };
1110
+ }
1111
+
1112
+ // src/adapters/viem/resources/deposits/index.ts
1113
+ var { wrap, toResult } = createErrorHandlers("deposits");
1114
+ var ROUTES = {
1115
+ "eth-base": routeEthDirect(),
1116
+ "eth-nonbase": routeEthNonBase(),
1117
+ "erc20-nonbase": routeErc20NonBase(),
1118
+ "erc20-base": routeErc20Base()
1119
+ };
1120
+ function createDepositsResource(client) {
1121
+ async function buildPlan(p) {
1122
+ const ctx = await commonCtx(p, client);
1123
+ const route = ctx.route;
1124
+ await ROUTES[route].preflight?.(p, ctx);
1125
+ const { steps, approvals, quoteExtras } = await ROUTES[route].build(p, ctx);
1126
+ const { baseCost, mintValue } = quoteExtras;
1127
+ const fallbackGasLimit = quoteExtras.l1GasLimit;
1128
+ const resolveGasLimit = () => {
1129
+ if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
1130
+ for (let i = steps.length - 1; i >= 0; i--) {
1131
+ const candidate = steps[i].tx.gas;
1132
+ if (candidate != null) return candidate;
1133
+ }
1134
+ if (fallbackGasLimit != null) return fallbackGasLimit;
1135
+ return ctx.l2GasLimit;
1136
+ };
1137
+ const gasLimit = resolveGasLimit();
1138
+ return {
1139
+ route: ctx.route,
1140
+ summary: {
1141
+ route: ctx.route,
1142
+ approvalsNeeded: approvals,
1143
+ baseCost,
1144
+ mintValue,
1145
+ gasPerPubdata: ctx.gasPerPubdata,
1146
+ fees: {
1147
+ gasLimit,
1148
+ maxFeePerGas: ctx.fee.maxFeePerGas,
1149
+ maxPriorityFeePerGas: ctx.fee.maxPriorityFeePerGas
1150
+ }
1151
+ },
1152
+ steps
1153
+ };
1154
+ }
1155
+ const quote = async (p) => wrap(
1156
+ OP_DEPOSITS.quote,
1157
+ async () => {
1158
+ const plan = await buildPlan(p);
1159
+ return plan.summary;
1160
+ },
1161
+ {
1162
+ message: "Internal error while preparing a deposit quote.",
1163
+ ctx: { token: p.token, where: "deposits.quote" }
1164
+ }
1165
+ );
1166
+ const tryQuote = (p) => toResult(OP_DEPOSITS.tryQuote, () => quote(p), {
1167
+ message: "Internal error while preparing a deposit quote.",
1168
+ ctx: { token: p.token, where: "deposits.tryQuote" }
1169
+ });
1170
+ const prepare = (p) => wrap(OP_DEPOSITS.prepare, () => buildPlan(p), {
1171
+ message: "Internal error while preparing a deposit plan.",
1172
+ ctx: { token: p.token, where: "deposits.prepare" }
1173
+ });
1174
+ const tryPrepare = (p) => toResult(OP_DEPOSITS.tryPrepare, () => prepare(p), {
1175
+ ctx: { token: p.token, where: "deposits.tryPrepare" }
1176
+ });
1177
+ const create = (p) => wrap(
1178
+ OP_DEPOSITS.create,
1179
+ async () => {
1180
+ const plan = await prepare(p);
1181
+ const stepHashes = {};
1182
+ const from = client.account.address;
1183
+ let next = await client.l1.getTransactionCount({ address: from, blockTag: "latest" });
1184
+ for (const step of plan.steps) {
1185
+ if (step.kind === "approve") {
1186
+ try {
1187
+ const [, token, router] = step.key.split(":");
1188
+ const current = await client.l1.readContract({
1189
+ address: token,
1190
+ abi: IERC20_default,
1191
+ functionName: "allowance",
1192
+ args: [from, router]
1193
+ });
1194
+ const target = plan.summary.approvalsNeeded.find(
1195
+ (need) => need.token.toLowerCase() === (token ?? "").toLowerCase() && need.spender.toLowerCase() === (router ?? "").toLowerCase()
1196
+ )?.amount ?? 0n;
1197
+ if (current >= target) {
1198
+ continue;
1199
+ }
1200
+ } catch (e) {
1201
+ throw toZKsyncError(
1202
+ "CONTRACT",
1203
+ {
1204
+ resource: "deposits",
1205
+ operation: "deposits.create.erc20-allowance-recheck",
1206
+ context: { where: "erc20.allowance(recheck)", step: step.key, from },
1207
+ message: "Failed to read ERC-20 allowance during deposit step."
1208
+ },
1209
+ e
1210
+ );
1211
+ }
1212
+ }
1213
+ if (p.l1TxOverrides) {
1214
+ const overrides = p.l1TxOverrides;
1215
+ if (overrides.maxFeePerGas != null) {
1216
+ step.tx.maxFeePerGas = overrides.maxFeePerGas;
1217
+ }
1218
+ if (overrides.maxPriorityFeePerGas != null) {
1219
+ step.tx.maxPriorityFeePerGas = overrides.maxPriorityFeePerGas;
1220
+ }
1221
+ if (overrides.gasLimit != null) {
1222
+ step.tx.gas = overrides.gasLimit;
1223
+ }
1224
+ }
1225
+ if (step.tx.gas == null) {
1226
+ try {
1227
+ const feePart = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
1228
+ maxFeePerGas: step.tx.maxFeePerGas,
1229
+ maxPriorityFeePerGas: step.tx.maxPriorityFeePerGas
1230
+ } : {};
1231
+ const params = {
1232
+ address: step.tx.address,
1233
+ abi: step.tx.abi,
1234
+ functionName: step.tx.functionName,
1235
+ args: step.tx.args,
1236
+ account: step.tx.account ?? client.account,
1237
+ ...step.tx.value != null ? { value: step.tx.value } : {},
1238
+ maxFeePerGas: step.tx.maxFeePerGas,
1239
+ maxPriorityFeePerGas: step.tx.maxPriorityFeePerGas,
1240
+ ...feePart
1241
+ };
1242
+ const gas = await client.l1.estimateContractGas({
1243
+ ...params
1244
+ });
1245
+ step.tx.gas = gas * 115n / 100n;
1246
+ } catch {
1247
+ }
1248
+ }
1249
+ const nonce = next++;
1250
+ const fee1559 = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
1251
+ maxFeePerGas: step.tx.maxFeePerGas,
1252
+ maxPriorityFeePerGas: step.tx.maxPriorityFeePerGas
1253
+ } : {};
1254
+ const baseReq = {
1255
+ address: step.tx.address,
1256
+ abi: step.tx.abi,
1257
+ functionName: step.tx.functionName,
1258
+ args: step.tx.args,
1259
+ account: step.tx.account ?? client.account,
1260
+ gas: step.tx.gas,
1261
+ nonce,
1262
+ ...fee1559,
1263
+ ...step.tx.dataSuffix ? { dataSuffix: step.tx.dataSuffix } : {},
1264
+ ...step.tx.chain ? { chain: step.tx.chain } : {}
1265
+ };
1266
+ const req = step.tx.value != null ? { ...baseReq, value: step.tx.value } : baseReq;
1267
+ let hash;
1268
+ try {
1269
+ hash = await client.l1Wallet.writeContract(req);
1270
+ stepHashes[step.key] = hash;
1271
+ const rcpt = await client.l1.waitForTransactionReceipt({ hash });
1272
+ if (!rcpt || rcpt.status !== "success") {
1273
+ throw createError("EXECUTION", {
1274
+ resource: "deposits",
1275
+ operation: "deposits.create.writeContract",
1276
+ message: "Deposit transaction reverted on L1 during a step.",
1277
+ context: { step: step.key, txHash: hash, status: rcpt?.status }
1278
+ });
1279
+ }
1280
+ } catch (e) {
1281
+ if (isZKsyncError(e)) throw e;
1282
+ throw toZKsyncError(
1283
+ "EXECUTION",
1284
+ {
1285
+ resource: "deposits",
1286
+ operation: "deposits.create.writeContract",
1287
+ context: { step: step.key, txHash: hash, nonce },
1288
+ message: "Failed to send or confirm a deposit transaction step."
1289
+ },
1290
+ e
1291
+ );
1292
+ }
1293
+ }
1294
+ const ordered = Object.entries(stepHashes);
1295
+ const last = ordered[ordered.length - 1][1];
1296
+ return { kind: "deposit", l1TxHash: last, stepHashes, plan };
1297
+ },
1298
+ {
1299
+ message: "Internal error while creating a deposit.",
1300
+ ctx: { token: p.token, amount: p.amount, to: p.to, where: "deposits.create" }
1301
+ }
1302
+ );
1303
+ const tryCreate = (p) => toResult(OP_DEPOSITS.tryCreate, () => create(p), {
1304
+ message: "Internal error while creating a deposit.",
1305
+ ctx: { token: p.token, amount: p.amount, to: p.to, where: "deposits.tryCreate" }
1306
+ });
1307
+ const status = (h) => wrap(
1308
+ OP_DEPOSITS.status,
1309
+ async () => {
1310
+ const l1TxHash = typeof h === "string" ? h : h.l1TxHash;
1311
+ if (!l1TxHash) return { phase: "UNKNOWN", l1TxHash: "0x" };
1312
+ let l1Rcpt;
1313
+ try {
1314
+ l1Rcpt = await client.l1.getTransactionReceipt({ hash: l1TxHash });
1315
+ } catch (e) {
1316
+ throw toZKsyncError(
1317
+ "RPC",
1318
+ {
1319
+ resource: "deposits",
1320
+ operation: "deposits.status.getTransactionReceipt",
1321
+ context: { where: "l1.getTransactionReceipt", l1TxHash },
1322
+ message: "Failed to fetch L1 transaction receipt."
1323
+ },
1324
+ e
1325
+ );
1326
+ }
1327
+ if (!l1Rcpt) return { phase: "L1_PENDING", l1TxHash };
1328
+ let l2TxHash;
1329
+ try {
1330
+ l2TxHash = extractL2TxHashFromL1Logs(l1Rcpt.logs) ?? void 0;
1331
+ } catch (e) {
1332
+ throw toZKsyncError(
1333
+ "INTERNAL",
1334
+ {
1335
+ resource: "deposits",
1336
+ operation: "deposits.status.extractL2TxHashFromL1Logs",
1337
+ context: { where: "extractL2TxHashFromL1Logs", l1TxHash },
1338
+ message: "Failed to derive L2 transaction hash from L1 logs."
1339
+ },
1340
+ e
1341
+ );
1342
+ }
1343
+ if (!l2TxHash) return { phase: "L1_INCLUDED", l1TxHash };
1344
+ let l2Rcpt;
1345
+ try {
1346
+ l2Rcpt = await client.l2.getTransactionReceipt({ hash: l2TxHash });
1347
+ } catch (e) {
1348
+ if (isReceiptNotFound(e)) {
1349
+ return { phase: "L2_PENDING", l1TxHash, l2TxHash };
1350
+ }
1351
+ throw toZKsyncError(
1352
+ "RPC",
1353
+ {
1354
+ resource: "deposits",
1355
+ operation: "deposits.status.getTransactionReceipt",
1356
+ message: "Failed to fetch L2 transaction receipt.",
1357
+ context: { l2TxHash, where: "l2.getTransactionReceipt" }
1358
+ },
1359
+ e
1360
+ );
1361
+ }
1362
+ if (!l2Rcpt) return { phase: "L2_PENDING", l1TxHash, l2TxHash };
1363
+ const ok = l2Rcpt.status === "success";
1364
+ return ok ? { phase: "L2_EXECUTED", l1TxHash, l2TxHash } : { phase: "L2_FAILED", l1TxHash, l2TxHash };
1365
+ },
1366
+ {
1367
+ message: "Internal error while checking deposit status.",
1368
+ ctx: { input: h, where: "deposits.status" }
1369
+ }
1370
+ );
1371
+ const wait = (h, opts) => wrap(
1372
+ OP_DEPOSITS.wait,
1373
+ async () => {
1374
+ const l1Hash = typeof h === "string" ? h : "l1TxHash" in h ? h.l1TxHash : void 0;
1375
+ if (!l1Hash) return null;
1376
+ let l1Receipt;
1377
+ try {
1378
+ l1Receipt = await client.l1.waitForTransactionReceipt({ hash: l1Hash });
1379
+ } catch (e) {
1380
+ throw toZKsyncError(
1381
+ "RPC",
1382
+ {
1383
+ resource: "deposits",
1384
+ operation: "deposits.waitForTransaction",
1385
+ context: { where: "l1.waitForTransactionReceipt", l1TxHash: l1Hash, for: opts.for },
1386
+ message: "Failed while waiting for L1 transaction."
1387
+ },
1388
+ e
1389
+ );
1390
+ }
1391
+ if (!l1Receipt) return null;
1392
+ if (opts.for === "l1") return l1Receipt;
1393
+ try {
1394
+ const { l2Receipt } = await waitForL2ExecutionFromL1Tx(client.l1, client.l2, l1Hash);
1395
+ return l2Receipt ?? null;
1396
+ } catch (e) {
1397
+ if (isZKsyncError(e)) throw e;
1398
+ throw toZKsyncError(
1399
+ "INTERNAL",
1400
+ {
1401
+ resource: "deposits",
1402
+ operation: "deposits.waitForL2ExecutionFromL1Tx",
1403
+ context: { where: "waitForL2ExecutionFromL1Tx", l1TxHash: l1Hash },
1404
+ message: "Internal error while waiting for L2 execution."
1405
+ },
1406
+ e
1407
+ );
1408
+ }
1409
+ },
1410
+ {
1411
+ message: "Internal error while waiting for deposit.",
1412
+ ctx: { input: h, for: opts?.for, where: "deposits.wait" }
1413
+ }
1414
+ );
1415
+ const tryWait = (h, opts) => toResult(
1416
+ OP_DEPOSITS.tryWait,
1417
+ async () => {
1418
+ const v = await wait(h, opts);
1419
+ if (v) return v;
1420
+ throw createError("STATE", {
1421
+ resource: "deposits",
1422
+ operation: "deposits.tryWait",
1423
+ message: opts.for === "l2" ? "No L2 receipt yet; the deposit has not executed on L2." : "No L1 receipt yet; the deposit has not been included on L1.",
1424
+ context: {
1425
+ for: opts.for,
1426
+ l1TxHash: typeof h === "string" ? h : "l1TxHash" in h ? h.l1TxHash : void 0,
1427
+ where: "deposits.tryWait"
1428
+ }
1429
+ });
1430
+ },
1431
+ {
1432
+ message: "Internal error while waiting for deposit.",
1433
+ ctx: { input: h, for: opts?.for, where: "deposits.tryWait" }
1434
+ }
1435
+ );
1436
+ return { quote, tryQuote, prepare, tryPrepare, create, tryCreate, status, wait, tryWait };
1437
+ }
1438
+
1439
+ // src/adapters/viem/resources/token-info.ts
1440
+ async function ntvBaseAssetId(l2, ntv) {
1441
+ return l2.readContract({
1442
+ address: ntv,
1443
+ abi: L2NativeTokenVault_default,
1444
+ functionName: "BASE_TOKEN_ASSET_ID"
1445
+ });
1446
+ }
1447
+ async function ntvL1ChainId(l2, ntv) {
1448
+ return l2.readContract({
1449
+ address: ntv,
1450
+ abi: L2NativeTokenVault_default,
1451
+ functionName: "L1_CHAIN_ID"
1452
+ });
1453
+ }
1454
+ async function isEthBasedChain(l2, ntv) {
1455
+ const [baseAssetId, l1ChainId] = await Promise.all([
1456
+ ntvBaseAssetId(l2, ntv),
1457
+ ntvL1ChainId(l2, ntv)
1458
+ ]);
1459
+ const ethAssetId = encodeNativeTokenVaultAssetId(l1ChainId, ETH_ADDRESS);
1460
+ return baseAssetId.toLowerCase() === ethAssetId.toLowerCase();
1461
+ }
1462
+
1463
+ // src/adapters/viem/resources/withdrawals/context.ts
1464
+ async function commonCtx2(p, client) {
1465
+ const sender = client.account.address;
1466
+ const {
1467
+ bridgehub,
1468
+ l1AssetRouter,
1469
+ l1Nullifier,
1470
+ l2AssetRouter,
1471
+ l2NativeTokenVault,
1472
+ l2BaseTokenSystem
1473
+ } = await client.ensureAddresses();
1474
+ const chainIdL2 = BigInt(await client.l2.getChainId());
1475
+ const baseIsEth = await isEthBasedChain(client.l2, l2NativeTokenVault);
1476
+ const fee = await getL2FeeOverrides(client, p.l2TxOverrides);
1477
+ const route = pickWithdrawRoute({
1478
+ token: p.token,
1479
+ baseIsEth
1480
+ });
1481
+ const l2GasLimit = p.l2GasLimit ?? 300000n;
1482
+ const gasBufferPct = 15;
1483
+ return {
1484
+ client,
1485
+ bridgehub,
1486
+ chainIdL2,
1487
+ sender,
1488
+ route,
1489
+ l1AssetRouter,
1490
+ l1Nullifier,
1491
+ l2AssetRouter,
1492
+ l2NativeTokenVault,
1493
+ l2BaseTokenSystem,
1494
+ baseIsEth,
1495
+ l2GasLimit,
1496
+ gasBufferPct,
1497
+ fee
1498
+ };
1499
+ }
1500
+
1501
+ // src/adapters/viem/resources/withdrawals/routes/eth.ts
1502
+ var { wrapAs: wrapAs5 } = createErrorHandlers("withdrawals");
1503
+ function routeEthBase() {
1504
+ return {
1505
+ async build(p, ctx) {
1506
+ const toL1 = p.to ?? ctx.sender;
1507
+ const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
1508
+ const sim = await wrapAs5(
1509
+ "CONTRACT",
1510
+ OP_WITHDRAWALS.eth.estGas,
1511
+ () => ctx.client.l2.simulateContract({
1512
+ address: L2_BASE_TOKEN_ADDRESS,
1513
+ abi: IBaseToken_default,
1514
+ functionName: "withdraw",
1515
+ args: [toL1],
1516
+ value: p.amount,
1517
+ account: ctx.client.account,
1518
+ ...txFeeOverrides
1519
+ }),
1520
+ {
1521
+ ctx: { where: "l2.simulateContract", to: L2_BASE_TOKEN_ADDRESS },
1522
+ message: "Failed to simulate L2 ETH withdraw."
1523
+ }
1524
+ );
1525
+ const steps = [
1526
+ {
1527
+ key: "l2-base-token:withdraw",
1528
+ kind: "l2-base-token:withdraw",
1529
+ description: "Withdraw ETH via L2 Base Token System",
1530
+ tx: { ...sim.request, ...txFeeOverrides }
1531
+ }
1532
+ ];
1533
+ return { steps, approvals: [], quoteExtras: {} };
1534
+ }
1535
+ };
1536
+ }
1537
+ var { wrapAs: wrapAs6 } = createErrorHandlers("withdrawals");
1538
+ function routeErc20NonBase2() {
1539
+ return {
1540
+ // TODO: add preflight validations here
1541
+ async build(p, ctx) {
1542
+ const toL1 = p.to ?? ctx.sender;
1543
+ const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
1544
+ const current = await wrapAs6(
1545
+ "CONTRACT",
1546
+ OP_WITHDRAWALS.erc20.allowance,
1547
+ () => ctx.client.l2.readContract({
1548
+ address: p.token,
1549
+ abi: IERC20_default,
1550
+ functionName: "allowance",
1551
+ args: [ctx.sender, ctx.l2NativeTokenVault],
1552
+ account: ctx.client.account
1553
+ }),
1554
+ {
1555
+ ctx: {
1556
+ where: "erc20.allowance",
1557
+ chain: "L2",
1558
+ token: p.token,
1559
+ spender: ctx.l2NativeTokenVault
1560
+ },
1561
+ message: "Failed to read L2 ERC-20 allowance."
1562
+ }
1563
+ );
1564
+ const needsApprove = current < p.amount;
1565
+ const steps = [];
1566
+ const approvals = [];
1567
+ if (needsApprove) {
1568
+ approvals.push({ token: p.token, spender: ctx.l2NativeTokenVault, amount: p.amount });
1569
+ const approveSim = await wrapAs6(
1570
+ "CONTRACT",
1571
+ OP_WITHDRAWALS.erc20.estGas,
1572
+ () => ctx.client.l2.simulateContract({
1573
+ address: p.token,
1574
+ abi: IERC20_default,
1575
+ functionName: "approve",
1576
+ args: [ctx.l2NativeTokenVault, p.amount],
1577
+ account: ctx.client.account,
1578
+ ...txFeeOverrides
1579
+ }),
1580
+ {
1581
+ ctx: { where: "l2.simulateContract", to: p.token },
1582
+ message: "Failed to simulate L2 ERC-20 approve."
1583
+ }
1584
+ );
1585
+ steps.push({
1586
+ key: `approve:l2:${p.token}:${ctx.l2NativeTokenVault}`,
1587
+ kind: "approve:l2",
1588
+ description: `Approve ${p.amount} to NativeTokenVault`,
1589
+ tx: { ...approveSim.request, ...txFeeOverrides }
1590
+ });
1591
+ }
1592
+ const ensure = await wrapAs6(
1593
+ "CONTRACT",
1594
+ OP_WITHDRAWALS.erc20.ensureRegistered,
1595
+ () => ctx.client.l2.simulateContract({
1596
+ address: ctx.l2NativeTokenVault,
1597
+ abi: L2NativeTokenVault_default,
1598
+ functionName: "ensureTokenIsRegistered",
1599
+ args: [p.token],
1600
+ account: ctx.client.account
1601
+ }),
1602
+ {
1603
+ ctx: { where: "L2NativeTokenVault.ensureTokenIsRegistered", token: p.token },
1604
+ message: "Failed to ensure token is registered in L2NativeTokenVault."
1605
+ }
1606
+ );
1607
+ const assetId = ensure.result;
1608
+ const assetData = encodeAbiParameters(
1609
+ [
1610
+ { type: "uint256", name: "amount" },
1611
+ { type: "address", name: "l1Receiver" },
1612
+ { type: "address", name: "l2Token" }
1613
+ ],
1614
+ [p.amount, toL1, p.token]
1615
+ );
1616
+ let withdrawTx;
1617
+ if (needsApprove) {
1618
+ withdrawTx = {
1619
+ address: ctx.l2AssetRouter,
1620
+ abi: IL2AssetRouter_default,
1621
+ functionName: "withdraw",
1622
+ args: [assetId, assetData],
1623
+ account: ctx.client.account,
1624
+ ...txFeeOverrides
1625
+ };
1626
+ } else {
1627
+ const sim = await wrapAs6(
1628
+ "CONTRACT",
1629
+ OP_WITHDRAWALS.erc20.estGas,
1630
+ () => ctx.client.l2.simulateContract({
1631
+ address: ctx.l2AssetRouter,
1632
+ abi: IL2AssetRouter_default,
1633
+ functionName: "withdraw",
1634
+ args: [assetId, assetData],
1635
+ account: ctx.client.account,
1636
+ ...txFeeOverrides
1637
+ }),
1638
+ {
1639
+ ctx: { where: "l2.simulateContract", to: ctx.l2AssetRouter },
1640
+ message: "Failed to simulate L2 ERC-20 withdraw."
1641
+ }
1642
+ );
1643
+ withdrawTx = { ...sim.request, ...txFeeOverrides };
1644
+ }
1645
+ steps.push({
1646
+ key: "l2-asset-router:withdraw",
1647
+ kind: "l2-asset-router:withdraw",
1648
+ description: "Burn on L2 & send L2\u2192L1 message",
1649
+ tx: withdrawTx
1650
+ });
1651
+ return { steps, approvals, quoteExtras: {} };
1652
+ }
1653
+ };
1654
+ }
1655
+
1656
+ // src/adapters/viem/resources/withdrawals/routes/eth-nonbase.ts
1657
+ var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
1658
+ function routeEthNonBase2() {
1659
+ return {
1660
+ async preflight(p, ctx) {
1661
+ await wrapAs7(
1662
+ "VALIDATION",
1663
+ OP_WITHDRAWALS.ethNonBase.assertNonEthBase,
1664
+ () => {
1665
+ if (p.token.toLowerCase() !== L2_BASE_TOKEN_ADDRESS.toLowerCase()) {
1666
+ throw new Error("eth-nonbase route requires the L2 base-token alias (0x\u2026800A).");
1667
+ }
1668
+ if (ctx.baseIsEth) {
1669
+ throw new Error("eth-nonbase route requires chain base \u2260 ETH.");
1670
+ }
1671
+ },
1672
+ { ctx: { token: p.token, baseIsEth: ctx.baseIsEth } }
1673
+ );
1674
+ },
1675
+ async build(p, ctx) {
1676
+ const toL1 = p.to ?? ctx.sender;
1677
+ const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
1678
+ const sim = await wrapAs7(
1679
+ "CONTRACT",
1680
+ OP_WITHDRAWALS.ethNonBase.estGas,
1681
+ () => ctx.client.l2.simulateContract({
1682
+ address: L2_BASE_TOKEN_ADDRESS,
1683
+ abi: IBaseToken_default,
1684
+ functionName: "withdraw",
1685
+ args: [toL1],
1686
+ value: p.amount,
1687
+ account: ctx.client.account,
1688
+ ...txFeeOverrides
1689
+ }),
1690
+ {
1691
+ ctx: { where: "l2.simulateContract", to: L2_BASE_TOKEN_ADDRESS },
1692
+ message: "Failed to simulate L2 base-token withdraw."
1693
+ }
1694
+ );
1695
+ const steps = [
1696
+ {
1697
+ key: "l2-base-token:withdraw",
1698
+ kind: "l2-base-token:withdraw",
1699
+ description: "Withdraw base token via L2 Base Token System (base \u2260 ETH)",
1700
+ tx: { ...sim.request, ...txFeeOverrides }
1701
+ }
1702
+ ];
1703
+ return { steps, approvals: [], quoteExtras: {} };
1704
+ }
1705
+ };
1706
+ }
1707
+ var { wrapAs: wrapAs8 } = createErrorHandlers("withdrawals");
1708
+ var IL1NullifierMini = [
1709
+ {
1710
+ type: "function",
1711
+ name: "isWithdrawalFinalized",
1712
+ stateMutability: "view",
1713
+ inputs: [
1714
+ { name: "chainId", type: "uint256" },
1715
+ { name: "l2BatchNumber", type: "uint256" },
1716
+ { name: "l2MessageIndex", type: "uint256" }
1717
+ ],
1718
+ outputs: [{ type: "bool" }]
1719
+ }
1720
+ ];
1721
+ function createFinalizationServices(client) {
1722
+ return {
1723
+ async fetchFinalizeDepositParams(l2TxHash) {
1724
+ const parsed = await wrapAs8(
1725
+ "RPC",
1726
+ OP_WITHDRAWALS.finalize.fetchParams.receipt,
1727
+ () => client.zks.getReceiptWithL2ToL1(l2TxHash),
1728
+ {
1729
+ ctx: { where: "getReceiptWithL2ToL1", l2TxHash },
1730
+ message: "Failed to fetch L2 receipt (with L2\u2192L1 logs)."
1731
+ }
1732
+ );
1733
+ if (!parsed) {
1734
+ throw createError("STATE", {
1735
+ resource: "withdrawals",
1736
+ operation: OP_WITHDRAWALS.finalize.fetchParams.receipt,
1737
+ message: "L2 receipt not found.",
1738
+ context: { l2TxHash }
1739
+ });
1740
+ }
1741
+ const ev = await wrapAs8(
1742
+ "INTERNAL",
1743
+ OP_WITHDRAWALS.finalize.fetchParams.findMessage,
1744
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
1745
+ () => Promise.resolve(findL1MessageSentLog(parsed, { index: 0 })),
1746
+ {
1747
+ ctx: { l2TxHash, index: 0 },
1748
+ message: "Failed to locate L1MessageSent event in L2 receipt."
1749
+ }
1750
+ );
1751
+ const message = await wrapAs8(
1752
+ "INTERNAL",
1753
+ OP_WITHDRAWALS.finalize.fetchParams.decodeMessage,
1754
+ () => {
1755
+ const [decoded] = decodeAbiParameters([{ type: "bytes" }], ev.data);
1756
+ return decoded;
1757
+ },
1758
+ {
1759
+ ctx: { where: "decode L1MessageSent", data: ev.data },
1760
+ message: "Failed to decode withdrawal message."
1761
+ }
1762
+ );
1763
+ const raw = await wrapAs8(
1764
+ "RPC",
1765
+ OP_WITHDRAWALS.finalize.fetchParams.rawReceipt,
1766
+ () => client.zks.getReceiptWithL2ToL1(l2TxHash),
1767
+ {
1768
+ ctx: { where: "getReceiptWithL2ToL1 (raw)", l2TxHash },
1769
+ message: "Failed to fetch raw L2 receipt."
1770
+ }
1771
+ );
1772
+ if (!raw) {
1773
+ throw createError("STATE", {
1774
+ resource: "withdrawals",
1775
+ operation: OP_WITHDRAWALS.finalize.fetchParams.rawReceipt,
1776
+ message: "Raw L2 receipt not found.",
1777
+ context: { l2TxHash }
1778
+ });
1779
+ }
1780
+ const idx = await wrapAs8(
1781
+ "INTERNAL",
1782
+ OP_WITHDRAWALS.finalize.fetchParams.messengerIndex,
1783
+ () => Promise.resolve(messengerLogIndex(raw, { index: 0, messenger: L1_MESSENGER_ADDRESS })),
1784
+ {
1785
+ ctx: { where: "derive messenger log index", l2TxHash, receipt: raw },
1786
+ message: "Failed to derive messenger log index."
1787
+ }
1788
+ );
1789
+ const proof = await wrapAs8(
1790
+ "RPC",
1791
+ OP_WITHDRAWALS.finalize.fetchParams.proof,
1792
+ () => client.zks.getL2ToL1LogProof(l2TxHash, idx),
1793
+ {
1794
+ ctx: { where: "get L2\u2192L1 log proof", l2TxHash, messengerLogIndex: idx },
1795
+ message: "Failed to fetch L2\u2192L1 log proof."
1796
+ }
1797
+ );
1798
+ const chainId = await wrapAs8(
1799
+ "RPC",
1800
+ OP_WITHDRAWALS.finalize.fetchParams.network,
1801
+ () => client.l2.getChainId(),
1802
+ { ctx: { where: "l2.getChainId" }, message: "Failed to read L2 chain id." }
1803
+ );
1804
+ const txIndex = Number(parsed.transactionIndex ?? 0);
1805
+ const params = {
1806
+ chainId: BigInt(chainId),
1807
+ l2BatchNumber: proof.batchNumber,
1808
+ l2MessageIndex: proof.id,
1809
+ l2Sender: L2_ASSET_ROUTER_ADDRESS,
1810
+ l2TxNumberInBatch: txIndex,
1811
+ message,
1812
+ merkleProof: proof.proof
1813
+ };
1814
+ const { l1Nullifier } = await wrapAs8(
1815
+ "INTERNAL",
1816
+ OP_WITHDRAWALS.finalize.fetchParams.ensureAddresses,
1817
+ () => client.ensureAddresses(),
1818
+ {
1819
+ ctx: { where: "ensureAddresses" },
1820
+ message: "Failed to ensure L1 Nullifier address."
1821
+ }
1822
+ );
1823
+ return { params, nullifier: l1Nullifier };
1824
+ },
1825
+ async simulateFinalizeReadiness(params) {
1826
+ const { l1Nullifier } = await wrapAs8(
1827
+ "INTERNAL",
1828
+ OP_WITHDRAWALS.finalize.readiness.ensureAddresses,
1829
+ () => client.ensureAddresses(),
1830
+ {
1831
+ ctx: { where: "ensureAddresses" },
1832
+ message: "Failed to ensure L1 Nullifier address."
1833
+ }
1834
+ );
1835
+ const done = await (async () => {
1836
+ try {
1837
+ const result = await wrapAs8(
1838
+ "RPC",
1839
+ OP_WITHDRAWALS.finalize.readiness.isFinalized,
1840
+ () => client.l1.readContract({
1841
+ address: l1Nullifier,
1842
+ abi: IL1NullifierMini,
1843
+ functionName: "isWithdrawalFinalized",
1844
+ args: [params.chainId, params.l2BatchNumber, params.l2MessageIndex]
1845
+ }),
1846
+ {
1847
+ ctx: { where: "isWithdrawalFinalized", params },
1848
+ message: "Failed to read finalization status."
1849
+ }
1850
+ );
1851
+ return result;
1852
+ } catch {
1853
+ return false;
1854
+ }
1855
+ })();
1856
+ if (done) return { kind: "FINALIZED" };
1857
+ try {
1858
+ await client.l1.simulateContract({
1859
+ address: l1Nullifier,
1860
+ abi: IL1Nullifier_default,
1861
+ functionName: "finalizeDeposit",
1862
+ args: [params],
1863
+ account: client.account
1864
+ });
1865
+ return { kind: "READY" };
1866
+ } catch (e) {
1867
+ return classifyReadinessFromRevert(e);
1868
+ }
1869
+ },
1870
+ async isWithdrawalFinalized(key) {
1871
+ const { l1Nullifier } = await wrapAs8(
1872
+ "INTERNAL",
1873
+ OP_WITHDRAWALS.finalize.fetchParams.ensureAddresses,
1874
+ () => client.ensureAddresses(),
1875
+ {
1876
+ ctx: { where: "ensureAddresses" },
1877
+ message: "Failed to ensure L1 Nullifier address."
1878
+ }
1879
+ );
1880
+ return await wrapAs8(
1881
+ "RPC",
1882
+ OP_WITHDRAWALS.finalize.isFinalized,
1883
+ () => client.l1.readContract({
1884
+ address: l1Nullifier,
1885
+ abi: IL1NullifierMini,
1886
+ functionName: "isWithdrawalFinalized",
1887
+ args: [key.chainIdL2, key.l2BatchNumber, key.l2MessageIndex]
1888
+ }),
1889
+ {
1890
+ ctx: { where: "isWithdrawalFinalized", key },
1891
+ message: "Failed to read finalization status."
1892
+ }
1893
+ );
1894
+ },
1895
+ async estimateFinalization(params) {
1896
+ const { l1Nullifier } = await wrapAs8(
1897
+ "INTERNAL",
1898
+ OP_WITHDRAWALS.finalize.estimate,
1899
+ () => client.ensureAddresses(),
1900
+ {
1901
+ ctx: { where: "ensureAddresses" },
1902
+ message: "Failed to ensure L1 Nullifier address."
1903
+ }
1904
+ );
1905
+ const gasLimit = await wrapAs8(
1906
+ "RPC",
1907
+ OP_WITHDRAWALS.finalize.estimate,
1908
+ () => client.l1.estimateContractGas({
1909
+ address: l1Nullifier,
1910
+ abi: IL1Nullifier_default,
1911
+ functionName: "finalizeDeposit",
1912
+ args: [params],
1913
+ account: client.account
1914
+ }),
1915
+ {
1916
+ ctx: {
1917
+ where: "estimateContractGas(finalizeDeposit)",
1918
+ chainIdL2: params.chainId,
1919
+ l2BatchNumber: params.l2BatchNumber,
1920
+ l2MessageIndex: params.l2MessageIndex,
1921
+ l1Nullifier
1922
+ },
1923
+ message: "Failed to estimate gas for finalizeDeposit."
1924
+ }
1925
+ );
1926
+ let maxFeePerGas;
1927
+ let maxPriorityFeePerGas;
1928
+ try {
1929
+ const fee = await wrapAs8(
1930
+ "RPC",
1931
+ OP_WITHDRAWALS.finalize.estimate,
1932
+ () => client.l1.estimateFeesPerGas(),
1933
+ {
1934
+ ctx: { where: "estimateFeesPerGas" },
1935
+ message: "Failed to estimate EIP-1559 fees."
1936
+ }
1937
+ );
1938
+ maxFeePerGas = fee.maxFeePerGas ?? (() => {
1939
+ throw createError("RPC", {
1940
+ resource: "withdrawals",
1941
+ operation: OP_WITHDRAWALS.finalize.estimate,
1942
+ message: "Provider did not return maxFeePerGas.",
1943
+ context: { fee }
1944
+ });
1945
+ })();
1946
+ maxPriorityFeePerGas = fee.maxPriorityFeePerGas ?? 0n;
1947
+ } catch {
1948
+ const gasPrice = await wrapAs8(
1949
+ "RPC",
1950
+ OP_WITHDRAWALS.finalize.estimate,
1951
+ () => client.l1.getGasPrice(),
1952
+ {
1953
+ ctx: { where: "getGasPrice" },
1954
+ message: "Failed to read gas price for finalizeDeposit."
1955
+ }
1956
+ );
1957
+ maxFeePerGas = gasPrice;
1958
+ maxPriorityFeePerGas = 0n;
1959
+ }
1960
+ return {
1961
+ gasLimit,
1962
+ maxFeePerGas,
1963
+ maxPriorityFeePerGas
1964
+ };
1965
+ },
1966
+ async finalizeDeposit(params) {
1967
+ const { l1Nullifier } = await wrapAs8(
1968
+ "INTERNAL",
1969
+ OP_WITHDRAWALS.finalize.fetchParams.ensureAddresses,
1970
+ () => client.ensureAddresses(),
1971
+ {
1972
+ ctx: { where: "ensureAddresses" },
1973
+ message: "Failed to ensure L1 Nullifier address."
1974
+ }
1975
+ );
1976
+ try {
1977
+ const hash = await client.l1Wallet.writeContract({
1978
+ address: l1Nullifier,
1979
+ abi: IL1Nullifier_default,
1980
+ functionName: "finalizeDeposit",
1981
+ args: [params],
1982
+ account: client.account
1983
+ });
1984
+ return {
1985
+ hash,
1986
+ wait: async () => {
1987
+ try {
1988
+ return await client.l1.waitForTransactionReceipt({ hash });
1989
+ } catch (e) {
1990
+ throw toZKsyncError(
1991
+ "EXECUTION",
1992
+ {
1993
+ resource: "withdrawals",
1994
+ operation: OP_WITHDRAWALS.finalize.wait,
1995
+ message: "Failed while waiting for finalizeDeposit transaction.",
1996
+ context: { txHash: hash }
1997
+ },
1998
+ e
1999
+ );
2000
+ }
2001
+ }
2002
+ };
2003
+ } catch (e) {
2004
+ throw toZKsyncError(
2005
+ "EXECUTION",
2006
+ {
2007
+ resource: "withdrawals",
2008
+ operation: OP_WITHDRAWALS.finalize.send,
2009
+ message: "Failed to send finalizeDeposit transaction.",
2010
+ context: {
2011
+ chainIdL2: params.chainId,
2012
+ l2BatchNumber: params.l2BatchNumber,
2013
+ l2MessageIndex: params.l2MessageIndex,
2014
+ l1Nullifier
2015
+ }
2016
+ },
2017
+ e
2018
+ );
2019
+ }
2020
+ }
2021
+ };
2022
+ }
2023
+
2024
+ // src/adapters/viem/resources/withdrawals/index.ts
2025
+ var ROUTES2 = {
2026
+ "eth-base": routeEthBase(),
2027
+ // BaseTokenSystem.withdraw, chain base = ETH
2028
+ "eth-nonbase": routeEthNonBase2(),
2029
+ // BaseTokenSystem.withdraw, chain base ≠ ETH
2030
+ "erc20-nonbase": routeErc20NonBase2()
2031
+ // AssetRouter.withdraw for non-base ERC-20s
2032
+ };
2033
+ function createWithdrawalsResource(client) {
2034
+ const svc = createFinalizationServices(client);
2035
+ const { wrap: wrap2, toResult: toResult2 } = createErrorHandlers("withdrawals");
2036
+ async function buildPlan(p) {
2037
+ const ctx = await commonCtx2(p, client);
2038
+ await ROUTES2[ctx.route].preflight?.(p, ctx);
2039
+ const { steps, approvals } = await ROUTES2[ctx.route].build(p, ctx);
2040
+ const resolveGasLimit = () => {
2041
+ if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
2042
+ for (let i = steps.length - 1; i >= 0; i--) {
2043
+ const candidate = steps[i].tx.gas;
2044
+ if (candidate != null) return candidate;
2045
+ }
2046
+ return void 0;
2047
+ };
2048
+ const gasLimit = resolveGasLimit();
2049
+ const summary = {
2050
+ route: ctx.route,
2051
+ approvalsNeeded: approvals,
2052
+ suggestedL2GasLimit: ctx.l2GasLimit,
2053
+ fees: {
2054
+ gasLimit,
2055
+ maxFeePerGas: ctx.fee.maxFeePerGas,
2056
+ maxPriorityFeePerGas: ctx.fee.maxPriorityFeePerGas
2057
+ }
2058
+ };
2059
+ return { route: ctx.route, summary, steps };
2060
+ }
2061
+ const finalizeCache = /* @__PURE__ */ new Map();
2062
+ const quote = (p) => wrap2(OP_WITHDRAWALS.quote, async () => (await buildPlan(p)).summary, {
2063
+ message: "Internal error while preparing a withdrawal quote.",
2064
+ ctx: { token: p.token, where: "withdrawals.quote" }
2065
+ });
2066
+ const tryQuote = (p) => toResult2(OP_WITHDRAWALS.tryQuote, () => quote(p), {
2067
+ message: "Internal error while preparing a withdrawal quote.",
2068
+ ctx: { token: p.token, where: "withdrawals.tryQuote" }
2069
+ });
2070
+ const prepare = (p) => wrap2(OP_WITHDRAWALS.prepare, () => buildPlan(p), {
2071
+ message: "Internal error while preparing a withdrawal plan.",
2072
+ ctx: { token: p.token, where: "withdrawals.prepare" }
2073
+ });
2074
+ const tryPrepare = (p) => toResult2(OP_WITHDRAWALS.tryPrepare, () => prepare(p), {
2075
+ message: "Internal error while preparing a withdrawal plan.",
2076
+ ctx: { token: p.token, where: "withdrawals.tryPrepare" }
2077
+ });
2078
+ const create = (p) => wrap2(
2079
+ OP_WITHDRAWALS.create,
2080
+ async () => {
2081
+ const plan = await prepare(p);
2082
+ const stepHashes = {};
2083
+ const l2Wallet = client.getL2Wallet();
2084
+ for (const step of plan.steps) {
2085
+ if (p.l2TxOverrides) {
2086
+ const overrides = p.l2TxOverrides;
2087
+ if (overrides.maxFeePerGas != null) step.tx.maxFeePerGas = overrides.maxFeePerGas;
2088
+ if (overrides.maxPriorityFeePerGas != null) {
2089
+ step.tx.maxPriorityFeePerGas = overrides.maxPriorityFeePerGas;
2090
+ }
2091
+ if (overrides.gasLimit != null) step.tx.gas = overrides.gasLimit;
2092
+ }
2093
+ if (step.tx.gas == null) {
2094
+ try {
2095
+ const feePart = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
2096
+ maxFeePerGas: step.tx.maxFeePerGas,
2097
+ maxPriorityFeePerGas: step.tx.maxPriorityFeePerGas
2098
+ } : {};
2099
+ const params = {
2100
+ address: step.tx.address,
2101
+ abi: step.tx.abi,
2102
+ functionName: step.tx.functionName,
2103
+ args: step.tx.args ?? [],
2104
+ account: step.tx.account ?? l2Wallet.account ?? client.account,
2105
+ ...step.tx.value != null ? { value: step.tx.value } : {},
2106
+ ...feePart
2107
+ };
2108
+ const gas = await client.l2.estimateContractGas(params);
2109
+ step.tx.gas = gas * 115n / 100n;
2110
+ } catch {
2111
+ }
2112
+ }
2113
+ const fee1559 = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
2114
+ maxFeePerGas: step.tx.maxFeePerGas,
2115
+ maxPriorityFeePerGas: step.tx.maxPriorityFeePerGas
2116
+ } : {};
2117
+ const baseReq = {
2118
+ address: step.tx.address,
2119
+ abi: step.tx.abi,
2120
+ functionName: step.tx.functionName,
2121
+ args: step.tx.args ?? [],
2122
+ account: step.tx.account ?? l2Wallet.account ?? client.account,
2123
+ gas: step.tx.gas,
2124
+ ...fee1559,
2125
+ ...step.tx.dataSuffix ? { dataSuffix: step.tx.dataSuffix } : {},
2126
+ ...step.tx.chain ? { chain: step.tx.chain } : {}
2127
+ };
2128
+ const execReq = step.tx.value != null ? { ...baseReq, value: step.tx.value } : baseReq;
2129
+ let hash;
2130
+ try {
2131
+ if (!client.l2Wallet) {
2132
+ throw createError("EXECUTION", {
2133
+ resource: "withdrawals",
2134
+ operation: "withdrawals.create.getL2Wallet",
2135
+ message: "No L2 wallet available to send withdrawal transaction step.",
2136
+ context: { step: step.key, l2Wallet }
2137
+ });
2138
+ }
2139
+ hash = await l2Wallet.writeContract(execReq);
2140
+ stepHashes[step.key] = hash;
2141
+ const rcpt = await client.l2.waitForTransactionReceipt({ hash });
2142
+ if (!rcpt || rcpt.status !== "success") {
2143
+ throw createError("EXECUTION", {
2144
+ resource: "withdrawals",
2145
+ operation: "withdrawals.create.writeContract",
2146
+ message: "Withdrawal transaction reverted on L2 during a step.",
2147
+ context: { step: step.key, txHash: hash, status: rcpt?.status }
2148
+ });
2149
+ }
2150
+ } catch (e) {
2151
+ throw toZKsyncError(
2152
+ "EXECUTION",
2153
+ {
2154
+ resource: "withdrawals",
2155
+ operation: "withdrawals.create.writeContract",
2156
+ message: "Failed to send or confirm a withdrawal transaction step.",
2157
+ context: { step: step.key, txHash: hash, l2Wallet }
2158
+ },
2159
+ e
2160
+ );
2161
+ }
2162
+ }
2163
+ const keys = Object.keys(stepHashes);
2164
+ const l2TxHash = stepHashes[keys[keys.length - 1]];
2165
+ return { kind: "withdrawal", l2TxHash, stepHashes, plan };
2166
+ },
2167
+ {
2168
+ message: "Internal error while creating withdrawal transactions.",
2169
+ ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.create" }
2170
+ }
2171
+ );
2172
+ const tryCreate = (p) => toResult2(OP_WITHDRAWALS.tryCreate, () => create(p), {
2173
+ message: "Internal error while creating withdrawal transactions.",
2174
+ ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.tryCreate" }
2175
+ });
2176
+ const status = (h) => wrap2(
2177
+ OP_WITHDRAWALS.status,
2178
+ async () => {
2179
+ const l2TxHash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
2180
+ if (!l2TxHash || l2TxHash === "0x") {
2181
+ return { phase: "UNKNOWN", l2TxHash: "0x" };
2182
+ }
2183
+ let l2Rcpt;
2184
+ try {
2185
+ l2Rcpt = await client.l2.getTransactionReceipt({ hash: l2TxHash });
2186
+ } catch (e) {
2187
+ if (isReceiptNotFound(e)) {
2188
+ return { phase: "L2_PENDING", l2TxHash };
2189
+ }
2190
+ throw toZKsyncError(
2191
+ "RPC",
2192
+ {
2193
+ resource: "withdrawals",
2194
+ operation: "withdrawals.status.getTransactionReceipt",
2195
+ message: "Failed to fetch L2 transaction receipt.",
2196
+ context: { l2TxHash, where: "l2.getTransactionReceipt" }
2197
+ },
2198
+ e
2199
+ );
2200
+ }
2201
+ if (!l2Rcpt) return { phase: "L2_PENDING", l2TxHash };
2202
+ let pack;
2203
+ try {
2204
+ pack = await svc.fetchFinalizeDepositParams(l2TxHash);
2205
+ } catch {
2206
+ return { phase: "PENDING", l2TxHash };
2207
+ }
2208
+ const key = {
2209
+ chainIdL2: pack.params.chainId,
2210
+ l2BatchNumber: pack.params.l2BatchNumber,
2211
+ l2MessageIndex: pack.params.l2MessageIndex
2212
+ };
2213
+ try {
2214
+ const done = await svc.isWithdrawalFinalized(key);
2215
+ if (done) return { phase: "FINALIZED", l2TxHash, key };
2216
+ } catch {
2217
+ }
2218
+ const readiness = await svc.simulateFinalizeReadiness(pack.params);
2219
+ if (readiness.kind === "FINALIZED") return { phase: "FINALIZED", l2TxHash, key };
2220
+ if (readiness.kind === "READY") return { phase: "READY_TO_FINALIZE", l2TxHash, key };
2221
+ return { phase: "PENDING", l2TxHash, key };
2222
+ },
2223
+ {
2224
+ message: "Internal error while checking withdrawal status.",
2225
+ ctx: { where: "withdrawals.status", l2TxHash: typeof h === "string" ? h : h.l2TxHash }
2226
+ }
2227
+ );
2228
+ const wait = (h, opts = {
2229
+ for: "l2",
2230
+ pollMs: 5500
2231
+ }) => wrap2(
2232
+ OP_WITHDRAWALS.wait,
2233
+ async () => {
2234
+ const l2Hash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
2235
+ if (!l2Hash || l2Hash === "0x") return null;
2236
+ if (opts.for === "l2") {
2237
+ let rcpt;
2238
+ try {
2239
+ rcpt = await client.l2.waitForTransactionReceipt({ hash: l2Hash });
2240
+ } catch (e) {
2241
+ throw toZKsyncError(
2242
+ "RPC",
2243
+ {
2244
+ resource: "withdrawals",
2245
+ operation: "withdrawals.wait.l2.waitForTransactionReceipt",
2246
+ message: "Failed while waiting for L2 transaction.",
2247
+ context: { l2TxHash: l2Hash }
2248
+ },
2249
+ e
2250
+ );
2251
+ }
2252
+ if (!rcpt) return null;
2253
+ try {
2254
+ const raw = await client.zks.getReceiptWithL2ToL1(l2Hash);
2255
+ const zkRcpt = {
2256
+ ...rcpt,
2257
+ l2ToL1Logs: raw?.l2ToL1Logs ?? []
2258
+ };
2259
+ return zkRcpt;
2260
+ } catch {
2261
+ const zkRcpt = { ...rcpt, l2ToL1Logs: [] };
2262
+ return zkRcpt;
2263
+ }
2264
+ }
2265
+ const poll = Math.max(1e3, opts.pollMs ?? 2500);
2266
+ const deadline = opts.timeoutMs ? Date.now() + opts.timeoutMs : void 0;
2267
+ while (true) {
2268
+ const s = await status(l2Hash);
2269
+ if (opts.for === "ready") {
2270
+ if (s.phase === "READY_TO_FINALIZE" || s.phase === "FINALIZED") return null;
2271
+ } else {
2272
+ if (s.phase === "FINALIZED") {
2273
+ const l1Hash = finalizeCache.get(l2Hash);
2274
+ if (l1Hash) {
2275
+ try {
2276
+ const l1Rcpt = await client.l1.getTransactionReceipt({ hash: l1Hash });
2277
+ if (l1Rcpt) {
2278
+ finalizeCache.delete(l2Hash);
2279
+ return l1Rcpt;
2280
+ }
2281
+ } catch {
2282
+ }
2283
+ }
2284
+ return null;
2285
+ }
2286
+ }
2287
+ if (deadline && Date.now() > deadline) return null;
2288
+ await new Promise((r) => setTimeout(r, poll));
2289
+ }
2290
+ },
2291
+ {
2292
+ message: "Internal error while waiting for withdrawal.",
2293
+ ctx: {
2294
+ where: "withdrawals.wait",
2295
+ l2TxHash: typeof h === "string" ? h : h.l2TxHash,
2296
+ for: opts.for
2297
+ }
2298
+ }
2299
+ );
2300
+ const finalize = (l2TxHash) => wrap2(
2301
+ OP_WITHDRAWALS.finalize.send,
2302
+ async () => {
2303
+ const pack = await (async () => {
2304
+ try {
2305
+ return await svc.fetchFinalizeDepositParams(l2TxHash);
2306
+ } catch (e) {
2307
+ throw createError("STATE", {
2308
+ resource: "withdrawals",
2309
+ operation: OP_WITHDRAWALS.finalize.fetchParams.receipt,
2310
+ message: "Withdrawal not ready: finalize params unavailable.",
2311
+ context: { l2TxHash },
2312
+ cause: e
2313
+ });
2314
+ }
2315
+ })();
2316
+ const { params } = pack;
2317
+ const key = {
2318
+ chainIdL2: params.chainId,
2319
+ l2BatchNumber: params.l2BatchNumber,
2320
+ l2MessageIndex: params.l2MessageIndex
2321
+ };
2322
+ try {
2323
+ const done = await svc.isWithdrawalFinalized(key);
2324
+ if (done) {
2325
+ const statusNow = await status(l2TxHash);
2326
+ return { status: statusNow };
2327
+ }
2328
+ } catch {
2329
+ }
2330
+ const readiness = await svc.simulateFinalizeReadiness(params);
2331
+ if (readiness.kind === "FINALIZED") {
2332
+ const statusNow = await status(l2TxHash);
2333
+ return { status: statusNow };
2334
+ }
2335
+ if (readiness.kind === "NOT_READY") {
2336
+ throw createError("STATE", {
2337
+ resource: "withdrawals",
2338
+ operation: OP_WITHDRAWALS.finalize.readiness.simulate,
2339
+ message: "Withdrawal not ready to finalize.",
2340
+ context: readiness
2341
+ });
2342
+ }
2343
+ try {
2344
+ const tx = await svc.finalizeDeposit(params);
2345
+ finalizeCache.set(l2TxHash, tx.hash);
2346
+ const rcpt = await tx.wait();
2347
+ const statusNow = await status(l2TxHash);
2348
+ return { status: statusNow, receipt: rcpt };
2349
+ } catch (e) {
2350
+ const statusNow = await status(l2TxHash);
2351
+ if (statusNow.phase === "FINALIZED") return { status: statusNow };
2352
+ try {
2353
+ const again = await svc.simulateFinalizeReadiness(params);
2354
+ if (again.kind === "NOT_READY") {
2355
+ throw createError("STATE", {
2356
+ resource: "withdrawals",
2357
+ operation: OP_WITHDRAWALS.finalize.readiness.simulate,
2358
+ message: "Withdrawal not ready to finalize.",
2359
+ context: again
2360
+ });
2361
+ }
2362
+ } catch {
2363
+ }
2364
+ throw e;
2365
+ }
2366
+ },
2367
+ {
2368
+ message: "Internal error while attempting to finalize withdrawal.",
2369
+ ctx: { l2TxHash, where: "withdrawals.finalize" }
2370
+ }
2371
+ );
2372
+ const tryFinalize = (l2TxHash) => toResult2("withdrawals.tryFinalize", () => finalize(l2TxHash), {
2373
+ message: "Internal error while attempting to tryFinalize withdrawal.",
2374
+ ctx: { l2TxHash, where: "withdrawals.tryFinalize" }
2375
+ });
2376
+ return {
2377
+ quote,
2378
+ tryQuote,
2379
+ prepare,
2380
+ tryPrepare,
2381
+ create,
2382
+ tryCreate,
2383
+ status,
2384
+ wait,
2385
+ finalize,
2386
+ tryFinalize
2387
+ };
2388
+ }
2389
+
2390
+ // src/adapters/viem/sdk.ts
2391
+ function createViemSdk(client) {
2392
+ return {
2393
+ deposits: createDepositsResource(client),
2394
+ withdrawals: createWithdrawalsResource(client),
2395
+ helpers: {
2396
+ addresses: () => client.ensureAddresses(),
2397
+ contracts: () => client.contracts(),
2398
+ async l1AssetRouter() {
2399
+ const { l1AssetRouter } = await client.contracts();
2400
+ return l1AssetRouter;
2401
+ },
2402
+ async l1NativeTokenVault() {
2403
+ const { l1NativeTokenVault } = await client.contracts();
2404
+ return l1NativeTokenVault;
2405
+ },
2406
+ async l1Nullifier() {
2407
+ const { l1Nullifier } = await client.contracts();
2408
+ return l1Nullifier;
2409
+ },
2410
+ async baseToken(chainId) {
2411
+ const id = chainId ?? BigInt(await client.l2.getChainId());
2412
+ return client.baseToken(id);
2413
+ },
2414
+ async l2TokenAddress(l1Token) {
2415
+ if (isAddressEq(l1Token, FORMAL_ETH_ADDRESS)) {
2416
+ return ETH_ADDRESS;
2417
+ }
2418
+ const base = await client.baseToken(BigInt(await client.l2.getChainId()));
2419
+ if (isAddressEq(l1Token, base)) {
2420
+ return L2_BASE_TOKEN_ADDRESS;
2421
+ }
2422
+ const { l2NativeTokenVault } = await client.contracts();
2423
+ const addr = await l2NativeTokenVault.read.l2TokenAddress([l1Token]);
2424
+ return addr;
2425
+ },
2426
+ async l1TokenAddress(l2Token) {
2427
+ if (isAddressEq(l2Token, FORMAL_ETH_ADDRESS)) {
2428
+ return FORMAL_ETH_ADDRESS;
2429
+ }
2430
+ const { l2AssetRouter } = await client.contracts();
2431
+ const addr = await l2AssetRouter.read.l1TokenAddress([l2Token]);
2432
+ return addr;
2433
+ },
2434
+ async assetId(l1Token) {
2435
+ const norm = isAddressEq(l1Token, FORMAL_ETH_ADDRESS) ? ETH_ADDRESS : l1Token;
2436
+ const { l1NativeTokenVault } = await client.contracts();
2437
+ const id = await l1NativeTokenVault.read.assetId([norm]);
2438
+ return id;
2439
+ }
2440
+ }
2441
+ };
2442
+ }
2443
+
2444
+ export { buildDirectRequestStruct, buildViemFeeOverrides, checkBaseCost, classifyReadinessFromRevert, createDepositsResource, createErrorHandlers, createFinalizationServices, createViemSdk, createWithdrawalsResource, decodeRevert, encodeNTVAssetId, encodeNTVTransferData, encodeNativeTokenVaultAssetId, encodeNativeTokenVaultTransferData, encodeSecondBridgeArgs, encodeSecondBridgeDataV1, encodeSecondBridgeErc20Args, encodeSecondBridgeEthArgs, getFeeOverrides, getGasPriceWei, getL2FeeOverrides, registerErrorAbi, scaleGasLimit, toZKsyncError };