@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,20 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { findL1MessageSentLog, messengerLogIndex, isAddressEq,
|
|
3
|
-
import {
|
|
4
|
-
import { isZKsyncError, createError, shapeCause, OP_WITHDRAWALS, OP_DEPOSITS, isReceiptNotFound } from './chunk-
|
|
5
|
-
import { ETH_ADDRESS,
|
|
6
|
-
import {
|
|
1
|
+
import { createNTVCodec, buildFeeBreakdown, quoteL2Gas, quoteL1Gas, quoteL2Gas2 } from './chunk-LL3WKCFJ.js';
|
|
2
|
+
import { findL1MessageSentLog, messengerLogIndex, normalizeL1Token, isAddressEq, hexEq, isHash66, isETH, normalizeAddrEq, pickWithdrawRoute } from './chunk-NEC2ZKHI.js';
|
|
3
|
+
import { REVERT_TO_READINESS } from './chunk-NCAIVYBR.js';
|
|
4
|
+
import { IL1Nullifier_default, IERC20_default, L1NativeTokenVault_default, L2NativeTokenVault_default, Mailbox_default, isZKsyncError, createError, shapeCause, OP_WITHDRAWALS, OP_DEPOSITS, isReceiptNotFound, IBridgehub_default, IL2AssetRouter_default, IBaseToken_default } 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
|
+
import { keccak256, encodeAbiParameters, concat, decodeErrorResult, decodeAbiParameters, decodeEventLog, encodeFunctionData, zeroAddress } from 'viem';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
);
|
|
17
|
-
|
|
8
|
+
// src/adapters/viem/resources/deposits/context.ts
|
|
9
|
+
async function commonCtx(p, client, tokens, contracts) {
|
|
10
|
+
const { bridgehub, l1AssetRouter } = await contracts.addresses();
|
|
11
|
+
const chainId = await client.l2.getChainId();
|
|
12
|
+
const sender = client.account.address;
|
|
13
|
+
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
14
|
+
const operatorTip = p.operatorTip ?? 0n;
|
|
15
|
+
const refundRecipient = p.refundRecipient ?? sender;
|
|
16
|
+
const resolvedToken = await tokens.resolve(p.token, { chain: "l1" });
|
|
17
|
+
const baseTokenAssetId = resolvedToken.baseTokenAssetId;
|
|
18
|
+
const baseTokenL1 = await tokens.l1TokenFromAssetId(baseTokenAssetId);
|
|
19
|
+
const baseIsEth = resolvedToken.isChainEthBased;
|
|
20
|
+
const route = (() => {
|
|
21
|
+
if (resolvedToken.kind === "eth") {
|
|
22
|
+
return baseIsEth ? "eth-base" : "eth-nonbase";
|
|
23
|
+
}
|
|
24
|
+
if (resolvedToken.kind === "base") {
|
|
25
|
+
return baseIsEth ? "eth-base" : "erc20-base";
|
|
26
|
+
}
|
|
27
|
+
return "erc20-nonbase";
|
|
28
|
+
})();
|
|
29
|
+
return {
|
|
30
|
+
client,
|
|
31
|
+
tokens,
|
|
32
|
+
contracts,
|
|
33
|
+
resolvedToken,
|
|
34
|
+
baseTokenAssetId,
|
|
35
|
+
baseTokenL1,
|
|
36
|
+
baseIsEth,
|
|
37
|
+
l1AssetRouter,
|
|
38
|
+
route,
|
|
39
|
+
bridgehub,
|
|
40
|
+
chainIdL2: BigInt(chainId),
|
|
41
|
+
sender,
|
|
42
|
+
gasOverrides: p.l1TxOverrides,
|
|
43
|
+
l2GasLimit: p.l2GasLimit,
|
|
44
|
+
gasPerPubdata,
|
|
45
|
+
operatorTip,
|
|
46
|
+
refundRecipient
|
|
47
|
+
};
|
|
18
48
|
}
|
|
19
49
|
function encodeNativeTokenVaultTransferData(amount, receiver, token) {
|
|
20
50
|
return encodeAbiParameters(
|
|
@@ -36,123 +66,6 @@ function encodeSecondBridgeDataV1(assetId, transferData) {
|
|
|
36
66
|
);
|
|
37
67
|
return concat(["0x01", data]);
|
|
38
68
|
}
|
|
39
|
-
var encodeNTVAssetId = encodeNativeTokenVaultAssetId;
|
|
40
|
-
var encodeNTVTransferData = encodeNativeTokenVaultTransferData;
|
|
41
|
-
function scaleGasLimit(gasLimit) {
|
|
42
|
-
return gasLimit * BigInt(L1_FEE_ESTIMATION_COEF_NUMERATOR) / BigInt(L1_FEE_ESTIMATION_COEF_DENOMINATOR);
|
|
43
|
-
}
|
|
44
|
-
async function checkBaseCost(baseCost, value) {
|
|
45
|
-
const resolved = await value;
|
|
46
|
-
if (baseCost > resolved) {
|
|
47
|
-
throw new Error(
|
|
48
|
-
`The base cost of performing the priority operation is higher than the provided value parameter for the transaction: baseCost: ${String(baseCost)}, provided value: ${String(resolved)}!`
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
async function getFeeOverrides(client, overrides) {
|
|
53
|
-
assertNoLegacyGas(overrides);
|
|
54
|
-
let maxFeePerGasFromProvider;
|
|
55
|
-
let maxPriorityFromProvider;
|
|
56
|
-
let gasPriceFromProvider;
|
|
57
|
-
try {
|
|
58
|
-
const fees = await client.l1.estimateFeesPerGas();
|
|
59
|
-
const { maxFeePerGas: maxFeePerGas2, maxPriorityFeePerGas: maxPriorityFeePerGas2 } = fees;
|
|
60
|
-
if (maxFeePerGas2 != null && maxPriorityFeePerGas2 != null) {
|
|
61
|
-
maxFeePerGasFromProvider = maxFeePerGas2;
|
|
62
|
-
maxPriorityFromProvider = maxPriorityFeePerGas2;
|
|
63
|
-
gasPriceFromProvider = fees.gasPrice ?? maxFeePerGas2;
|
|
64
|
-
} else if (fees.gasPrice != null) {
|
|
65
|
-
gasPriceFromProvider = fees.gasPrice;
|
|
66
|
-
}
|
|
67
|
-
} catch {
|
|
68
|
-
}
|
|
69
|
-
if (gasPriceFromProvider == null) {
|
|
70
|
-
try {
|
|
71
|
-
gasPriceFromProvider = await client.l1.getGasPrice();
|
|
72
|
-
} catch {
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider;
|
|
76
|
-
if (maxFeePerGas == null) {
|
|
77
|
-
throw new Error("L1 provider returned no gas price data");
|
|
78
|
-
}
|
|
79
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
80
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
81
|
-
const gasPriceForBaseCost = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider ?? maxFeePerGas;
|
|
82
|
-
return {
|
|
83
|
-
gasLimit: overrides?.gasLimit,
|
|
84
|
-
maxFeePerGas,
|
|
85
|
-
maxPriorityFeePerGas,
|
|
86
|
-
gasPriceForBaseCost
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
async function getL2FeeOverrides(client, overrides) {
|
|
90
|
-
assertNoLegacyGas(overrides);
|
|
91
|
-
let maxFeePerGasFromProvider;
|
|
92
|
-
let maxPriorityFromProvider;
|
|
93
|
-
let gasPriceFromProvider;
|
|
94
|
-
try {
|
|
95
|
-
const fees = await client.l2.estimateFeesPerGas();
|
|
96
|
-
if (fees?.maxFeePerGas != null && fees.maxPriorityFeePerGas != null) {
|
|
97
|
-
maxFeePerGasFromProvider = fees.maxFeePerGas;
|
|
98
|
-
maxPriorityFromProvider = fees.maxPriorityFeePerGas;
|
|
99
|
-
gasPriceFromProvider = fees.gasPrice ?? fees.maxFeePerGas;
|
|
100
|
-
} else if (fees?.gasPrice != null) {
|
|
101
|
-
gasPriceFromProvider = fees.gasPrice;
|
|
102
|
-
}
|
|
103
|
-
} catch {
|
|
104
|
-
}
|
|
105
|
-
if (gasPriceFromProvider == null) {
|
|
106
|
-
try {
|
|
107
|
-
gasPriceFromProvider = await client.l2.getGasPrice();
|
|
108
|
-
} catch {
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider;
|
|
112
|
-
if (maxFeePerGas == null) {
|
|
113
|
-
throw new Error("provider returned no gas price data");
|
|
114
|
-
}
|
|
115
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
116
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
117
|
-
return {
|
|
118
|
-
gasLimit: overrides?.gasLimit,
|
|
119
|
-
maxFeePerGas,
|
|
120
|
-
maxPriorityFeePerGas
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
function buildViemFeeOverrides(fees) {
|
|
124
|
-
return {
|
|
125
|
-
maxFeePerGas: fees.maxFeePerGas,
|
|
126
|
-
maxPriorityFeePerGas: fees.maxPriorityFeePerGas,
|
|
127
|
-
gas: fees.gasLimit
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
async function getGasPriceWei(client) {
|
|
131
|
-
try {
|
|
132
|
-
const gp = await client.l1.getGasPrice();
|
|
133
|
-
if (gp != null) return gp;
|
|
134
|
-
} catch {
|
|
135
|
-
}
|
|
136
|
-
try {
|
|
137
|
-
const fees = await client.l1.estimateFeesPerGas();
|
|
138
|
-
if (fees?.maxFeePerGas != null) return fees.maxFeePerGas;
|
|
139
|
-
} catch {
|
|
140
|
-
}
|
|
141
|
-
throw new Error("provider returned no gas price data");
|
|
142
|
-
}
|
|
143
|
-
function buildDirectRequestStruct(args) {
|
|
144
|
-
return {
|
|
145
|
-
chainId: args.chainId,
|
|
146
|
-
l2Contract: args.l2Contract,
|
|
147
|
-
mintValue: args.mintValue,
|
|
148
|
-
l2Value: args.l2Value,
|
|
149
|
-
l2Calldata: "0x",
|
|
150
|
-
l2GasLimit: args.l2GasLimit,
|
|
151
|
-
l2GasPerPubdataByteLimit: args.gasPerPubdata,
|
|
152
|
-
factoryDeps: [],
|
|
153
|
-
refundRecipient: args.refundRecipient
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
69
|
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
157
70
|
return encodeAbiParameters(
|
|
158
71
|
[
|
|
@@ -169,30 +82,17 @@ function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
|
169
82
|
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
170
83
|
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
171
84
|
}
|
|
172
|
-
|
|
173
|
-
// src/adapters/viem/resources/deposits/context.ts
|
|
174
|
-
async function commonCtx(p, client) {
|
|
175
|
-
const { bridgehub, l1AssetRouter } = await client.ensureAddresses();
|
|
176
|
-
const chainId = await client.l2.getChainId();
|
|
177
|
-
const sender = client.account.address;
|
|
178
|
-
const fee = await getFeeOverrides(client, p.l1TxOverrides);
|
|
179
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
180
|
-
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
181
|
-
const operatorTip = p.operatorTip ?? 0n;
|
|
182
|
-
const refundRecipient = p.refundRecipient ?? sender;
|
|
183
|
-
const route = await pickDepositRoute(client, BigInt(chainId), p.token);
|
|
85
|
+
function buildDirectRequestStruct(args) {
|
|
184
86
|
return {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
operatorTip,
|
|
195
|
-
refundRecipient
|
|
87
|
+
chainId: args.chainId,
|
|
88
|
+
l2Contract: args.l2Contract,
|
|
89
|
+
mintValue: args.mintValue,
|
|
90
|
+
l2Value: args.l2Value,
|
|
91
|
+
l2Calldata: "0x",
|
|
92
|
+
l2GasLimit: args.l2GasLimit,
|
|
93
|
+
l2GasPerPubdataByteLimit: args.gasPerPubdata,
|
|
94
|
+
factoryDeps: [],
|
|
95
|
+
refundRecipient: args.refundRecipient
|
|
196
96
|
};
|
|
197
97
|
}
|
|
198
98
|
var ERROR_ABIS = [];
|
|
@@ -323,7 +223,7 @@ function createErrorHandlers(resource) {
|
|
|
323
223
|
function wrap2(operation, fn, opts) {
|
|
324
224
|
return run("INTERNAL", operation, fn, opts);
|
|
325
225
|
}
|
|
326
|
-
function
|
|
226
|
+
function wrapAs10(kind, operation, fn, opts) {
|
|
327
227
|
return run(kind, operation, fn, opts);
|
|
328
228
|
}
|
|
329
229
|
async function toResult2(operation, fn, opts) {
|
|
@@ -344,44 +244,225 @@ function createErrorHandlers(resource) {
|
|
|
344
244
|
return { ok: false, error: shaped };
|
|
345
245
|
}
|
|
346
246
|
}
|
|
347
|
-
return { wrap: wrap2, wrapAs:
|
|
247
|
+
return { wrap: wrap2, wrapAs: wrapAs10, toResult: toResult2 };
|
|
348
248
|
}
|
|
349
249
|
|
|
350
|
-
// src/adapters/viem/
|
|
250
|
+
// src/adapters/viem/estimator.ts
|
|
251
|
+
function toCoreTx(tx) {
|
|
252
|
+
return {
|
|
253
|
+
to: tx.to,
|
|
254
|
+
from: tx.from,
|
|
255
|
+
data: tx.data,
|
|
256
|
+
value: tx.value,
|
|
257
|
+
gasLimit: tx.gas,
|
|
258
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
259
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function viemToGasEstimator(client) {
|
|
263
|
+
return {
|
|
264
|
+
async estimateGas(tx, stateOverrides) {
|
|
265
|
+
if (stateOverrides) {
|
|
266
|
+
try {
|
|
267
|
+
const result = await client.request({
|
|
268
|
+
method: "eth_estimateGas",
|
|
269
|
+
params: [
|
|
270
|
+
{
|
|
271
|
+
from: tx.from,
|
|
272
|
+
to: tx.to,
|
|
273
|
+
data: tx.data,
|
|
274
|
+
value: tx.value,
|
|
275
|
+
gas: tx.gasLimit,
|
|
276
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
277
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
278
|
+
},
|
|
279
|
+
"latest",
|
|
280
|
+
stateOverrides
|
|
281
|
+
]
|
|
282
|
+
});
|
|
283
|
+
return BigInt(result);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.warn(
|
|
286
|
+
"Failed to estimate gas with state overrides, falling back to standard estimation:",
|
|
287
|
+
error
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return await client.estimateGas({
|
|
292
|
+
account: tx.from,
|
|
293
|
+
to: tx.to,
|
|
294
|
+
data: tx.data,
|
|
295
|
+
value: tx.value,
|
|
296
|
+
gas: tx.gasLimit,
|
|
297
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
298
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
299
|
+
});
|
|
300
|
+
},
|
|
301
|
+
async estimateFeesPerGas() {
|
|
302
|
+
try {
|
|
303
|
+
const fees = await client.estimateFeesPerGas();
|
|
304
|
+
return {
|
|
305
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
306
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas
|
|
307
|
+
};
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const gp = await client.getGasPrice();
|
|
312
|
+
return { gasPrice: gp };
|
|
313
|
+
} catch {
|
|
314
|
+
return {};
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
async getGasPrice() {
|
|
318
|
+
return await client.getGasPrice();
|
|
319
|
+
},
|
|
320
|
+
async call(tx) {
|
|
321
|
+
const res = await client.call({
|
|
322
|
+
to: tx.to,
|
|
323
|
+
data: tx.data,
|
|
324
|
+
value: tx.value,
|
|
325
|
+
account: tx.from
|
|
326
|
+
});
|
|
327
|
+
return res.data ?? "0x";
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/adapters/viem/resources/deposits/services/gas.ts
|
|
333
|
+
async function quoteL1Gas2(input) {
|
|
334
|
+
const { ctx, tx, overrides, fallbackGasLimit } = input;
|
|
335
|
+
const estimator = viemToGasEstimator(ctx.client.l1);
|
|
336
|
+
return quoteL1Gas({
|
|
337
|
+
estimator,
|
|
338
|
+
tx: toCoreTx(tx),
|
|
339
|
+
overrides,
|
|
340
|
+
fallbackGasLimit
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
async function quoteL2Gas3(input) {
|
|
344
|
+
const { ctx, route, l2TxForModeling, overrideGasLimit } = input;
|
|
345
|
+
const estimator = viemToGasEstimator(ctx.client.l2);
|
|
346
|
+
return quoteL2Gas({
|
|
347
|
+
estimator,
|
|
348
|
+
route,
|
|
349
|
+
tx: l2TxForModeling ? toCoreTx(l2TxForModeling) : void 0,
|
|
350
|
+
gasPerPubdata: ctx.gasPerPubdata,
|
|
351
|
+
l2GasLimit: ctx.l2GasLimit,
|
|
352
|
+
// TODO: investigate if this should be passed here; weird viem quirk
|
|
353
|
+
overrideGasLimit,
|
|
354
|
+
stateOverrides: input.stateOverrides
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
async function determineErc20L2Gas(input) {
|
|
358
|
+
const { ctx, l1Token } = input;
|
|
359
|
+
const DEFAULT_SAFE_L2_GAS_LIMIT = 3000000n;
|
|
360
|
+
if (ctx.l2GasLimit != null) {
|
|
361
|
+
return quoteL2Gas3({
|
|
362
|
+
ctx,
|
|
363
|
+
route: "erc20-nonbase",
|
|
364
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
const l2TokenAddress = ctx.tokens ? await ctx.tokens.toL2Address(l1Token) : await (await ctx.contracts.l2NativeTokenVault()).read.l2TokenAddress([l1Token]);
|
|
369
|
+
if (l2TokenAddress === zeroAddress) {
|
|
370
|
+
return quoteL2Gas3({
|
|
371
|
+
ctx,
|
|
372
|
+
route: "erc20-nonbase",
|
|
373
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
const modelTx = {
|
|
377
|
+
to: input.modelTx?.to ?? ctx.sender,
|
|
378
|
+
from: input.modelTx?.from ?? ctx.sender,
|
|
379
|
+
data: input.modelTx?.data ?? "0x",
|
|
380
|
+
value: input.modelTx?.value ?? 0n
|
|
381
|
+
};
|
|
382
|
+
const gas = await quoteL2Gas3({
|
|
383
|
+
ctx,
|
|
384
|
+
route: "erc20-nonbase",
|
|
385
|
+
l2TxForModeling: modelTx
|
|
386
|
+
});
|
|
387
|
+
if (!gas) {
|
|
388
|
+
return quoteL2Gas3({
|
|
389
|
+
ctx,
|
|
390
|
+
route: "erc20-nonbase",
|
|
391
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return gas;
|
|
395
|
+
} catch (err) {
|
|
396
|
+
console.warn("Failed to determine ERC20 L2 gas; defaulting to safe gas limit.", err);
|
|
397
|
+
return quoteL2Gas3({
|
|
398
|
+
ctx,
|
|
399
|
+
route: "erc20-nonbase",
|
|
400
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// src/adapters/viem/resources/deposits/services/fee.ts
|
|
351
406
|
var { wrapAs } = createErrorHandlers("deposits");
|
|
407
|
+
async function quoteL2BaseCost(input) {
|
|
408
|
+
const { ctx, l2GasLimit } = input;
|
|
409
|
+
const estimator = viemToGasEstimator(ctx.client.l1);
|
|
410
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
411
|
+
const gasPrice = fees.maxFeePerGas ?? fees.gasPrice ?? await estimator.getGasPrice();
|
|
412
|
+
return wrapAs(
|
|
413
|
+
"RPC",
|
|
414
|
+
"deposits.fees.l2BaseCost",
|
|
415
|
+
async () => {
|
|
416
|
+
return await ctx.client.l1.readContract({
|
|
417
|
+
address: ctx.bridgehub,
|
|
418
|
+
abi: IBridgehub_default,
|
|
419
|
+
functionName: "l2TransactionBaseCost",
|
|
420
|
+
args: [ctx.chainIdL2, gasPrice, l2GasLimit, ctx.gasPerPubdata]
|
|
421
|
+
});
|
|
422
|
+
},
|
|
423
|
+
{ ctx: { chainIdL2: ctx.chainIdL2 } }
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// src/adapters/viem/resources/deposits/routes/eth.ts
|
|
428
|
+
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
352
429
|
function routeEthDirect() {
|
|
353
430
|
return {
|
|
354
431
|
async build(p, ctx) {
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
"
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
{
|
|
367
|
-
ctx: {
|
|
368
|
-
|
|
432
|
+
const l2TxModel = {
|
|
433
|
+
to: p.to ?? ctx.sender,
|
|
434
|
+
from: ctx.sender,
|
|
435
|
+
data: "0x",
|
|
436
|
+
value: p.amount
|
|
437
|
+
};
|
|
438
|
+
const l2GasParams = await quoteL2Gas3({
|
|
439
|
+
ctx,
|
|
440
|
+
route: "eth-base",
|
|
441
|
+
l2TxForModeling: l2TxModel,
|
|
442
|
+
overrideGasLimit: ctx.l2GasLimit,
|
|
443
|
+
stateOverrides: {
|
|
444
|
+
[ctx.sender]: {
|
|
445
|
+
balance: "0xffffffffffffffffffff"
|
|
446
|
+
}
|
|
369
447
|
}
|
|
370
|
-
);
|
|
371
|
-
|
|
448
|
+
});
|
|
449
|
+
if (!l2GasParams) {
|
|
450
|
+
throw new Error("Failed to estimate L2 gas for deposit.");
|
|
451
|
+
}
|
|
452
|
+
const baseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
372
453
|
const l2Contract = p.to ?? ctx.sender;
|
|
373
454
|
const l2Value = p.amount;
|
|
374
455
|
const mintValue = baseCost + ctx.operatorTip + l2Value;
|
|
375
456
|
const req = buildDirectRequestStruct({
|
|
376
457
|
chainId: ctx.chainIdL2,
|
|
377
458
|
mintValue,
|
|
378
|
-
l2GasLimit:
|
|
459
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
379
460
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
380
461
|
refundRecipient: ctx.refundRecipient,
|
|
381
462
|
l2Contract,
|
|
382
463
|
l2Value
|
|
383
464
|
});
|
|
384
|
-
const sim = await
|
|
465
|
+
const sim = await wrapAs2(
|
|
385
466
|
"RPC",
|
|
386
467
|
OP_DEPOSITS.eth.estGas,
|
|
387
468
|
() => ctx.client.l1.simulateContract({
|
|
@@ -397,120 +478,116 @@ function routeEthDirect() {
|
|
|
397
478
|
message: "Failed to simulate Bridgehub.requestL2TransactionDirect."
|
|
398
479
|
}
|
|
399
480
|
);
|
|
400
|
-
const
|
|
481
|
+
const data = encodeFunctionData({
|
|
482
|
+
abi: sim.request.abi,
|
|
483
|
+
functionName: sim.request.functionName,
|
|
484
|
+
args: sim.request.args
|
|
485
|
+
});
|
|
486
|
+
const l1TxCandidate = {
|
|
487
|
+
to: ctx.bridgehub,
|
|
488
|
+
data,
|
|
489
|
+
value: mintValue,
|
|
490
|
+
from: ctx.sender,
|
|
491
|
+
...ctx.gasOverrides
|
|
492
|
+
};
|
|
493
|
+
const l1Gas = await quoteL1Gas2({
|
|
494
|
+
ctx,
|
|
495
|
+
tx: l1TxCandidate,
|
|
496
|
+
overrides: ctx.gasOverrides
|
|
497
|
+
});
|
|
401
498
|
const steps = [
|
|
402
499
|
{
|
|
403
500
|
key: "bridgehub:direct",
|
|
404
501
|
kind: "bridgehub:direct",
|
|
405
502
|
description: "Bridge ETH via Bridgehub.requestL2TransactionDirect",
|
|
406
|
-
tx: { ...sim.request, ...
|
|
503
|
+
tx: { ...sim.request, ...l1Gas }
|
|
407
504
|
}
|
|
408
505
|
];
|
|
506
|
+
const fees = buildFeeBreakdown({
|
|
507
|
+
feeToken: ETH_ADDRESS,
|
|
508
|
+
l1Gas,
|
|
509
|
+
l2Gas: l2GasParams,
|
|
510
|
+
l2BaseCost: baseCost,
|
|
511
|
+
operatorTip: ctx.operatorTip,
|
|
512
|
+
mintValue
|
|
513
|
+
});
|
|
409
514
|
return {
|
|
410
515
|
steps,
|
|
411
516
|
approvals: [],
|
|
412
|
-
|
|
517
|
+
fees
|
|
413
518
|
};
|
|
414
519
|
}
|
|
415
520
|
};
|
|
416
521
|
}
|
|
417
|
-
|
|
418
|
-
// src/adapters/viem/resources/deposits/routes/erc20-nonbase.ts
|
|
419
|
-
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
420
|
-
var BASE_COST_BUFFER_BPS = 100n;
|
|
421
|
-
var BPS = 10000n;
|
|
422
|
-
var withBuffer = (x) => x * (BPS + BASE_COST_BUFFER_BPS) / BPS;
|
|
522
|
+
var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
|
|
423
523
|
function routeErc20NonBase() {
|
|
424
524
|
return {
|
|
525
|
+
// TODO: do we even need these validations?
|
|
425
526
|
async preflight(p, ctx) {
|
|
426
|
-
await
|
|
527
|
+
await wrapAs3(
|
|
427
528
|
"VALIDATION",
|
|
428
529
|
OP_DEPOSITS.nonbase.assertNotEthAsset,
|
|
429
530
|
() => {
|
|
430
|
-
if (isETH(p.token)) {
|
|
531
|
+
if (ctx.resolvedToken?.kind === "eth" || isETH(p.token)) {
|
|
431
532
|
throw new Error("erc20-nonbase route requires an ERC-20 token (not ETH).");
|
|
432
533
|
}
|
|
433
534
|
},
|
|
434
535
|
{ ctx: { token: p.token } }
|
|
435
536
|
);
|
|
436
|
-
const baseToken = await
|
|
437
|
-
|
|
438
|
-
OP_DEPOSITS.nonbase.baseToken,
|
|
439
|
-
() => ctx.client.l1.readContract({
|
|
440
|
-
address: ctx.bridgehub,
|
|
441
|
-
abi: IBridgehub_default,
|
|
442
|
-
functionName: "baseToken",
|
|
443
|
-
args: [ctx.chainIdL2]
|
|
444
|
-
}),
|
|
445
|
-
{ ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 } }
|
|
446
|
-
);
|
|
447
|
-
await wrapAs2(
|
|
537
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
538
|
+
await wrapAs3(
|
|
448
539
|
"VALIDATION",
|
|
449
540
|
OP_DEPOSITS.nonbase.assertNonBaseToken,
|
|
450
541
|
() => {
|
|
451
|
-
if (normalizeAddrEq(baseToken, p.token)) {
|
|
542
|
+
if (ctx.resolvedToken?.kind === "base" || normalizeAddrEq(baseToken, p.token)) {
|
|
452
543
|
throw new Error("erc20-nonbase route requires a non-base ERC-20 deposit token.");
|
|
453
544
|
}
|
|
454
545
|
},
|
|
455
546
|
{ ctx: { depositToken: p.token, baseToken } }
|
|
456
547
|
);
|
|
457
|
-
return;
|
|
458
548
|
},
|
|
459
549
|
async build(p, ctx) {
|
|
460
|
-
const
|
|
461
|
-
const
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
const
|
|
476
|
-
"CONTRACT",
|
|
477
|
-
OP_DEPOSITS.nonbase.baseCost,
|
|
478
|
-
() => ctx.client.l1.readContract({
|
|
479
|
-
address: ctx.bridgehub,
|
|
480
|
-
abi: IBridgehub_default,
|
|
481
|
-
functionName: "l2TransactionBaseCost",
|
|
482
|
-
args: [ctx.chainIdL2, gasPriceForBaseCost, l2GasLimitUsed, ctx.gasPerPubdata]
|
|
483
|
-
}),
|
|
484
|
-
{ ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 } }
|
|
485
|
-
);
|
|
486
|
-
const baseCost = rawBaseCost;
|
|
487
|
-
const mintValue = withBuffer(baseCost + ctx.operatorTip);
|
|
550
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
551
|
+
const baseIsEth = ctx.baseIsEth ?? isETH(baseToken);
|
|
552
|
+
const assetRouter = ctx.l1AssetRouter;
|
|
553
|
+
const l2Gas = await determineErc20L2Gas({
|
|
554
|
+
ctx,
|
|
555
|
+
l1Token: p.token,
|
|
556
|
+
modelTx: {
|
|
557
|
+
to: p.to ?? ctx.sender,
|
|
558
|
+
from: ctx.sender,
|
|
559
|
+
data: "0x",
|
|
560
|
+
value: 0n
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
if (!l2Gas) throw new Error("Failed to establish L2 gas parameters.");
|
|
564
|
+
const l2BaseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2Gas.gasLimit });
|
|
565
|
+
const mintValue = l2BaseCost + ctx.operatorTip;
|
|
488
566
|
const approvals = [];
|
|
489
567
|
const steps = [];
|
|
490
|
-
const depositAllowance = await
|
|
568
|
+
const depositAllowance = await wrapAs3(
|
|
491
569
|
"CONTRACT",
|
|
492
|
-
OP_DEPOSITS.nonbase.
|
|
570
|
+
OP_DEPOSITS.nonbase.allowanceToken,
|
|
493
571
|
() => ctx.client.l1.readContract({
|
|
494
572
|
address: p.token,
|
|
495
573
|
abi: IERC20_default,
|
|
496
574
|
functionName: "allowance",
|
|
497
|
-
args: [ctx.sender,
|
|
575
|
+
args: [ctx.sender, assetRouter]
|
|
498
576
|
}),
|
|
499
577
|
{
|
|
500
|
-
ctx: { where: "erc20.allowance", token: p.token, spender:
|
|
501
|
-
message: "Failed to read
|
|
578
|
+
ctx: { where: "erc20.allowance", token: p.token, spender: assetRouter },
|
|
579
|
+
message: "Failed to read deposit-token allowance."
|
|
502
580
|
}
|
|
503
581
|
);
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
const approveDepReq = await wrapAs2(
|
|
582
|
+
if (depositAllowance < p.amount) {
|
|
583
|
+
const approveSim = await wrapAs3(
|
|
507
584
|
"CONTRACT",
|
|
508
585
|
OP_DEPOSITS.nonbase.estGas,
|
|
509
586
|
() => ctx.client.l1.simulateContract({
|
|
510
587
|
address: p.token,
|
|
511
588
|
abi: IERC20_default,
|
|
512
589
|
functionName: "approve",
|
|
513
|
-
args: [
|
|
590
|
+
args: [assetRouter, p.amount],
|
|
514
591
|
account: ctx.client.account
|
|
515
592
|
}),
|
|
516
593
|
{
|
|
@@ -518,60 +595,55 @@ function routeErc20NonBase() {
|
|
|
518
595
|
message: "Failed to simulate deposit token approve."
|
|
519
596
|
}
|
|
520
597
|
);
|
|
521
|
-
approvals.push({ token: p.token, spender:
|
|
598
|
+
approvals.push({ token: p.token, spender: assetRouter, amount: p.amount });
|
|
522
599
|
steps.push({
|
|
523
|
-
key: `approve:${p.token}:${
|
|
600
|
+
key: `approve:${p.token}:${assetRouter}`,
|
|
524
601
|
kind: "approve",
|
|
525
602
|
description: `Approve deposit token for amount`,
|
|
526
|
-
tx: { ...
|
|
603
|
+
tx: { ...approveSim.request }
|
|
527
604
|
});
|
|
528
605
|
}
|
|
529
|
-
const baseIsEth = isETH(baseToken);
|
|
530
|
-
let msgValue = 0n;
|
|
531
606
|
if (!baseIsEth) {
|
|
532
|
-
const baseAllowance = await
|
|
607
|
+
const baseAllowance = await wrapAs3(
|
|
533
608
|
"CONTRACT",
|
|
534
|
-
OP_DEPOSITS.nonbase.
|
|
609
|
+
OP_DEPOSITS.nonbase.allowanceBase,
|
|
535
610
|
() => ctx.client.l1.readContract({
|
|
536
611
|
address: baseToken,
|
|
537
612
|
abi: IERC20_default,
|
|
538
613
|
functionName: "allowance",
|
|
539
|
-
args: [ctx.sender,
|
|
614
|
+
args: [ctx.sender, assetRouter]
|
|
540
615
|
}),
|
|
541
616
|
{
|
|
542
|
-
ctx: { where: "erc20.allowance", token: baseToken, spender:
|
|
617
|
+
ctx: { where: "erc20.allowance", token: baseToken, spender: assetRouter },
|
|
543
618
|
message: "Failed to read base-token allowance."
|
|
544
619
|
}
|
|
545
620
|
);
|
|
546
621
|
if (baseAllowance < mintValue) {
|
|
547
|
-
const
|
|
622
|
+
const approveBaseSim = await wrapAs3(
|
|
548
623
|
"CONTRACT",
|
|
549
624
|
OP_DEPOSITS.nonbase.estGas,
|
|
550
625
|
() => ctx.client.l1.simulateContract({
|
|
551
626
|
address: baseToken,
|
|
552
627
|
abi: IERC20_default,
|
|
553
628
|
functionName: "approve",
|
|
554
|
-
args: [
|
|
629
|
+
args: [assetRouter, mintValue],
|
|
555
630
|
account: ctx.client.account
|
|
556
631
|
}),
|
|
557
632
|
{
|
|
558
633
|
ctx: { where: "l1.simulateContract", to: baseToken },
|
|
559
|
-
message: "Failed to simulate base
|
|
634
|
+
message: "Failed to simulate base token approve."
|
|
560
635
|
}
|
|
561
636
|
);
|
|
562
|
-
approvals.push({ token: baseToken, spender:
|
|
637
|
+
approvals.push({ token: baseToken, spender: assetRouter, amount: mintValue });
|
|
563
638
|
steps.push({
|
|
564
|
-
key: `approve:${baseToken}:${
|
|
639
|
+
key: `approve:${baseToken}:${assetRouter}`,
|
|
565
640
|
kind: "approve",
|
|
566
641
|
description: `Approve base token for mintValue`,
|
|
567
|
-
tx: { ...
|
|
642
|
+
tx: { ...approveBaseSim.request }
|
|
568
643
|
});
|
|
569
644
|
}
|
|
570
|
-
msgValue = 0n;
|
|
571
|
-
} else {
|
|
572
|
-
msgValue = mintValue;
|
|
573
645
|
}
|
|
574
|
-
const secondBridgeCalldata = await
|
|
646
|
+
const secondBridgeCalldata = await wrapAs3(
|
|
575
647
|
"INTERNAL",
|
|
576
648
|
OP_DEPOSITS.nonbase.encodeCalldata,
|
|
577
649
|
() => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, p.to ?? ctx.sender)),
|
|
@@ -580,44 +652,60 @@ function routeErc20NonBase() {
|
|
|
580
652
|
where: "encodeSecondBridgeErc20Args",
|
|
581
653
|
token: p.token,
|
|
582
654
|
amount: p.amount.toString()
|
|
583
|
-
}
|
|
655
|
+
},
|
|
656
|
+
message: "Failed to encode bridging calldata."
|
|
584
657
|
}
|
|
585
658
|
);
|
|
586
|
-
const
|
|
659
|
+
const requestStruct = {
|
|
587
660
|
chainId: ctx.chainIdL2,
|
|
588
661
|
mintValue,
|
|
589
662
|
l2Value: 0n,
|
|
590
|
-
l2GasLimit:
|
|
663
|
+
l2GasLimit: l2Gas.gasLimit,
|
|
591
664
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
592
665
|
refundRecipient: ctx.refundRecipient,
|
|
593
|
-
secondBridgeAddress:
|
|
666
|
+
secondBridgeAddress: assetRouter,
|
|
594
667
|
secondBridgeValue: 0n,
|
|
595
668
|
secondBridgeCalldata
|
|
596
669
|
};
|
|
670
|
+
const msgValue = baseIsEth ? mintValue : 0n;
|
|
671
|
+
const calldata = encodeFunctionData({
|
|
672
|
+
abi: IBridgehub_default,
|
|
673
|
+
functionName: "requestL2TransactionTwoBridges",
|
|
674
|
+
args: [requestStruct]
|
|
675
|
+
});
|
|
676
|
+
const l1TxCandidate = {
|
|
677
|
+
to: ctx.bridgehub,
|
|
678
|
+
data: calldata,
|
|
679
|
+
value: msgValue,
|
|
680
|
+
from: ctx.sender,
|
|
681
|
+
...ctx.gasOverrides
|
|
682
|
+
};
|
|
683
|
+
const l1Gas = await quoteL1Gas2({
|
|
684
|
+
ctx,
|
|
685
|
+
tx: l1TxCandidate,
|
|
686
|
+
overrides: ctx.gasOverrides,
|
|
687
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
688
|
+
});
|
|
597
689
|
const approvalsNeeded = approvals.length > 0;
|
|
598
690
|
let bridgeTx;
|
|
599
|
-
let resolvedL1GasLimit;
|
|
600
|
-
const gasOverride = txFeeOverrides.gas;
|
|
601
691
|
if (approvalsNeeded) {
|
|
602
692
|
bridgeTx = {
|
|
603
693
|
address: ctx.bridgehub,
|
|
604
694
|
abi: IBridgehub_default,
|
|
605
695
|
functionName: "requestL2TransactionTwoBridges",
|
|
606
|
-
args: [
|
|
696
|
+
args: [requestStruct],
|
|
607
697
|
value: msgValue,
|
|
608
|
-
account: ctx.client.account
|
|
609
|
-
...txFeeOverrides
|
|
698
|
+
account: ctx.client.account
|
|
610
699
|
};
|
|
611
|
-
resolvedL1GasLimit = gasOverride ?? ctx.l2GasLimit;
|
|
612
700
|
} else {
|
|
613
|
-
const sim = await
|
|
701
|
+
const sim = await wrapAs3(
|
|
614
702
|
"CONTRACT",
|
|
615
703
|
OP_DEPOSITS.nonbase.estGas,
|
|
616
704
|
() => ctx.client.l1.simulateContract({
|
|
617
705
|
address: ctx.bridgehub,
|
|
618
706
|
abi: IBridgehub_default,
|
|
619
707
|
functionName: "requestL2TransactionTwoBridges",
|
|
620
|
-
args: [
|
|
708
|
+
args: [requestStruct],
|
|
621
709
|
value: msgValue,
|
|
622
710
|
account: ctx.client.account
|
|
623
711
|
}),
|
|
@@ -626,67 +714,64 @@ function routeErc20NonBase() {
|
|
|
626
714
|
message: "Failed to simulate two-bridges request."
|
|
627
715
|
}
|
|
628
716
|
);
|
|
629
|
-
bridgeTx = { ...sim.request
|
|
630
|
-
|
|
717
|
+
bridgeTx = { ...sim.request };
|
|
718
|
+
}
|
|
719
|
+
if (l1Gas) {
|
|
720
|
+
bridgeTx = {
|
|
721
|
+
...bridgeTx,
|
|
722
|
+
gas: l1Gas.gasLimit,
|
|
723
|
+
maxFeePerGas: l1Gas.maxFeePerGas,
|
|
724
|
+
maxPriorityFeePerGas: l1Gas.maxPriorityFeePerGas
|
|
725
|
+
};
|
|
631
726
|
}
|
|
632
727
|
steps.push({
|
|
633
|
-
key: "bridgehub:two-bridges:nonbase",
|
|
728
|
+
key: "bridgehub:two-bridges:erc20-nonbase",
|
|
634
729
|
kind: "bridgehub:two-bridges",
|
|
635
730
|
description: baseIsEth ? "Bridge ERC-20 (fees in ETH) via Bridgehub.requestL2TransactionTwoBridges" : "Bridge ERC-20 (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
|
|
636
731
|
tx: bridgeTx
|
|
637
732
|
});
|
|
733
|
+
const fees = buildFeeBreakdown({
|
|
734
|
+
feeToken: baseToken,
|
|
735
|
+
l1Gas,
|
|
736
|
+
l2Gas,
|
|
737
|
+
l2BaseCost,
|
|
738
|
+
operatorTip: ctx.operatorTip,
|
|
739
|
+
mintValue
|
|
740
|
+
});
|
|
638
741
|
return {
|
|
639
742
|
steps,
|
|
640
743
|
approvals,
|
|
641
|
-
|
|
744
|
+
fees
|
|
642
745
|
};
|
|
643
746
|
}
|
|
644
747
|
};
|
|
645
748
|
}
|
|
646
|
-
|
|
647
|
-
// src/adapters/viem/resources/deposits/routes/eth-nonbase.ts
|
|
648
|
-
var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
|
|
649
|
-
var BASE_COST_BUFFER_BPS2 = 100n;
|
|
650
|
-
var BPS2 = 10000n;
|
|
651
|
-
var withBuffer2 = (x) => x * (BPS2 + BASE_COST_BUFFER_BPS2) / BPS2;
|
|
749
|
+
var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
|
|
652
750
|
function routeEthNonBase() {
|
|
653
751
|
return {
|
|
752
|
+
// TODO: do we even need these validations?
|
|
654
753
|
async preflight(p, ctx) {
|
|
655
|
-
await
|
|
754
|
+
await wrapAs4(
|
|
656
755
|
"VALIDATION",
|
|
657
756
|
OP_DEPOSITS.ethNonBase.assertEthAsset,
|
|
658
757
|
() => {
|
|
659
|
-
if (!isETH(p.token)) {
|
|
758
|
+
if (ctx.resolvedToken?.kind !== "eth" && !isETH(p.token)) {
|
|
660
759
|
throw new Error("eth-nonbase route requires ETH as the deposit asset.");
|
|
661
760
|
}
|
|
662
761
|
},
|
|
663
762
|
{ ctx: { token: p.token } }
|
|
664
763
|
);
|
|
665
|
-
|
|
666
|
-
"CONTRACT",
|
|
667
|
-
OP_DEPOSITS.ethNonBase.baseToken,
|
|
668
|
-
() => ctx.client.l1.readContract({
|
|
669
|
-
address: ctx.bridgehub,
|
|
670
|
-
abi: IBridgehub_default,
|
|
671
|
-
functionName: "baseToken",
|
|
672
|
-
args: [ctx.chainIdL2]
|
|
673
|
-
}),
|
|
674
|
-
{
|
|
675
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
676
|
-
message: "Failed to read base token."
|
|
677
|
-
}
|
|
678
|
-
);
|
|
679
|
-
await wrapAs3(
|
|
764
|
+
await wrapAs4(
|
|
680
765
|
"VALIDATION",
|
|
681
766
|
OP_DEPOSITS.ethNonBase.assertNonEthBase,
|
|
682
767
|
() => {
|
|
683
|
-
if (
|
|
768
|
+
if (ctx.baseIsEth) {
|
|
684
769
|
throw new Error("eth-nonbase route requires target chain base token \u2260 ETH.");
|
|
685
770
|
}
|
|
686
771
|
},
|
|
687
|
-
{ ctx: {
|
|
772
|
+
{ ctx: { baseIsEth: ctx.baseIsEth, chainIdL2: ctx.chainIdL2 } }
|
|
688
773
|
);
|
|
689
|
-
const ethBal = await
|
|
774
|
+
const ethBal = await wrapAs4(
|
|
690
775
|
"RPC",
|
|
691
776
|
OP_DEPOSITS.ethNonBase.ethBalance,
|
|
692
777
|
() => ctx.client.l1.getBalance({ address: ctx.sender }),
|
|
@@ -695,7 +780,7 @@ function routeEthNonBase() {
|
|
|
695
780
|
message: "Failed to read L1 ETH balance."
|
|
696
781
|
}
|
|
697
782
|
);
|
|
698
|
-
await
|
|
783
|
+
await wrapAs4(
|
|
699
784
|
"VALIDATION",
|
|
700
785
|
OP_DEPOSITS.ethNonBase.assertEthBalance,
|
|
701
786
|
() => {
|
|
@@ -705,45 +790,27 @@ function routeEthNonBase() {
|
|
|
705
790
|
},
|
|
706
791
|
{ ctx: { required: p.amount.toString(), balance: ethBal.toString() } }
|
|
707
792
|
);
|
|
708
|
-
return;
|
|
709
793
|
},
|
|
710
794
|
async build(p, ctx) {
|
|
711
|
-
const
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
const rawBaseCost = await wrapAs3(
|
|
728
|
-
"CONTRACT",
|
|
729
|
-
OP_DEPOSITS.ethNonBase.baseCost,
|
|
730
|
-
() => ctx.client.l1.readContract({
|
|
731
|
-
address: ctx.bridgehub,
|
|
732
|
-
abi: IBridgehub_default,
|
|
733
|
-
functionName: "l2TransactionBaseCost",
|
|
734
|
-
args: [ctx.chainIdL2, gasPriceForBaseCost, ctx.l2GasLimit, ctx.gasPerPubdata]
|
|
735
|
-
}),
|
|
736
|
-
{
|
|
737
|
-
ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
|
|
738
|
-
message: "Could not fetch L2 base cost."
|
|
739
|
-
}
|
|
740
|
-
);
|
|
741
|
-
const baseCost = BigInt(rawBaseCost);
|
|
742
|
-
const mintValueRaw = baseCost + ctx.operatorTip;
|
|
743
|
-
const mintValue = withBuffer2(mintValueRaw);
|
|
795
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
796
|
+
const l2TxModel = {
|
|
797
|
+
to: p.to ?? ctx.sender,
|
|
798
|
+
from: ctx.sender,
|
|
799
|
+
data: "0x",
|
|
800
|
+
value: 0n
|
|
801
|
+
};
|
|
802
|
+
const l2Gas = await quoteL2Gas3({
|
|
803
|
+
ctx,
|
|
804
|
+
route: "eth-nonbase",
|
|
805
|
+
l2TxForModeling: l2TxModel,
|
|
806
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
807
|
+
});
|
|
808
|
+
if (!l2Gas) throw new Error("Failed to estimate L2 gas parameters.");
|
|
809
|
+
const l2BaseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2Gas.gasLimit });
|
|
810
|
+
const mintValue = l2BaseCost + ctx.operatorTip;
|
|
744
811
|
const approvals = [];
|
|
745
812
|
const steps = [];
|
|
746
|
-
const allowance = await
|
|
813
|
+
const allowance = await wrapAs4(
|
|
747
814
|
"CONTRACT",
|
|
748
815
|
OP_DEPOSITS.ethNonBase.allowanceBase,
|
|
749
816
|
() => ctx.client.l1.readContract({
|
|
@@ -759,7 +826,7 @@ function routeEthNonBase() {
|
|
|
759
826
|
);
|
|
760
827
|
const needsApprove = allowance < mintValue;
|
|
761
828
|
if (needsApprove) {
|
|
762
|
-
const approveSim = await
|
|
829
|
+
const approveSim = await wrapAs4(
|
|
763
830
|
"CONTRACT",
|
|
764
831
|
OP_DEPOSITS.ethNonBase.estGas,
|
|
765
832
|
() => ctx.client.l1.simulateContract({
|
|
@@ -778,11 +845,11 @@ function routeEthNonBase() {
|
|
|
778
845
|
steps.push({
|
|
779
846
|
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
780
847
|
kind: "approve",
|
|
781
|
-
description: `Approve base token for mintValue`,
|
|
848
|
+
description: `Approve base token for fees (mintValue)`,
|
|
782
849
|
tx: { ...approveSim.request }
|
|
783
850
|
});
|
|
784
851
|
}
|
|
785
|
-
const secondBridgeCalldata = await
|
|
852
|
+
const secondBridgeCalldata = await wrapAs4(
|
|
786
853
|
"INTERNAL",
|
|
787
854
|
OP_DEPOSITS.ethNonBase.encodeCalldata,
|
|
788
855
|
() => Promise.resolve(encodeSecondBridgeEthArgs(p.amount, p.to ?? ctx.sender)),
|
|
@@ -795,11 +862,11 @@ function routeEthNonBase() {
|
|
|
795
862
|
message: "Failed to encode ETH bridging calldata."
|
|
796
863
|
}
|
|
797
864
|
);
|
|
798
|
-
const
|
|
865
|
+
const requestStruct = {
|
|
799
866
|
chainId: ctx.chainIdL2,
|
|
800
867
|
mintValue,
|
|
801
|
-
l2Value:
|
|
802
|
-
l2GasLimit:
|
|
868
|
+
l2Value: p.amount,
|
|
869
|
+
l2GasLimit: l2Gas.gasLimit,
|
|
803
870
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
804
871
|
refundRecipient: ctx.refundRecipient,
|
|
805
872
|
secondBridgeAddress: ctx.l1AssetRouter,
|
|
@@ -807,29 +874,32 @@ function routeEthNonBase() {
|
|
|
807
874
|
secondBridgeCalldata
|
|
808
875
|
};
|
|
809
876
|
let bridgeTx;
|
|
810
|
-
let
|
|
877
|
+
let calldata;
|
|
811
878
|
if (needsApprove) {
|
|
812
879
|
bridgeTx = {
|
|
813
880
|
address: ctx.bridgehub,
|
|
814
881
|
abi: IBridgehub_default,
|
|
815
882
|
functionName: "requestL2TransactionTwoBridges",
|
|
816
|
-
args: [
|
|
883
|
+
args: [requestStruct],
|
|
817
884
|
value: p.amount,
|
|
818
885
|
// base ≠ ETH ⇒ msg.value == secondBridgeValue
|
|
819
886
|
account: ctx.client.account
|
|
820
887
|
};
|
|
821
|
-
|
|
888
|
+
calldata = encodeFunctionData({
|
|
889
|
+
abi: IBridgehub_default,
|
|
890
|
+
functionName: "requestL2TransactionTwoBridges",
|
|
891
|
+
args: [requestStruct]
|
|
892
|
+
});
|
|
822
893
|
} else {
|
|
823
|
-
const
|
|
894
|
+
const sim = await wrapAs4(
|
|
824
895
|
"CONTRACT",
|
|
825
896
|
OP_DEPOSITS.ethNonBase.estGas,
|
|
826
897
|
() => ctx.client.l1.simulateContract({
|
|
827
898
|
address: ctx.bridgehub,
|
|
828
899
|
abi: IBridgehub_default,
|
|
829
900
|
functionName: "requestL2TransactionTwoBridges",
|
|
830
|
-
args: [
|
|
901
|
+
args: [requestStruct],
|
|
831
902
|
value: p.amount,
|
|
832
|
-
// base ≠ ETH ⇒ msg.value == secondBridgeValue
|
|
833
903
|
account: ctx.client.account
|
|
834
904
|
}),
|
|
835
905
|
{
|
|
@@ -837,8 +907,33 @@ function routeEthNonBase() {
|
|
|
837
907
|
message: "Failed to simulate Bridgehub two-bridges request."
|
|
838
908
|
}
|
|
839
909
|
);
|
|
840
|
-
|
|
841
|
-
|
|
910
|
+
calldata = encodeFunctionData({
|
|
911
|
+
abi: sim.request.abi,
|
|
912
|
+
functionName: sim.request.functionName,
|
|
913
|
+
args: sim.request.args
|
|
914
|
+
});
|
|
915
|
+
bridgeTx = { ...sim.request };
|
|
916
|
+
}
|
|
917
|
+
const l1TxCandidate = {
|
|
918
|
+
to: ctx.bridgehub,
|
|
919
|
+
data: calldata,
|
|
920
|
+
value: p.amount,
|
|
921
|
+
from: ctx.sender,
|
|
922
|
+
...ctx.gasOverrides
|
|
923
|
+
};
|
|
924
|
+
const l1Gas = await quoteL1Gas2({
|
|
925
|
+
ctx,
|
|
926
|
+
tx: l1TxCandidate,
|
|
927
|
+
overrides: ctx.gasOverrides,
|
|
928
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
929
|
+
});
|
|
930
|
+
if (l1Gas) {
|
|
931
|
+
bridgeTx = {
|
|
932
|
+
...bridgeTx,
|
|
933
|
+
gas: l1Gas.gasLimit,
|
|
934
|
+
maxFeePerGas: l1Gas.maxFeePerGas,
|
|
935
|
+
maxPriorityFeePerGas: l1Gas.maxPriorityFeePerGas
|
|
936
|
+
};
|
|
842
937
|
}
|
|
843
938
|
steps.push({
|
|
844
939
|
key: "bridgehub:two-bridges:eth-nonbase",
|
|
@@ -846,48 +941,38 @@ function routeEthNonBase() {
|
|
|
846
941
|
description: "Bridge ETH (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
|
|
847
942
|
tx: bridgeTx
|
|
848
943
|
});
|
|
944
|
+
const fees = buildFeeBreakdown({
|
|
945
|
+
feeToken: baseToken,
|
|
946
|
+
l1Gas,
|
|
947
|
+
l2Gas,
|
|
948
|
+
l2BaseCost,
|
|
949
|
+
operatorTip: ctx.operatorTip,
|
|
950
|
+
mintValue
|
|
951
|
+
});
|
|
849
952
|
return {
|
|
850
953
|
steps,
|
|
851
954
|
approvals,
|
|
852
|
-
|
|
955
|
+
fees
|
|
853
956
|
};
|
|
854
957
|
}
|
|
855
958
|
};
|
|
856
959
|
}
|
|
857
|
-
|
|
858
|
-
// src/adapters/viem/resources/deposits/routes/erc20-base.ts
|
|
859
|
-
var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
|
|
860
|
-
var BASE_COST_BUFFER_BPS3 = 100n;
|
|
861
|
-
var BPS3 = 10000n;
|
|
862
|
-
var withBuffer3 = (x) => x * (BPS3 + BASE_COST_BUFFER_BPS3) / BPS3;
|
|
960
|
+
var { wrapAs: wrapAs5 } = createErrorHandlers("deposits");
|
|
863
961
|
function routeErc20Base() {
|
|
864
962
|
return {
|
|
865
963
|
async preflight(p, ctx) {
|
|
866
|
-
await
|
|
964
|
+
await wrapAs5(
|
|
867
965
|
"VALIDATION",
|
|
868
966
|
OP_DEPOSITS.base.assertErc20Asset,
|
|
869
967
|
() => {
|
|
870
|
-
if (isETH(p.token)) {
|
|
968
|
+
if (ctx.resolvedToken?.kind === "eth" || isETH(p.token)) {
|
|
871
969
|
throw new Error("erc20-base route requires an ERC-20 token (not ETH).");
|
|
872
970
|
}
|
|
873
971
|
},
|
|
874
972
|
{ ctx: { token: p.token } }
|
|
875
973
|
);
|
|
876
|
-
const baseToken = await
|
|
877
|
-
|
|
878
|
-
OP_DEPOSITS.base.baseToken,
|
|
879
|
-
() => ctx.client.l1.readContract({
|
|
880
|
-
address: ctx.bridgehub,
|
|
881
|
-
abi: IBridgehub_default,
|
|
882
|
-
functionName: "baseToken",
|
|
883
|
-
args: [ctx.chainIdL2]
|
|
884
|
-
}),
|
|
885
|
-
{
|
|
886
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
887
|
-
message: "Failed to read base token."
|
|
888
|
-
}
|
|
889
|
-
);
|
|
890
|
-
await wrapAs4(
|
|
974
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
975
|
+
await wrapAs5(
|
|
891
976
|
"VALIDATION",
|
|
892
977
|
OP_DEPOSITS.base.assertMatchesBase,
|
|
893
978
|
() => {
|
|
@@ -897,45 +982,27 @@ function routeErc20Base() {
|
|
|
897
982
|
},
|
|
898
983
|
{ ctx: { baseToken, provided: p.token, chainIdL2: ctx.chainIdL2 } }
|
|
899
984
|
);
|
|
900
|
-
return;
|
|
901
985
|
},
|
|
902
986
|
async build(p, ctx) {
|
|
903
|
-
const
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
"
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
OP_DEPOSITS.base.baseCost,
|
|
923
|
-
() => ctx.client.l1.readContract({
|
|
924
|
-
address: ctx.bridgehub,
|
|
925
|
-
abi: IBridgehub_default,
|
|
926
|
-
functionName: "l2TransactionBaseCost",
|
|
927
|
-
args: [ctx.chainIdL2, gasPriceForBaseCost, ctx.l2GasLimit, ctx.gasPerPubdata]
|
|
928
|
-
}),
|
|
929
|
-
{
|
|
930
|
-
ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
|
|
931
|
-
message: "Could not fetch L2 base cost from Bridgehub."
|
|
932
|
-
}
|
|
933
|
-
);
|
|
934
|
-
const baseCost = rawBaseCost;
|
|
935
|
-
const l2Value = p.amount;
|
|
936
|
-
const rawMintValue = baseCost + ctx.operatorTip + l2Value;
|
|
937
|
-
const mintValue = withBuffer3(rawMintValue);
|
|
938
|
-
const allowance = await wrapAs4(
|
|
987
|
+
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
988
|
+
const l2TxModel = {
|
|
989
|
+
to: p.to ?? ctx.sender,
|
|
990
|
+
from: ctx.sender,
|
|
991
|
+
data: "0x",
|
|
992
|
+
value: 0n
|
|
993
|
+
};
|
|
994
|
+
const l2Gas = await quoteL2Gas3({
|
|
995
|
+
ctx,
|
|
996
|
+
route: "erc20-base",
|
|
997
|
+
l2TxForModeling: l2TxModel,
|
|
998
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
999
|
+
});
|
|
1000
|
+
if (!l2Gas) throw new Error("Failed to estimate L2 gas parameters.");
|
|
1001
|
+
const l2BaseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2Gas.gasLimit });
|
|
1002
|
+
const mintValue = l2BaseCost + ctx.operatorTip + p.amount;
|
|
1003
|
+
const approvals = [];
|
|
1004
|
+
const steps = [];
|
|
1005
|
+
const allowance = await wrapAs5(
|
|
939
1006
|
"CONTRACT",
|
|
940
1007
|
OP_DEPOSITS.base.allowance,
|
|
941
1008
|
() => ctx.client.l1.readContract({
|
|
@@ -949,11 +1016,9 @@ function routeErc20Base() {
|
|
|
949
1016
|
message: "Failed to read base-token allowance."
|
|
950
1017
|
}
|
|
951
1018
|
);
|
|
952
|
-
const approvals = [];
|
|
953
|
-
const steps = [];
|
|
954
1019
|
const needsApprove = allowance < mintValue;
|
|
955
1020
|
if (needsApprove) {
|
|
956
|
-
const approveSim = await
|
|
1021
|
+
const approveSim = await wrapAs5(
|
|
957
1022
|
"CONTRACT",
|
|
958
1023
|
OP_DEPOSITS.base.estGas,
|
|
959
1024
|
() => ctx.client.l1.simulateContract({
|
|
@@ -973,20 +1038,20 @@ function routeErc20Base() {
|
|
|
973
1038
|
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
974
1039
|
kind: "approve",
|
|
975
1040
|
description: "Approve base token for mintValue",
|
|
976
|
-
tx: { ...approveSim.request
|
|
1041
|
+
tx: { ...approveSim.request }
|
|
977
1042
|
});
|
|
978
1043
|
}
|
|
979
1044
|
const req = buildDirectRequestStruct({
|
|
980
1045
|
chainId: ctx.chainIdL2,
|
|
981
1046
|
mintValue,
|
|
982
|
-
l2GasLimit:
|
|
1047
|
+
l2GasLimit: l2Gas.gasLimit,
|
|
983
1048
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
984
1049
|
refundRecipient: ctx.refundRecipient,
|
|
985
1050
|
l2Contract: p.to ?? ctx.sender,
|
|
986
|
-
l2Value
|
|
1051
|
+
l2Value: p.amount
|
|
987
1052
|
});
|
|
988
1053
|
let bridgeTx;
|
|
989
|
-
let
|
|
1054
|
+
let calldata;
|
|
990
1055
|
if (needsApprove) {
|
|
991
1056
|
bridgeTx = {
|
|
992
1057
|
address: ctx.bridgehub,
|
|
@@ -994,13 +1059,16 @@ function routeErc20Base() {
|
|
|
994
1059
|
functionName: "requestL2TransactionDirect",
|
|
995
1060
|
args: [req],
|
|
996
1061
|
value: 0n,
|
|
997
|
-
// base is ERC-20 ⇒ msg.value MUST be 0
|
|
998
|
-
account: ctx.client.account
|
|
999
|
-
...txFeeOverrides
|
|
1062
|
+
// base token is ERC-20 ⇒ msg.value MUST be 0
|
|
1063
|
+
account: ctx.client.account
|
|
1000
1064
|
};
|
|
1001
|
-
|
|
1065
|
+
calldata = encodeFunctionData({
|
|
1066
|
+
abi: IBridgehub_default,
|
|
1067
|
+
functionName: "requestL2TransactionDirect",
|
|
1068
|
+
args: [req]
|
|
1069
|
+
});
|
|
1002
1070
|
} else {
|
|
1003
|
-
const sim = await
|
|
1071
|
+
const sim = await wrapAs5(
|
|
1004
1072
|
"RPC",
|
|
1005
1073
|
OP_DEPOSITS.base.estGas,
|
|
1006
1074
|
() => ctx.client.l1.simulateContract({
|
|
@@ -1016,8 +1084,33 @@ function routeErc20Base() {
|
|
|
1016
1084
|
message: "Failed to simulate Bridgehub.requestL2TransactionDirect."
|
|
1017
1085
|
}
|
|
1018
1086
|
);
|
|
1019
|
-
|
|
1020
|
-
|
|
1087
|
+
calldata = encodeFunctionData({
|
|
1088
|
+
abi: sim.request.abi,
|
|
1089
|
+
functionName: sim.request.functionName,
|
|
1090
|
+
args: sim.request.args
|
|
1091
|
+
});
|
|
1092
|
+
bridgeTx = { ...sim.request };
|
|
1093
|
+
}
|
|
1094
|
+
const l1TxCandidate = {
|
|
1095
|
+
to: ctx.bridgehub,
|
|
1096
|
+
data: calldata,
|
|
1097
|
+
value: 0n,
|
|
1098
|
+
from: ctx.sender,
|
|
1099
|
+
...ctx.gasOverrides
|
|
1100
|
+
};
|
|
1101
|
+
const l1Gas = await quoteL1Gas2({
|
|
1102
|
+
ctx,
|
|
1103
|
+
tx: l1TxCandidate,
|
|
1104
|
+
overrides: ctx.gasOverrides,
|
|
1105
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
1106
|
+
});
|
|
1107
|
+
if (l1Gas) {
|
|
1108
|
+
bridgeTx = {
|
|
1109
|
+
...bridgeTx,
|
|
1110
|
+
gas: l1Gas.gasLimit,
|
|
1111
|
+
maxFeePerGas: l1Gas.maxFeePerGas,
|
|
1112
|
+
maxPriorityFeePerGas: l1Gas.maxPriorityFeePerGas
|
|
1113
|
+
};
|
|
1021
1114
|
}
|
|
1022
1115
|
steps.push({
|
|
1023
1116
|
key: "bridgehub:direct:erc20-base",
|
|
@@ -1025,10 +1118,18 @@ function routeErc20Base() {
|
|
|
1025
1118
|
description: "Bridge base ERC-20 via Bridgehub.requestL2TransactionDirect",
|
|
1026
1119
|
tx: bridgeTx
|
|
1027
1120
|
});
|
|
1121
|
+
const fees = buildFeeBreakdown({
|
|
1122
|
+
feeToken: baseToken,
|
|
1123
|
+
l1Gas,
|
|
1124
|
+
l2Gas,
|
|
1125
|
+
l2BaseCost,
|
|
1126
|
+
operatorTip: ctx.operatorTip,
|
|
1127
|
+
mintValue
|
|
1128
|
+
});
|
|
1028
1129
|
return {
|
|
1029
1130
|
steps,
|
|
1030
1131
|
approvals,
|
|
1031
|
-
|
|
1132
|
+
fees
|
|
1032
1133
|
};
|
|
1033
1134
|
}
|
|
1034
1135
|
};
|
|
@@ -1108,6 +1209,260 @@ async function waitForL2ExecutionFromL1Tx(l1, l2, l1TxHash) {
|
|
|
1108
1209
|
}
|
|
1109
1210
|
return { l2Receipt, l2TxHash };
|
|
1110
1211
|
}
|
|
1212
|
+
var { wrapAs: wrapAs6 } = createErrorHandlers("tokens");
|
|
1213
|
+
var ntvCodec = createNTVCodec({
|
|
1214
|
+
encode: (types, values) => encodeAbiParameters(
|
|
1215
|
+
types.map((t, i) => ({ type: t, name: `arg${i}` })),
|
|
1216
|
+
values
|
|
1217
|
+
),
|
|
1218
|
+
keccak256: (data) => keccak256(data)
|
|
1219
|
+
});
|
|
1220
|
+
function createTokensResource(client) {
|
|
1221
|
+
let l2NtvL1ChainIdPromise = null;
|
|
1222
|
+
let baseTokenAssetIdPromise = null;
|
|
1223
|
+
let wethL1Promise = null;
|
|
1224
|
+
let wethL2Promise = null;
|
|
1225
|
+
async function getL1ChainId() {
|
|
1226
|
+
if (!l2NtvL1ChainIdPromise) {
|
|
1227
|
+
l2NtvL1ChainIdPromise = wrapAs6("INTERNAL", "getL1ChainId", async () => {
|
|
1228
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1229
|
+
return await l2NativeTokenVault.read.L1_CHAIN_ID();
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
return l2NtvL1ChainIdPromise;
|
|
1233
|
+
}
|
|
1234
|
+
async function getBaseTokenAssetId() {
|
|
1235
|
+
if (!baseTokenAssetIdPromise) {
|
|
1236
|
+
baseTokenAssetIdPromise = wrapAs6("INTERNAL", "baseTokenAssetId", async () => {
|
|
1237
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1238
|
+
const assetId = await l2NativeTokenVault.read.BASE_TOKEN_ASSET_ID();
|
|
1239
|
+
return assetId;
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
return baseTokenAssetIdPromise;
|
|
1243
|
+
}
|
|
1244
|
+
async function getWethL1() {
|
|
1245
|
+
if (!wethL1Promise) {
|
|
1246
|
+
wethL1Promise = wrapAs6("INTERNAL", "wethL1", async () => {
|
|
1247
|
+
const { l1NativeTokenVault } = await client.contracts();
|
|
1248
|
+
const weth = await l1NativeTokenVault.read.WETH_TOKEN();
|
|
1249
|
+
return weth;
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
return wethL1Promise;
|
|
1253
|
+
}
|
|
1254
|
+
async function getWethL2() {
|
|
1255
|
+
if (!wethL2Promise) {
|
|
1256
|
+
wethL2Promise = wrapAs6("INTERNAL", "wethL2", async () => {
|
|
1257
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1258
|
+
const weth = await l2NativeTokenVault.read.WETH_TOKEN();
|
|
1259
|
+
return weth;
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
return wethL2Promise;
|
|
1263
|
+
}
|
|
1264
|
+
async function toL2Address(l1Token) {
|
|
1265
|
+
return wrapAs6("CONTRACT", "tokens.toL2Address", async () => {
|
|
1266
|
+
const normalized = normalizeL1Token(l1Token);
|
|
1267
|
+
const chainId = BigInt(await client.l2.getChainId());
|
|
1268
|
+
const baseToken = await client.baseToken(chainId);
|
|
1269
|
+
if (isAddressEq(normalized, baseToken)) {
|
|
1270
|
+
return L2_BASE_TOKEN_ADDRESS;
|
|
1271
|
+
}
|
|
1272
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1273
|
+
const l2Token = await l2NativeTokenVault.read.l2TokenAddress([normalized]);
|
|
1274
|
+
return l2Token;
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
async function toL1Address(l2Token) {
|
|
1278
|
+
return wrapAs6("CONTRACT", "tokens.toL1Address", async () => {
|
|
1279
|
+
if (isAddressEq(l2Token, ETH_ADDRESS)) return ETH_ADDRESS;
|
|
1280
|
+
if (isAddressEq(l2Token, L2_BASE_TOKEN_ADDRESS)) {
|
|
1281
|
+
const chainId = BigInt(await client.l2.getChainId());
|
|
1282
|
+
return await client.baseToken(chainId);
|
|
1283
|
+
}
|
|
1284
|
+
const { l2AssetRouter } = await client.contracts();
|
|
1285
|
+
const l1Token = await l2AssetRouter.read.l1TokenAddress([l2Token]);
|
|
1286
|
+
return l1Token;
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
async function assetIdOfL1(l1Token) {
|
|
1290
|
+
return wrapAs6("CONTRACT", "tokens.assetIdOfL1", async () => {
|
|
1291
|
+
const normalized = normalizeL1Token(l1Token);
|
|
1292
|
+
const { l1NativeTokenVault } = await client.contracts();
|
|
1293
|
+
return await l1NativeTokenVault.read.assetId([normalized]);
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
async function assetIdOfL2(l2Token) {
|
|
1297
|
+
return wrapAs6("CONTRACT", "tokens.assetIdOfL2", async () => {
|
|
1298
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1299
|
+
return await l2NativeTokenVault.read.assetId([l2Token]);
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
async function l2TokenFromAssetId(assetId) {
|
|
1303
|
+
return wrapAs6("CONTRACT", "tokens.l2TokenFromAssetId", async () => {
|
|
1304
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1305
|
+
return await l2NativeTokenVault.read.tokenAddress([assetId]);
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
async function l1TokenFromAssetId(assetId) {
|
|
1309
|
+
return wrapAs6("CONTRACT", "tokens.l1TokenFromAssetId", async () => {
|
|
1310
|
+
const { l1NativeTokenVault } = await client.contracts();
|
|
1311
|
+
return await l1NativeTokenVault.read.tokenAddress([assetId]);
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
async function originChainId(assetId) {
|
|
1315
|
+
return wrapAs6("CONTRACT", "tokens.originChainId", async () => {
|
|
1316
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1317
|
+
return await l2NativeTokenVault.read.originChainId([assetId]);
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
async function baseTokenAssetId() {
|
|
1321
|
+
return getBaseTokenAssetId();
|
|
1322
|
+
}
|
|
1323
|
+
async function isChainEthBased() {
|
|
1324
|
+
return wrapAs6("CONTRACT", "tokens.isChainEthBased", async () => {
|
|
1325
|
+
const baseAssetId = await getBaseTokenAssetId();
|
|
1326
|
+
const l1ChainId = await getL1ChainId();
|
|
1327
|
+
const ethAssetId = ntvCodec.encodeAssetId(
|
|
1328
|
+
l1ChainId,
|
|
1329
|
+
L2_NATIVE_TOKEN_VAULT_ADDRESS,
|
|
1330
|
+
ETH_ADDRESS
|
|
1331
|
+
);
|
|
1332
|
+
return hexEq(baseAssetId, ethAssetId);
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
async function wethL1() {
|
|
1336
|
+
return getWethL1();
|
|
1337
|
+
}
|
|
1338
|
+
async function wethL2() {
|
|
1339
|
+
return getWethL2();
|
|
1340
|
+
}
|
|
1341
|
+
async function computeL2BridgedAddress(args) {
|
|
1342
|
+
return wrapAs6("CONTRACT", "tokens.computeL2BridgedAddress", async () => {
|
|
1343
|
+
const normalized = normalizeL1Token(args.l1Token);
|
|
1344
|
+
const { l2NativeTokenVault } = await client.contracts();
|
|
1345
|
+
const predicted = await l2NativeTokenVault.read.calculateCreate2TokenAddress([
|
|
1346
|
+
args.originChainId,
|
|
1347
|
+
normalized
|
|
1348
|
+
]);
|
|
1349
|
+
return predicted;
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
async function resolve(ref, opts) {
|
|
1353
|
+
return wrapAs6("CONTRACT", "tokens.resolve", async () => {
|
|
1354
|
+
let chain;
|
|
1355
|
+
let address;
|
|
1356
|
+
if (typeof ref === "string") {
|
|
1357
|
+
chain = opts?.chain ?? "l1";
|
|
1358
|
+
address = ref;
|
|
1359
|
+
} else {
|
|
1360
|
+
chain = ref.chain;
|
|
1361
|
+
address = ref.address;
|
|
1362
|
+
}
|
|
1363
|
+
let l1;
|
|
1364
|
+
let l2;
|
|
1365
|
+
if (chain === "l1") {
|
|
1366
|
+
l1 = normalizeL1Token(address);
|
|
1367
|
+
l2 = await toL2Address(address);
|
|
1368
|
+
} else {
|
|
1369
|
+
l2 = address;
|
|
1370
|
+
l1 = await toL1Address(address);
|
|
1371
|
+
}
|
|
1372
|
+
const assetId = await assetIdOfL1(l1);
|
|
1373
|
+
const originChainIdVal = await originChainId(assetId);
|
|
1374
|
+
const [baseAssetId, wethL1Addr, wethL2Addr, ethBased] = await Promise.all([
|
|
1375
|
+
baseTokenAssetId(),
|
|
1376
|
+
wethL1(),
|
|
1377
|
+
wethL2(),
|
|
1378
|
+
isChainEthBased()
|
|
1379
|
+
]);
|
|
1380
|
+
let kind;
|
|
1381
|
+
if (isAddressEq(l1, ETH_ADDRESS)) {
|
|
1382
|
+
kind = "eth";
|
|
1383
|
+
} else if (hexEq(assetId, baseAssetId)) {
|
|
1384
|
+
kind = "base";
|
|
1385
|
+
} else {
|
|
1386
|
+
kind = "erc20";
|
|
1387
|
+
}
|
|
1388
|
+
return {
|
|
1389
|
+
kind,
|
|
1390
|
+
l1,
|
|
1391
|
+
l2,
|
|
1392
|
+
assetId,
|
|
1393
|
+
originChainId: originChainIdVal,
|
|
1394
|
+
isChainEthBased: ethBased,
|
|
1395
|
+
baseTokenAssetId: baseAssetId,
|
|
1396
|
+
wethL1: wethL1Addr,
|
|
1397
|
+
wethL2: wethL2Addr
|
|
1398
|
+
};
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
return {
|
|
1402
|
+
resolve,
|
|
1403
|
+
toL2Address,
|
|
1404
|
+
toL1Address,
|
|
1405
|
+
assetIdOfL1,
|
|
1406
|
+
assetIdOfL2,
|
|
1407
|
+
l2TokenFromAssetId,
|
|
1408
|
+
l1TokenFromAssetId,
|
|
1409
|
+
originChainId,
|
|
1410
|
+
baseTokenAssetId,
|
|
1411
|
+
isChainEthBased,
|
|
1412
|
+
wethL1,
|
|
1413
|
+
wethL2,
|
|
1414
|
+
computeL2BridgedAddress
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// src/adapters/viem/resources/contracts/contracts.ts
|
|
1419
|
+
function createContractsResource(client) {
|
|
1420
|
+
async function addresses() {
|
|
1421
|
+
return client.ensureAddresses();
|
|
1422
|
+
}
|
|
1423
|
+
async function instances() {
|
|
1424
|
+
return client.contracts();
|
|
1425
|
+
}
|
|
1426
|
+
async function bridgehub() {
|
|
1427
|
+
const { bridgehub: bridgehub2 } = await instances();
|
|
1428
|
+
return bridgehub2;
|
|
1429
|
+
}
|
|
1430
|
+
async function l1AssetRouter() {
|
|
1431
|
+
const { l1AssetRouter: l1AssetRouter2 } = await instances();
|
|
1432
|
+
return l1AssetRouter2;
|
|
1433
|
+
}
|
|
1434
|
+
async function l1NativeTokenVault() {
|
|
1435
|
+
const { l1NativeTokenVault: l1NativeTokenVault2 } = await instances();
|
|
1436
|
+
return l1NativeTokenVault2;
|
|
1437
|
+
}
|
|
1438
|
+
async function l1Nullifier() {
|
|
1439
|
+
const { l1Nullifier: l1Nullifier2 } = await instances();
|
|
1440
|
+
return l1Nullifier2;
|
|
1441
|
+
}
|
|
1442
|
+
async function l2AssetRouter() {
|
|
1443
|
+
const { l2AssetRouter: l2AssetRouter2 } = await instances();
|
|
1444
|
+
return l2AssetRouter2;
|
|
1445
|
+
}
|
|
1446
|
+
async function l2NativeTokenVault() {
|
|
1447
|
+
const { l2NativeTokenVault: l2NativeTokenVault2 } = await instances();
|
|
1448
|
+
return l2NativeTokenVault2;
|
|
1449
|
+
}
|
|
1450
|
+
async function l2BaseTokenSystem() {
|
|
1451
|
+
const { l2BaseTokenSystem: l2BaseTokenSystem2 } = await instances();
|
|
1452
|
+
return l2BaseTokenSystem2;
|
|
1453
|
+
}
|
|
1454
|
+
return {
|
|
1455
|
+
addresses,
|
|
1456
|
+
instances,
|
|
1457
|
+
bridgehub,
|
|
1458
|
+
l1AssetRouter,
|
|
1459
|
+
l1NativeTokenVault,
|
|
1460
|
+
l1Nullifier,
|
|
1461
|
+
l2AssetRouter,
|
|
1462
|
+
l2NativeTokenVault,
|
|
1463
|
+
l2BaseTokenSystem
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1111
1466
|
|
|
1112
1467
|
// src/adapters/viem/resources/deposits/index.ts
|
|
1113
1468
|
var { wrap, toResult } = createErrorHandlers("deposits");
|
|
@@ -1117,37 +1472,26 @@ var ROUTES = {
|
|
|
1117
1472
|
"erc20-nonbase": routeErc20NonBase(),
|
|
1118
1473
|
"erc20-base": routeErc20Base()
|
|
1119
1474
|
};
|
|
1120
|
-
function createDepositsResource(client) {
|
|
1475
|
+
function createDepositsResource(client, tokens, contracts) {
|
|
1476
|
+
const tokensResource = tokens ?? createTokensResource(client);
|
|
1477
|
+
const contractsResource = contracts ?? createContractsResource(client);
|
|
1121
1478
|
async function buildPlan(p) {
|
|
1122
|
-
const ctx = await commonCtx(p, client);
|
|
1479
|
+
const ctx = await commonCtx(p, client, tokensResource, contractsResource);
|
|
1123
1480
|
const route = ctx.route;
|
|
1124
1481
|
await ROUTES[route].preflight?.(p, ctx);
|
|
1125
|
-
const { steps, approvals,
|
|
1126
|
-
const { baseCost, mintValue } = quoteExtras;
|
|
1127
|
-
const fallbackGasLimit = quoteExtras.l1GasLimit;
|
|
1128
|
-
const resolveGasLimit = () => {
|
|
1129
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
1130
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
1131
|
-
const candidate = steps[i].tx.gas;
|
|
1132
|
-
if (candidate != null) return candidate;
|
|
1133
|
-
}
|
|
1134
|
-
if (fallbackGasLimit != null) return fallbackGasLimit;
|
|
1135
|
-
return ctx.l2GasLimit;
|
|
1136
|
-
};
|
|
1137
|
-
const gasLimit = resolveGasLimit();
|
|
1482
|
+
const { steps, approvals, fees } = await ROUTES[route].build(p, ctx);
|
|
1138
1483
|
return {
|
|
1139
1484
|
route: ctx.route,
|
|
1140
1485
|
summary: {
|
|
1141
1486
|
route: ctx.route,
|
|
1142
1487
|
approvalsNeeded: approvals,
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
fees
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
}
|
|
1488
|
+
amounts: {
|
|
1489
|
+
transfer: { token: p.token, amount: p.amount }
|
|
1490
|
+
},
|
|
1491
|
+
fees,
|
|
1492
|
+
// Legacy fields (maintained for backward compatibility)
|
|
1493
|
+
baseCost: fees.l2?.baseCost,
|
|
1494
|
+
mintValue: fees.mintValue
|
|
1151
1495
|
},
|
|
1152
1496
|
steps
|
|
1153
1497
|
};
|
|
@@ -1222,7 +1566,7 @@ function createDepositsResource(client) {
|
|
|
1222
1566
|
step.tx.gas = overrides.gasLimit;
|
|
1223
1567
|
}
|
|
1224
1568
|
}
|
|
1225
|
-
if (
|
|
1569
|
+
if (!p.l1TxOverrides?.gasLimit) {
|
|
1226
1570
|
try {
|
|
1227
1571
|
const feePart = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
|
|
1228
1572
|
maxFeePerGas: step.tx.maxFeePerGas,
|
|
@@ -1436,32 +1780,8 @@ function createDepositsResource(client) {
|
|
|
1436
1780
|
return { quote, tryQuote, prepare, tryPrepare, create, tryCreate, status, wait, tryWait };
|
|
1437
1781
|
}
|
|
1438
1782
|
|
|
1439
|
-
// src/adapters/viem/resources/token-info.ts
|
|
1440
|
-
async function ntvBaseAssetId(l2, ntv) {
|
|
1441
|
-
return l2.readContract({
|
|
1442
|
-
address: ntv,
|
|
1443
|
-
abi: L2NativeTokenVault_default,
|
|
1444
|
-
functionName: "BASE_TOKEN_ASSET_ID"
|
|
1445
|
-
});
|
|
1446
|
-
}
|
|
1447
|
-
async function ntvL1ChainId(l2, ntv) {
|
|
1448
|
-
return l2.readContract({
|
|
1449
|
-
address: ntv,
|
|
1450
|
-
abi: L2NativeTokenVault_default,
|
|
1451
|
-
functionName: "L1_CHAIN_ID"
|
|
1452
|
-
});
|
|
1453
|
-
}
|
|
1454
|
-
async function isEthBasedChain(l2, ntv) {
|
|
1455
|
-
const [baseAssetId, l1ChainId] = await Promise.all([
|
|
1456
|
-
ntvBaseAssetId(l2, ntv),
|
|
1457
|
-
ntvL1ChainId(l2, ntv)
|
|
1458
|
-
]);
|
|
1459
|
-
const ethAssetId = encodeNativeTokenVaultAssetId(l1ChainId, ETH_ADDRESS);
|
|
1460
|
-
return baseAssetId.toLowerCase() === ethAssetId.toLowerCase();
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
1783
|
// src/adapters/viem/resources/withdrawals/context.ts
|
|
1464
|
-
async function commonCtx2(p, client) {
|
|
1784
|
+
async function commonCtx2(p, client, tokens, contracts) {
|
|
1465
1785
|
const sender = client.account.address;
|
|
1466
1786
|
const {
|
|
1467
1787
|
bridgehub,
|
|
@@ -1470,18 +1790,20 @@ async function commonCtx2(p, client) {
|
|
|
1470
1790
|
l2AssetRouter,
|
|
1471
1791
|
l2NativeTokenVault,
|
|
1472
1792
|
l2BaseTokenSystem
|
|
1473
|
-
} = await
|
|
1793
|
+
} = await contracts.addresses();
|
|
1474
1794
|
const chainIdL2 = BigInt(await client.l2.getChainId());
|
|
1475
|
-
const
|
|
1476
|
-
const
|
|
1477
|
-
const
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
});
|
|
1481
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
1482
|
-
const gasBufferPct = 15;
|
|
1795
|
+
const resolvedToken = await tokens.resolve(p.token, { chain: "l2" });
|
|
1796
|
+
const baseTokenAssetId = resolvedToken.baseTokenAssetId;
|
|
1797
|
+
const baseTokenL1 = await tokens.l1TokenFromAssetId(baseTokenAssetId);
|
|
1798
|
+
const baseIsEth = resolvedToken.isChainEthBased;
|
|
1799
|
+
const route = pickWithdrawRoute({ token: p.token, baseIsEth });
|
|
1483
1800
|
return {
|
|
1484
1801
|
client,
|
|
1802
|
+
tokens,
|
|
1803
|
+
contracts,
|
|
1804
|
+
resolvedToken,
|
|
1805
|
+
baseTokenAssetId,
|
|
1806
|
+
baseTokenL1,
|
|
1485
1807
|
bridgehub,
|
|
1486
1808
|
chainIdL2,
|
|
1487
1809
|
sender,
|
|
@@ -1492,56 +1814,101 @@ async function commonCtx2(p, client) {
|
|
|
1492
1814
|
l2NativeTokenVault,
|
|
1493
1815
|
l2BaseTokenSystem,
|
|
1494
1816
|
baseIsEth,
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1817
|
+
gasOverrides: p.l2TxOverrides
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
// src/adapters/viem/resources/withdrawals/services/gas.ts
|
|
1822
|
+
async function quoteL2Gas4(input) {
|
|
1823
|
+
const { ctx, tx } = input;
|
|
1824
|
+
const estimator = viemToGasEstimator(ctx.client.l2);
|
|
1825
|
+
return quoteL2Gas2({
|
|
1826
|
+
estimator,
|
|
1827
|
+
tx: toCoreTx(tx),
|
|
1828
|
+
overrides: ctx.gasOverrides
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
// src/adapters/viem/resources/withdrawals/services/fee.ts
|
|
1833
|
+
function buildFeeBreakdown2(p) {
|
|
1834
|
+
const l2Total = p.l2Gas?.maxCost ?? 0n;
|
|
1835
|
+
const l2 = {
|
|
1836
|
+
total: l2Total,
|
|
1837
|
+
gasLimit: p.l2Gas?.gasLimit ?? 0n,
|
|
1838
|
+
maxFeePerGas: p.l2Gas?.maxFeePerGas ?? 0n,
|
|
1839
|
+
maxPriorityFeePerGas: p.l2Gas?.maxPriorityFeePerGas
|
|
1840
|
+
};
|
|
1841
|
+
return {
|
|
1842
|
+
token: p.feeToken,
|
|
1843
|
+
maxTotal: l2Total,
|
|
1844
|
+
l2
|
|
1498
1845
|
};
|
|
1499
1846
|
}
|
|
1500
1847
|
|
|
1501
1848
|
// src/adapters/viem/resources/withdrawals/routes/eth.ts
|
|
1502
|
-
var { wrapAs:
|
|
1849
|
+
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
1503
1850
|
function routeEthBase() {
|
|
1504
1851
|
return {
|
|
1505
1852
|
async build(p, ctx) {
|
|
1506
|
-
const
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
account: ctx.client.account,
|
|
1518
|
-
...txFeeOverrides
|
|
1519
|
-
}),
|
|
1853
|
+
const steps = [];
|
|
1854
|
+
const data = await wrapAs7(
|
|
1855
|
+
"INTERNAL",
|
|
1856
|
+
OP_WITHDRAWALS.eth.encodeWithdraw,
|
|
1857
|
+
() => Promise.resolve(
|
|
1858
|
+
encodeFunctionData({
|
|
1859
|
+
abi: IBaseToken_default,
|
|
1860
|
+
functionName: "withdraw",
|
|
1861
|
+
args: [p.to ?? ctx.sender]
|
|
1862
|
+
})
|
|
1863
|
+
),
|
|
1520
1864
|
{
|
|
1521
|
-
ctx: { where: "
|
|
1522
|
-
message: "Failed to
|
|
1865
|
+
ctx: { where: "L2BaseToken.withdraw", to: p.to ?? ctx.sender },
|
|
1866
|
+
message: "Failed to encode ETH withdraw calldata."
|
|
1523
1867
|
}
|
|
1524
1868
|
);
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1869
|
+
const L2tx = {
|
|
1870
|
+
to: L2_BASE_TOKEN_ADDRESS,
|
|
1871
|
+
data,
|
|
1872
|
+
value: p.amount,
|
|
1873
|
+
from: ctx.sender
|
|
1874
|
+
};
|
|
1875
|
+
const l2Gas = await quoteL2Gas4({ ctx, tx: L2tx });
|
|
1876
|
+
if (l2Gas) {
|
|
1877
|
+
L2tx.gas = l2Gas.gasLimit;
|
|
1878
|
+
L2tx.maxFeePerGas = l2Gas.maxFeePerGas;
|
|
1879
|
+
L2tx.maxPriorityFeePerGas = l2Gas.maxPriorityFeePerGas;
|
|
1880
|
+
}
|
|
1881
|
+
const tx = {
|
|
1882
|
+
address: L2_BASE_TOKEN_ADDRESS,
|
|
1883
|
+
abi: IBaseToken_default,
|
|
1884
|
+
functionName: "withdraw",
|
|
1885
|
+
args: [p.to ?? ctx.sender],
|
|
1886
|
+
value: p.amount,
|
|
1887
|
+
account: ctx.client.account,
|
|
1888
|
+
...l2Gas
|
|
1889
|
+
};
|
|
1890
|
+
const fees = buildFeeBreakdown2({
|
|
1891
|
+
feeToken: L2_BASE_TOKEN_ADDRESS,
|
|
1892
|
+
l2Gas
|
|
1893
|
+
});
|
|
1894
|
+
steps.push({
|
|
1895
|
+
key: "l2-base-token:withdraw",
|
|
1896
|
+
kind: "l2-base-token:withdraw",
|
|
1897
|
+
description: "Withdraw ETH via L2 Base Token System",
|
|
1898
|
+
tx
|
|
1899
|
+
});
|
|
1900
|
+
return { steps, approvals: [], fees };
|
|
1534
1901
|
}
|
|
1535
1902
|
};
|
|
1536
1903
|
}
|
|
1537
|
-
var { wrapAs:
|
|
1904
|
+
var { wrapAs: wrapAs8 } = createErrorHandlers("withdrawals");
|
|
1538
1905
|
function routeErc20NonBase2() {
|
|
1539
1906
|
return {
|
|
1540
1907
|
// TODO: add preflight validations here
|
|
1541
1908
|
async build(p, ctx) {
|
|
1542
|
-
const
|
|
1543
|
-
const
|
|
1544
|
-
const current = await
|
|
1909
|
+
const steps = [];
|
|
1910
|
+
const approvals = [];
|
|
1911
|
+
const current = await wrapAs8(
|
|
1545
1912
|
"CONTRACT",
|
|
1546
1913
|
OP_WITHDRAWALS.erc20.allowance,
|
|
1547
1914
|
() => ctx.client.l2.readContract({
|
|
@@ -1561,12 +1928,26 @@ function routeErc20NonBase2() {
|
|
|
1561
1928
|
message: "Failed to read L2 ERC-20 allowance."
|
|
1562
1929
|
}
|
|
1563
1930
|
);
|
|
1564
|
-
|
|
1565
|
-
const steps = [];
|
|
1566
|
-
const approvals = [];
|
|
1567
|
-
if (needsApprove) {
|
|
1931
|
+
if (current < p.amount) {
|
|
1568
1932
|
approvals.push({ token: p.token, spender: ctx.l2NativeTokenVault, amount: p.amount });
|
|
1569
|
-
const
|
|
1933
|
+
const data = encodeFunctionData({
|
|
1934
|
+
abi: IERC20_default,
|
|
1935
|
+
functionName: "approve",
|
|
1936
|
+
args: [ctx.l2NativeTokenVault, p.amount]
|
|
1937
|
+
});
|
|
1938
|
+
const approveTxCandidate = {
|
|
1939
|
+
to: p.token,
|
|
1940
|
+
data,
|
|
1941
|
+
value: 0n,
|
|
1942
|
+
from: ctx.sender
|
|
1943
|
+
};
|
|
1944
|
+
const approveGas = await quoteL2Gas4({ ctx, tx: approveTxCandidate });
|
|
1945
|
+
if (approveGas) {
|
|
1946
|
+
approveTxCandidate.gas = approveGas.gasLimit;
|
|
1947
|
+
approveTxCandidate.maxFeePerGas = approveGas.maxFeePerGas;
|
|
1948
|
+
approveTxCandidate.maxPriorityFeePerGas = approveGas.maxPriorityFeePerGas;
|
|
1949
|
+
}
|
|
1950
|
+
const approveSim = await wrapAs8(
|
|
1570
1951
|
"CONTRACT",
|
|
1571
1952
|
OP_WITHDRAWALS.erc20.estGas,
|
|
1572
1953
|
() => ctx.client.l2.simulateContract({
|
|
@@ -1575,21 +1956,26 @@ function routeErc20NonBase2() {
|
|
|
1575
1956
|
functionName: "approve",
|
|
1576
1957
|
args: [ctx.l2NativeTokenVault, p.amount],
|
|
1577
1958
|
account: ctx.client.account,
|
|
1578
|
-
...
|
|
1959
|
+
...approveGas
|
|
1579
1960
|
}),
|
|
1580
1961
|
{
|
|
1581
1962
|
ctx: { where: "l2.simulateContract", to: p.token },
|
|
1582
1963
|
message: "Failed to simulate L2 ERC-20 approve."
|
|
1583
1964
|
}
|
|
1584
1965
|
);
|
|
1966
|
+
const { ...approveRequest } = approveSim.request;
|
|
1967
|
+
const approveTx = {
|
|
1968
|
+
...approveRequest
|
|
1969
|
+
};
|
|
1585
1970
|
steps.push({
|
|
1586
1971
|
key: `approve:l2:${p.token}:${ctx.l2NativeTokenVault}`,
|
|
1587
1972
|
kind: "approve:l2",
|
|
1588
1973
|
description: `Approve ${p.amount} to NativeTokenVault`,
|
|
1589
|
-
tx:
|
|
1974
|
+
tx: approveTx
|
|
1590
1975
|
});
|
|
1591
1976
|
}
|
|
1592
|
-
const
|
|
1977
|
+
const resolved = ctx.resolvedToken ?? (ctx.tokens ? await ctx.tokens.resolve(p.token, { chain: "l2" }) : void 0);
|
|
1978
|
+
const assetId = resolved?.assetId ?? (await wrapAs8(
|
|
1593
1979
|
"CONTRACT",
|
|
1594
1980
|
OP_WITHDRAWALS.erc20.ensureRegistered,
|
|
1595
1981
|
() => ctx.client.l2.simulateContract({
|
|
@@ -1603,28 +1989,44 @@ function routeErc20NonBase2() {
|
|
|
1603
1989
|
ctx: { where: "L2NativeTokenVault.ensureTokenIsRegistered", token: p.token },
|
|
1604
1990
|
message: "Failed to ensure token is registered in L2NativeTokenVault."
|
|
1605
1991
|
}
|
|
1606
|
-
);
|
|
1607
|
-
const assetId = ensure.result;
|
|
1992
|
+
)).result;
|
|
1608
1993
|
const assetData = encodeAbiParameters(
|
|
1609
1994
|
[
|
|
1610
1995
|
{ type: "uint256", name: "amount" },
|
|
1611
1996
|
{ type: "address", name: "l1Receiver" },
|
|
1612
1997
|
{ type: "address", name: "l2Token" }
|
|
1613
1998
|
],
|
|
1614
|
-
[p.amount,
|
|
1999
|
+
[p.amount, p.to ?? ctx.sender, p.token]
|
|
1615
2000
|
);
|
|
2001
|
+
const withdrawCalldata = encodeFunctionData({
|
|
2002
|
+
abi: IL2AssetRouter_default,
|
|
2003
|
+
functionName: "withdraw",
|
|
2004
|
+
args: [assetId, assetData]
|
|
2005
|
+
});
|
|
2006
|
+
const withdrawTxCandidate = {
|
|
2007
|
+
to: ctx.l2AssetRouter,
|
|
2008
|
+
data: withdrawCalldata,
|
|
2009
|
+
value: 0n,
|
|
2010
|
+
from: ctx.sender
|
|
2011
|
+
};
|
|
2012
|
+
const withdrawGas = await quoteL2Gas4({ ctx, tx: withdrawTxCandidate });
|
|
2013
|
+
if (withdrawGas) {
|
|
2014
|
+
withdrawTxCandidate.gas = withdrawGas.gasLimit;
|
|
2015
|
+
withdrawTxCandidate.maxFeePerGas = withdrawGas.maxFeePerGas;
|
|
2016
|
+
withdrawTxCandidate.maxPriorityFeePerGas = withdrawGas.maxPriorityFeePerGas;
|
|
2017
|
+
}
|
|
1616
2018
|
let withdrawTx;
|
|
1617
|
-
if (
|
|
2019
|
+
if (current < p.amount) {
|
|
1618
2020
|
withdrawTx = {
|
|
1619
2021
|
address: ctx.l2AssetRouter,
|
|
1620
2022
|
abi: IL2AssetRouter_default,
|
|
1621
2023
|
functionName: "withdraw",
|
|
1622
2024
|
args: [assetId, assetData],
|
|
1623
2025
|
account: ctx.client.account,
|
|
1624
|
-
...
|
|
2026
|
+
...withdrawGas
|
|
1625
2027
|
};
|
|
1626
2028
|
} else {
|
|
1627
|
-
const sim = await
|
|
2029
|
+
const sim = await wrapAs8(
|
|
1628
2030
|
"CONTRACT",
|
|
1629
2031
|
OP_WITHDRAWALS.erc20.estGas,
|
|
1630
2032
|
() => ctx.client.l2.simulateContract({
|
|
@@ -1633,14 +2035,18 @@ function routeErc20NonBase2() {
|
|
|
1633
2035
|
functionName: "withdraw",
|
|
1634
2036
|
args: [assetId, assetData],
|
|
1635
2037
|
account: ctx.client.account,
|
|
1636
|
-
...
|
|
2038
|
+
...withdrawGas
|
|
1637
2039
|
}),
|
|
1638
2040
|
{
|
|
1639
2041
|
ctx: { where: "l2.simulateContract", to: ctx.l2AssetRouter },
|
|
1640
2042
|
message: "Failed to simulate L2 ERC-20 withdraw."
|
|
1641
2043
|
}
|
|
1642
2044
|
);
|
|
1643
|
-
|
|
2045
|
+
const { ...withdrawRequest } = sim.request;
|
|
2046
|
+
withdrawTx = {
|
|
2047
|
+
...withdrawRequest,
|
|
2048
|
+
...withdrawGas
|
|
2049
|
+
};
|
|
1644
2050
|
}
|
|
1645
2051
|
steps.push({
|
|
1646
2052
|
key: "l2-asset-router:withdraw",
|
|
@@ -1648,63 +2054,15 @@ function routeErc20NonBase2() {
|
|
|
1648
2054
|
description: "Burn on L2 & send L2\u2192L1 message",
|
|
1649
2055
|
tx: withdrawTx
|
|
1650
2056
|
});
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
// src/adapters/viem/resources/withdrawals/routes/eth-nonbase.ts
|
|
1657
|
-
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
1658
|
-
function routeEthNonBase2() {
|
|
1659
|
-
return {
|
|
1660
|
-
async preflight(p, ctx) {
|
|
1661
|
-
await wrapAs7(
|
|
1662
|
-
"VALIDATION",
|
|
1663
|
-
OP_WITHDRAWALS.ethNonBase.assertNonEthBase,
|
|
1664
|
-
() => {
|
|
1665
|
-
if (p.token.toLowerCase() !== L2_BASE_TOKEN_ADDRESS.toLowerCase()) {
|
|
1666
|
-
throw new Error("eth-nonbase route requires the L2 base-token alias (0x\u2026800A).");
|
|
1667
|
-
}
|
|
1668
|
-
if (ctx.baseIsEth) {
|
|
1669
|
-
throw new Error("eth-nonbase route requires chain base \u2260 ETH.");
|
|
1670
|
-
}
|
|
1671
|
-
},
|
|
1672
|
-
{ ctx: { token: p.token, baseIsEth: ctx.baseIsEth } }
|
|
1673
|
-
);
|
|
1674
|
-
},
|
|
1675
|
-
async build(p, ctx) {
|
|
1676
|
-
const toL1 = p.to ?? ctx.sender;
|
|
1677
|
-
const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
|
|
1678
|
-
const sim = await wrapAs7(
|
|
1679
|
-
"CONTRACT",
|
|
1680
|
-
OP_WITHDRAWALS.ethNonBase.estGas,
|
|
1681
|
-
() => ctx.client.l2.simulateContract({
|
|
1682
|
-
address: L2_BASE_TOKEN_ADDRESS,
|
|
1683
|
-
abi: IBaseToken_default,
|
|
1684
|
-
functionName: "withdraw",
|
|
1685
|
-
args: [toL1],
|
|
1686
|
-
value: p.amount,
|
|
1687
|
-
account: ctx.client.account,
|
|
1688
|
-
...txFeeOverrides
|
|
1689
|
-
}),
|
|
1690
|
-
{
|
|
1691
|
-
ctx: { where: "l2.simulateContract", to: L2_BASE_TOKEN_ADDRESS },
|
|
1692
|
-
message: "Failed to simulate L2 base-token withdraw."
|
|
1693
|
-
}
|
|
1694
|
-
);
|
|
1695
|
-
const steps = [
|
|
1696
|
-
{
|
|
1697
|
-
key: "l2-base-token:withdraw",
|
|
1698
|
-
kind: "l2-base-token:withdraw",
|
|
1699
|
-
description: "Withdraw base token via L2 Base Token System (base \u2260 ETH)",
|
|
1700
|
-
tx: { ...sim.request, ...txFeeOverrides }
|
|
1701
|
-
}
|
|
1702
|
-
];
|
|
1703
|
-
return { steps, approvals: [], quoteExtras: {} };
|
|
2057
|
+
const fees = buildFeeBreakdown2({
|
|
2058
|
+
feeToken: ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2),
|
|
2059
|
+
l2Gas: withdrawGas
|
|
2060
|
+
});
|
|
2061
|
+
return { steps, approvals, fees };
|
|
1704
2062
|
}
|
|
1705
2063
|
};
|
|
1706
2064
|
}
|
|
1707
|
-
var { wrapAs:
|
|
2065
|
+
var { wrapAs: wrapAs9 } = createErrorHandlers("withdrawals");
|
|
1708
2066
|
var IL1NullifierMini = [
|
|
1709
2067
|
{
|
|
1710
2068
|
type: "function",
|
|
@@ -1721,7 +2079,7 @@ var IL1NullifierMini = [
|
|
|
1721
2079
|
function createFinalizationServices(client) {
|
|
1722
2080
|
return {
|
|
1723
2081
|
async fetchFinalizeDepositParams(l2TxHash) {
|
|
1724
|
-
const parsed = await
|
|
2082
|
+
const parsed = await wrapAs9(
|
|
1725
2083
|
"RPC",
|
|
1726
2084
|
OP_WITHDRAWALS.finalize.fetchParams.receipt,
|
|
1727
2085
|
() => client.zks.getReceiptWithL2ToL1(l2TxHash),
|
|
@@ -1738,7 +2096,7 @@ function createFinalizationServices(client) {
|
|
|
1738
2096
|
context: { l2TxHash }
|
|
1739
2097
|
});
|
|
1740
2098
|
}
|
|
1741
|
-
const ev = await
|
|
2099
|
+
const ev = await wrapAs9(
|
|
1742
2100
|
"INTERNAL",
|
|
1743
2101
|
OP_WITHDRAWALS.finalize.fetchParams.findMessage,
|
|
1744
2102
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
@@ -1748,7 +2106,7 @@ function createFinalizationServices(client) {
|
|
|
1748
2106
|
message: "Failed to locate L1MessageSent event in L2 receipt."
|
|
1749
2107
|
}
|
|
1750
2108
|
);
|
|
1751
|
-
const message = await
|
|
2109
|
+
const message = await wrapAs9(
|
|
1752
2110
|
"INTERNAL",
|
|
1753
2111
|
OP_WITHDRAWALS.finalize.fetchParams.decodeMessage,
|
|
1754
2112
|
() => {
|
|
@@ -1760,7 +2118,7 @@ function createFinalizationServices(client) {
|
|
|
1760
2118
|
message: "Failed to decode withdrawal message."
|
|
1761
2119
|
}
|
|
1762
2120
|
);
|
|
1763
|
-
const raw = await
|
|
2121
|
+
const raw = await wrapAs9(
|
|
1764
2122
|
"RPC",
|
|
1765
2123
|
OP_WITHDRAWALS.finalize.fetchParams.rawReceipt,
|
|
1766
2124
|
() => client.zks.getReceiptWithL2ToL1(l2TxHash),
|
|
@@ -1777,7 +2135,7 @@ function createFinalizationServices(client) {
|
|
|
1777
2135
|
context: { l2TxHash }
|
|
1778
2136
|
});
|
|
1779
2137
|
}
|
|
1780
|
-
const idx = await
|
|
2138
|
+
const idx = await wrapAs9(
|
|
1781
2139
|
"INTERNAL",
|
|
1782
2140
|
OP_WITHDRAWALS.finalize.fetchParams.messengerIndex,
|
|
1783
2141
|
() => Promise.resolve(messengerLogIndex(raw, { index: 0, messenger: L1_MESSENGER_ADDRESS })),
|
|
@@ -1786,7 +2144,7 @@ function createFinalizationServices(client) {
|
|
|
1786
2144
|
message: "Failed to derive messenger log index."
|
|
1787
2145
|
}
|
|
1788
2146
|
);
|
|
1789
|
-
const proof = await
|
|
2147
|
+
const proof = await wrapAs9(
|
|
1790
2148
|
"RPC",
|
|
1791
2149
|
OP_WITHDRAWALS.finalize.fetchParams.proof,
|
|
1792
2150
|
() => client.zks.getL2ToL1LogProof(l2TxHash, idx),
|
|
@@ -1795,7 +2153,7 @@ function createFinalizationServices(client) {
|
|
|
1795
2153
|
message: "Failed to fetch L2\u2192L1 log proof."
|
|
1796
2154
|
}
|
|
1797
2155
|
);
|
|
1798
|
-
const chainId = await
|
|
2156
|
+
const chainId = await wrapAs9(
|
|
1799
2157
|
"RPC",
|
|
1800
2158
|
OP_WITHDRAWALS.finalize.fetchParams.network,
|
|
1801
2159
|
() => client.l2.getChainId(),
|
|
@@ -1811,7 +2169,7 @@ function createFinalizationServices(client) {
|
|
|
1811
2169
|
message,
|
|
1812
2170
|
merkleProof: proof.proof
|
|
1813
2171
|
};
|
|
1814
|
-
const { l1Nullifier } = await
|
|
2172
|
+
const { l1Nullifier } = await wrapAs9(
|
|
1815
2173
|
"INTERNAL",
|
|
1816
2174
|
OP_WITHDRAWALS.finalize.fetchParams.ensureAddresses,
|
|
1817
2175
|
() => client.ensureAddresses(),
|
|
@@ -1823,7 +2181,7 @@ function createFinalizationServices(client) {
|
|
|
1823
2181
|
return { params, nullifier: l1Nullifier };
|
|
1824
2182
|
},
|
|
1825
2183
|
async simulateFinalizeReadiness(params) {
|
|
1826
|
-
const { l1Nullifier } = await
|
|
2184
|
+
const { l1Nullifier } = await wrapAs9(
|
|
1827
2185
|
"INTERNAL",
|
|
1828
2186
|
OP_WITHDRAWALS.finalize.readiness.ensureAddresses,
|
|
1829
2187
|
() => client.ensureAddresses(),
|
|
@@ -1834,7 +2192,7 @@ function createFinalizationServices(client) {
|
|
|
1834
2192
|
);
|
|
1835
2193
|
const done = await (async () => {
|
|
1836
2194
|
try {
|
|
1837
|
-
const result = await
|
|
2195
|
+
const result = await wrapAs9(
|
|
1838
2196
|
"RPC",
|
|
1839
2197
|
OP_WITHDRAWALS.finalize.readiness.isFinalized,
|
|
1840
2198
|
() => client.l1.readContract({
|
|
@@ -1868,7 +2226,7 @@ function createFinalizationServices(client) {
|
|
|
1868
2226
|
}
|
|
1869
2227
|
},
|
|
1870
2228
|
async isWithdrawalFinalized(key) {
|
|
1871
|
-
const { l1Nullifier } = await
|
|
2229
|
+
const { l1Nullifier } = await wrapAs9(
|
|
1872
2230
|
"INTERNAL",
|
|
1873
2231
|
OP_WITHDRAWALS.finalize.fetchParams.ensureAddresses,
|
|
1874
2232
|
() => client.ensureAddresses(),
|
|
@@ -1877,7 +2235,7 @@ function createFinalizationServices(client) {
|
|
|
1877
2235
|
message: "Failed to ensure L1 Nullifier address."
|
|
1878
2236
|
}
|
|
1879
2237
|
);
|
|
1880
|
-
return await
|
|
2238
|
+
return await wrapAs9(
|
|
1881
2239
|
"RPC",
|
|
1882
2240
|
OP_WITHDRAWALS.finalize.isFinalized,
|
|
1883
2241
|
() => client.l1.readContract({
|
|
@@ -1893,7 +2251,7 @@ function createFinalizationServices(client) {
|
|
|
1893
2251
|
);
|
|
1894
2252
|
},
|
|
1895
2253
|
async estimateFinalization(params) {
|
|
1896
|
-
const { l1Nullifier } = await
|
|
2254
|
+
const { l1Nullifier } = await wrapAs9(
|
|
1897
2255
|
"INTERNAL",
|
|
1898
2256
|
OP_WITHDRAWALS.finalize.estimate,
|
|
1899
2257
|
() => client.ensureAddresses(),
|
|
@@ -1902,7 +2260,7 @@ function createFinalizationServices(client) {
|
|
|
1902
2260
|
message: "Failed to ensure L1 Nullifier address."
|
|
1903
2261
|
}
|
|
1904
2262
|
);
|
|
1905
|
-
const gasLimit = await
|
|
2263
|
+
const gasLimit = await wrapAs9(
|
|
1906
2264
|
"RPC",
|
|
1907
2265
|
OP_WITHDRAWALS.finalize.estimate,
|
|
1908
2266
|
() => client.l1.estimateContractGas({
|
|
@@ -1926,7 +2284,7 @@ function createFinalizationServices(client) {
|
|
|
1926
2284
|
let maxFeePerGas;
|
|
1927
2285
|
let maxPriorityFeePerGas;
|
|
1928
2286
|
try {
|
|
1929
|
-
const fee = await
|
|
2287
|
+
const fee = await wrapAs9(
|
|
1930
2288
|
"RPC",
|
|
1931
2289
|
OP_WITHDRAWALS.finalize.estimate,
|
|
1932
2290
|
() => client.l1.estimateFeesPerGas(),
|
|
@@ -1945,7 +2303,7 @@ function createFinalizationServices(client) {
|
|
|
1945
2303
|
})();
|
|
1946
2304
|
maxPriorityFeePerGas = fee.maxPriorityFeePerGas ?? 0n;
|
|
1947
2305
|
} catch {
|
|
1948
|
-
const gasPrice = await
|
|
2306
|
+
const gasPrice = await wrapAs9(
|
|
1949
2307
|
"RPC",
|
|
1950
2308
|
OP_WITHDRAWALS.finalize.estimate,
|
|
1951
2309
|
() => client.l1.getGasPrice(),
|
|
@@ -1964,7 +2322,7 @@ function createFinalizationServices(client) {
|
|
|
1964
2322
|
};
|
|
1965
2323
|
},
|
|
1966
2324
|
async finalizeDeposit(params) {
|
|
1967
|
-
const { l1Nullifier } = await
|
|
2325
|
+
const { l1Nullifier } = await wrapAs9(
|
|
1968
2326
|
"INTERNAL",
|
|
1969
2327
|
OP_WITHDRAWALS.finalize.fetchParams.ensureAddresses,
|
|
1970
2328
|
() => client.ensureAddresses(),
|
|
@@ -2023,40 +2381,32 @@ function createFinalizationServices(client) {
|
|
|
2023
2381
|
|
|
2024
2382
|
// src/adapters/viem/resources/withdrawals/index.ts
|
|
2025
2383
|
var ROUTES2 = {
|
|
2026
|
-
|
|
2384
|
+
base: routeEthBase(),
|
|
2027
2385
|
// BaseTokenSystem.withdraw, chain base = ETH
|
|
2028
|
-
"eth-nonbase": routeEthNonBase2(),
|
|
2029
|
-
// BaseTokenSystem.withdraw, chain base ≠ ETH
|
|
2030
2386
|
"erc20-nonbase": routeErc20NonBase2()
|
|
2031
2387
|
// AssetRouter.withdraw for non-base ERC-20s
|
|
2032
2388
|
};
|
|
2033
|
-
function createWithdrawalsResource(client) {
|
|
2389
|
+
function createWithdrawalsResource(client, tokens, contracts) {
|
|
2034
2390
|
const svc = createFinalizationServices(client);
|
|
2035
2391
|
const { wrap: wrap2, toResult: toResult2 } = createErrorHandlers("withdrawals");
|
|
2392
|
+
const tokensResource = tokens ?? createTokensResource(client);
|
|
2393
|
+
const contractsResource = contracts ?? createContractsResource(client);
|
|
2036
2394
|
async function buildPlan(p) {
|
|
2037
|
-
const ctx = await commonCtx2(p, client);
|
|
2395
|
+
const ctx = await commonCtx2(p, client, tokensResource, contractsResource);
|
|
2038
2396
|
await ROUTES2[ctx.route].preflight?.(p, ctx);
|
|
2039
|
-
const { steps, approvals } = await ROUTES2[ctx.route].build(p, ctx);
|
|
2040
|
-
|
|
2041
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
2042
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
2043
|
-
const candidate = steps[i].tx.gas;
|
|
2044
|
-
if (candidate != null) return candidate;
|
|
2045
|
-
}
|
|
2046
|
-
return void 0;
|
|
2047
|
-
};
|
|
2048
|
-
const gasLimit = resolveGasLimit();
|
|
2049
|
-
const summary = {
|
|
2397
|
+
const { steps, approvals, fees } = await ROUTES2[ctx.route].build(p, ctx);
|
|
2398
|
+
return {
|
|
2050
2399
|
route: ctx.route,
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2400
|
+
summary: {
|
|
2401
|
+
route: ctx.route,
|
|
2402
|
+
approvalsNeeded: approvals,
|
|
2403
|
+
amounts: {
|
|
2404
|
+
transfer: { token: p.token, amount: p.amount }
|
|
2405
|
+
},
|
|
2406
|
+
fees
|
|
2407
|
+
},
|
|
2408
|
+
steps
|
|
2058
2409
|
};
|
|
2059
|
-
return { route: ctx.route, summary, steps };
|
|
2060
2410
|
}
|
|
2061
2411
|
const finalizeCache = /* @__PURE__ */ new Map();
|
|
2062
2412
|
const quote = (p) => wrap2(OP_WITHDRAWALS.quote, async () => (await buildPlan(p)).summary, {
|
|
@@ -2090,7 +2440,7 @@ function createWithdrawalsResource(client) {
|
|
|
2090
2440
|
}
|
|
2091
2441
|
if (overrides.gasLimit != null) step.tx.gas = overrides.gasLimit;
|
|
2092
2442
|
}
|
|
2093
|
-
if (
|
|
2443
|
+
if (!p.l2TxOverrides?.gasLimit) {
|
|
2094
2444
|
try {
|
|
2095
2445
|
const feePart = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
|
|
2096
2446
|
maxFeePerGas: step.tx.maxFeePerGas,
|
|
@@ -2389,56 +2739,14 @@ function createWithdrawalsResource(client) {
|
|
|
2389
2739
|
|
|
2390
2740
|
// src/adapters/viem/sdk.ts
|
|
2391
2741
|
function createViemSdk(client) {
|
|
2742
|
+
const tokens = createTokensResource(client);
|
|
2743
|
+
const contracts = createContractsResource(client);
|
|
2392
2744
|
return {
|
|
2393
|
-
deposits: createDepositsResource(client),
|
|
2394
|
-
withdrawals: createWithdrawalsResource(client),
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
contracts: () => client.contracts(),
|
|
2398
|
-
async l1AssetRouter() {
|
|
2399
|
-
const { l1AssetRouter } = await client.contracts();
|
|
2400
|
-
return l1AssetRouter;
|
|
2401
|
-
},
|
|
2402
|
-
async l1NativeTokenVault() {
|
|
2403
|
-
const { l1NativeTokenVault } = await client.contracts();
|
|
2404
|
-
return l1NativeTokenVault;
|
|
2405
|
-
},
|
|
2406
|
-
async l1Nullifier() {
|
|
2407
|
-
const { l1Nullifier } = await client.contracts();
|
|
2408
|
-
return l1Nullifier;
|
|
2409
|
-
},
|
|
2410
|
-
async baseToken(chainId) {
|
|
2411
|
-
const id = chainId ?? BigInt(await client.l2.getChainId());
|
|
2412
|
-
return client.baseToken(id);
|
|
2413
|
-
},
|
|
2414
|
-
async l2TokenAddress(l1Token) {
|
|
2415
|
-
if (isAddressEq(l1Token, FORMAL_ETH_ADDRESS)) {
|
|
2416
|
-
return ETH_ADDRESS;
|
|
2417
|
-
}
|
|
2418
|
-
const base = await client.baseToken(BigInt(await client.l2.getChainId()));
|
|
2419
|
-
if (isAddressEq(l1Token, base)) {
|
|
2420
|
-
return L2_BASE_TOKEN_ADDRESS;
|
|
2421
|
-
}
|
|
2422
|
-
const { l2NativeTokenVault } = await client.contracts();
|
|
2423
|
-
const addr = await l2NativeTokenVault.read.l2TokenAddress([l1Token]);
|
|
2424
|
-
return addr;
|
|
2425
|
-
},
|
|
2426
|
-
async l1TokenAddress(l2Token) {
|
|
2427
|
-
if (isAddressEq(l2Token, FORMAL_ETH_ADDRESS)) {
|
|
2428
|
-
return FORMAL_ETH_ADDRESS;
|
|
2429
|
-
}
|
|
2430
|
-
const { l2AssetRouter } = await client.contracts();
|
|
2431
|
-
const addr = await l2AssetRouter.read.l1TokenAddress([l2Token]);
|
|
2432
|
-
return addr;
|
|
2433
|
-
},
|
|
2434
|
-
async assetId(l1Token) {
|
|
2435
|
-
const norm = isAddressEq(l1Token, FORMAL_ETH_ADDRESS) ? ETH_ADDRESS : l1Token;
|
|
2436
|
-
const { l1NativeTokenVault } = await client.contracts();
|
|
2437
|
-
const id = await l1NativeTokenVault.read.assetId([norm]);
|
|
2438
|
-
return id;
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2745
|
+
deposits: createDepositsResource(client, tokens, contracts),
|
|
2746
|
+
withdrawals: createWithdrawalsResource(client, tokens, contracts),
|
|
2747
|
+
tokens,
|
|
2748
|
+
contracts
|
|
2441
2749
|
};
|
|
2442
2750
|
}
|
|
2443
2751
|
|
|
2444
|
-
export { buildDirectRequestStruct,
|
|
2752
|
+
export { buildDirectRequestStruct, classifyReadinessFromRevert, createContractsResource, createDepositsResource, createErrorHandlers, createFinalizationServices, createTokensResource, createViemSdk, createWithdrawalsResource, decodeRevert, encodeNativeTokenVaultTransferData, encodeSecondBridgeArgs, encodeSecondBridgeDataV1, encodeSecondBridgeErc20Args, encodeSecondBridgeEthArgs, registerErrorAbi, toZKsyncError };
|