@matterlabs/zksync-js 0.0.1 → 0.0.3
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.
- package/README.md +12 -12
- package/dist/adapters/ethers/client.cjs +642 -1
- package/dist/adapters/ethers/client.cjs.map +1 -1
- package/dist/adapters/ethers/client.js +6 -5
- package/dist/adapters/ethers/estimator.d.ts +4 -0
- package/dist/adapters/ethers/index.cjs +1279 -925
- package/dist/adapters/ethers/index.cjs.map +1 -1
- package/dist/adapters/ethers/index.d.ts +1 -0
- package/dist/adapters/ethers/index.js +9 -8
- package/dist/adapters/ethers/resources/contracts/contracts.d.ts +9 -0
- package/dist/adapters/ethers/resources/contracts/index.d.ts +2 -0
- package/dist/adapters/ethers/resources/contracts/types.d.ts +60 -0
- package/dist/adapters/ethers/resources/deposits/context.d.ts +21 -7
- package/dist/adapters/ethers/resources/deposits/index.d.ts +3 -1
- package/dist/adapters/ethers/resources/deposits/routes/types.d.ts +2 -6
- package/dist/adapters/ethers/resources/deposits/services/fee.d.ts +6 -0
- package/dist/adapters/ethers/resources/deposits/services/gas.d.ts +41 -0
- package/dist/adapters/ethers/resources/tokens/index.d.ts +1 -0
- package/dist/adapters/ethers/resources/tokens/tokens.d.ts +10 -0
- package/dist/adapters/ethers/resources/utils.d.ts +3 -17
- package/dist/adapters/ethers/resources/withdrawals/context.d.ts +15 -7
- package/dist/adapters/ethers/resources/withdrawals/index.d.ts +3 -1
- package/dist/adapters/ethers/resources/withdrawals/routes/types.d.ts +2 -2
- package/dist/adapters/ethers/resources/withdrawals/services/fees.d.ts +14 -0
- package/dist/adapters/ethers/resources/withdrawals/services/gas.d.ts +12 -0
- package/dist/adapters/ethers/sdk.cjs +1388 -1501
- package/dist/adapters/ethers/sdk.cjs.map +1 -1
- package/dist/adapters/ethers/sdk.d.ts +5 -22
- package/dist/adapters/ethers/sdk.js +7 -6
- package/dist/adapters/viem/client.cjs.map +1 -1
- package/dist/adapters/viem/client.d.ts +1 -1
- package/dist/adapters/viem/client.js +4 -5
- package/dist/adapters/viem/estimator.d.ts +4 -0
- package/dist/adapters/viem/index.cjs +1233 -744
- package/dist/adapters/viem/index.cjs.map +1 -1
- package/dist/adapters/viem/index.d.ts +3 -0
- package/dist/adapters/viem/index.js +8 -8
- package/dist/adapters/viem/resources/contracts/contracts.d.ts +9 -0
- package/dist/adapters/viem/resources/contracts/index.d.ts +2 -0
- package/dist/adapters/viem/resources/contracts/types.d.ts +61 -0
- package/dist/adapters/viem/resources/deposits/context.d.ts +21 -7
- package/dist/adapters/viem/resources/deposits/index.d.ts +3 -1
- package/dist/adapters/viem/resources/deposits/routes/types.d.ts +2 -6
- package/dist/adapters/viem/resources/deposits/services/fee.d.ts +6 -0
- package/dist/adapters/viem/resources/deposits/services/gas.d.ts +37 -0
- package/dist/adapters/viem/resources/tokens/index.d.ts +1 -0
- package/dist/adapters/viem/resources/tokens/tokens.d.ts +3 -0
- package/dist/adapters/viem/resources/utils.d.ts +3 -19
- package/dist/adapters/viem/resources/withdrawals/context.d.ts +14 -9
- package/dist/adapters/viem/resources/withdrawals/index.d.ts +3 -1
- package/dist/adapters/viem/resources/withdrawals/routes/types.d.ts +12 -2
- package/dist/adapters/viem/resources/withdrawals/services/fee.d.ts +17 -0
- package/dist/adapters/viem/resources/withdrawals/services/gas.d.ts +12 -0
- package/dist/adapters/viem/sdk.cjs +1225 -699
- package/dist/adapters/viem/sdk.cjs.map +1 -1
- package/dist/adapters/viem/sdk.d.ts +5 -25
- package/dist/adapters/viem/sdk.js +6 -6
- package/dist/{chunk-3LALBFFE.js → chunk-3MRGU4HV.js} +9 -5
- package/dist/{chunk-CGO27P7F.js → chunk-5YWP4CZP.js} +849 -835
- package/dist/{chunk-4HLJJKIY.js → chunk-6K6VJQAL.js} +2 -2
- package/dist/{chunk-6GCT6TLS.js → chunk-F2ENUV3A.js} +13 -1
- package/dist/{chunk-7M4V3FMT.js → chunk-JXUFGIJG.js} +986 -678
- package/dist/chunk-LL3WKCFJ.js +231 -0
- package/dist/{chunk-Y75OMFK6.js → chunk-M5J2MM2U.js} +351 -1
- package/dist/{chunk-263G6636.js → chunk-NCAIVYBR.js} +1 -14
- package/dist/{chunk-DI2CJDPZ.js → chunk-NEC2ZKHI.js} +5 -13
- package/dist/chunk-NTEIA5KA.js +13 -0
- package/dist/chunk-XRE7H466.js +157 -0
- package/dist/{chunk-BD2LUO5T.js → chunk-YUK547UF.js} +3 -3
- package/dist/core/abi.d.ts +9 -0
- package/dist/core/adapters/interfaces.d.ts +25 -0
- package/dist/core/codec/ntv.d.ts +48 -0
- package/dist/core/constants.cjs +12 -0
- package/dist/core/constants.cjs.map +1 -1
- package/dist/core/constants.d.ts +6 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/index.cjs +4508 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +5 -4
- package/dist/core/resources/deposits/fee.d.ts +15 -0
- package/dist/core/resources/deposits/gas.d.ts +38 -0
- package/dist/core/resources/withdrawals/gas.d.ts +14 -0
- package/dist/core/types/errors.d.ts +1 -1
- package/dist/core/types/fees.d.ts +40 -0
- package/dist/core/types/flows/base.d.ts +0 -10
- package/dist/core/types/flows/deposits.d.ts +20 -6
- package/dist/core/types/flows/route.d.ts +2 -3
- package/dist/core/types/flows/token.d.ts +192 -0
- package/dist/core/types/flows/withdrawals.d.ts +12 -6
- package/dist/core/utils/addr.d.ts +2 -0
- package/dist/index.cjs +4520 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -4
- package/package.json +5 -1
- package/dist/adapters/ethers/resources/token-info.d.ts +0 -31
- package/dist/adapters/ethers/resources/withdrawals/routes/eth-nonbase.d.ts +0 -2
- package/dist/adapters/viem/resources/token-info.d.ts +0 -34
- package/dist/adapters/viem/resources/withdrawals/routes/eth-nonbase.d.ts +0 -2
- package/dist/chunk-B77GWPO5.js +0 -339
- package/dist/core/internal/abi-registry.d.ts +0 -9
- package/dist/core/utils/gas.d.ts +0 -13
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { findL1MessageSentLog, messengerLogIndex, isAddressEq,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { ETH_ADDRESS,
|
|
1
|
+
import { createNTVCodec, buildFeeBreakdown, quoteL2Gas, quoteL2BaseCost, quoteL1Gas, quoteL2Gas2 } from './chunk-LL3WKCFJ.js';
|
|
2
|
+
import { findL1MessageSentLog, messengerLogIndex, normalizeL1Token, isAddressEq, hexEq, isHash66, isETH, normalizeAddrEq, pickWithdrawRoute } from './chunk-NEC2ZKHI.js';
|
|
3
|
+
import { createErrorHandlers, toZKsyncError, classifyReadinessFromRevert } from './chunk-XRE7H466.js';
|
|
4
|
+
import { OP_WITHDRAWALS, IL1Nullifier_default, createError, OP_DEPOSITS, IERC20_default, isZKsyncError, isReceiptNotFound } from './chunk-M5J2MM2U.js';
|
|
5
|
+
import { ETH_ADDRESS, L1_MESSENGER_ADDRESS, L2_ASSET_ROUTER_ADDRESS, L2_BASE_TOKEN_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, TOPIC_CANONICAL_ASSIGNED, TOPIC_CANONICAL_SUCCESS, SAFE_L1_BRIDGE_GAS } from './chunk-F2ENUV3A.js';
|
|
6
6
|
import { Interface, AbiCoder, ethers, Contract, NonceManager } from 'ethers';
|
|
7
7
|
|
|
8
8
|
var I_BRIDGEHUB = new Interface([
|
|
@@ -68,105 +68,67 @@ async function waitForL2ExecutionFromL1Tx(l1, l2, l1TxHash) {
|
|
|
68
68
|
}
|
|
69
69
|
return { l2Receipt, l2TxHash };
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
|
|
72
|
+
// src/adapters/ethers/resources/deposits/context.ts
|
|
73
|
+
async function commonCtx(p, client, tokens, contracts) {
|
|
74
|
+
const { bridgehub, l1AssetRouter } = await contracts.addresses();
|
|
75
|
+
const { chainId } = await client.l2.getNetwork();
|
|
76
|
+
const sender = await client.signer.getAddress();
|
|
77
|
+
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
78
|
+
const operatorTip = p.operatorTip ?? 0n;
|
|
79
|
+
const refundRecipient = p.refundRecipient ?? sender;
|
|
80
|
+
const resolvedToken = await tokens.resolve(p.token, { chain: "l1" });
|
|
81
|
+
const baseTokenAssetId = resolvedToken.baseTokenAssetId;
|
|
82
|
+
const baseTokenL1 = await tokens.l1TokenFromAssetId(baseTokenAssetId);
|
|
83
|
+
const baseIsEth = resolvedToken.isChainEthBased;
|
|
84
|
+
const route = (() => {
|
|
85
|
+
if (resolvedToken.kind === "eth") {
|
|
86
|
+
return baseIsEth ? "eth-base" : "eth-nonbase";
|
|
87
|
+
}
|
|
88
|
+
if (resolvedToken.kind === "base") {
|
|
89
|
+
return baseIsEth ? "eth-base" : "erc20-base";
|
|
90
|
+
}
|
|
91
|
+
return "erc20-nonbase";
|
|
92
|
+
})();
|
|
93
|
+
return {
|
|
94
|
+
client,
|
|
95
|
+
tokens,
|
|
96
|
+
contracts,
|
|
97
|
+
resolvedToken,
|
|
98
|
+
baseTokenAssetId,
|
|
99
|
+
baseTokenL1,
|
|
100
|
+
baseIsEth,
|
|
101
|
+
l1AssetRouter,
|
|
102
|
+
route,
|
|
103
|
+
bridgehub,
|
|
104
|
+
chainIdL2: BigInt(chainId),
|
|
105
|
+
sender,
|
|
106
|
+
gasOverrides: p.l1TxOverrides,
|
|
107
|
+
l2GasLimit: p.l2GasLimit,
|
|
108
|
+
gasPerPubdata,
|
|
109
|
+
operatorTip,
|
|
110
|
+
refundRecipient
|
|
111
|
+
};
|
|
81
112
|
}
|
|
82
113
|
function encodeNativeTokenVaultTransferData(amount, receiver, token) {
|
|
83
114
|
return new AbiCoder().encode(["uint256", "address", "address"], [amount, receiver, token]);
|
|
84
115
|
}
|
|
85
116
|
function encodeSecondBridgeDataV1(assetId, transferData) {
|
|
86
|
-
const
|
|
87
|
-
const data =
|
|
117
|
+
const abi2 = new AbiCoder();
|
|
118
|
+
const data = abi2.encode(["bytes32", "bytes"], [assetId, transferData]);
|
|
88
119
|
return ethers.concat(["0x01", data]);
|
|
89
120
|
}
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
[
|
|
94
|
-
[chainId, L2_NATIVE_TOKEN_VAULT_ADDRESS, address]
|
|
121
|
+
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
122
|
+
return AbiCoder.defaultAbiCoder().encode(
|
|
123
|
+
["address", "uint256", "address"],
|
|
124
|
+
[token, amount, l2Receiver]
|
|
95
125
|
);
|
|
96
|
-
return ethers.keccak256(hex);
|
|
97
|
-
}
|
|
98
|
-
function encodeNTVTransferData(amount, receiver, token) {
|
|
99
|
-
return new AbiCoder().encode(["uint256", "address", "address"], [amount, receiver, token]);
|
|
100
126
|
}
|
|
101
|
-
function
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
async function checkBaseCost(baseCost, value) {
|
|
105
|
-
const resolvedValue = await value;
|
|
106
|
-
if (baseCost > resolvedValue) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`The base cost of performing the priority operation is higher than the provided value parameter for the transaction: baseCost: ${String(baseCost)}, provided value: ${String(resolvedValue)}!`
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
async function getFeeOverrides(client, overrides) {
|
|
113
|
-
assertNoLegacyGas(overrides);
|
|
114
|
-
const fd = await client.l1.getFeeData();
|
|
115
|
-
const maxFeeFromProvider = fd.maxFeePerGas ?? void 0;
|
|
116
|
-
const maxPriorityFromProvider = fd.maxPriorityFeePerGas ?? void 0;
|
|
117
|
-
const gasPriceFallback = fd.gasPrice ?? void 0;
|
|
118
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeeFromProvider ?? gasPriceFallback;
|
|
119
|
-
if (maxFeePerGas == null) throw new Error("provider returned no gas price data");
|
|
120
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
121
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
122
|
-
const gasPriceForBaseCost = overrides?.maxFeePerGas ?? maxFeeFromProvider ?? gasPriceFallback ?? maxFeePerGas;
|
|
123
|
-
return {
|
|
124
|
-
gasLimit: overrides?.gasLimit,
|
|
125
|
-
maxFeePerGas,
|
|
126
|
-
maxPriorityFeePerGas,
|
|
127
|
-
gasPriceForBaseCost
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
async function getL2FeeOverrides(client, overrides) {
|
|
131
|
-
assertNoLegacyGas(overrides);
|
|
132
|
-
let maxFeeFromProvider;
|
|
133
|
-
let maxPriorityFromProvider;
|
|
134
|
-
let gasPriceFallback;
|
|
135
|
-
try {
|
|
136
|
-
const fd = await client.l2.getFeeData();
|
|
137
|
-
if (fd?.maxFeePerGas != null) maxFeeFromProvider = fd.maxFeePerGas;
|
|
138
|
-
if (fd?.maxPriorityFeePerGas != null) {
|
|
139
|
-
maxPriorityFromProvider = fd.maxPriorityFeePerGas;
|
|
140
|
-
}
|
|
141
|
-
if (fd?.gasPrice != null) gasPriceFallback = fd.gasPrice;
|
|
142
|
-
} catch {
|
|
143
|
-
}
|
|
144
|
-
if (gasPriceFallback == null) {
|
|
145
|
-
try {
|
|
146
|
-
if (supportsGetGasPrice(client.l2)) {
|
|
147
|
-
const gp = await client.l2.getGasPrice();
|
|
148
|
-
gasPriceFallback = typeof gp === "bigint" ? gp : BigInt(gp.toString());
|
|
149
|
-
}
|
|
150
|
-
} catch {
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeeFromProvider ?? gasPriceFallback;
|
|
154
|
-
if (maxFeePerGas == null) {
|
|
155
|
-
throw new Error("L2 provider returned no gas price data");
|
|
156
|
-
}
|
|
157
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
158
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
159
|
-
return {
|
|
160
|
-
gasLimit: overrides?.gasLimit,
|
|
161
|
-
maxFeePerGas,
|
|
162
|
-
maxPriorityFeePerGas
|
|
163
|
-
};
|
|
127
|
+
function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
128
|
+
return encodeSecondBridgeArgs(token, amount, l2Receiver);
|
|
164
129
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (fd.gasPrice != null) return fd.gasPrice;
|
|
168
|
-
if (fd.maxFeePerGas != null) return fd.maxFeePerGas;
|
|
169
|
-
throw new Error("provider returned no gas price data");
|
|
130
|
+
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
131
|
+
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
170
132
|
}
|
|
171
133
|
function buildDirectRequestStruct(args) {
|
|
172
134
|
return {
|
|
@@ -181,352 +143,310 @@ function buildDirectRequestStruct(args) {
|
|
|
181
143
|
refundRecipient: args.refundRecipient
|
|
182
144
|
};
|
|
183
145
|
}
|
|
184
|
-
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
185
|
-
return AbiCoder.defaultAbiCoder().encode(
|
|
186
|
-
["address", "uint256", "address"],
|
|
187
|
-
[token, amount, l2Receiver]
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
191
|
-
return encodeSecondBridgeArgs(token, amount, l2Receiver);
|
|
192
|
-
}
|
|
193
|
-
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
194
|
-
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
195
|
-
}
|
|
196
146
|
|
|
197
|
-
// src/adapters/ethers/
|
|
198
|
-
|
|
199
|
-
const { bridgehub, l1AssetRouter } = await client.ensureAddresses();
|
|
200
|
-
const { chainId } = await client.l2.getNetwork();
|
|
201
|
-
const sender = await client.signer.getAddress();
|
|
202
|
-
const fee = await getFeeOverrides(client, p.l1TxOverrides);
|
|
203
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
204
|
-
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
205
|
-
const operatorTip = p.operatorTip ?? 0n;
|
|
206
|
-
const refundRecipient = p.refundRecipient ?? sender;
|
|
207
|
-
const route = await pickDepositRoute(client, BigInt(chainId), p.token);
|
|
147
|
+
// src/adapters/ethers/estimator.ts
|
|
148
|
+
function toCoreTx(tx) {
|
|
208
149
|
return {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
l2GasLimit,
|
|
217
|
-
gasPerPubdata,
|
|
218
|
-
operatorTip,
|
|
219
|
-
refundRecipient
|
|
150
|
+
to: tx.to,
|
|
151
|
+
from: tx.from,
|
|
152
|
+
data: tx.data,
|
|
153
|
+
value: tx.value ? BigInt(tx.value) : void 0,
|
|
154
|
+
gasLimit: tx.gasLimit ? BigInt(tx.gasLimit) : void 0,
|
|
155
|
+
maxFeePerGas: tx.maxFeePerGas ? BigInt(tx.maxFeePerGas) : void 0,
|
|
156
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas ? BigInt(tx.maxPriorityFeePerGas) : void 0
|
|
220
157
|
};
|
|
221
158
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
ERROR_IFACES.push({ name: "Mailbox", iface: new Interface(Mailbox_default) });
|
|
253
|
-
} catch {
|
|
254
|
-
}
|
|
255
|
-
})();
|
|
256
|
-
function registerErrorAbi(name, abi) {
|
|
257
|
-
const existing = ERROR_IFACES.findIndex((x) => x.name === name);
|
|
258
|
-
const entry = { name, iface: new Interface(abi) };
|
|
259
|
-
if (existing >= 0) ERROR_IFACES[existing] = entry;
|
|
260
|
-
else ERROR_IFACES.push(entry);
|
|
261
|
-
}
|
|
262
|
-
function extractRevertData(e) {
|
|
263
|
-
const maybe = (
|
|
264
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
265
|
-
e?.data?.data ?? e?.error?.data ?? e?.data ?? e?.error?.error?.data ?? e?.info?.error?.data
|
|
266
|
-
);
|
|
267
|
-
if (typeof maybe === "string" && maybe.startsWith("0x") && maybe.length >= 10) {
|
|
268
|
-
return maybe;
|
|
269
|
-
}
|
|
270
|
-
return void 0;
|
|
271
|
-
}
|
|
272
|
-
function decodeRevert(e) {
|
|
273
|
-
const data = extractRevertData(e);
|
|
274
|
-
if (!data) return;
|
|
275
|
-
const selector = `0x${data.slice(2, 10)}`;
|
|
276
|
-
try {
|
|
277
|
-
const parsed = IFACE_ERROR_STRING.parseError(data);
|
|
278
|
-
if (parsed?.name === "Error") {
|
|
279
|
-
const args = parsed.args ? Array.from(parsed.args) : void 0;
|
|
280
|
-
return { selector, name: "Error", args };
|
|
281
|
-
}
|
|
282
|
-
} catch {
|
|
283
|
-
}
|
|
284
|
-
try {
|
|
285
|
-
const parsed = IFACE_PANIC.parseError(data);
|
|
286
|
-
if (parsed?.name === "Panic") {
|
|
287
|
-
const args = parsed.args ? Array.from(parsed.args) : void 0;
|
|
288
|
-
return { selector, name: "Panic", args };
|
|
289
|
-
}
|
|
290
|
-
} catch {
|
|
291
|
-
}
|
|
292
|
-
for (const { name, iface } of ERROR_IFACES) {
|
|
293
|
-
try {
|
|
294
|
-
const parsed = iface.parseError(data);
|
|
295
|
-
if (parsed) {
|
|
296
|
-
const args = parsed.args ? Array.from(parsed.args) : void 0;
|
|
297
|
-
return {
|
|
298
|
-
selector,
|
|
299
|
-
name: parsed.name,
|
|
300
|
-
args,
|
|
301
|
-
contract: name
|
|
302
|
-
};
|
|
159
|
+
function ethersToGasEstimator(provider) {
|
|
160
|
+
return {
|
|
161
|
+
async estimateGas(tx, stateOverrides) {
|
|
162
|
+
const ethTx = {
|
|
163
|
+
to: tx.to,
|
|
164
|
+
from: tx.from,
|
|
165
|
+
data: tx.data,
|
|
166
|
+
value: tx.value,
|
|
167
|
+
gasLimit: tx.gasLimit,
|
|
168
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
169
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
170
|
+
};
|
|
171
|
+
if (stateOverrides && "send" in provider) {
|
|
172
|
+
try {
|
|
173
|
+
const jsonRpcProvider = provider;
|
|
174
|
+
const result = await jsonRpcProvider.send("eth_estimateGas", [
|
|
175
|
+
ethTx,
|
|
176
|
+
"latest",
|
|
177
|
+
stateOverrides
|
|
178
|
+
]);
|
|
179
|
+
return BigInt(result);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.warn(
|
|
182
|
+
"Failed to estimate gas with state overrides, falling back to standard estimation:",
|
|
183
|
+
error
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
} else if (stateOverrides) {
|
|
187
|
+
console.warn('Provider does not support "send", skipping state overrides estimation.');
|
|
303
188
|
}
|
|
304
|
-
|
|
189
|
+
return await provider.estimateGas(ethTx);
|
|
190
|
+
},
|
|
191
|
+
async estimateFeesPerGas() {
|
|
192
|
+
const fd = await provider.getFeeData();
|
|
193
|
+
return {
|
|
194
|
+
maxFeePerGas: fd.maxFeePerGas != null ? BigInt(fd.maxFeePerGas) : void 0,
|
|
195
|
+
maxPriorityFeePerGas: fd.maxPriorityFeePerGas != null ? BigInt(fd.maxPriorityFeePerGas) : void 0,
|
|
196
|
+
gasPrice: fd.gasPrice != null ? BigInt(fd.gasPrice) : void 0
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
async getGasPrice() {
|
|
200
|
+
const fd = await provider.getFeeData();
|
|
201
|
+
if (fd.gasPrice != null) return BigInt(fd.gasPrice);
|
|
202
|
+
throw new Error("Could not fetch gas price");
|
|
203
|
+
},
|
|
204
|
+
async call(tx) {
|
|
205
|
+
const ethTx = {
|
|
206
|
+
to: tx.to,
|
|
207
|
+
data: tx.data,
|
|
208
|
+
value: tx.value,
|
|
209
|
+
from: tx.from
|
|
210
|
+
};
|
|
211
|
+
return await provider.call(ethTx);
|
|
305
212
|
}
|
|
306
|
-
}
|
|
307
|
-
return { selector };
|
|
213
|
+
};
|
|
308
214
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
215
|
+
|
|
216
|
+
// src/adapters/ethers/resources/deposits/services/fee.ts
|
|
217
|
+
var { wrapAs } = createErrorHandlers("deposits");
|
|
218
|
+
var encode = (abi2, fn, args) => {
|
|
219
|
+
return new Interface(abi2).encodeFunctionData(fn, args);
|
|
220
|
+
};
|
|
221
|
+
async function quoteL2BaseCost2(input) {
|
|
222
|
+
const { ctx, l2GasLimit } = input;
|
|
223
|
+
const estimator = ethersToGasEstimator(ctx.client.l1);
|
|
224
|
+
return wrapAs(
|
|
225
|
+
"RPC",
|
|
226
|
+
"deposits.fees.l2BaseCost",
|
|
227
|
+
() => quoteL2BaseCost({
|
|
228
|
+
estimator,
|
|
229
|
+
encode,
|
|
230
|
+
bridgehub: ctx.bridgehub,
|
|
231
|
+
chainIdL2: ctx.chainIdL2,
|
|
232
|
+
l2GasLimit,
|
|
233
|
+
gasPerPubdata: ctx.gasPerPubdata
|
|
234
|
+
}),
|
|
235
|
+
{ ctx: { chainIdL2: ctx.chainIdL2 } }
|
|
236
|
+
);
|
|
325
237
|
}
|
|
326
238
|
|
|
327
|
-
// src/adapters/ethers/
|
|
328
|
-
function
|
|
329
|
-
|
|
330
|
-
const
|
|
331
|
-
return
|
|
239
|
+
// src/adapters/ethers/resources/deposits/services/gas.ts
|
|
240
|
+
async function quoteL1Gas2(input) {
|
|
241
|
+
const { ctx, tx, overrides, fallbackGasLimit } = input;
|
|
242
|
+
const estimator = ethersToGasEstimator(ctx.client.l1);
|
|
243
|
+
return quoteL1Gas({
|
|
244
|
+
estimator,
|
|
245
|
+
tx: toCoreTx(tx),
|
|
246
|
+
overrides,
|
|
247
|
+
fallbackGasLimit
|
|
248
|
+
});
|
|
332
249
|
}
|
|
333
|
-
function
|
|
334
|
-
|
|
335
|
-
|
|
250
|
+
async function quoteL2Gas3(input) {
|
|
251
|
+
const { ctx, route, l2TxForModeling, overrideGasLimit } = input;
|
|
252
|
+
const estimator = ethersToGasEstimator(ctx.client.l2);
|
|
253
|
+
return quoteL2Gas({
|
|
254
|
+
estimator,
|
|
255
|
+
route,
|
|
256
|
+
tx: l2TxForModeling ? toCoreTx(l2TxForModeling) : void 0,
|
|
257
|
+
gasPerPubdata: ctx.gasPerPubdata,
|
|
258
|
+
l2GasLimit: ctx.l2GasLimit,
|
|
259
|
+
overrideGasLimit,
|
|
260
|
+
stateOverrides: input.stateOverrides
|
|
261
|
+
});
|
|
336
262
|
}
|
|
337
|
-
function
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
function wrap2(operation, fn, opts) {
|
|
348
|
-
return run("INTERNAL", operation, fn, opts);
|
|
349
|
-
}
|
|
350
|
-
function wrapAs9(kind, operation, fn, opts) {
|
|
351
|
-
return run(kind, operation, fn, opts);
|
|
263
|
+
async function determineErc20L2Gas(input) {
|
|
264
|
+
const { ctx, l1Token } = input;
|
|
265
|
+
const DEFAULT_SAFE_L2_GAS_LIMIT = 3000000n;
|
|
266
|
+
if (ctx.l2GasLimit != null) {
|
|
267
|
+
return quoteL2Gas3({
|
|
268
|
+
ctx,
|
|
269
|
+
route: "erc20-nonbase",
|
|
270
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
271
|
+
});
|
|
352
272
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
resource,
|
|
362
|
-
operation,
|
|
363
|
-
context: opts?.ctx ?? {},
|
|
364
|
-
message: resolveMessage(operation, opts?.message)
|
|
365
|
-
},
|
|
366
|
-
e
|
|
367
|
-
);
|
|
368
|
-
return { ok: false, error: shaped };
|
|
273
|
+
try {
|
|
274
|
+
const l2TokenAddress = ctx.tokens ? await ctx.tokens.toL2Address(l1Token) : await (await ctx.contracts.l2NativeTokenVault()).l2TokenAddress(l1Token);
|
|
275
|
+
if (l2TokenAddress === "0x0000000000000000000000000000000000000000") {
|
|
276
|
+
return quoteL2Gas3({
|
|
277
|
+
ctx,
|
|
278
|
+
route: "erc20-nonbase",
|
|
279
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
280
|
+
});
|
|
369
281
|
}
|
|
282
|
+
const modelTx = {
|
|
283
|
+
to: input.modelTx?.to ?? ctx.sender,
|
|
284
|
+
from: input.modelTx?.from ?? ctx.sender,
|
|
285
|
+
data: input.modelTx?.data ?? "0x",
|
|
286
|
+
value: input.modelTx?.value ?? 0n
|
|
287
|
+
};
|
|
288
|
+
const gas = await quoteL2Gas3({
|
|
289
|
+
ctx,
|
|
290
|
+
route: "erc20-nonbase",
|
|
291
|
+
l2TxForModeling: modelTx
|
|
292
|
+
});
|
|
293
|
+
if (!gas) {
|
|
294
|
+
return quoteL2Gas3({
|
|
295
|
+
ctx,
|
|
296
|
+
route: "erc20-nonbase",
|
|
297
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return gas;
|
|
301
|
+
} catch (err) {
|
|
302
|
+
console.warn("Failed to determine ERC20 L2 gas; defaulting to safe gas limit.", err);
|
|
303
|
+
return quoteL2Gas3({
|
|
304
|
+
ctx,
|
|
305
|
+
route: "erc20-nonbase",
|
|
306
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
307
|
+
});
|
|
370
308
|
}
|
|
371
|
-
return { wrap: wrap2, wrapAs: wrapAs9, toResult: toResult2 };
|
|
372
309
|
}
|
|
373
310
|
|
|
374
311
|
// src/adapters/ethers/resources/deposits/routes/eth.ts
|
|
375
|
-
var { wrapAs } = createErrorHandlers("deposits");
|
|
376
312
|
function routeEthDirect() {
|
|
377
313
|
return {
|
|
378
314
|
async build(p, ctx) {
|
|
379
|
-
const bh =
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
315
|
+
const bh = await ctx.contracts.bridgehub();
|
|
316
|
+
const l2TxModel = {
|
|
317
|
+
to: p.to ?? ctx.sender,
|
|
318
|
+
from: ctx.sender,
|
|
319
|
+
data: "0x",
|
|
320
|
+
value: 0n
|
|
321
|
+
};
|
|
322
|
+
const l2GasParams = await quoteL2Gas3({
|
|
323
|
+
ctx,
|
|
324
|
+
route: "eth-base",
|
|
325
|
+
l2TxForModeling: l2TxModel,
|
|
326
|
+
overrideGasLimit: ctx.l2GasLimit,
|
|
327
|
+
stateOverrides: {
|
|
328
|
+
[ctx.sender]: {
|
|
329
|
+
balance: "0xffffffffffffffffffff"
|
|
330
|
+
}
|
|
393
331
|
}
|
|
394
|
-
);
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const
|
|
332
|
+
});
|
|
333
|
+
if (!l2GasParams) {
|
|
334
|
+
throw new Error("Failed to estimate L2 gas for deposit.");
|
|
335
|
+
}
|
|
336
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
337
|
+
const mintValue = baseCost + ctx.operatorTip + p.amount;
|
|
399
338
|
const req = buildDirectRequestStruct({
|
|
400
339
|
chainId: ctx.chainIdL2,
|
|
401
340
|
mintValue,
|
|
402
|
-
l2GasLimit:
|
|
341
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
403
342
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
404
343
|
refundRecipient: ctx.refundRecipient,
|
|
405
|
-
l2Contract,
|
|
406
|
-
l2Value
|
|
344
|
+
l2Contract: p.to ?? ctx.sender,
|
|
345
|
+
l2Value: p.amount
|
|
407
346
|
});
|
|
408
347
|
const data = bh.interface.encodeFunctionData("requestL2TransactionDirect", [req]);
|
|
409
|
-
|
|
410
|
-
const tx = {
|
|
348
|
+
const l1TxCandidate = {
|
|
411
349
|
to: ctx.bridgehub,
|
|
412
350
|
data,
|
|
413
351
|
value: mintValue,
|
|
414
352
|
from: ctx.sender,
|
|
415
|
-
...
|
|
353
|
+
...ctx.gasOverrides
|
|
416
354
|
};
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
{
|
|
427
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub },
|
|
428
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
429
|
-
}
|
|
430
|
-
);
|
|
431
|
-
const buffered = BigInt(est) * 115n / 100n;
|
|
432
|
-
tx.gasLimit = buffered;
|
|
433
|
-
resolvedL1GasLimit = buffered;
|
|
434
|
-
} catch {
|
|
435
|
-
}
|
|
355
|
+
const l1GasParams = await quoteL1Gas2({
|
|
356
|
+
ctx,
|
|
357
|
+
tx: l1TxCandidate,
|
|
358
|
+
overrides: ctx.gasOverrides
|
|
359
|
+
});
|
|
360
|
+
if (l1GasParams) {
|
|
361
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
362
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
363
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
436
364
|
}
|
|
437
365
|
const steps = [
|
|
438
366
|
{
|
|
439
367
|
key: "bridgehub:direct",
|
|
440
368
|
kind: "bridgehub:direct",
|
|
441
369
|
description: "Bridge ETH via Bridgehub.requestL2TransactionDirect",
|
|
442
|
-
tx
|
|
370
|
+
tx: l1TxCandidate
|
|
443
371
|
}
|
|
444
372
|
];
|
|
373
|
+
const fees = buildFeeBreakdown({
|
|
374
|
+
feeToken: ETH_ADDRESS,
|
|
375
|
+
l1Gas: l1GasParams,
|
|
376
|
+
l2Gas: l2GasParams,
|
|
377
|
+
l2BaseCost: baseCost,
|
|
378
|
+
operatorTip: ctx.operatorTip,
|
|
379
|
+
mintValue
|
|
380
|
+
});
|
|
445
381
|
return {
|
|
446
382
|
steps,
|
|
447
383
|
approvals: [],
|
|
448
|
-
|
|
384
|
+
fees
|
|
449
385
|
};
|
|
450
386
|
}
|
|
451
387
|
};
|
|
452
388
|
}
|
|
453
389
|
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
454
|
-
var MIN_L2_GAS_FOR_ERC20 = 2500000n;
|
|
455
390
|
function routeErc20NonBase() {
|
|
456
391
|
return {
|
|
457
|
-
async preflight() {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const bh = new Contract(ctx.bridgehub, IBridgehub_default, ctx.client.l1);
|
|
461
|
-
const assetRouter = ctx.l1AssetRouter;
|
|
462
|
-
const { gasPriceForBaseCost, gasLimit: overrideGasLimit, ...txFeeOverrides } = ctx.fee;
|
|
463
|
-
const txOverrides = overrideGasLimit != null ? { ...txFeeOverrides, gasLimit: overrideGasLimit } : txFeeOverrides;
|
|
464
|
-
let resolvedL1GasLimit = overrideGasLimit ?? ctx.l2GasLimit;
|
|
465
|
-
const baseToken = await wrapAs2(
|
|
466
|
-
"CONTRACT",
|
|
467
|
-
OP_DEPOSITS.nonbase.baseToken ?? "deposits.erc20-nonbase:baseToken",
|
|
468
|
-
() => bh.baseToken(ctx.chainIdL2),
|
|
469
|
-
{
|
|
470
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
471
|
-
message: "Failed to read base token."
|
|
472
|
-
}
|
|
473
|
-
);
|
|
392
|
+
async preflight(p, ctx) {
|
|
393
|
+
const resolved = ctx.resolvedToken ?? (ctx.tokens ? await ctx.tokens.resolve(p.token, { chain: "l1" }) : void 0);
|
|
394
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
474
395
|
await wrapAs2(
|
|
475
396
|
"VALIDATION",
|
|
476
397
|
OP_DEPOSITS.nonbase.assertNonBaseToken,
|
|
477
398
|
() => {
|
|
478
|
-
if (
|
|
399
|
+
if (resolved?.kind === "base" || resolved?.kind === "eth") {
|
|
479
400
|
throw new Error("erc20-nonbase route requires a non-base ERC-20 deposit token.");
|
|
480
401
|
}
|
|
481
402
|
},
|
|
482
403
|
{ ctx: { depositToken: p.token, baseToken } }
|
|
483
404
|
);
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
405
|
+
},
|
|
406
|
+
async build(p, ctx) {
|
|
407
|
+
const l1Signer = ctx.client.getL1Signer();
|
|
408
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
409
|
+
const baseIsEth = ctx.baseIsEth ?? isETH(baseToken);
|
|
410
|
+
const l2GasParams = await determineErc20L2Gas({
|
|
411
|
+
ctx,
|
|
412
|
+
l1Token: p.token,
|
|
413
|
+
modelTx: {
|
|
414
|
+
to: p.to ?? ctx.sender,
|
|
415
|
+
from: ctx.sender,
|
|
416
|
+
data: "0x",
|
|
417
|
+
value: 0n
|
|
497
418
|
}
|
|
498
|
-
);
|
|
499
|
-
|
|
419
|
+
});
|
|
420
|
+
if (!l2GasParams) throw new Error("Failed to establish L2 gas parameters.");
|
|
421
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
500
422
|
const mintValue = baseCost + ctx.operatorTip;
|
|
501
423
|
const approvals = [];
|
|
502
424
|
const steps = [];
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
{
|
|
511
|
-
|
|
512
|
-
message: "Failed to read deposit-token allowance."
|
|
513
|
-
}
|
|
514
|
-
);
|
|
515
|
-
if (allowanceToken < p.amount) {
|
|
516
|
-
approvals.push({ token: p.token, spender: assetRouter, amount: p.amount });
|
|
517
|
-
const data = erc20Deposit.interface.encodeFunctionData("approve", [
|
|
518
|
-
assetRouter,
|
|
519
|
-
p.amount
|
|
520
|
-
]);
|
|
521
|
-
steps.push({
|
|
522
|
-
key: `approve:${p.token}:${assetRouter}`,
|
|
523
|
-
kind: "approve",
|
|
524
|
-
description: `Approve ${p.amount} for router (deposit token)`,
|
|
525
|
-
tx: { to: p.token, data, from: ctx.sender, ...txOverrides }
|
|
526
|
-
});
|
|
425
|
+
const assetRouter = ctx.l1AssetRouter;
|
|
426
|
+
const erc20Deposit = new Contract(p.token, IERC20_default, l1Signer);
|
|
427
|
+
const allowanceToken = await wrapAs2(
|
|
428
|
+
"RPC",
|
|
429
|
+
OP_DEPOSITS.nonbase.allowanceToken,
|
|
430
|
+
() => erc20Deposit.allowance(ctx.sender, assetRouter),
|
|
431
|
+
{
|
|
432
|
+
ctx: { where: "erc20.allowance", token: p.token, spender: assetRouter },
|
|
433
|
+
message: "Failed to read deposit-token allowance."
|
|
527
434
|
}
|
|
435
|
+
);
|
|
436
|
+
if (allowanceToken < p.amount) {
|
|
437
|
+
approvals.push({ token: p.token, spender: assetRouter, amount: p.amount });
|
|
438
|
+
steps.push({
|
|
439
|
+
key: `approve:${p.token}:${assetRouter}`,
|
|
440
|
+
kind: "approve",
|
|
441
|
+
description: `Approve ${p.amount} for router (deposit token)`,
|
|
442
|
+
tx: {
|
|
443
|
+
to: p.token,
|
|
444
|
+
data: erc20Deposit.interface.encodeFunctionData("approve", [assetRouter, p.amount]),
|
|
445
|
+
from: ctx.sender,
|
|
446
|
+
...ctx.gasOverrides
|
|
447
|
+
}
|
|
448
|
+
});
|
|
528
449
|
}
|
|
529
|
-
const baseIsEth = isETH(baseToken);
|
|
530
450
|
if (!baseIsEth) {
|
|
531
451
|
const erc20Base = new Contract(baseToken, IERC20_default, l1Signer);
|
|
532
452
|
const allowanceBase = await wrapAs2(
|
|
@@ -540,12 +460,16 @@ function routeErc20NonBase() {
|
|
|
540
460
|
);
|
|
541
461
|
if (allowanceBase < mintValue) {
|
|
542
462
|
approvals.push({ token: baseToken, spender: assetRouter, amount: mintValue });
|
|
543
|
-
const data = erc20Base.interface.encodeFunctionData("approve", [assetRouter, mintValue]);
|
|
544
463
|
steps.push({
|
|
545
464
|
key: `approve:${baseToken}:${assetRouter}`,
|
|
546
465
|
kind: "approve",
|
|
547
466
|
description: `Approve base token for mintValue`,
|
|
548
|
-
tx: {
|
|
467
|
+
tx: {
|
|
468
|
+
to: baseToken,
|
|
469
|
+
data: erc20Base.interface.encodeFunctionData("approve", [assetRouter, mintValue]),
|
|
470
|
+
from: ctx.sender,
|
|
471
|
+
...ctx.gasOverrides
|
|
472
|
+
}
|
|
549
473
|
});
|
|
550
474
|
}
|
|
551
475
|
}
|
|
@@ -558,96 +482,86 @@ function routeErc20NonBase() {
|
|
|
558
482
|
message: "Failed to encode bridging calldata."
|
|
559
483
|
}
|
|
560
484
|
);
|
|
561
|
-
const
|
|
485
|
+
const requestStruct = {
|
|
562
486
|
chainId: ctx.chainIdL2,
|
|
563
487
|
mintValue,
|
|
564
|
-
// fees (in ETH if base=ETH, else pulled as base ERC-20)
|
|
565
488
|
l2Value: 0n,
|
|
566
|
-
l2GasLimit:
|
|
489
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
567
490
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
568
491
|
refundRecipient: ctx.refundRecipient,
|
|
569
492
|
secondBridgeAddress: assetRouter,
|
|
570
493
|
secondBridgeValue: 0n,
|
|
571
494
|
secondBridgeCalldata
|
|
572
495
|
};
|
|
573
|
-
const
|
|
574
|
-
const
|
|
496
|
+
const bh = await ctx.contracts.bridgehub();
|
|
497
|
+
const data = bh.interface.encodeFunctionData("requestL2TransactionTwoBridges", [
|
|
498
|
+
requestStruct
|
|
499
|
+
]);
|
|
500
|
+
const txValue = baseIsEth ? mintValue : 0n;
|
|
501
|
+
const l1TxCandidate = {
|
|
575
502
|
to: ctx.bridgehub,
|
|
576
|
-
data
|
|
577
|
-
value:
|
|
503
|
+
data,
|
|
504
|
+
value: txValue,
|
|
578
505
|
from: ctx.sender,
|
|
579
|
-
...
|
|
506
|
+
...ctx.gasOverrides
|
|
580
507
|
};
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub, baseIsEth },
|
|
592
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
593
|
-
}
|
|
594
|
-
);
|
|
595
|
-
const buffered = BigInt(est) * 125n / 100n;
|
|
596
|
-
bridgeTx.gasLimit = buffered;
|
|
597
|
-
resolvedL1GasLimit = buffered;
|
|
598
|
-
} catch {
|
|
599
|
-
}
|
|
508
|
+
const l1GasParams = await quoteL1Gas2({
|
|
509
|
+
ctx,
|
|
510
|
+
tx: l1TxCandidate,
|
|
511
|
+
overrides: ctx.gasOverrides,
|
|
512
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
513
|
+
});
|
|
514
|
+
if (l1GasParams) {
|
|
515
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
516
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
517
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
600
518
|
}
|
|
601
519
|
steps.push({
|
|
602
|
-
key: "bridgehub:two-bridges
|
|
520
|
+
key: "bridgehub:two-bridges",
|
|
603
521
|
kind: "bridgehub:two-bridges",
|
|
604
|
-
description: baseIsEth ? "Bridge ERC-20 (
|
|
605
|
-
tx:
|
|
522
|
+
description: baseIsEth ? "Bridge ERC-20 (Fees paid in ETH)" : "Bridge ERC-20 (Fees paid in Base Token)",
|
|
523
|
+
tx: l1TxCandidate
|
|
524
|
+
});
|
|
525
|
+
const fees = buildFeeBreakdown({
|
|
526
|
+
feeToken: baseToken,
|
|
527
|
+
l1Gas: l1GasParams,
|
|
528
|
+
l2Gas: l2GasParams,
|
|
529
|
+
l2BaseCost: baseCost,
|
|
530
|
+
operatorTip: ctx.operatorTip,
|
|
531
|
+
mintValue
|
|
606
532
|
});
|
|
607
533
|
return {
|
|
608
534
|
steps,
|
|
609
535
|
approvals,
|
|
610
|
-
|
|
536
|
+
fees
|
|
611
537
|
};
|
|
612
538
|
}
|
|
613
539
|
};
|
|
614
540
|
}
|
|
615
541
|
var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
|
|
616
|
-
var BASE_COST_BUFFER_BPS = 100n;
|
|
617
|
-
var BPS = 10000n;
|
|
618
|
-
var withBuffer = (x) => x * (BPS + BASE_COST_BUFFER_BPS) / BPS;
|
|
619
542
|
function routeEthNonBase() {
|
|
620
543
|
return {
|
|
621
544
|
async preflight(p, ctx) {
|
|
545
|
+
const resolved = ctx.resolvedToken ?? (ctx.tokens ? await ctx.tokens.resolve(p.token, { chain: "l1" }) : void 0);
|
|
622
546
|
await wrapAs3(
|
|
623
547
|
"VALIDATION",
|
|
624
548
|
OP_DEPOSITS.ethNonBase.assertEthAsset,
|
|
625
549
|
() => {
|
|
626
|
-
if (!isETH(p.token)) {
|
|
550
|
+
if (resolved?.kind !== "eth" && !isETH(p.token)) {
|
|
627
551
|
throw new Error("eth-nonbase route requires ETH as the deposit asset.");
|
|
628
552
|
}
|
|
629
553
|
},
|
|
630
554
|
{ ctx: { token: p.token } }
|
|
631
555
|
);
|
|
632
|
-
const bh = new Contract(ctx.bridgehub, IBridgehub_default, ctx.client.l1);
|
|
633
|
-
const baseToken = await wrapAs3(
|
|
634
|
-
"CONTRACT",
|
|
635
|
-
OP_DEPOSITS.ethNonBase.baseToken,
|
|
636
|
-
() => bh.baseToken(ctx.chainIdL2),
|
|
637
|
-
{
|
|
638
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
639
|
-
message: "Failed to read base token."
|
|
640
|
-
}
|
|
641
|
-
);
|
|
642
556
|
await wrapAs3(
|
|
643
557
|
"VALIDATION",
|
|
644
558
|
OP_DEPOSITS.ethNonBase.assertNonEthBase,
|
|
645
559
|
() => {
|
|
646
|
-
if (
|
|
560
|
+
if (ctx.baseIsEth) {
|
|
647
561
|
throw new Error("eth-nonbase route requires target chain base token \u2260 ETH.");
|
|
648
562
|
}
|
|
649
563
|
},
|
|
650
|
-
{ ctx: {
|
|
564
|
+
{ ctx: { baseIsEth: ctx.baseIsEth, chainIdL2: ctx.chainIdL2 } }
|
|
651
565
|
);
|
|
652
566
|
const ethBal = await wrapAs3(
|
|
653
567
|
"RPC",
|
|
@@ -671,61 +585,48 @@ function routeEthNonBase() {
|
|
|
671
585
|
return;
|
|
672
586
|
},
|
|
673
587
|
async build(p, ctx) {
|
|
674
|
-
const
|
|
675
|
-
const
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
588
|
+
const l1Signer = ctx.client.getL1Signer();
|
|
589
|
+
const baseToken = ctx.baseTokenL1;
|
|
590
|
+
const l2TxModel = {
|
|
591
|
+
to: p.to ?? ctx.sender,
|
|
592
|
+
from: ctx.sender,
|
|
593
|
+
data: "0x",
|
|
594
|
+
value: 0n
|
|
595
|
+
};
|
|
596
|
+
const l2GasParams = await quoteL2Gas3({
|
|
597
|
+
ctx,
|
|
598
|
+
route: "eth-nonbase",
|
|
599
|
+
l2TxForModeling: l2TxModel,
|
|
600
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
601
|
+
});
|
|
602
|
+
if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
|
|
603
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
604
|
+
const mintValue = baseCost + ctx.operatorTip;
|
|
605
|
+
const approvals = [];
|
|
606
|
+
const steps = [];
|
|
607
|
+
const erc20Base = new Contract(baseToken, IERC20_default, l1Signer);
|
|
608
|
+
const allowance = await wrapAs3(
|
|
687
609
|
"RPC",
|
|
688
|
-
OP_DEPOSITS.ethNonBase.
|
|
689
|
-
() =>
|
|
690
|
-
ctx.chainIdL2,
|
|
691
|
-
gasPriceForBaseCost,
|
|
692
|
-
ctx.l2GasLimit,
|
|
693
|
-
ctx.gasPerPubdata
|
|
694
|
-
),
|
|
610
|
+
OP_DEPOSITS.ethNonBase.allowanceBase,
|
|
611
|
+
() => erc20Base.allowance(ctx.sender, ctx.l1AssetRouter),
|
|
695
612
|
{
|
|
696
|
-
ctx: { where: "
|
|
697
|
-
message: "
|
|
613
|
+
ctx: { where: "erc20.allowance", token: baseToken, spender: ctx.l1AssetRouter },
|
|
614
|
+
message: "Failed to read base-token allowance."
|
|
698
615
|
}
|
|
699
616
|
);
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
{
|
|
712
|
-
ctx: { where: "erc20.allowance", token: baseToken, spender: ctx.l1AssetRouter },
|
|
713
|
-
message: "Failed to read base-token allowance."
|
|
617
|
+
if (allowance < mintValue) {
|
|
618
|
+
approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
|
|
619
|
+
steps.push({
|
|
620
|
+
key: `approve:${baseToken}`,
|
|
621
|
+
kind: "approve",
|
|
622
|
+
description: `Approve base token for fees (mintValue)`,
|
|
623
|
+
tx: {
|
|
624
|
+
to: baseToken,
|
|
625
|
+
data: erc20Base.interface.encodeFunctionData("approve", [ctx.l1AssetRouter, mintValue]),
|
|
626
|
+
from: ctx.sender,
|
|
627
|
+
...ctx.gasOverrides
|
|
714
628
|
}
|
|
715
|
-
);
|
|
716
|
-
if (allowance < mintValue) {
|
|
717
|
-
approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
|
|
718
|
-
const data = erc20.interface.encodeFunctionData("approve", [
|
|
719
|
-
ctx.l1AssetRouter,
|
|
720
|
-
mintValue
|
|
721
|
-
]);
|
|
722
|
-
steps.push({
|
|
723
|
-
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
724
|
-
kind: "approve",
|
|
725
|
-
description: `Approve base token for mintValue`,
|
|
726
|
-
tx: { to: baseToken, data, from: ctx.sender, ...txOverrides }
|
|
727
|
-
});
|
|
728
|
-
}
|
|
629
|
+
});
|
|
729
630
|
}
|
|
730
631
|
const secondBridgeCalldata = await wrapAs3(
|
|
731
632
|
"INTERNAL",
|
|
@@ -739,92 +640,78 @@ function routeEthNonBase() {
|
|
|
739
640
|
}
|
|
740
641
|
}
|
|
741
642
|
);
|
|
742
|
-
const
|
|
643
|
+
const requestStruct = {
|
|
743
644
|
chainId: ctx.chainIdL2,
|
|
744
645
|
mintValue,
|
|
745
|
-
l2Value:
|
|
746
|
-
l2GasLimit:
|
|
646
|
+
l2Value: p.amount,
|
|
647
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
747
648
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
748
649
|
refundRecipient: ctx.refundRecipient,
|
|
749
650
|
secondBridgeAddress: ctx.l1AssetRouter,
|
|
750
651
|
secondBridgeValue: p.amount,
|
|
751
652
|
secondBridgeCalldata
|
|
752
653
|
};
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
let resolvedL1GasLimit = overrideGasLimit ?? ctx.l2GasLimit;
|
|
759
|
-
const bridgeTx = {
|
|
654
|
+
const bridgehub = await ctx.contracts.bridgehub();
|
|
655
|
+
const data = bridgehub.interface.encodeFunctionData("requestL2TransactionTwoBridges", [
|
|
656
|
+
requestStruct
|
|
657
|
+
]);
|
|
658
|
+
const l1TxCandidate = {
|
|
760
659
|
to: ctx.bridgehub,
|
|
761
|
-
data
|
|
660
|
+
data,
|
|
762
661
|
value: p.amount,
|
|
763
662
|
// base ≠ ETH ⇒ msg.value == secondBridgeValue
|
|
764
663
|
from: ctx.sender,
|
|
765
|
-
...
|
|
664
|
+
...ctx.gasOverrides
|
|
766
665
|
};
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub },
|
|
778
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
779
|
-
}
|
|
780
|
-
);
|
|
781
|
-
const buffered = BigInt(est) * 115n / 100n;
|
|
782
|
-
bridgeTx.gasLimit = buffered;
|
|
783
|
-
resolvedL1GasLimit = buffered;
|
|
784
|
-
} catch {
|
|
785
|
-
}
|
|
666
|
+
const l1GasParams = await quoteL1Gas2({
|
|
667
|
+
ctx,
|
|
668
|
+
tx: l1TxCandidate,
|
|
669
|
+
overrides: ctx.gasOverrides,
|
|
670
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
671
|
+
});
|
|
672
|
+
if (l1GasParams) {
|
|
673
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
674
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
675
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
786
676
|
}
|
|
787
677
|
steps.push({
|
|
788
678
|
key: "bridgehub:two-bridges:eth-nonbase",
|
|
789
679
|
kind: "bridgehub:two-bridges",
|
|
790
680
|
description: "Bridge ETH (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
|
|
791
|
-
tx:
|
|
681
|
+
tx: l1TxCandidate
|
|
682
|
+
});
|
|
683
|
+
const fees = buildFeeBreakdown({
|
|
684
|
+
feeToken: baseToken,
|
|
685
|
+
l1Gas: l1GasParams,
|
|
686
|
+
l2Gas: l2GasParams,
|
|
687
|
+
l2BaseCost: baseCost,
|
|
688
|
+
operatorTip: ctx.operatorTip,
|
|
689
|
+
mintValue
|
|
792
690
|
});
|
|
793
691
|
return {
|
|
794
692
|
steps,
|
|
795
693
|
approvals,
|
|
796
|
-
|
|
694
|
+
fees
|
|
797
695
|
};
|
|
798
696
|
}
|
|
799
697
|
};
|
|
800
698
|
}
|
|
801
699
|
var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
|
|
802
|
-
var BASE_COST_BUFFER_BPS2 = 100n;
|
|
803
|
-
var BPS2 = 10000n;
|
|
804
|
-
var withBuffer2 = (x) => x * (BPS2 + BASE_COST_BUFFER_BPS2) / BPS2;
|
|
805
700
|
function routeErc20Base() {
|
|
806
701
|
return {
|
|
807
702
|
async preflight(p, ctx) {
|
|
703
|
+
const resolved = ctx.resolvedToken ?? (ctx.tokens ? await ctx.tokens.resolve(p.token, { chain: "l1" }) : void 0);
|
|
808
704
|
await wrapAs4(
|
|
809
705
|
"VALIDATION",
|
|
810
706
|
OP_DEPOSITS.base.assertErc20Asset,
|
|
811
707
|
() => {
|
|
812
|
-
if (isETH(p.token)) {
|
|
708
|
+
if (resolved?.kind === "eth" || isETH(p.token)) {
|
|
813
709
|
throw new Error("erc20-base route requires an ERC-20 token (not ETH).");
|
|
814
710
|
}
|
|
815
711
|
},
|
|
816
712
|
{ ctx: { token: p.token } }
|
|
817
713
|
);
|
|
818
|
-
const
|
|
819
|
-
const baseToken = await wrapAs4(
|
|
820
|
-
"CONTRACT",
|
|
821
|
-
OP_DEPOSITS.base.baseToken,
|
|
822
|
-
() => bh.baseToken(ctx.chainIdL2),
|
|
823
|
-
{
|
|
824
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
825
|
-
message: "Failed to read base token."
|
|
826
|
-
}
|
|
827
|
-
);
|
|
714
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
828
715
|
await wrapAs4(
|
|
829
716
|
"VALIDATION",
|
|
830
717
|
OP_DEPOSITS.base.assertMatchesBase,
|
|
@@ -838,41 +725,27 @@ function routeErc20Base() {
|
|
|
838
725
|
return;
|
|
839
726
|
},
|
|
840
727
|
async build(p, ctx) {
|
|
841
|
-
const
|
|
842
|
-
const
|
|
843
|
-
const
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
"
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
ctx.chainIdL2,
|
|
859
|
-
gasPriceForBaseCost,
|
|
860
|
-
ctx.l2GasLimit,
|
|
861
|
-
ctx.gasPerPubdata
|
|
862
|
-
),
|
|
863
|
-
{
|
|
864
|
-
ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
|
|
865
|
-
message: "Could not fetch L2 base cost from Bridgehub."
|
|
866
|
-
}
|
|
867
|
-
);
|
|
868
|
-
const baseCost = BigInt(rawBaseCost);
|
|
869
|
-
const l2Value = p.amount;
|
|
870
|
-
const rawMintValue = baseCost + ctx.operatorTip + l2Value;
|
|
871
|
-
const mintValue = withBuffer2(rawMintValue);
|
|
728
|
+
const l1Signer = ctx.client.getL1Signer();
|
|
729
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
730
|
+
const l2TxModel = {
|
|
731
|
+
to: p.to ?? ctx.sender,
|
|
732
|
+
from: ctx.sender,
|
|
733
|
+
data: "0x",
|
|
734
|
+
value: 0n
|
|
735
|
+
};
|
|
736
|
+
const l2GasParams = await quoteL2Gas3({
|
|
737
|
+
ctx,
|
|
738
|
+
route: "erc20-base",
|
|
739
|
+
l2TxForModeling: l2TxModel,
|
|
740
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
741
|
+
});
|
|
742
|
+
if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
|
|
743
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
744
|
+
const mintValue = baseCost + ctx.operatorTip + p.amount;
|
|
872
745
|
const approvals = [];
|
|
873
746
|
const steps = [];
|
|
874
747
|
{
|
|
875
|
-
const erc20 = new Contract(baseToken, IERC20_default,
|
|
748
|
+
const erc20 = new Contract(baseToken, IERC20_default, l1Signer);
|
|
876
749
|
const allowance = await wrapAs4(
|
|
877
750
|
"RPC",
|
|
878
751
|
OP_DEPOSITS.base.allowance,
|
|
@@ -884,74 +757,333 @@ function routeErc20Base() {
|
|
|
884
757
|
);
|
|
885
758
|
if (allowance < mintValue) {
|
|
886
759
|
approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
|
|
887
|
-
const data2 = erc20.interface.encodeFunctionData("approve", [
|
|
888
|
-
ctx.l1AssetRouter,
|
|
889
|
-
mintValue
|
|
890
|
-
]);
|
|
891
760
|
steps.push({
|
|
892
761
|
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
893
762
|
kind: "approve",
|
|
894
763
|
description: "Approve base token for mintValue",
|
|
895
|
-
tx: {
|
|
764
|
+
tx: {
|
|
765
|
+
to: baseToken,
|
|
766
|
+
data: erc20.interface.encodeFunctionData("approve", [ctx.l1AssetRouter, mintValue]),
|
|
767
|
+
from: ctx.sender,
|
|
768
|
+
...ctx.gasOverrides
|
|
769
|
+
}
|
|
896
770
|
});
|
|
897
771
|
}
|
|
898
772
|
}
|
|
899
|
-
const
|
|
773
|
+
const requestStruct = buildDirectRequestStruct({
|
|
900
774
|
chainId: ctx.chainIdL2,
|
|
901
775
|
mintValue,
|
|
902
|
-
l2GasLimit:
|
|
776
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
903
777
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
904
778
|
refundRecipient: ctx.refundRecipient,
|
|
905
779
|
l2Contract: p.to ?? ctx.sender,
|
|
906
|
-
l2Value
|
|
780
|
+
l2Value: p.amount
|
|
907
781
|
});
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
const tx = {
|
|
782
|
+
const bridgehub = await ctx.contracts.bridgehub();
|
|
783
|
+
const data = bridgehub.interface.encodeFunctionData("requestL2TransactionDirect", [
|
|
784
|
+
requestStruct
|
|
785
|
+
]);
|
|
786
|
+
const l1TxCandidate = {
|
|
914
787
|
to: ctx.bridgehub,
|
|
915
788
|
data,
|
|
916
789
|
value: 0n,
|
|
917
790
|
// base token is ERC-20 ⇒ msg.value MUST be 0
|
|
918
791
|
from: ctx.sender,
|
|
919
|
-
...
|
|
792
|
+
...ctx.gasOverrides
|
|
920
793
|
};
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub },
|
|
932
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
933
|
-
}
|
|
934
|
-
);
|
|
935
|
-
const buffered = BigInt(est) * 115n / 100n;
|
|
936
|
-
tx.gasLimit = buffered;
|
|
937
|
-
resolvedL1GasLimit = buffered;
|
|
938
|
-
} catch {
|
|
939
|
-
}
|
|
794
|
+
const l1GasParams = await quoteL1Gas2({
|
|
795
|
+
ctx,
|
|
796
|
+
tx: l1TxCandidate,
|
|
797
|
+
overrides: ctx.gasOverrides,
|
|
798
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
799
|
+
});
|
|
800
|
+
if (l1GasParams) {
|
|
801
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
802
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
803
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
940
804
|
}
|
|
941
805
|
steps.push({
|
|
942
806
|
key: "bridgehub:direct:erc20-base",
|
|
943
807
|
kind: "bridgehub:direct",
|
|
944
808
|
description: "Bridge base ERC-20 via Bridgehub.requestL2TransactionDirect",
|
|
945
|
-
tx
|
|
809
|
+
tx: l1TxCandidate
|
|
810
|
+
});
|
|
811
|
+
const fees = buildFeeBreakdown({
|
|
812
|
+
feeToken: baseToken,
|
|
813
|
+
l1Gas: l1GasParams,
|
|
814
|
+
l2Gas: l2GasParams,
|
|
815
|
+
l2BaseCost: baseCost,
|
|
816
|
+
operatorTip: ctx.operatorTip,
|
|
817
|
+
mintValue
|
|
946
818
|
});
|
|
947
819
|
return {
|
|
948
820
|
steps,
|
|
949
821
|
approvals,
|
|
950
|
-
|
|
822
|
+
fees
|
|
951
823
|
};
|
|
952
824
|
}
|
|
953
825
|
};
|
|
954
826
|
}
|
|
827
|
+
var { wrapAs: wrapAs5 } = createErrorHandlers("tokens");
|
|
828
|
+
var abi = AbiCoder.defaultAbiCoder();
|
|
829
|
+
var ntvCodec = createNTVCodec({
|
|
830
|
+
encode: (types, values) => abi.encode(types, values),
|
|
831
|
+
keccak256: (data) => ethers.keccak256(data)
|
|
832
|
+
});
|
|
833
|
+
function createTokensResource(client) {
|
|
834
|
+
let l2NtvL1ChainIdPromise = null;
|
|
835
|
+
let baseTokenAssetIdPromise = null;
|
|
836
|
+
let wethL1Promise = null;
|
|
837
|
+
let wethL2Promise = null;
|
|
838
|
+
async function getL1ChainId() {
|
|
839
|
+
if (!l2NtvL1ChainIdPromise) {
|
|
840
|
+
l2NtvL1ChainIdPromise = wrapAs5("INTERNAL", "getL1ChainId", async () => {
|
|
841
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
842
|
+
const chainId = await l2NativeTokenVault.L1_CHAIN_ID();
|
|
843
|
+
return chainId;
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
return l2NtvL1ChainIdPromise;
|
|
847
|
+
}
|
|
848
|
+
async function getBaseTokenAssetId() {
|
|
849
|
+
if (!baseTokenAssetIdPromise) {
|
|
850
|
+
baseTokenAssetIdPromise = wrapAs5("INTERNAL", "baseTokenAssetId", async () => {
|
|
851
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
852
|
+
const assetId = await l2NativeTokenVault.BASE_TOKEN_ASSET_ID();
|
|
853
|
+
return assetId;
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
return baseTokenAssetIdPromise;
|
|
857
|
+
}
|
|
858
|
+
async function getWethL1() {
|
|
859
|
+
if (!wethL1Promise) {
|
|
860
|
+
wethL1Promise = wrapAs5("INTERNAL", "wethL1", async () => {
|
|
861
|
+
const { l1NativeTokenVault } = await client.contracts();
|
|
862
|
+
const weth = await l1NativeTokenVault.WETH_TOKEN();
|
|
863
|
+
return weth;
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
return wethL1Promise;
|
|
867
|
+
}
|
|
868
|
+
async function getWethL2() {
|
|
869
|
+
if (!wethL2Promise) {
|
|
870
|
+
wethL2Promise = wrapAs5("INTERNAL", "wethL2", async () => {
|
|
871
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
872
|
+
const weth = await l2NativeTokenVault.WETH_TOKEN();
|
|
873
|
+
return weth;
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
return wethL2Promise;
|
|
877
|
+
}
|
|
878
|
+
async function toL2Address(l1Token) {
|
|
879
|
+
return wrapAs5("CONTRACT", "tokens.toL2Address", async () => {
|
|
880
|
+
const normalized = normalizeL1Token(l1Token);
|
|
881
|
+
const { chainId } = await client.l2.getNetwork();
|
|
882
|
+
const baseToken = await client.baseToken(BigInt(chainId));
|
|
883
|
+
if (isAddressEq(normalized, baseToken)) {
|
|
884
|
+
return L2_BASE_TOKEN_ADDRESS;
|
|
885
|
+
}
|
|
886
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
887
|
+
const l2Token = await l2NativeTokenVault.l2TokenAddress(normalized);
|
|
888
|
+
return l2Token;
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
async function toL1Address(l2Token) {
|
|
892
|
+
return wrapAs5("CONTRACT", "tokens.toL1Address", async () => {
|
|
893
|
+
if (isAddressEq(l2Token, ETH_ADDRESS)) {
|
|
894
|
+
return ETH_ADDRESS;
|
|
895
|
+
}
|
|
896
|
+
if (isAddressEq(l2Token, L2_BASE_TOKEN_ADDRESS)) {
|
|
897
|
+
const { chainId } = await client.l2.getNetwork();
|
|
898
|
+
return await client.baseToken(BigInt(chainId));
|
|
899
|
+
}
|
|
900
|
+
const { l2AssetRouter } = await client.contracts();
|
|
901
|
+
const l1Token = await l2AssetRouter.l1TokenAddress(l2Token);
|
|
902
|
+
return l1Token;
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
async function assetIdOfL1(l1Token) {
|
|
906
|
+
return wrapAs5("CONTRACT", "tokens.assetIdOfL1", async () => {
|
|
907
|
+
const normalized = normalizeL1Token(l1Token);
|
|
908
|
+
const { l1NativeTokenVault } = await client.contracts();
|
|
909
|
+
const assetId = await l1NativeTokenVault.assetId(normalized);
|
|
910
|
+
return assetId;
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
async function assetIdOfL2(l2Token) {
|
|
914
|
+
return wrapAs5("CONTRACT", "tokens.assetIdOfL2", async () => {
|
|
915
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
916
|
+
const assetId = await l2NativeTokenVault.assetId(l2Token);
|
|
917
|
+
return assetId;
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
async function l2TokenFromAssetId(assetId) {
|
|
921
|
+
return wrapAs5("CONTRACT", "tokens.l2TokenFromAssetId", async () => {
|
|
922
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
923
|
+
const tokenAddr = await l2NativeTokenVault.tokenAddress(assetId);
|
|
924
|
+
return tokenAddr;
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
async function l1TokenFromAssetId(assetId) {
|
|
928
|
+
return wrapAs5("CONTRACT", "tokens.l1TokenFromAssetId", async () => {
|
|
929
|
+
const { l1NativeTokenVault } = await client.contracts();
|
|
930
|
+
const tokenAddr = await l1NativeTokenVault.tokenAddress(assetId);
|
|
931
|
+
return tokenAddr;
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
async function originChainId(assetId) {
|
|
935
|
+
return wrapAs5("CONTRACT", "tokens.originChainId", async () => {
|
|
936
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
937
|
+
const chainId = await l2NativeTokenVault.originChainId(assetId);
|
|
938
|
+
return chainId;
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
async function baseTokenAssetId() {
|
|
942
|
+
return getBaseTokenAssetId();
|
|
943
|
+
}
|
|
944
|
+
async function isChainEthBased() {
|
|
945
|
+
return wrapAs5("CONTRACT", "tokens.isChainEthBased", async () => {
|
|
946
|
+
const baseAssetId = await getBaseTokenAssetId();
|
|
947
|
+
const l1ChainId = await getL1ChainId();
|
|
948
|
+
const ethAssetId = ntvCodec.encodeAssetId(
|
|
949
|
+
l1ChainId,
|
|
950
|
+
L2_NATIVE_TOKEN_VAULT_ADDRESS,
|
|
951
|
+
ETH_ADDRESS
|
|
952
|
+
);
|
|
953
|
+
return hexEq(baseAssetId, ethAssetId);
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
async function wethL1() {
|
|
957
|
+
return getWethL1();
|
|
958
|
+
}
|
|
959
|
+
async function wethL2() {
|
|
960
|
+
return getWethL2();
|
|
961
|
+
}
|
|
962
|
+
async function computeL2BridgedAddress(args) {
|
|
963
|
+
return wrapAs5("CONTRACT", "tokens.computeL2BridgedAddress", async () => {
|
|
964
|
+
const normalized = normalizeL1Token(args.l1Token);
|
|
965
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
966
|
+
const predicted = await l2NativeTokenVault.calculateCreate2TokenAddress(
|
|
967
|
+
args.originChainId,
|
|
968
|
+
normalized
|
|
969
|
+
);
|
|
970
|
+
return predicted;
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
async function resolve(ref, opts) {
|
|
974
|
+
return wrapAs5("CONTRACT", "tokens.resolve", async () => {
|
|
975
|
+
let chain;
|
|
976
|
+
let address;
|
|
977
|
+
if (typeof ref === "string") {
|
|
978
|
+
chain = opts?.chain ?? "l1";
|
|
979
|
+
address = ref;
|
|
980
|
+
} else {
|
|
981
|
+
chain = ref.chain;
|
|
982
|
+
address = ref.address;
|
|
983
|
+
}
|
|
984
|
+
let l1;
|
|
985
|
+
let l2;
|
|
986
|
+
if (chain === "l1") {
|
|
987
|
+
l1 = normalizeL1Token(address);
|
|
988
|
+
l2 = await toL2Address(address);
|
|
989
|
+
} else {
|
|
990
|
+
l2 = address;
|
|
991
|
+
l1 = await toL1Address(address);
|
|
992
|
+
}
|
|
993
|
+
const assetId = await assetIdOfL1(l1);
|
|
994
|
+
const originChainIdVal = await originChainId(assetId);
|
|
995
|
+
const [baseAssetId, wethL1Addr, wethL2Addr, ethBased] = await Promise.all([
|
|
996
|
+
baseTokenAssetId(),
|
|
997
|
+
wethL1(),
|
|
998
|
+
wethL2(),
|
|
999
|
+
isChainEthBased()
|
|
1000
|
+
]);
|
|
1001
|
+
let kind;
|
|
1002
|
+
if (isAddressEq(l1, ETH_ADDRESS)) {
|
|
1003
|
+
kind = "eth";
|
|
1004
|
+
} else if (hexEq(assetId, baseAssetId)) {
|
|
1005
|
+
kind = "base";
|
|
1006
|
+
} else {
|
|
1007
|
+
kind = "erc20";
|
|
1008
|
+
}
|
|
1009
|
+
return {
|
|
1010
|
+
kind,
|
|
1011
|
+
l1,
|
|
1012
|
+
l2,
|
|
1013
|
+
assetId,
|
|
1014
|
+
originChainId: originChainIdVal,
|
|
1015
|
+
isChainEthBased: ethBased,
|
|
1016
|
+
baseTokenAssetId: baseAssetId,
|
|
1017
|
+
wethL1: wethL1Addr,
|
|
1018
|
+
wethL2: wethL2Addr
|
|
1019
|
+
};
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
return {
|
|
1023
|
+
resolve,
|
|
1024
|
+
toL2Address,
|
|
1025
|
+
toL1Address,
|
|
1026
|
+
assetIdOfL1,
|
|
1027
|
+
assetIdOfL2,
|
|
1028
|
+
l2TokenFromAssetId,
|
|
1029
|
+
l1TokenFromAssetId,
|
|
1030
|
+
originChainId,
|
|
1031
|
+
baseTokenAssetId,
|
|
1032
|
+
isChainEthBased,
|
|
1033
|
+
wethL1,
|
|
1034
|
+
wethL2,
|
|
1035
|
+
computeL2BridgedAddress
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// src/adapters/ethers/resources/contracts/contracts.ts
|
|
1040
|
+
function createContractsResource(client) {
|
|
1041
|
+
async function addresses() {
|
|
1042
|
+
return client.ensureAddresses();
|
|
1043
|
+
}
|
|
1044
|
+
async function instances() {
|
|
1045
|
+
return client.contracts();
|
|
1046
|
+
}
|
|
1047
|
+
async function bridgehub() {
|
|
1048
|
+
const { bridgehub: bridgehub2 } = await instances();
|
|
1049
|
+
return bridgehub2;
|
|
1050
|
+
}
|
|
1051
|
+
async function l1AssetRouter() {
|
|
1052
|
+
const { l1AssetRouter: l1AssetRouter2 } = await instances();
|
|
1053
|
+
return l1AssetRouter2;
|
|
1054
|
+
}
|
|
1055
|
+
async function l1NativeTokenVault() {
|
|
1056
|
+
const { l1NativeTokenVault: l1NativeTokenVault2 } = await instances();
|
|
1057
|
+
return l1NativeTokenVault2;
|
|
1058
|
+
}
|
|
1059
|
+
async function l1Nullifier() {
|
|
1060
|
+
const { l1Nullifier: l1Nullifier2 } = await instances();
|
|
1061
|
+
return l1Nullifier2;
|
|
1062
|
+
}
|
|
1063
|
+
async function l2AssetRouter() {
|
|
1064
|
+
const { l2AssetRouter: l2AssetRouter2 } = await instances();
|
|
1065
|
+
return l2AssetRouter2;
|
|
1066
|
+
}
|
|
1067
|
+
async function l2NativeTokenVault() {
|
|
1068
|
+
const { l2NativeTokenVault: l2NativeTokenVault2 } = await instances();
|
|
1069
|
+
return l2NativeTokenVault2;
|
|
1070
|
+
}
|
|
1071
|
+
async function l2BaseTokenSystem() {
|
|
1072
|
+
const { l2BaseTokenSystem: l2BaseTokenSystem2 } = await instances();
|
|
1073
|
+
return l2BaseTokenSystem2;
|
|
1074
|
+
}
|
|
1075
|
+
return {
|
|
1076
|
+
addresses,
|
|
1077
|
+
instances,
|
|
1078
|
+
bridgehub,
|
|
1079
|
+
l1AssetRouter,
|
|
1080
|
+
l1NativeTokenVault,
|
|
1081
|
+
l1Nullifier,
|
|
1082
|
+
l2AssetRouter,
|
|
1083
|
+
l2NativeTokenVault,
|
|
1084
|
+
l2BaseTokenSystem
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
955
1087
|
|
|
956
1088
|
// src/adapters/ethers/resources/deposits/index.ts
|
|
957
1089
|
var { wrap, toResult } = createErrorHandlers("deposits");
|
|
@@ -961,42 +1093,26 @@ var ROUTES = {
|
|
|
961
1093
|
"erc20-nonbase": routeErc20NonBase(),
|
|
962
1094
|
"erc20-base": routeErc20Base()
|
|
963
1095
|
};
|
|
964
|
-
function createDepositsResource(client) {
|
|
1096
|
+
function createDepositsResource(client, tokens, contracts) {
|
|
1097
|
+
const tokensResource = tokens ?? createTokensResource(client);
|
|
1098
|
+
const contractsResource = contracts ?? createContractsResource(client);
|
|
965
1099
|
async function buildPlan(p) {
|
|
966
|
-
const ctx = await commonCtx(p, client);
|
|
1100
|
+
const ctx = await commonCtx(p, client, tokensResource, contractsResource);
|
|
967
1101
|
const route = ctx.route;
|
|
968
1102
|
await ROUTES[route].preflight?.(p, ctx);
|
|
969
|
-
const { steps, approvals,
|
|
970
|
-
const { baseCost, mintValue } = quoteExtras;
|
|
971
|
-
const fallbackGasLimit = quoteExtras.l1GasLimit;
|
|
972
|
-
const resolveGasLimit = () => {
|
|
973
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
974
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
975
|
-
const candidate = steps[i].tx.gasLimit;
|
|
976
|
-
if (candidate == null) continue;
|
|
977
|
-
if (typeof candidate === "bigint") return candidate;
|
|
978
|
-
try {
|
|
979
|
-
return BigInt(candidate.toString());
|
|
980
|
-
} catch {
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
if (fallbackGasLimit != null) return fallbackGasLimit;
|
|
984
|
-
return ctx.l2GasLimit;
|
|
985
|
-
};
|
|
986
|
-
const gasLimit = resolveGasLimit();
|
|
1103
|
+
const { steps, approvals, fees } = await ROUTES[route].build(p, ctx);
|
|
987
1104
|
return {
|
|
988
1105
|
route: ctx.route,
|
|
989
1106
|
summary: {
|
|
990
1107
|
route: ctx.route,
|
|
991
1108
|
approvalsNeeded: approvals,
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
fees
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
}
|
|
1109
|
+
amounts: {
|
|
1110
|
+
transfer: { token: p.token, amount: p.amount }
|
|
1111
|
+
},
|
|
1112
|
+
fees,
|
|
1113
|
+
// Legacy fields (maintained for backward compatibility)
|
|
1114
|
+
baseCost: fees.l2?.baseCost,
|
|
1115
|
+
mintValue: fees.mintValue
|
|
1000
1116
|
},
|
|
1001
1117
|
steps
|
|
1002
1118
|
};
|
|
@@ -1065,7 +1181,7 @@ function createDepositsResource(client) {
|
|
|
1065
1181
|
step.tx.maxPriorityFeePerGas = overrides.maxPriorityFeePerGas;
|
|
1066
1182
|
}
|
|
1067
1183
|
}
|
|
1068
|
-
if (!
|
|
1184
|
+
if (!p.l1TxOverrides?.gasLimit) {
|
|
1069
1185
|
try {
|
|
1070
1186
|
const est = await client.l1.estimateGas(step.tx);
|
|
1071
1187
|
step.tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
@@ -1246,25 +1362,9 @@ function createDepositsResource(client) {
|
|
|
1246
1362
|
);
|
|
1247
1363
|
return { quote, tryQuote, prepare, tryPrepare, create, tryCreate, status, wait, tryWait };
|
|
1248
1364
|
}
|
|
1249
|
-
async function ntvBaseAssetId(l2, ntv) {
|
|
1250
|
-
const c = new Contract(ntv, L2NativeTokenVault_default, l2);
|
|
1251
|
-
return await c.BASE_TOKEN_ASSET_ID();
|
|
1252
|
-
}
|
|
1253
|
-
async function ntvL1ChainId(l2, ntv) {
|
|
1254
|
-
const c = new Contract(ntv, L2NativeTokenVault_default, l2);
|
|
1255
|
-
return await c.L1_CHAIN_ID();
|
|
1256
|
-
}
|
|
1257
|
-
async function isEthBasedChain(l2, ntv) {
|
|
1258
|
-
const [baseAssetId, l1ChainId] = await Promise.all([
|
|
1259
|
-
ntvBaseAssetId(l2, ntv),
|
|
1260
|
-
ntvL1ChainId(l2, ntv)
|
|
1261
|
-
]);
|
|
1262
|
-
const ethAssetId = encodeNativeTokenVaultAssetId(l1ChainId, ETH_ADDRESS);
|
|
1263
|
-
return baseAssetId.toLowerCase() === ethAssetId.toLowerCase();
|
|
1264
|
-
}
|
|
1265
1365
|
|
|
1266
1366
|
// src/adapters/ethers/resources/withdrawals/context.ts
|
|
1267
|
-
async function commonCtx2(p, client) {
|
|
1367
|
+
async function commonCtx2(p, client, tokens, contracts) {
|
|
1268
1368
|
const sender = await client.signer.getAddress();
|
|
1269
1369
|
const {
|
|
1270
1370
|
bridgehub,
|
|
@@ -1273,16 +1373,21 @@ async function commonCtx2(p, client) {
|
|
|
1273
1373
|
l2AssetRouter,
|
|
1274
1374
|
l2NativeTokenVault,
|
|
1275
1375
|
l2BaseTokenSystem
|
|
1276
|
-
} = await
|
|
1376
|
+
} = await contracts.addresses();
|
|
1277
1377
|
const { chainId } = await client.l2.getNetwork();
|
|
1278
1378
|
const chainIdL2 = BigInt(chainId);
|
|
1279
|
-
const
|
|
1280
|
-
const
|
|
1379
|
+
const resolvedToken = await tokens.resolve(p.token, { chain: "l2" });
|
|
1380
|
+
const baseTokenAssetId = resolvedToken.baseTokenAssetId;
|
|
1381
|
+
const baseTokenL1 = await tokens.l1TokenFromAssetId(baseTokenAssetId);
|
|
1382
|
+
const baseIsEth = resolvedToken.isChainEthBased;
|
|
1281
1383
|
const route = pickWithdrawRoute({ token: p.token, baseIsEth });
|
|
1282
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
1283
|
-
const gasBufferPct = 15;
|
|
1284
1384
|
return {
|
|
1285
1385
|
client,
|
|
1386
|
+
tokens,
|
|
1387
|
+
contracts,
|
|
1388
|
+
resolvedToken,
|
|
1389
|
+
baseTokenAssetId,
|
|
1390
|
+
baseTokenL1,
|
|
1286
1391
|
bridgehub,
|
|
1287
1392
|
chainIdL2,
|
|
1288
1393
|
sender,
|
|
@@ -1293,29 +1398,50 @@ async function commonCtx2(p, client) {
|
|
|
1293
1398
|
l2NativeTokenVault,
|
|
1294
1399
|
l2BaseTokenSystem,
|
|
1295
1400
|
baseIsEth,
|
|
1296
|
-
|
|
1297
|
-
gasBufferPct,
|
|
1298
|
-
fee
|
|
1401
|
+
gasOverrides: p.l2TxOverrides
|
|
1299
1402
|
};
|
|
1300
1403
|
}
|
|
1301
|
-
|
|
1404
|
+
|
|
1405
|
+
// src/adapters/ethers/resources/withdrawals/services/gas.ts
|
|
1406
|
+
async function quoteL2Gas4(input) {
|
|
1407
|
+
const { ctx, tx } = input;
|
|
1408
|
+
const estimator = ethersToGasEstimator(ctx.client.l2);
|
|
1409
|
+
return quoteL2Gas2({
|
|
1410
|
+
estimator,
|
|
1411
|
+
tx: toCoreTx(tx),
|
|
1412
|
+
overrides: ctx.gasOverrides
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/adapters/ethers/resources/withdrawals/services/fees.ts
|
|
1417
|
+
function buildFeeBreakdown2(p) {
|
|
1418
|
+
const l2Total = p.l2Gas?.maxCost ?? 0n;
|
|
1419
|
+
const l2 = {
|
|
1420
|
+
total: l2Total,
|
|
1421
|
+
gasLimit: p.l2Gas?.gasLimit ?? 0n,
|
|
1422
|
+
maxFeePerGas: p.l2Gas?.maxFeePerGas ?? 0n,
|
|
1423
|
+
maxPriorityFeePerGas: p.l2Gas?.maxPriorityFeePerGas
|
|
1424
|
+
};
|
|
1425
|
+
return {
|
|
1426
|
+
token: p.feeToken,
|
|
1427
|
+
maxTotal: l2Total,
|
|
1428
|
+
l2
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// src/adapters/ethers/resources/withdrawals/routes/eth.ts
|
|
1433
|
+
var { wrapAs: wrapAs6 } = createErrorHandlers("withdrawals");
|
|
1302
1434
|
function routeEthBase() {
|
|
1303
1435
|
return {
|
|
1304
1436
|
async build(p, ctx) {
|
|
1305
1437
|
const steps = [];
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1308
|
-
L2_BASE_TOKEN_ADDRESS,
|
|
1309
|
-
new Interface(IBaseToken_default),
|
|
1310
|
-
ctx.client.l2
|
|
1311
|
-
);
|
|
1312
|
-
const toL1 = p.to ?? ctx.sender;
|
|
1313
|
-
const data = await wrapAs5(
|
|
1438
|
+
const base = await ctx.contracts.l2BaseTokenSystem();
|
|
1439
|
+
const data = await wrapAs6(
|
|
1314
1440
|
"INTERNAL",
|
|
1315
1441
|
OP_WITHDRAWALS.eth.encodeWithdraw,
|
|
1316
|
-
() => Promise.resolve(base.interface.encodeFunctionData("withdraw", [
|
|
1442
|
+
() => Promise.resolve(base.interface.encodeFunctionData("withdraw", [p.to ?? ctx.sender])),
|
|
1317
1443
|
{
|
|
1318
|
-
ctx: { where: "L2BaseToken.withdraw", to:
|
|
1444
|
+
ctx: { where: "L2BaseToken.withdraw", to: p.to ?? ctx.sender },
|
|
1319
1445
|
message: "Failed to encode ETH withdraw calldata."
|
|
1320
1446
|
}
|
|
1321
1447
|
);
|
|
@@ -1323,38 +1449,29 @@ function routeEthBase() {
|
|
|
1323
1449
|
to: L2_BASE_TOKEN_ADDRESS,
|
|
1324
1450
|
data,
|
|
1325
1451
|
from: ctx.sender,
|
|
1326
|
-
value: p.amount
|
|
1327
|
-
maxFeePerGas,
|
|
1328
|
-
maxPriorityFeePerGas
|
|
1452
|
+
value: p.amount
|
|
1329
1453
|
};
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
"RPC",
|
|
1336
|
-
OP_WITHDRAWALS.eth.estGas,
|
|
1337
|
-
() => ctx.client.l2.estimateGas(tx),
|
|
1338
|
-
{
|
|
1339
|
-
ctx: { where: "l2.estimateGas", to: L2_BASE_TOKEN_ADDRESS },
|
|
1340
|
-
message: "Failed to estimate gas for L2 ETH withdraw."
|
|
1341
|
-
}
|
|
1342
|
-
);
|
|
1343
|
-
tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
1344
|
-
} catch {
|
|
1345
|
-
}
|
|
1454
|
+
const gas = await quoteL2Gas4({ ctx, tx });
|
|
1455
|
+
if (gas) {
|
|
1456
|
+
tx.gasLimit = gas.gasLimit;
|
|
1457
|
+
tx.maxFeePerGas = gas.maxFeePerGas;
|
|
1458
|
+
tx.maxPriorityFeePerGas = gas.maxPriorityFeePerGas;
|
|
1346
1459
|
}
|
|
1460
|
+
const fees = buildFeeBreakdown2({
|
|
1461
|
+
feeToken: L2_BASE_TOKEN_ADDRESS,
|
|
1462
|
+
l2Gas: gas
|
|
1463
|
+
});
|
|
1347
1464
|
steps.push({
|
|
1348
1465
|
key: "l2-base-token:withdraw",
|
|
1349
1466
|
kind: "l2-base-token:withdraw",
|
|
1350
1467
|
description: "Withdraw ETH via L2 Base Token System",
|
|
1351
1468
|
tx
|
|
1352
1469
|
});
|
|
1353
|
-
return { steps, approvals: [],
|
|
1470
|
+
return { steps, approvals: [], fees };
|
|
1354
1471
|
}
|
|
1355
1472
|
};
|
|
1356
1473
|
}
|
|
1357
|
-
var { wrapAs:
|
|
1474
|
+
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
1358
1475
|
var SIG = {
|
|
1359
1476
|
withdraw: "withdraw(bytes32,bytes)"
|
|
1360
1477
|
};
|
|
@@ -1363,10 +1480,8 @@ function routeErc20NonBase2() {
|
|
|
1363
1480
|
async build(p, ctx) {
|
|
1364
1481
|
const steps = [];
|
|
1365
1482
|
const approvals = [];
|
|
1366
|
-
const { gasLimit: overrideGasLimit, maxFeePerGas, maxPriorityFeePerGas } = ctx.fee;
|
|
1367
|
-
const txOverrides = overrideGasLimit != null ? { maxFeePerGas, maxPriorityFeePerGas, gasLimit: overrideGasLimit } : { maxFeePerGas, maxPriorityFeePerGas };
|
|
1368
1483
|
const erc20 = new Contract(p.token, IERC20_default, ctx.client.getL2Signer());
|
|
1369
|
-
const current = await
|
|
1484
|
+
const current = await wrapAs7(
|
|
1370
1485
|
"CONTRACT",
|
|
1371
1486
|
OP_WITHDRAWALS.erc20.allowance,
|
|
1372
1487
|
() => erc20.allowance(ctx.sender, ctx.l2NativeTokenVault),
|
|
@@ -1386,39 +1501,51 @@ function routeErc20NonBase2() {
|
|
|
1386
1501
|
ctx.l2NativeTokenVault,
|
|
1387
1502
|
p.amount
|
|
1388
1503
|
]);
|
|
1504
|
+
const approveTx = {
|
|
1505
|
+
to: p.token,
|
|
1506
|
+
data,
|
|
1507
|
+
from: ctx.sender
|
|
1508
|
+
};
|
|
1509
|
+
const approveGas = await quoteL2Gas4({ ctx, tx: approveTx });
|
|
1510
|
+
if (approveGas) {
|
|
1511
|
+
approveTx.gasLimit = approveGas.gasLimit;
|
|
1512
|
+
approveTx.maxFeePerGas = approveGas.maxFeePerGas;
|
|
1513
|
+
approveTx.maxPriorityFeePerGas = approveGas.maxPriorityFeePerGas;
|
|
1514
|
+
}
|
|
1389
1515
|
steps.push({
|
|
1390
1516
|
key: `approve:l2:${p.token}:${ctx.l2NativeTokenVault}`,
|
|
1391
1517
|
kind: "approve:l2",
|
|
1392
1518
|
description: `Approve ${p.amount} to NativeTokenVault`,
|
|
1393
|
-
tx:
|
|
1519
|
+
tx: approveTx
|
|
1394
1520
|
});
|
|
1395
1521
|
}
|
|
1396
|
-
const
|
|
1397
|
-
const assetId = await
|
|
1522
|
+
const resolved = ctx.resolvedToken ?? (ctx.tokens ? await ctx.tokens.resolve(p.token, { chain: "l2" }) : void 0);
|
|
1523
|
+
const assetId = resolved?.assetId ?? await wrapAs7(
|
|
1398
1524
|
"CONTRACT",
|
|
1399
1525
|
OP_WITHDRAWALS.erc20.ensureRegistered,
|
|
1400
|
-
() =>
|
|
1526
|
+
async () => {
|
|
1527
|
+
const ntv = await ctx.contracts.l2NativeTokenVault();
|
|
1528
|
+
const ensured = await ntv.getFunction("ensureTokenIsRegistered").staticCall(p.token);
|
|
1529
|
+
return ensured;
|
|
1530
|
+
},
|
|
1401
1531
|
{
|
|
1402
1532
|
ctx: { where: "L2NativeTokenVault.ensureTokenIsRegistered", token: p.token },
|
|
1403
1533
|
message: "Failed to ensure token is registered in L2NativeTokenVault."
|
|
1404
1534
|
}
|
|
1405
1535
|
);
|
|
1406
|
-
const assetData = await
|
|
1536
|
+
const assetData = await wrapAs7(
|
|
1407
1537
|
"INTERNAL",
|
|
1408
1538
|
OP_WITHDRAWALS.erc20.encodeAssetData,
|
|
1409
1539
|
() => Promise.resolve(
|
|
1410
|
-
|
|
1411
|
-
["uint256", "address", "address"],
|
|
1412
|
-
[p.amount, p.to ?? ctx.sender, p.token]
|
|
1413
|
-
)
|
|
1540
|
+
encodeNativeTokenVaultTransferData(p.amount, p.to ?? ctx.sender, p.token)
|
|
1414
1541
|
),
|
|
1415
1542
|
{
|
|
1416
1543
|
ctx: { where: "AbiCoder.encode", token: p.token, to: p.to ?? ctx.sender },
|
|
1417
1544
|
message: "Failed to encode burn/withdraw asset data."
|
|
1418
1545
|
}
|
|
1419
1546
|
);
|
|
1420
|
-
const l2ar =
|
|
1421
|
-
const dataWithdraw = await
|
|
1547
|
+
const l2ar = await ctx.contracts.l2AssetRouter();
|
|
1548
|
+
const dataWithdraw = await wrapAs7(
|
|
1422
1549
|
"INTERNAL",
|
|
1423
1550
|
OP_WITHDRAWALS.erc20.encodeWithdraw,
|
|
1424
1551
|
() => Promise.resolve(l2ar.interface.encodeFunctionData(SIG.withdraw, [assetId, assetData])),
|
|
@@ -1430,81 +1557,25 @@ function routeErc20NonBase2() {
|
|
|
1430
1557
|
const withdrawTx = {
|
|
1431
1558
|
to: ctx.l2AssetRouter,
|
|
1432
1559
|
data: dataWithdraw,
|
|
1433
|
-
from: ctx.sender
|
|
1434
|
-
...txOverrides
|
|
1560
|
+
from: ctx.sender
|
|
1435
1561
|
};
|
|
1562
|
+
const withdrawGas = await quoteL2Gas4({ ctx, tx: withdrawTx });
|
|
1563
|
+
if (withdrawGas) {
|
|
1564
|
+
withdrawTx.gasLimit = withdrawGas.gasLimit;
|
|
1565
|
+
withdrawTx.maxFeePerGas = withdrawGas.maxFeePerGas;
|
|
1566
|
+
withdrawTx.maxPriorityFeePerGas = withdrawGas.maxPriorityFeePerGas;
|
|
1567
|
+
}
|
|
1436
1568
|
steps.push({
|
|
1437
1569
|
key: "l2-asset-router:withdraw",
|
|
1438
1570
|
kind: "l2-asset-router:withdraw",
|
|
1439
1571
|
description: "Burn on L2 & send L2\u2192L1 message",
|
|
1440
1572
|
tx: withdrawTx
|
|
1441
1573
|
});
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
}
|
|
1446
|
-
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
1447
|
-
function routeEthNonBase2() {
|
|
1448
|
-
return {
|
|
1449
|
-
async preflight(p, ctx) {
|
|
1450
|
-
await wrapAs7(
|
|
1451
|
-
"VALIDATION",
|
|
1452
|
-
OP_WITHDRAWALS.ethNonBase.assertNonEthBase,
|
|
1453
|
-
() => {
|
|
1454
|
-
if (p.token.toLowerCase() !== L2_BASE_TOKEN_ADDRESS.toLowerCase()) {
|
|
1455
|
-
throw new Error("eth-nonbase route requires the L2 base-token alias (0x\u2026800A).");
|
|
1456
|
-
}
|
|
1457
|
-
if (ctx.baseIsEth) {
|
|
1458
|
-
throw new Error("eth-nonbase route requires chain base \u2260 ETH.");
|
|
1459
|
-
}
|
|
1460
|
-
},
|
|
1461
|
-
{ ctx: { token: p.token, baseIsEth: ctx.baseIsEth } }
|
|
1462
|
-
);
|
|
1463
|
-
},
|
|
1464
|
-
async build(p, ctx) {
|
|
1465
|
-
const steps = [];
|
|
1466
|
-
const { gasLimit: overrideGasLimit, maxFeePerGas, maxPriorityFeePerGas } = ctx.fee;
|
|
1467
|
-
const toL1 = p.to ?? ctx.sender;
|
|
1468
|
-
const iface = new Interface(IBaseToken_default);
|
|
1469
|
-
const data = await wrapAs7(
|
|
1470
|
-
"INTERNAL",
|
|
1471
|
-
OP_WITHDRAWALS.eth.encodeWithdraw,
|
|
1472
|
-
// reuse label for base-token system call
|
|
1473
|
-
() => Promise.resolve(iface.encodeFunctionData("withdraw", [toL1])),
|
|
1474
|
-
{ ctx: { where: "L2BaseToken.withdraw", to: toL1 } }
|
|
1475
|
-
);
|
|
1476
|
-
const tx = {
|
|
1477
|
-
to: L2_BASE_TOKEN_ADDRESS,
|
|
1478
|
-
data,
|
|
1479
|
-
from: ctx.sender,
|
|
1480
|
-
value: p.amount,
|
|
1481
|
-
maxFeePerGas,
|
|
1482
|
-
maxPriorityFeePerGas
|
|
1483
|
-
};
|
|
1484
|
-
if (overrideGasLimit != null) {
|
|
1485
|
-
tx.gasLimit = overrideGasLimit;
|
|
1486
|
-
} else {
|
|
1487
|
-
try {
|
|
1488
|
-
const est = await wrapAs7(
|
|
1489
|
-
"RPC",
|
|
1490
|
-
OP_WITHDRAWALS.eth.estGas,
|
|
1491
|
-
() => ctx.client.l2.estimateGas(tx),
|
|
1492
|
-
{
|
|
1493
|
-
ctx: { where: "l2.estimateGas", to: L2_BASE_TOKEN_ADDRESS },
|
|
1494
|
-
message: "Failed to estimate gas for L2 base-token withdraw."
|
|
1495
|
-
}
|
|
1496
|
-
);
|
|
1497
|
-
tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
1498
|
-
} catch {
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
steps.push({
|
|
1502
|
-
key: "l2-base-token:withdraw",
|
|
1503
|
-
kind: "l2-base-token:withdraw",
|
|
1504
|
-
description: "Withdraw base token via L2 Base Token System (base \u2260 ETH)",
|
|
1505
|
-
tx
|
|
1574
|
+
const fees = buildFeeBreakdown2({
|
|
1575
|
+
feeToken: ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2),
|
|
1576
|
+
l2Gas: withdrawGas
|
|
1506
1577
|
});
|
|
1507
|
-
return { steps, approvals
|
|
1578
|
+
return { steps, approvals, fees };
|
|
1508
1579
|
}
|
|
1509
1580
|
};
|
|
1510
1581
|
}
|
|
@@ -1782,45 +1853,32 @@ function createFinalizationServices(client) {
|
|
|
1782
1853
|
|
|
1783
1854
|
// src/adapters/ethers/resources/withdrawals/index.ts
|
|
1784
1855
|
var ROUTES2 = {
|
|
1785
|
-
|
|
1856
|
+
base: routeEthBase(),
|
|
1786
1857
|
// BaseTokenSystem.withdraw, chain base = ETH
|
|
1787
|
-
"eth-nonbase": routeEthNonBase2(),
|
|
1788
|
-
// BaseTokenSystem.withdraw, chain base ≠ ETH
|
|
1789
1858
|
"erc20-nonbase": routeErc20NonBase2()
|
|
1790
1859
|
// AssetRouter.withdraw for non-base ERC-20s
|
|
1791
1860
|
};
|
|
1792
|
-
function createWithdrawalsResource(client) {
|
|
1861
|
+
function createWithdrawalsResource(client, tokens, contracts) {
|
|
1793
1862
|
const svc = createFinalizationServices(client);
|
|
1794
1863
|
const { wrap: wrap2, toResult: toResult2 } = createErrorHandlers("withdrawals");
|
|
1864
|
+
const tokensResource = tokens ?? createTokensResource(client);
|
|
1865
|
+
const contractsResource = contracts ?? createContractsResource(client);
|
|
1795
1866
|
async function buildPlan(p) {
|
|
1796
|
-
const ctx = await commonCtx2(p, client);
|
|
1867
|
+
const ctx = await commonCtx2(p, client, tokensResource, contractsResource);
|
|
1797
1868
|
await ROUTES2[ctx.route].preflight?.(p, ctx);
|
|
1798
|
-
const { steps, approvals } = await ROUTES2[ctx.route].build(p, ctx);
|
|
1799
|
-
|
|
1800
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
1801
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
1802
|
-
const candidate = steps[i].tx.gasLimit;
|
|
1803
|
-
if (candidate == null) continue;
|
|
1804
|
-
if (typeof candidate === "bigint") return candidate;
|
|
1805
|
-
try {
|
|
1806
|
-
return BigInt(candidate.toString());
|
|
1807
|
-
} catch {
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
return void 0;
|
|
1811
|
-
};
|
|
1812
|
-
const gasLimit = resolveGasLimit();
|
|
1813
|
-
const summary = {
|
|
1869
|
+
const { steps, approvals, fees } = await ROUTES2[ctx.route].build(p, ctx);
|
|
1870
|
+
return {
|
|
1814
1871
|
route: ctx.route,
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1872
|
+
summary: {
|
|
1873
|
+
route: ctx.route,
|
|
1874
|
+
approvalsNeeded: approvals,
|
|
1875
|
+
amounts: {
|
|
1876
|
+
transfer: { token: p.token, amount: p.amount }
|
|
1877
|
+
},
|
|
1878
|
+
fees
|
|
1879
|
+
},
|
|
1880
|
+
steps
|
|
1822
1881
|
};
|
|
1823
|
-
return { route: ctx.route, summary, steps };
|
|
1824
1882
|
}
|
|
1825
1883
|
const finalizeCache = /* @__PURE__ */ new Map();
|
|
1826
1884
|
const quote = (p) => wrap2(
|
|
@@ -2130,58 +2188,14 @@ function createWithdrawalsResource(client) {
|
|
|
2130
2188
|
|
|
2131
2189
|
// src/adapters/ethers/sdk.ts
|
|
2132
2190
|
function createEthersSdk(client) {
|
|
2191
|
+
const tokens = createTokensResource(client);
|
|
2192
|
+
const contracts = createContractsResource(client);
|
|
2133
2193
|
return {
|
|
2134
|
-
deposits: createDepositsResource(client),
|
|
2135
|
-
withdrawals: createWithdrawalsResource(client),
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
addresses: () => client.ensureAddresses(),
|
|
2139
|
-
contracts: () => client.contracts(),
|
|
2140
|
-
async l1AssetRouter() {
|
|
2141
|
-
const { l1AssetRouter } = await client.contracts();
|
|
2142
|
-
return l1AssetRouter;
|
|
2143
|
-
},
|
|
2144
|
-
async l1NativeTokenVault() {
|
|
2145
|
-
const { l1NativeTokenVault } = await client.contracts();
|
|
2146
|
-
return l1NativeTokenVault;
|
|
2147
|
-
},
|
|
2148
|
-
async l1Nullifier() {
|
|
2149
|
-
const { l1Nullifier } = await client.contracts();
|
|
2150
|
-
return l1Nullifier;
|
|
2151
|
-
},
|
|
2152
|
-
async baseToken(chainId) {
|
|
2153
|
-
const id = chainId ?? BigInt((await client.l2.getNetwork()).chainId);
|
|
2154
|
-
return client.baseToken(id);
|
|
2155
|
-
},
|
|
2156
|
-
async l2TokenAddress(l1Token) {
|
|
2157
|
-
if (isAddressEq(l1Token, FORMAL_ETH_ADDRESS)) {
|
|
2158
|
-
return ETH_ADDRESS;
|
|
2159
|
-
}
|
|
2160
|
-
const { chainId } = await client.l2.getNetwork();
|
|
2161
|
-
const base = await client.baseToken(BigInt(chainId));
|
|
2162
|
-
if (isAddressEq(l1Token, base)) {
|
|
2163
|
-
return L2_BASE_TOKEN_ADDRESS;
|
|
2164
|
-
}
|
|
2165
|
-
const { l2NativeTokenVault } = await client.contracts();
|
|
2166
|
-
const addr = await l2NativeTokenVault.l2TokenAddress(l1Token);
|
|
2167
|
-
return addr;
|
|
2168
|
-
},
|
|
2169
|
-
async l1TokenAddress(l2Token) {
|
|
2170
|
-
if (isAddressEq(l2Token, ETH_ADDRESS)) {
|
|
2171
|
-
return ETH_ADDRESS;
|
|
2172
|
-
}
|
|
2173
|
-
const { l2AssetRouter } = await client.contracts();
|
|
2174
|
-
const addr = await l2AssetRouter.l1TokenAddress(l2Token);
|
|
2175
|
-
return addr;
|
|
2176
|
-
},
|
|
2177
|
-
async assetId(l1Token) {
|
|
2178
|
-
const norm = isAddressEq(l1Token, FORMAL_ETH_ADDRESS) ? ETH_ADDRESS : l1Token;
|
|
2179
|
-
const { l1NativeTokenVault } = await client.contracts();
|
|
2180
|
-
const id = await l1NativeTokenVault.assetId(norm);
|
|
2181
|
-
return id;
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2194
|
+
deposits: createDepositsResource(client, tokens, contracts),
|
|
2195
|
+
withdrawals: createWithdrawalsResource(client, tokens, contracts),
|
|
2196
|
+
tokens,
|
|
2197
|
+
contracts
|
|
2184
2198
|
};
|
|
2185
2199
|
}
|
|
2186
2200
|
|
|
2187
|
-
export { buildDirectRequestStruct,
|
|
2201
|
+
export { buildDirectRequestStruct, createDepositsResource, createEthersSdk, createFinalizationServices, createTokensResource, createWithdrawalsResource, encodeNativeTokenVaultTransferData, encodeSecondBridgeArgs, encodeSecondBridgeDataV1, encodeSecondBridgeErc20Args, encodeSecondBridgeEthArgs };
|