viem 2.30.1 → 2.30.2

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 (134) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/_cjs/actions/public/call.js +2 -2
  3. package/_cjs/actions/public/call.js.map +1 -1
  4. package/_cjs/actions/public/estimateGas.js +1 -1
  5. package/_cjs/actions/public/estimateGas.js.map +1 -1
  6. package/_cjs/actions/public/simulateBlocks.js +1 -1
  7. package/_cjs/actions/public/simulateBlocks.js.map +1 -1
  8. package/_cjs/actions/public/watchBlocks.js +4 -2
  9. package/_cjs/actions/public/watchBlocks.js.map +1 -1
  10. package/_cjs/chains/definitions/bitkub.js +3 -3
  11. package/_cjs/chains/definitions/bitkub.js.map +1 -1
  12. package/_cjs/chains/definitions/jbc.js +1 -1
  13. package/_cjs/chains/definitions/jbc.js.map +1 -1
  14. package/_cjs/chains/definitions/riseTestnet.js +29 -0
  15. package/_cjs/chains/definitions/riseTestnet.js.map +1 -0
  16. package/_cjs/chains/index.js +6 -4
  17. package/_cjs/chains/index.js.map +1 -1
  18. package/_cjs/errors/version.js +1 -1
  19. package/_cjs/utils/rpc/socket.js +8 -4
  20. package/_cjs/utils/rpc/socket.js.map +1 -1
  21. package/_cjs/zksync/actions/claimFailedDeposit.js +146 -0
  22. package/_cjs/zksync/actions/claimFailedDeposit.js.map +1 -0
  23. package/_cjs/zksync/actions/deposit.js +51 -4
  24. package/_cjs/zksync/actions/deposit.js.map +1 -1
  25. package/_cjs/zksync/actions/finalizeWithdrawal.js +41 -41
  26. package/_cjs/zksync/actions/finalizeWithdrawal.js.map +1 -1
  27. package/_cjs/zksync/actions/getDefaultBridgeAddresses.js +2 -0
  28. package/_cjs/zksync/actions/getDefaultBridgeAddresses.js.map +1 -1
  29. package/_cjs/zksync/actions/isWithdrawalFinalized.js +2 -17
  30. package/_cjs/zksync/actions/isWithdrawalFinalized.js.map +1 -1
  31. package/_cjs/zksync/actions/withdraw.js +49 -8
  32. package/_cjs/zksync/actions/withdraw.js.map +1 -1
  33. package/_cjs/zksync/constants/address.js +4 -1
  34. package/_cjs/zksync/constants/address.js.map +1 -1
  35. package/_cjs/zksync/decorators/walletL1.js +2 -0
  36. package/_cjs/zksync/decorators/walletL1.js.map +1 -1
  37. package/_cjs/zksync/errors/bridge.js +23 -1
  38. package/_cjs/zksync/errors/bridge.js.map +1 -1
  39. package/_cjs/zksync/index.js +4 -2
  40. package/_cjs/zksync/index.js.map +1 -1
  41. package/_esm/actions/public/call.js +2 -2
  42. package/_esm/actions/public/call.js.map +1 -1
  43. package/_esm/actions/public/estimateGas.js +1 -1
  44. package/_esm/actions/public/estimateGas.js.map +1 -1
  45. package/_esm/actions/public/simulateBlocks.js +1 -1
  46. package/_esm/actions/public/simulateBlocks.js.map +1 -1
  47. package/_esm/actions/public/watchBlocks.js +4 -2
  48. package/_esm/actions/public/watchBlocks.js.map +1 -1
  49. package/_esm/chains/definitions/bitkub.js +3 -3
  50. package/_esm/chains/definitions/bitkub.js.map +1 -1
  51. package/_esm/chains/definitions/jbc.js +1 -1
  52. package/_esm/chains/definitions/jbc.js.map +1 -1
  53. package/_esm/chains/definitions/riseTestnet.js +26 -0
  54. package/_esm/chains/definitions/riseTestnet.js.map +1 -0
  55. package/_esm/chains/index.js +2 -0
  56. package/_esm/chains/index.js.map +1 -1
  57. package/_esm/errors/version.js +1 -1
  58. package/_esm/utils/rpc/socket.js +10 -6
  59. package/_esm/utils/rpc/socket.js.map +1 -1
  60. package/_esm/zksync/actions/claimFailedDeposit.js +199 -0
  61. package/_esm/zksync/actions/claimFailedDeposit.js.map +1 -0
  62. package/_esm/zksync/actions/deposit.js +61 -11
  63. package/_esm/zksync/actions/deposit.js.map +1 -1
  64. package/_esm/zksync/actions/finalizeWithdrawal.js +42 -42
  65. package/_esm/zksync/actions/finalizeWithdrawal.js.map +1 -1
  66. package/_esm/zksync/actions/getDefaultBridgeAddresses.js +2 -0
  67. package/_esm/zksync/actions/getDefaultBridgeAddresses.js.map +1 -1
  68. package/_esm/zksync/actions/isWithdrawalFinalized.js +3 -18
  69. package/_esm/zksync/actions/isWithdrawalFinalized.js.map +1 -1
  70. package/_esm/zksync/actions/withdraw.js +54 -10
  71. package/_esm/zksync/actions/withdraw.js.map +1 -1
  72. package/_esm/zksync/constants/address.js +3 -0
  73. package/_esm/zksync/constants/address.js.map +1 -1
  74. package/_esm/zksync/decorators/walletL1.js +2 -0
  75. package/_esm/zksync/decorators/walletL1.js.map +1 -1
  76. package/_esm/zksync/errors/bridge.js +19 -0
  77. package/_esm/zksync/errors/bridge.js.map +1 -1
  78. package/_esm/zksync/index.js +1 -0
  79. package/_esm/zksync/index.js.map +1 -1
  80. package/_types/actions/public/call.d.ts +1 -1
  81. package/_types/actions/public/estimateGas.d.ts +1 -1
  82. package/_types/actions/public/watchBlocks.d.ts.map +1 -1
  83. package/_types/chains/definitions/bitkub.d.ts +3 -3
  84. package/_types/chains/definitions/jbc.d.ts +1 -1
  85. package/_types/chains/definitions/riseTestnet.d.ts +35 -0
  86. package/_types/chains/definitions/riseTestnet.d.ts.map +1 -0
  87. package/_types/chains/index.d.ts +2 -0
  88. package/_types/chains/index.d.ts.map +1 -1
  89. package/_types/errors/version.d.ts +1 -1
  90. package/_types/utils/rpc/socket.d.ts.map +1 -1
  91. package/_types/zksync/actions/claimFailedDeposit.d.ts +77 -0
  92. package/_types/zksync/actions/claimFailedDeposit.d.ts.map +1 -0
  93. package/_types/zksync/actions/deposit.d.ts +0 -1
  94. package/_types/zksync/actions/deposit.d.ts.map +1 -1
  95. package/_types/zksync/actions/finalizeWithdrawal.d.ts.map +1 -1
  96. package/_types/zksync/actions/getDefaultBridgeAddresses.d.ts.map +1 -1
  97. package/_types/zksync/actions/isWithdrawalFinalized.d.ts.map +1 -1
  98. package/_types/zksync/actions/withdraw.d.ts +1 -1
  99. package/_types/zksync/actions/withdraw.d.ts.map +1 -1
  100. package/_types/zksync/constants/address.d.ts +3 -0
  101. package/_types/zksync/constants/address.d.ts.map +1 -1
  102. package/_types/zksync/decorators/walletL1.d.ts +32 -1
  103. package/_types/zksync/decorators/walletL1.d.ts.map +1 -1
  104. package/_types/zksync/errors/bridge.d.ts +23 -0
  105. package/_types/zksync/errors/bridge.d.ts.map +1 -1
  106. package/_types/zksync/index.d.ts +1 -0
  107. package/_types/zksync/index.d.ts.map +1 -1
  108. package/_types/zksync/types/contract.d.ts +2 -0
  109. package/_types/zksync/types/contract.d.ts.map +1 -1
  110. package/_types/zksync/types/eip1193.d.ts +2 -0
  111. package/_types/zksync/types/eip1193.d.ts.map +1 -1
  112. package/actions/public/call.ts +3 -3
  113. package/actions/public/estimateGas.ts +2 -2
  114. package/actions/public/simulateBlocks.ts +1 -1
  115. package/actions/public/watchBlocks.ts +7 -5
  116. package/chains/definitions/bitkub.ts +3 -3
  117. package/chains/definitions/jbc.ts +1 -1
  118. package/chains/definitions/riseTestnet.ts +26 -0
  119. package/chains/index.ts +2 -0
  120. package/errors/version.ts +1 -1
  121. package/package.json +1 -1
  122. package/utils/rpc/socket.ts +10 -8
  123. package/zksync/actions/claimFailedDeposit.ts +319 -0
  124. package/zksync/actions/deposit.ts +116 -14
  125. package/zksync/actions/finalizeWithdrawal.ts +53 -51
  126. package/zksync/actions/getDefaultBridgeAddresses.ts +3 -0
  127. package/zksync/actions/isWithdrawalFinalized.ts +4 -22
  128. package/zksync/actions/withdraw.ts +64 -8
  129. package/zksync/constants/address.ts +9 -0
  130. package/zksync/decorators/walletL1.ts +49 -1
  131. package/zksync/errors/bridge.ts +35 -0
  132. package/zksync/index.ts +6 -0
  133. package/zksync/types/contract.ts +2 -0
  134. package/zksync/types/eip1193.ts +2 -0
@@ -0,0 +1,319 @@
1
+ import { type Address, parseAbi } from 'abitype'
2
+ import { ethers } from 'ethers'
3
+ import type { Account } from '../../accounts/types.js'
4
+ import { getTransaction } from '../../actions/public/getTransaction.js'
5
+ import { getTransactionReceipt } from '../../actions/public/getTransactionReceipt.js'
6
+ import { readContract } from '../../actions/public/readContract.js'
7
+ import {
8
+ type SendTransactionErrorType,
9
+ type SendTransactionParameters,
10
+ type SendTransactionReturnType,
11
+ sendTransaction,
12
+ } from '../../actions/wallet/sendTransaction.js'
13
+ import type { Client } from '../../clients/createClient.js'
14
+ import type { Transport } from '../../clients/transports/createTransport.js'
15
+ import { AccountNotFoundError } from '../../errors/account.js'
16
+ import { ClientChainNotConfiguredError } from '../../errors/chain.js'
17
+ import type { TransactionReceiptNotFoundErrorType } from '../../errors/transaction.js'
18
+ import type { GetAccountParameter } from '../../types/account.js'
19
+ import type {
20
+ Chain,
21
+ DeriveChain,
22
+ GetChainParameter,
23
+ } from '../../types/chain.js'
24
+ import type { Hash } from '../../types/misc.js'
25
+ import type { Hex } from '../../types/misc.js'
26
+ import type { UnionEvaluate, UnionOmit } from '../../types/utils.js'
27
+ import {
28
+ type FormattedTransactionRequest,
29
+ decodeAbiParameters,
30
+ decodeFunctionData,
31
+ encodeAbiParameters,
32
+ encodeFunctionData,
33
+ isAddressEqual,
34
+ parseAccount,
35
+ } from '../../utils/index.js'
36
+ import { bootloaderFormalAddress } from '../constants/address.js'
37
+ import {
38
+ CannotClaimSuccessfulDepositError,
39
+ type CannotClaimSuccessfulDepositErrorType,
40
+ L2BridgeNotFoundError,
41
+ type L2BridgeNotFoundErrorType,
42
+ LogProofNotFoundError,
43
+ type LogProofNotFoundErrorType,
44
+ } from '../errors/bridge.js'
45
+ import type { ChainEIP712 } from '../types/chain.js'
46
+ import type { BridgeContractAddresses } from '../types/contract.js'
47
+ import type { ZksyncTransactionReceipt } from '../types/transaction.js'
48
+ import { undoL1ToL2Alias } from '../utils/bridge/undoL1ToL2Alias.js'
49
+ import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
50
+ import { getLogProof } from './getLogProof.js'
51
+
52
+ export type ClaimFailedDepositParameters<
53
+ chain extends Chain | undefined = Chain | undefined,
54
+ account extends Account | undefined = Account | undefined,
55
+ chainOverride extends Chain | undefined = Chain | undefined,
56
+ chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
57
+ accountL2 extends Account | undefined = Account | undefined,
58
+ _derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
59
+ > = UnionEvaluate<
60
+ UnionOmit<FormattedTransactionRequest<_derivedChain>, 'data' | 'to' | 'from'>
61
+ > &
62
+ Partial<GetChainParameter<chain, chainOverride>> &
63
+ Partial<GetAccountParameter<account>> & {
64
+ /** L2 client. */
65
+ client: Client<Transport, chainL2, accountL2>
66
+ /** The L2 transaction hash of the failed deposit. */
67
+ depositHash: Hash
68
+ }
69
+
70
+ export type ClaimFailedDepositReturnType = SendTransactionReturnType
71
+
72
+ export type ClaimFailedDepositErrorType =
73
+ | SendTransactionErrorType
74
+ | TransactionReceiptNotFoundErrorType
75
+ | CannotClaimSuccessfulDepositErrorType
76
+ | LogProofNotFoundErrorType
77
+ | L2BridgeNotFoundErrorType
78
+
79
+ /**
80
+ * Withdraws funds from the initiated deposit, which failed when finalizing on L2.
81
+ * If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the
82
+ * L1 bridge, which results in returning L1 tokens back to the depositor.
83
+ *
84
+ * @param client - Client to use
85
+ * @param parameters - {@link ClaimFailedDepositParameters}
86
+ * @returns hash - The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link ClaimFailedDepositReturnType}
87
+ *
88
+ * @example
89
+ * import { createPublicClient, http } from 'viem'
90
+ * import { privateKeyToAccount } from 'viem/accounts'
91
+ * import { zksync, mainnet } from 'viem/chains'
92
+ * import { claimFailedDeposit, publicActionsL2 } from 'viem/zksync'
93
+ *
94
+ * const client = createPublicClient({
95
+ * chain: mainnet,
96
+ * transport: http(),
97
+ * })
98
+ *
99
+ * const clientL2 = createPublicClient({
100
+ * chain: zksync,
101
+ * transport: http(),
102
+ * }).extend(publicActionsL2())
103
+ *
104
+ * const account = privateKeyToAccount('0x…')
105
+ *
106
+ * const hash = await claimFailedDeposit(client, {
107
+ * client: clientL2,
108
+ * account,
109
+ * depositHash: <L2_HASH_OF_FAILED_DEPOSIT>,
110
+ * })
111
+ *
112
+ * @example Account Hoisting
113
+ * import { createPublicClient, createWalletClient, http } from 'viem'
114
+ * import { privateKeyToAccount } from 'viem/accounts'
115
+ * import { zksync, mainnet } from 'viem/chains'
116
+ * import { publicActionsL2 } from 'viem/zksync'
117
+ *
118
+ * const walletClient = createWalletClient({
119
+ * chain: mainnet,
120
+ * transport: http(),
121
+ * account: privateKeyToAccount('0x…'),
122
+ * })
123
+ *
124
+ * const clientL2 = createPublicClient({
125
+ * chain: zksync,
126
+ * transport: http(),
127
+ * }).extend(publicActionsL2())
128
+ *
129
+ * const hash = await claimFailedDeposit(walletClient, {
130
+ * client: clientL2,
131
+ * depositHash: <L2_HASH_OF_FAILED_DEPOSIT>,
132
+ * })
133
+ */
134
+ export async function claimFailedDeposit<
135
+ chain extends Chain | undefined,
136
+ account extends Account | undefined,
137
+ chainOverride extends Chain | undefined = Chain | undefined,
138
+ chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
139
+ accountL2 extends Account | undefined = Account | undefined,
140
+ _derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
141
+ >(
142
+ client: Client<Transport, chain, account>,
143
+ parameters: ClaimFailedDepositParameters<
144
+ chain,
145
+ account,
146
+ chainOverride,
147
+ chainL2,
148
+ accountL2
149
+ >,
150
+ ): Promise<ClaimFailedDepositReturnType> {
151
+ const {
152
+ account: account_ = client.account,
153
+ chain: chain_ = client.chain,
154
+ client: l2Client,
155
+ depositHash,
156
+ ...rest
157
+ } = parameters
158
+
159
+ const account = account_ ? parseAccount(account_) : client.account
160
+ if (!account)
161
+ throw new AccountNotFoundError({
162
+ docsPath: '/docs/actions/wallet/sendTransaction',
163
+ })
164
+ if (!l2Client.chain) throw new ClientChainNotConfiguredError()
165
+
166
+ const receipt = <ZksyncTransactionReceipt>(
167
+ await getTransactionReceipt(l2Client, { hash: depositHash })
168
+ )
169
+
170
+ const successL2ToL1LogIndex = receipt.l2ToL1Logs.findIndex(
171
+ (l2ToL1log) =>
172
+ isAddressEqual(<Hex>l2ToL1log.sender, bootloaderFormalAddress) &&
173
+ l2ToL1log.key === depositHash,
174
+ )
175
+ const successL2ToL1Log = receipt.l2ToL1Logs[successL2ToL1LogIndex]
176
+ if (successL2ToL1Log?.value !== ethers.ZeroHash)
177
+ throw new CannotClaimSuccessfulDepositError({ hash: depositHash })
178
+
179
+ const tx = await getTransaction(l2Client, { hash: depositHash })
180
+
181
+ // Undo the aliasing, since the Mailbox contract set it as for contract address.
182
+ const l1BridgeAddress = undoL1ToL2Alias(receipt.from)
183
+ const l2BridgeAddress = receipt.to
184
+ if (!l2BridgeAddress) throw new L2BridgeNotFoundError()
185
+
186
+ const l1NativeTokenVault = (await getBridgeAddresses(client, l2Client))
187
+ .l1NativeTokenVault
188
+
189
+ let depositSender: Hex
190
+ let assetId: Hex
191
+ let assetData: Hex
192
+ try {
193
+ const { args } = decodeFunctionData({
194
+ abi: parseAbi([
195
+ 'function finalizeDeposit(address _l1Sender, address _l2Receiver, address _l1Token, uint256 _amount, bytes _data)',
196
+ ]),
197
+ data: tx.input,
198
+ })
199
+ assetData = encodeAbiParameters(
200
+ [{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
201
+ [args[3], args[1], args[2]],
202
+ )
203
+ assetId = await readContract(client, {
204
+ address: l1NativeTokenVault,
205
+ abi: parseAbi(['function assetId(address token) view returns (bytes32)']),
206
+ functionName: 'assetId',
207
+ args: [args[2]],
208
+ })
209
+ depositSender = args[0]
210
+ if (assetId === ethers.ZeroHash)
211
+ throw new Error(`Token ${args[2]} not registered in NTV`)
212
+ } catch (_e) {
213
+ const { args } = decodeFunctionData({
214
+ abi: parseAbi([
215
+ 'function finalizeDeposit(uint256 _chainId, bytes32 _assetId, bytes _transferData)',
216
+ ]),
217
+ data: tx.input,
218
+ })
219
+ assetId = args[1]
220
+ const transferData = args[2]
221
+ const l1TokenAddress = await readContract(client, {
222
+ address: l1NativeTokenVault,
223
+ abi: parseAbi([
224
+ 'function tokenAddress(bytes32 assetId) view returns (address)',
225
+ ]),
226
+ functionName: 'tokenAddress',
227
+ args: [assetId],
228
+ })
229
+ const transferDataDecoded = decodeAbiParameters(
230
+ [
231
+ { type: 'address' },
232
+ { type: 'address' },
233
+ { type: 'address' },
234
+ { type: 'uint256' },
235
+ { type: 'bytes' },
236
+ ],
237
+ transferData,
238
+ )
239
+ assetData = encodeAbiParameters(
240
+ [{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
241
+ [transferDataDecoded[3], transferDataDecoded[1], l1TokenAddress],
242
+ )
243
+ depositSender = transferDataDecoded[0]
244
+ }
245
+
246
+ const proof = await getLogProof(l2Client, {
247
+ txHash: depositHash,
248
+ index: successL2ToL1LogIndex,
249
+ })
250
+ if (!proof)
251
+ throw new LogProofNotFoundError({
252
+ hash: depositHash,
253
+ index: successL2ToL1LogIndex,
254
+ })
255
+
256
+ const data = encodeFunctionData({
257
+ abi: parseAbi([
258
+ 'function bridgeRecoverFailedTransfer(uint256 _chainId, address _depositSender, bytes32 _assetId, bytes _assetData, bytes32 _l2TxHash, uint256 _l2BatchNumber, uint256 _l2MessageIndex, uint16 _l2TxNumberInBatch, bytes32[] _merkleProof)',
259
+ ]),
260
+ functionName: 'bridgeRecoverFailedTransfer',
261
+ args: [
262
+ BigInt(l2Client.chain.id),
263
+ depositSender,
264
+ assetId,
265
+ assetData,
266
+ depositHash,
267
+ receipt.l1BatchNumber!,
268
+ BigInt(proof.id),
269
+ Number(receipt.l1BatchTxIndex),
270
+ proof.proof,
271
+ ],
272
+ })
273
+
274
+ return await sendTransaction(client, {
275
+ chain: chain_,
276
+ account,
277
+ to: l1BridgeAddress,
278
+ data,
279
+ ...rest,
280
+ } as SendTransactionParameters)
281
+ }
282
+
283
+ async function getBridgeAddresses<
284
+ chain extends Chain | undefined,
285
+ chainL2 extends ChainEIP712 | undefined,
286
+ >(
287
+ client: Client<Transport, chain>,
288
+ l2Client: Client<Transport, chainL2>,
289
+ ): Promise<
290
+ BridgeContractAddresses & {
291
+ l1Nullifier: Address
292
+ l1NativeTokenVault: Address
293
+ }
294
+ > {
295
+ const addresses = await getDefaultBridgeAddresses(l2Client)
296
+ let l1Nullifier = addresses.l1Nullifier
297
+ let l1NativeTokenVault = addresses.l1NativeTokenVault
298
+
299
+ if (!l1Nullifier)
300
+ l1Nullifier = await readContract(client, {
301
+ address: addresses.sharedL1,
302
+ abi: parseAbi(['function L1_NULLIFIER() view returns (address)']),
303
+ functionName: 'L1_NULLIFIER',
304
+ args: [],
305
+ })
306
+ if (!l1NativeTokenVault)
307
+ l1NativeTokenVault = await readContract(client, {
308
+ address: addresses.sharedL1,
309
+ abi: parseAbi(['function nativeTokenVault() view returns (address)']),
310
+ functionName: 'nativeTokenVault',
311
+ args: [],
312
+ })
313
+
314
+ return {
315
+ ...addresses,
316
+ l1Nullifier,
317
+ l1NativeTokenVault,
318
+ }
319
+ }
@@ -1,4 +1,5 @@
1
- import { type Address, parseAbi, parseAbiParameters } from 'abitype'
1
+ import { type Address, parseAbi } from 'abitype'
2
+ import { ethers } from 'ethers'
2
3
  import type { Account } from '../../accounts/types.js'
3
4
  import {
4
5
  type EstimateGasParameters,
@@ -33,14 +34,17 @@ import type { Hex } from '../../types/misc.js'
33
34
  import type { UnionEvaluate, UnionOmit } from '../../types/utils.js'
34
35
  import {
35
36
  type FormattedTransactionRequest,
37
+ concatHex,
36
38
  encodeAbiParameters,
37
39
  encodeFunctionData,
38
40
  isAddressEqual,
41
+ keccak256,
39
42
  parseAccount,
40
43
  } from '../../utils/index.js'
41
44
  import { bridgehubAbi } from '../constants/abis.js'
42
45
  import {
43
46
  ethAddressInContracts,
47
+ l2NativeTokenVaultAddress,
44
48
  legacyEthAddress,
45
49
  } from '../constants/address.js'
46
50
  import { requiredL1ToL2GasPerPubdataLimit } from '../constants/number.js'
@@ -184,7 +188,6 @@ export type DepositErrorType =
184
188
  *
185
189
  * const hash = await deposit(walletClient, {
186
190
  * client: clientL2,
187
- * account,
188
191
  * token: legacyEthAddress,
189
192
  * to: walletClient.account.address,
190
193
  * amount: 1_000_000_000_000_000_000n,
@@ -228,7 +231,7 @@ export async function deposit<
228
231
 
229
232
  if (isAddressEqual(token, legacyEthAddress)) token = ethAddressInContracts
230
233
 
231
- const bridgeAddresses = await getDefaultBridgeAddresses(l2Client)
234
+ const bridgeAddresses = await getBridgeAddresses(client, l2Client)
232
235
  const bridgehub = await getBridgehubContractAddress(l2Client)
233
236
  const baseToken = await readContract(client, {
234
237
  address: bridgehub,
@@ -240,7 +243,6 @@ export async function deposit<
240
243
  const { mintValue, tx } = await getL1DepositTx(
241
244
  client,
242
245
  account,
243
- // @ts-ignore
244
246
  { ...parameters, token },
245
247
  bridgeAddresses,
246
248
  bridgehub,
@@ -296,7 +298,10 @@ async function getL1DepositTx<
296
298
  accountL2,
297
299
  _derivedChain
298
300
  >,
299
- bridgeAddresses: BridgeContractAddresses,
301
+ bridgeAddresses: BridgeContractAddresses & {
302
+ l1Nullifier: Address
303
+ l1NativeTokenVault: Address
304
+ },
300
305
  bridgehub: Address,
301
306
  baseToken: Address,
302
307
  ) {
@@ -406,9 +411,12 @@ async function getL1DepositTx<
406
411
  refundRecipient,
407
412
  secondBridgeAddress: bridgeAddress,
408
413
  secondBridgeValue: 0n,
409
- secondBridgeCalldata: encodeAbiParameters(
410
- parseAbiParameters('address x, uint256 y, address z'),
411
- [token, amount, to],
414
+ secondBridgeCalldata: await getSecondBridgeCalldata(
415
+ client,
416
+ bridgeAddresses.l1NativeTokenVault,
417
+ token,
418
+ amount,
419
+ to,
412
420
  ),
413
421
  },
414
422
  ],
@@ -435,9 +443,12 @@ async function getL1DepositTx<
435
443
  refundRecipient,
436
444
  secondBridgeAddress: bridgeAddress,
437
445
  secondBridgeValue: amount,
438
- secondBridgeCalldata: encodeAbiParameters(
439
- parseAbiParameters('address x, uint256 y, address z'),
440
- [ethAddressInContracts, 0n, to],
446
+ secondBridgeCalldata: await getSecondBridgeCalldata(
447
+ client,
448
+ bridgeAddresses.l1NativeTokenVault,
449
+ ethAddressInContracts,
450
+ amount,
451
+ to,
441
452
  ),
442
453
  },
443
454
  ],
@@ -464,9 +475,12 @@ async function getL1DepositTx<
464
475
  refundRecipient,
465
476
  secondBridgeAddress: bridgeAddress,
466
477
  secondBridgeValue: 0n,
467
- secondBridgeCalldata: encodeAbiParameters(
468
- parseAbiParameters('address x, uint256 y, address z'),
469
- [token, amount, to],
478
+ secondBridgeCalldata: await getSecondBridgeCalldata(
479
+ client,
480
+ bridgeAddresses.l1NativeTokenVault,
481
+ token,
482
+ amount,
483
+ to,
470
484
  ),
471
485
  },
472
486
  ],
@@ -839,6 +853,94 @@ async function encodeDefaultBridgeData<chain extends Chain | undefined>(
839
853
  )
840
854
  }
841
855
 
856
+ async function getSecondBridgeCalldata<chain extends Chain | undefined>(
857
+ client: Client<Transport, chain>,
858
+ l1NativeTokenVault: Address,
859
+ token: Address,
860
+ amount: bigint,
861
+ to: Address,
862
+ ): Promise<Hex> {
863
+ let assetId: Hex
864
+ let token_ = token
865
+ if (isAddressEqual(token, legacyEthAddress)) token_ = ethAddressInContracts
866
+
867
+ const assetIdFromNTV = await readContract(client, {
868
+ address: l1NativeTokenVault,
869
+ abi: parseAbi(['function assetId(address token) view returns (bytes32)']),
870
+ functionName: 'assetId',
871
+ args: [token_],
872
+ })
873
+
874
+ if (assetIdFromNTV && assetIdFromNTV !== ethers.ZeroHash)
875
+ assetId = assetIdFromNTV
876
+ else {
877
+ // Okay, the token have not been registered within the Native token vault.
878
+ // There are two cases when it is possible:
879
+ // - The token is native to L1 (it may or may not be bridged), but it has not been
880
+ // registered within NTV after the Gateway upgrade. We assume that this is not the case
881
+ // as the SDK is expected to work only after the full migration is done.
882
+ // - The token is native to the current chain and it has never been bridged.
883
+
884
+ if (!client.chain) throw new ClientChainNotConfiguredError()
885
+ assetId = keccak256(
886
+ encodeAbiParameters(
887
+ [{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
888
+ [BigInt(client.chain.id), l2NativeTokenVaultAddress, token_],
889
+ ),
890
+ )
891
+ }
892
+
893
+ const ntvData = encodeAbiParameters(
894
+ [{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
895
+ [BigInt(amount), to, token_],
896
+ )
897
+
898
+ const data = encodeAbiParameters(
899
+ [{ type: 'bytes32' }, { type: 'bytes' }],
900
+ [assetId, ntvData],
901
+ )
902
+
903
+ return concatHex(['0x01', data])
904
+ }
905
+
906
+ async function getBridgeAddresses<
907
+ chain extends Chain | undefined,
908
+ chainL2 extends ChainEIP712 | undefined,
909
+ >(
910
+ client: Client<Transport, chain>,
911
+ l2Client: Client<Transport, chainL2>,
912
+ ): Promise<
913
+ BridgeContractAddresses & {
914
+ l1Nullifier: Address
915
+ l1NativeTokenVault: Address
916
+ }
917
+ > {
918
+ const addresses = await getDefaultBridgeAddresses(l2Client)
919
+ let l1Nullifier = addresses.l1Nullifier
920
+ let l1NativeTokenVault = addresses.l1NativeTokenVault
921
+
922
+ if (!l1Nullifier)
923
+ l1Nullifier = await readContract(client, {
924
+ address: addresses.sharedL1,
925
+ abi: parseAbi(['function L1_NULLIFIER() view returns (address)']),
926
+ functionName: 'L1_NULLIFIER',
927
+ args: [],
928
+ })
929
+ if (!l1NativeTokenVault)
930
+ l1NativeTokenVault = await readContract(client, {
931
+ address: addresses.sharedL1,
932
+ abi: parseAbi(['function nativeTokenVault() view returns (address)']),
933
+ functionName: 'nativeTokenVault',
934
+ args: [],
935
+ })
936
+
937
+ return {
938
+ ...addresses,
939
+ l1Nullifier,
940
+ l1NativeTokenVault,
941
+ }
942
+ }
943
+
842
944
  function scaleGasLimit(gasLimit: bigint): bigint {
843
945
  return (gasLimit * BigInt(12)) / BigInt(10)
844
946
  }
@@ -1,4 +1,4 @@
1
- import type { Address } from 'abitype'
1
+ import { type Address, parseAbi } from 'abitype'
2
2
  import type { Account } from '../../accounts/types.js'
3
3
  import { readContract } from '../../actions/public/readContract.js'
4
4
  import {
@@ -20,17 +20,15 @@ import type { Hex } from '../../types/misc.js'
20
20
  import {
21
21
  decodeAbiParameters,
22
22
  encodeFunctionData,
23
- isAddressEqual,
24
23
  parseAccount,
25
24
  slice,
26
25
  } from '../../utils/index.js'
27
- import { l1SharedBridgeAbi, l2SharedBridgeAbi } from '../constants/abis.js'
28
- import { l2BaseTokenAddress } from '../constants/address.js'
29
26
  import {
30
27
  WithdrawalLogNotFoundError,
31
28
  type WithdrawalLogNotFoundErrorType,
32
29
  } from '../errors/bridge.js'
33
30
  import type { ChainEIP712 } from '../types/chain.js'
31
+ import type { BridgeContractAddresses } from '../types/contract.js'
34
32
  import { getWithdrawalL2ToL1Log } from '../utils/bridge/getWithdrawalL2ToL1Log.js'
35
33
  import { getWithdrawalLog } from '../utils/bridge/getWithdrawalLog.js'
36
34
  import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
@@ -149,52 +147,35 @@ export async function finalizeWithdrawal<
149
147
  })
150
148
  if (!l2Client.chain) throw new ChainNotFoundError()
151
149
 
152
- const {
153
- l1BatchNumber,
154
- l2MessageIndex,
155
- l2TxNumberInBlock,
156
- message,
157
- sender,
158
- proof,
159
- } = await getFinalizeWithdrawalParams(l2Client, { hash, index })
160
-
161
- let l1Bridge: Address
150
+ const finalizeWithdrawalParams = await getFinalizeWithdrawalParams(l2Client, {
151
+ hash,
152
+ index,
153
+ })
162
154
 
163
- if (isAddressEqual(sender, l2BaseTokenAddress))
164
- l1Bridge = (await getDefaultBridgeAddresses(l2Client)).sharedL1
165
- else if (!(await isLegacyBridge(l2Client, { address: sender })))
166
- l1Bridge = await readContract(l2Client, {
167
- address: sender,
168
- abi: l2SharedBridgeAbi,
169
- functionName: 'l1SharedBridge',
170
- args: [],
171
- })
172
- else
173
- l1Bridge = await readContract(l2Client, {
174
- address: sender,
175
- abi: l2SharedBridgeAbi,
176
- functionName: 'l1Bridge',
177
- args: [],
178
- })
155
+ const l1Nullifier = (await getBridgeAddresses(client, l2Client)).l1Nullifier
179
156
 
180
157
  const data = encodeFunctionData({
181
- abi: l1SharedBridgeAbi,
182
- functionName: 'finalizeWithdrawal',
158
+ abi: parseAbi([
159
+ 'function finalizeDeposit((uint256 chainId, uint256 l2BatchNumber, uint256 l2MessageIndex, address l2Sender, uint16 l2TxNumberInBatch, bytes message, bytes32[] merkleProof) _finalizeWithdrawalParams)',
160
+ ]),
161
+ functionName: 'finalizeDeposit',
183
162
  args: [
184
- BigInt(l2Client.chain.id),
185
- l1BatchNumber!,
186
- BigInt(l2MessageIndex),
187
- Number(l2TxNumberInBlock),
188
- message,
189
- proof,
163
+ {
164
+ chainId: BigInt(l2Client.chain.id),
165
+ l2BatchNumber: finalizeWithdrawalParams.l1BatchNumber!,
166
+ l2MessageIndex: BigInt(finalizeWithdrawalParams.l2MessageIndex),
167
+ l2Sender: finalizeWithdrawalParams.sender,
168
+ l2TxNumberInBatch: Number(finalizeWithdrawalParams.l2TxNumberInBlock),
169
+ message: finalizeWithdrawalParams.message,
170
+ merkleProof: finalizeWithdrawalParams.proof,
171
+ },
190
172
  ],
191
173
  })
192
174
 
193
175
  return await sendTransaction(client, {
194
176
  account,
195
- to: l1Bridge,
177
+ to: l1Nullifier,
196
178
  data,
197
- value: 0n,
198
179
  ...rest,
199
180
  } as SendTransactionParameters)
200
181
  }
@@ -230,19 +211,40 @@ async function getFinalizeWithdrawalParams<
230
211
  }
231
212
  }
232
213
 
233
- async function isLegacyBridge<
214
+ async function getBridgeAddresses<
234
215
  chain extends Chain | undefined,
235
- account extends Account | undefined,
236
- >(client: Client<Transport, chain, account>, parameters: { address: Address }) {
237
- try {
238
- await readContract(client, {
239
- address: parameters.address,
240
- abi: l2SharedBridgeAbi,
241
- functionName: 'l1SharedBridge',
216
+ chainL2 extends ChainEIP712 | undefined,
217
+ >(
218
+ client: Client<Transport, chain>,
219
+ l2Client: Client<Transport, chainL2>,
220
+ ): Promise<
221
+ BridgeContractAddresses & {
222
+ l1Nullifier: Address
223
+ l1NativeTokenVault: Address
224
+ }
225
+ > {
226
+ const addresses = await getDefaultBridgeAddresses(l2Client)
227
+ let l1Nullifier = addresses.l1Nullifier
228
+ let l1NativeTokenVault = addresses.l1NativeTokenVault
229
+
230
+ if (!l1Nullifier)
231
+ l1Nullifier = await readContract(client, {
232
+ address: addresses.sharedL1,
233
+ abi: parseAbi(['function L1_NULLIFIER() view returns (address)']),
234
+ functionName: 'L1_NULLIFIER',
242
235
  args: [],
243
236
  })
244
- return false
245
- } catch (_e) {
246
- return true
237
+ if (!l1NativeTokenVault)
238
+ l1NativeTokenVault = await readContract(client, {
239
+ address: addresses.sharedL1,
240
+ abi: parseAbi(['function nativeTokenVault() view returns (address)']),
241
+ functionName: 'nativeTokenVault',
242
+ args: [],
243
+ })
244
+
245
+ return {
246
+ ...addresses,
247
+ l1Nullifier,
248
+ l1NativeTokenVault,
247
249
  }
248
250
  }
@@ -14,9 +14,12 @@ export async function getDefaultBridgeAddresses<
14
14
  client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
15
15
  ): Promise<GetDefaultBridgeAddressesReturnType> {
16
16
  const addresses = await client.request({ method: 'zks_getBridgeContracts' })
17
+
17
18
  return {
18
19
  erc20L1: addresses.l1Erc20DefaultBridge,
19
20
  sharedL1: addresses.l1SharedDefaultBridge,
20
21
  sharedL2: addresses.l2SharedDefaultBridge,
22
+ l1Nullifier: addresses.l1Nullifier,
23
+ l1NativeTokenVault: addresses.l1NativeTokenVault,
21
24
  }
22
25
  }