@matterlabs/zksync-js 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +934 -801
- package/dist/adapters/ethers/index.cjs.map +1 -1
- package/dist/adapters/ethers/index.js +9 -8
- package/dist/adapters/ethers/resources/deposits/context.d.ts +5 -5
- 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 +40 -0
- package/dist/adapters/ethers/resources/utils.d.ts +4 -15
- package/dist/adapters/ethers/resources/withdrawals/context.d.ts +4 -4
- 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 +947 -1292
- package/dist/adapters/ethers/sdk.cjs.map +1 -1
- 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 +944 -662
- package/dist/adapters/viem/index.cjs.map +1 -1
- package/dist/adapters/viem/index.js +8 -8
- package/dist/adapters/viem/resources/deposits/context.d.ts +5 -5
- 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 +36 -0
- package/dist/adapters/viem/resources/utils.d.ts +3 -16
- package/dist/adapters/viem/resources/withdrawals/context.d.ts +3 -6
- 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 +877 -563
- package/dist/adapters/viem/sdk.cjs.map +1 -1
- package/dist/adapters/viem/sdk.d.ts +1 -1
- package/dist/adapters/viem/sdk.js +6 -6
- package/dist/{chunk-3LALBFFE.js → chunk-3MRGU4HV.js} +9 -5
- package/dist/{chunk-4HLJJKIY.js → chunk-6K6VJQAL.js} +2 -2
- package/dist/{chunk-CGO27P7F.js → chunk-BCCKWWOX.js} +540 -741
- package/dist/{chunk-6GCT6TLS.js → chunk-F2ENUV3A.js} +13 -1
- package/dist/{chunk-DI2CJDPZ.js → chunk-HLUANWGN.js} +2 -2
- package/dist/{chunk-Y75OMFK6.js → chunk-M5J2MM2U.js} +351 -1
- package/dist/{chunk-263G6636.js → chunk-NCAIVYBR.js} +1 -14
- package/dist/{chunk-7M4V3FMT.js → chunk-OC6ZVLSP.js} +669 -559
- package/dist/chunk-QJS6ETEE.js +217 -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/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 +4504 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +4 -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/withdrawals.d.ts +12 -6
- package/dist/index.cjs +4516 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/package.json +5 -1
- package/dist/adapters/ethers/resources/withdrawals/routes/eth-nonbase.d.ts +0 -2
- package/dist/adapters/viem/resources/withdrawals/routes/eth-nonbase.d.ts +0 -2
- package/dist/chunk-B77GWPO5.js +0 -339
- package/dist/core/internal/abi-registry.d.ts +0 -9
- package/dist/core/utils/gas.d.ts +0 -13
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var viem = require('viem');
|
|
4
3
|
var sha3 = require('@noble/hashes/sha3');
|
|
5
4
|
var utils = require('@noble/hashes/utils');
|
|
5
|
+
var viem = require('viem');
|
|
6
6
|
|
|
7
7
|
// src/core/internal/abis/IBridgehub.ts
|
|
8
8
|
var IBridgehubABI = [
|
|
@@ -3656,139 +3656,12 @@ var TOPIC_L1_MESSAGE_SENT_NEW = k256hex("L1MessageSent(uint256,bytes32,bytes)");
|
|
|
3656
3656
|
var TOPIC_L1_MESSAGE_SENT_LEG = k256hex("L1MessageSent(address,bytes32,bytes)");
|
|
3657
3657
|
var TOPIC_CANONICAL_ASSIGNED = "0x779f441679936c5441b671969f37400b8c3ed0071cb47444431bf985754560df";
|
|
3658
3658
|
var TOPIC_CANONICAL_SUCCESS = "0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df";
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
}
|
|
3666
|
-
}
|
|
3667
|
-
function assertPriorityFeeBounds(fees) {
|
|
3668
|
-
if (fees.maxPriorityFeePerGas > fees.maxFeePerGas) {
|
|
3669
|
-
throw new Error("maxPriorityFeePerGas cannot exceed maxFeePerGas.");
|
|
3670
|
-
}
|
|
3671
|
-
}
|
|
3672
|
-
|
|
3673
|
-
// src/adapters/viem/resources/utils.ts
|
|
3674
|
-
function encodeNativeTokenVaultAssetId(chainId, address) {
|
|
3675
|
-
const encoded = viem.encodeAbiParameters(
|
|
3676
|
-
[
|
|
3677
|
-
{ type: "uint256", name: "originChainId" },
|
|
3678
|
-
{ type: "address", name: "ntv" },
|
|
3679
|
-
{ type: "address", name: "token" }
|
|
3680
|
-
],
|
|
3681
|
-
[chainId, L2_NATIVE_TOKEN_VAULT_ADDRESS, address]
|
|
3682
|
-
);
|
|
3683
|
-
return viem.keccak256(encoded);
|
|
3684
|
-
}
|
|
3685
|
-
async function getFeeOverrides(client, overrides) {
|
|
3686
|
-
assertNoLegacyGas(overrides);
|
|
3687
|
-
let maxFeePerGasFromProvider;
|
|
3688
|
-
let maxPriorityFromProvider;
|
|
3689
|
-
let gasPriceFromProvider;
|
|
3690
|
-
try {
|
|
3691
|
-
const fees = await client.l1.estimateFeesPerGas();
|
|
3692
|
-
const { maxFeePerGas: maxFeePerGas2, maxPriorityFeePerGas: maxPriorityFeePerGas2 } = fees;
|
|
3693
|
-
if (maxFeePerGas2 != null && maxPriorityFeePerGas2 != null) {
|
|
3694
|
-
maxFeePerGasFromProvider = maxFeePerGas2;
|
|
3695
|
-
maxPriorityFromProvider = maxPriorityFeePerGas2;
|
|
3696
|
-
gasPriceFromProvider = fees.gasPrice ?? maxFeePerGas2;
|
|
3697
|
-
} else if (fees.gasPrice != null) {
|
|
3698
|
-
gasPriceFromProvider = fees.gasPrice;
|
|
3699
|
-
}
|
|
3700
|
-
} catch {
|
|
3701
|
-
}
|
|
3702
|
-
if (gasPriceFromProvider == null) {
|
|
3703
|
-
try {
|
|
3704
|
-
gasPriceFromProvider = await client.l1.getGasPrice();
|
|
3705
|
-
} catch {
|
|
3706
|
-
}
|
|
3707
|
-
}
|
|
3708
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider;
|
|
3709
|
-
if (maxFeePerGas == null) {
|
|
3710
|
-
throw new Error("L1 provider returned no gas price data");
|
|
3711
|
-
}
|
|
3712
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
3713
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
3714
|
-
const gasPriceForBaseCost = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider ?? maxFeePerGas;
|
|
3715
|
-
return {
|
|
3716
|
-
gasLimit: overrides?.gasLimit,
|
|
3717
|
-
maxFeePerGas,
|
|
3718
|
-
maxPriorityFeePerGas,
|
|
3719
|
-
gasPriceForBaseCost
|
|
3720
|
-
};
|
|
3721
|
-
}
|
|
3722
|
-
async function getL2FeeOverrides(client, overrides) {
|
|
3723
|
-
assertNoLegacyGas(overrides);
|
|
3724
|
-
let maxFeePerGasFromProvider;
|
|
3725
|
-
let maxPriorityFromProvider;
|
|
3726
|
-
let gasPriceFromProvider;
|
|
3727
|
-
try {
|
|
3728
|
-
const fees = await client.l2.estimateFeesPerGas();
|
|
3729
|
-
if (fees?.maxFeePerGas != null && fees.maxPriorityFeePerGas != null) {
|
|
3730
|
-
maxFeePerGasFromProvider = fees.maxFeePerGas;
|
|
3731
|
-
maxPriorityFromProvider = fees.maxPriorityFeePerGas;
|
|
3732
|
-
gasPriceFromProvider = fees.gasPrice ?? fees.maxFeePerGas;
|
|
3733
|
-
} else if (fees?.gasPrice != null) {
|
|
3734
|
-
gasPriceFromProvider = fees.gasPrice;
|
|
3735
|
-
}
|
|
3736
|
-
} catch {
|
|
3737
|
-
}
|
|
3738
|
-
if (gasPriceFromProvider == null) {
|
|
3739
|
-
try {
|
|
3740
|
-
gasPriceFromProvider = await client.l2.getGasPrice();
|
|
3741
|
-
} catch {
|
|
3742
|
-
}
|
|
3743
|
-
}
|
|
3744
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeePerGasFromProvider ?? gasPriceFromProvider;
|
|
3745
|
-
if (maxFeePerGas == null) {
|
|
3746
|
-
throw new Error("provider returned no gas price data");
|
|
3747
|
-
}
|
|
3748
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
3749
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
3750
|
-
return {
|
|
3751
|
-
gasLimit: overrides?.gasLimit,
|
|
3752
|
-
maxFeePerGas,
|
|
3753
|
-
maxPriorityFeePerGas
|
|
3754
|
-
};
|
|
3755
|
-
}
|
|
3756
|
-
function buildViemFeeOverrides(fees) {
|
|
3757
|
-
return {
|
|
3758
|
-
maxFeePerGas: fees.maxFeePerGas,
|
|
3759
|
-
maxPriorityFeePerGas: fees.maxPriorityFeePerGas,
|
|
3760
|
-
gas: fees.gasLimit
|
|
3761
|
-
};
|
|
3762
|
-
}
|
|
3763
|
-
function buildDirectRequestStruct(args) {
|
|
3764
|
-
return {
|
|
3765
|
-
chainId: args.chainId,
|
|
3766
|
-
l2Contract: args.l2Contract,
|
|
3767
|
-
mintValue: args.mintValue,
|
|
3768
|
-
l2Value: args.l2Value,
|
|
3769
|
-
l2Calldata: "0x",
|
|
3770
|
-
l2GasLimit: args.l2GasLimit,
|
|
3771
|
-
l2GasPerPubdataByteLimit: args.gasPerPubdata,
|
|
3772
|
-
factoryDeps: [],
|
|
3773
|
-
refundRecipient: args.refundRecipient
|
|
3774
|
-
};
|
|
3775
|
-
}
|
|
3776
|
-
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
3777
|
-
return viem.encodeAbiParameters(
|
|
3778
|
-
[
|
|
3779
|
-
{ type: "address", name: "token" },
|
|
3780
|
-
{ type: "uint256", name: "amount" },
|
|
3781
|
-
{ type: "address", name: "l2Receiver" }
|
|
3782
|
-
],
|
|
3783
|
-
[token, amount, l2Receiver]
|
|
3784
|
-
);
|
|
3785
|
-
}
|
|
3786
|
-
function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
3787
|
-
return encodeSecondBridgeArgs(token, amount, l2Receiver);
|
|
3788
|
-
}
|
|
3789
|
-
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
3790
|
-
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
3791
|
-
}
|
|
3659
|
+
var BUFFER = 20n;
|
|
3660
|
+
var TX_OVERHEAD_GAS = 10000n;
|
|
3661
|
+
var TX_MEMORY_OVERHEAD_GAS = 10n;
|
|
3662
|
+
var DEFAULT_PUBDATA_BYTES = 155n;
|
|
3663
|
+
var DEFAULT_ABI_BYTES = 400n;
|
|
3664
|
+
var SAFE_L1_BRIDGE_GAS = 600000n;
|
|
3792
3665
|
|
|
3793
3666
|
// src/core/utils/addr.ts
|
|
3794
3667
|
var isHash66 = (x) => !!x && x.startsWith("0x") && x.length === 66;
|
|
@@ -3823,8 +3696,6 @@ async function commonCtx(p, client) {
|
|
|
3823
3696
|
const { bridgehub, l1AssetRouter } = await client.ensureAddresses();
|
|
3824
3697
|
const chainId = await client.l2.getChainId();
|
|
3825
3698
|
const sender = client.account.address;
|
|
3826
|
-
const fee = await getFeeOverrides(client, p.l1TxOverrides);
|
|
3827
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
3828
3699
|
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
3829
3700
|
const operatorTip = p.operatorTip ?? 0n;
|
|
3830
3701
|
const refundRecipient = p.refundRecipient ?? sender;
|
|
@@ -3836,13 +3707,53 @@ async function commonCtx(p, client) {
|
|
|
3836
3707
|
bridgehub,
|
|
3837
3708
|
chainIdL2: BigInt(chainId),
|
|
3838
3709
|
sender,
|
|
3839
|
-
|
|
3840
|
-
l2GasLimit,
|
|
3710
|
+
gasOverrides: p.l1TxOverrides,
|
|
3711
|
+
l2GasLimit: p.l2GasLimit,
|
|
3841
3712
|
gasPerPubdata,
|
|
3842
3713
|
operatorTip,
|
|
3843
3714
|
refundRecipient
|
|
3844
3715
|
};
|
|
3845
3716
|
}
|
|
3717
|
+
function encodeNativeTokenVaultAssetId(chainId, address) {
|
|
3718
|
+
const encoded = viem.encodeAbiParameters(
|
|
3719
|
+
[
|
|
3720
|
+
{ type: "uint256", name: "originChainId" },
|
|
3721
|
+
{ type: "address", name: "ntv" },
|
|
3722
|
+
{ type: "address", name: "token" }
|
|
3723
|
+
],
|
|
3724
|
+
[chainId, L2_NATIVE_TOKEN_VAULT_ADDRESS, address]
|
|
3725
|
+
);
|
|
3726
|
+
return viem.keccak256(encoded);
|
|
3727
|
+
}
|
|
3728
|
+
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
3729
|
+
return viem.encodeAbiParameters(
|
|
3730
|
+
[
|
|
3731
|
+
{ type: "address", name: "token" },
|
|
3732
|
+
{ type: "uint256", name: "amount" },
|
|
3733
|
+
{ type: "address", name: "l2Receiver" }
|
|
3734
|
+
],
|
|
3735
|
+
[token, amount, l2Receiver]
|
|
3736
|
+
);
|
|
3737
|
+
}
|
|
3738
|
+
function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
3739
|
+
return encodeSecondBridgeArgs(token, amount, l2Receiver);
|
|
3740
|
+
}
|
|
3741
|
+
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
3742
|
+
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
3743
|
+
}
|
|
3744
|
+
function buildDirectRequestStruct(args) {
|
|
3745
|
+
return {
|
|
3746
|
+
chainId: args.chainId,
|
|
3747
|
+
l2Contract: args.l2Contract,
|
|
3748
|
+
mintValue: args.mintValue,
|
|
3749
|
+
l2Value: args.l2Value,
|
|
3750
|
+
l2Calldata: "0x",
|
|
3751
|
+
l2GasLimit: args.l2GasLimit,
|
|
3752
|
+
l2GasPerPubdataByteLimit: args.gasPerPubdata,
|
|
3753
|
+
factoryDeps: [],
|
|
3754
|
+
refundRecipient: args.refundRecipient
|
|
3755
|
+
};
|
|
3756
|
+
}
|
|
3846
3757
|
|
|
3847
3758
|
// src/core/errors/formatter.ts
|
|
3848
3759
|
function elideMiddle(s, max = 96) {
|
|
@@ -4055,27 +3966,21 @@ var OP_DEPOSITS = {
|
|
|
4055
3966
|
base: {
|
|
4056
3967
|
assertErc20Asset: "deposits.erc20-base:assertErc20Asset",
|
|
4057
3968
|
assertMatchesBase: "deposits.erc20-base:assertMatchesBase",
|
|
4058
|
-
baseToken: "deposits.erc20-base:baseToken",
|
|
4059
3969
|
allowance: "deposits.erc20-base:allowance",
|
|
4060
|
-
baseCost: "deposits.erc20-base:l2TransactionBaseCost",
|
|
4061
3970
|
estGas: "deposits.erc20-base:estimateGas"
|
|
4062
3971
|
},
|
|
4063
3972
|
nonbase: {
|
|
4064
|
-
baseToken: "deposits.erc20-nonbase:baseToken",
|
|
4065
3973
|
assertNotEthAsset: "deposits.erc20-nonbase:assertNotEthAsset",
|
|
4066
|
-
allowance: "deposits.erc20-nonbase:allowance",
|
|
4067
|
-
allowanceFees: "deposits.erc20-nonbase:allowanceFeesBaseToken",
|
|
4068
|
-
baseCost: "deposits.erc20-nonbase:l2TransactionBaseCost",
|
|
4069
3974
|
encodeCalldata: "deposits.erc20-nonbase:encodeSecondBridgeErc20Args",
|
|
4070
3975
|
estGas: "deposits.erc20-nonbase:estimateGas",
|
|
4071
|
-
assertNonBaseToken: "deposits.erc20-nonbase:assertNonBaseToken"
|
|
3976
|
+
assertNonBaseToken: "deposits.erc20-nonbase:assertNonBaseToken",
|
|
3977
|
+
allowanceToken: "deposits.erc20-nonbase:allowanceToken",
|
|
3978
|
+
allowanceBase: "deposits.erc20-nonbase:allowanceBase"
|
|
3979
|
+
},
|
|
4072
3980
|
eth: {
|
|
4073
|
-
baseCost: "deposits.eth:l2TransactionBaseCost",
|
|
4074
3981
|
estGas: "deposits.eth:estimateGas"
|
|
4075
3982
|
},
|
|
4076
3983
|
ethNonBase: {
|
|
4077
|
-
baseToken: "deposits.eth-nonbase:baseToken",
|
|
4078
|
-
baseCost: "deposits.eth-nonbase:l2TransactionBaseCost",
|
|
4079
3984
|
allowanceBase: "deposits.eth-nonbase:allowanceBaseToken",
|
|
4080
3985
|
ethBalance: "deposits.eth-nonbase:getEthBalance",
|
|
4081
3986
|
encodeCalldata: "deposits.eth-nonbase:encodeSecondBridgeEthArgs",
|
|
@@ -4337,41 +4242,361 @@ function createErrorHandlers(resource) {
|
|
|
4337
4242
|
return { wrap: wrap2, wrapAs: wrapAs9, toResult: toResult2 };
|
|
4338
4243
|
}
|
|
4339
4244
|
|
|
4340
|
-
// src/
|
|
4245
|
+
// src/core/resources/deposits/gas.ts
|
|
4246
|
+
function makeGasQuote(p) {
|
|
4247
|
+
const maxPriorityFeePerGas = p.maxPriorityFeePerGas ?? 0n;
|
|
4248
|
+
return {
|
|
4249
|
+
gasLimit: p.gasLimit,
|
|
4250
|
+
maxFeePerGas: p.maxFeePerGas,
|
|
4251
|
+
maxPriorityFeePerGas,
|
|
4252
|
+
gasPerPubdata: p.gasPerPubdata,
|
|
4253
|
+
maxCost: p.gasLimit * p.maxFeePerGas
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4256
|
+
async function fetchFees(estimator) {
|
|
4257
|
+
try {
|
|
4258
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
4259
|
+
if (fees.maxFeePerGas != null) {
|
|
4260
|
+
return {
|
|
4261
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
4262
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? 0n
|
|
4263
|
+
};
|
|
4264
|
+
}
|
|
4265
|
+
if (fees.gasPrice != null) {
|
|
4266
|
+
return {
|
|
4267
|
+
maxFeePerGas: fees.gasPrice,
|
|
4268
|
+
maxPriorityFeePerGas: 0n
|
|
4269
|
+
};
|
|
4270
|
+
}
|
|
4271
|
+
} catch {
|
|
4272
|
+
}
|
|
4273
|
+
try {
|
|
4274
|
+
const gp = await estimator.getGasPrice();
|
|
4275
|
+
return { maxFeePerGas: gp, maxPriorityFeePerGas: 0n };
|
|
4276
|
+
} catch {
|
|
4277
|
+
return { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n };
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
async function quoteL1Gas(input) {
|
|
4281
|
+
const { estimator, tx, overrides, fallbackGasLimit } = input;
|
|
4282
|
+
let market;
|
|
4283
|
+
const getMarket = async () => {
|
|
4284
|
+
if (market) return market;
|
|
4285
|
+
market = await fetchFees(estimator);
|
|
4286
|
+
return market;
|
|
4287
|
+
};
|
|
4288
|
+
const maxFeePerGas = overrides?.maxFeePerGas ?? (tx.maxFeePerGas != null ? BigInt(tx.maxFeePerGas) : (await getMarket()).maxFeePerGas);
|
|
4289
|
+
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? (tx.maxPriorityFeePerGas != null ? BigInt(tx.maxPriorityFeePerGas) : (await getMarket()).maxPriorityFeePerGas);
|
|
4290
|
+
const explicitGasLimit = overrides?.gasLimit ?? (tx.gasLimit != null ? BigInt(tx.gasLimit) : void 0);
|
|
4291
|
+
if (explicitGasLimit != null) {
|
|
4292
|
+
return makeGasQuote({ gasLimit: explicitGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
4293
|
+
}
|
|
4294
|
+
try {
|
|
4295
|
+
const est = await estimator.estimateGas(tx);
|
|
4296
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
4297
|
+
return makeGasQuote({ gasLimit: buffered, maxFeePerGas, maxPriorityFeePerGas });
|
|
4298
|
+
} catch (err) {
|
|
4299
|
+
if (fallbackGasLimit != null) {
|
|
4300
|
+
return makeGasQuote({ gasLimit: fallbackGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
4301
|
+
}
|
|
4302
|
+
console.warn("L1 gas estimation failed", err);
|
|
4303
|
+
return void 0;
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
async function quoteL2Gas(input) {
|
|
4307
|
+
const { estimator, route, tx, gasPerPubdata, l2GasLimit, overrideGasLimit, stateOverrides } = input;
|
|
4308
|
+
const market = await fetchFees(estimator);
|
|
4309
|
+
const maxFeePerGas = market.maxFeePerGas || market.maxPriorityFeePerGas || 0n;
|
|
4310
|
+
const txGasLimit = tx?.gasLimit != null ? BigInt(tx.gasLimit) : void 0;
|
|
4311
|
+
const explicit = overrideGasLimit ?? txGasLimit;
|
|
4312
|
+
if (explicit != null) {
|
|
4313
|
+
return makeGasQuote({
|
|
4314
|
+
gasLimit: explicit,
|
|
4315
|
+
maxFeePerGas,
|
|
4316
|
+
gasPerPubdata
|
|
4317
|
+
});
|
|
4318
|
+
}
|
|
4319
|
+
if (!tx) {
|
|
4320
|
+
return makeGasQuote({
|
|
4321
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
4322
|
+
maxFeePerGas,
|
|
4323
|
+
gasPerPubdata
|
|
4324
|
+
});
|
|
4325
|
+
}
|
|
4326
|
+
try {
|
|
4327
|
+
const execEstimate = await estimator.estimateGas(tx, stateOverrides);
|
|
4328
|
+
const memoryBytes = route === "erc20-nonbase" ? 500n : DEFAULT_ABI_BYTES;
|
|
4329
|
+
const pubdataBytes = route === "erc20-nonbase" ? 200n : DEFAULT_PUBDATA_BYTES;
|
|
4330
|
+
const pp = gasPerPubdata ?? 800n;
|
|
4331
|
+
const memoryOverhead = memoryBytes * TX_MEMORY_OVERHEAD_GAS;
|
|
4332
|
+
const pubdataOverhead = pubdataBytes * pp;
|
|
4333
|
+
let total = BigInt(execEstimate) + TX_OVERHEAD_GAS + memoryOverhead + pubdataOverhead;
|
|
4334
|
+
total = total * (100n + BUFFER) / 100n;
|
|
4335
|
+
return makeGasQuote({
|
|
4336
|
+
gasLimit: total,
|
|
4337
|
+
maxFeePerGas,
|
|
4338
|
+
gasPerPubdata: pp
|
|
4339
|
+
});
|
|
4340
|
+
} catch (err) {
|
|
4341
|
+
console.warn("L2 gas estimation failed", err);
|
|
4342
|
+
return makeGasQuote({
|
|
4343
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
4344
|
+
maxFeePerGas,
|
|
4345
|
+
gasPerPubdata
|
|
4346
|
+
});
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4350
|
+
// src/adapters/viem/estimator.ts
|
|
4351
|
+
function toCoreTx(tx) {
|
|
4352
|
+
return {
|
|
4353
|
+
to: tx.to,
|
|
4354
|
+
from: tx.from,
|
|
4355
|
+
data: tx.data,
|
|
4356
|
+
value: tx.value,
|
|
4357
|
+
gasLimit: tx.gas,
|
|
4358
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
4359
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
4360
|
+
};
|
|
4361
|
+
}
|
|
4362
|
+
function viemToGasEstimator(client) {
|
|
4363
|
+
return {
|
|
4364
|
+
async estimateGas(tx, stateOverrides) {
|
|
4365
|
+
if (stateOverrides) {
|
|
4366
|
+
try {
|
|
4367
|
+
const result = await client.request({
|
|
4368
|
+
method: "eth_estimateGas",
|
|
4369
|
+
params: [
|
|
4370
|
+
{
|
|
4371
|
+
from: tx.from,
|
|
4372
|
+
to: tx.to,
|
|
4373
|
+
data: tx.data,
|
|
4374
|
+
value: tx.value,
|
|
4375
|
+
gas: tx.gasLimit,
|
|
4376
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
4377
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
4378
|
+
},
|
|
4379
|
+
"latest",
|
|
4380
|
+
stateOverrides
|
|
4381
|
+
]
|
|
4382
|
+
});
|
|
4383
|
+
return BigInt(result);
|
|
4384
|
+
} catch (error) {
|
|
4385
|
+
console.warn(
|
|
4386
|
+
"Failed to estimate gas with state overrides, falling back to standard estimation:",
|
|
4387
|
+
error
|
|
4388
|
+
);
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
return await client.estimateGas({
|
|
4392
|
+
account: tx.from,
|
|
4393
|
+
to: tx.to,
|
|
4394
|
+
data: tx.data,
|
|
4395
|
+
value: tx.value,
|
|
4396
|
+
gas: tx.gasLimit,
|
|
4397
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
4398
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
4399
|
+
});
|
|
4400
|
+
},
|
|
4401
|
+
async estimateFeesPerGas() {
|
|
4402
|
+
try {
|
|
4403
|
+
const fees = await client.estimateFeesPerGas();
|
|
4404
|
+
return {
|
|
4405
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
4406
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas
|
|
4407
|
+
};
|
|
4408
|
+
} catch {
|
|
4409
|
+
}
|
|
4410
|
+
try {
|
|
4411
|
+
const gp = await client.getGasPrice();
|
|
4412
|
+
return { gasPrice: gp };
|
|
4413
|
+
} catch {
|
|
4414
|
+
return {};
|
|
4415
|
+
}
|
|
4416
|
+
},
|
|
4417
|
+
async getGasPrice() {
|
|
4418
|
+
return await client.getGasPrice();
|
|
4419
|
+
},
|
|
4420
|
+
async call(tx) {
|
|
4421
|
+
const res = await client.call({
|
|
4422
|
+
to: tx.to,
|
|
4423
|
+
data: tx.data,
|
|
4424
|
+
value: tx.value,
|
|
4425
|
+
account: tx.from
|
|
4426
|
+
});
|
|
4427
|
+
return res.data ?? "0x";
|
|
4428
|
+
}
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4432
|
+
// src/adapters/viem/resources/deposits/services/gas.ts
|
|
4433
|
+
async function quoteL1Gas2(input) {
|
|
4434
|
+
const { ctx, tx, overrides, fallbackGasLimit } = input;
|
|
4435
|
+
const estimator = viemToGasEstimator(ctx.client.l1);
|
|
4436
|
+
return quoteL1Gas({
|
|
4437
|
+
estimator,
|
|
4438
|
+
tx: toCoreTx(tx),
|
|
4439
|
+
overrides,
|
|
4440
|
+
fallbackGasLimit
|
|
4441
|
+
});
|
|
4442
|
+
}
|
|
4443
|
+
async function quoteL2Gas2(input) {
|
|
4444
|
+
const { ctx, route, l2TxForModeling, overrideGasLimit } = input;
|
|
4445
|
+
const estimator = viemToGasEstimator(ctx.client.l2);
|
|
4446
|
+
return quoteL2Gas({
|
|
4447
|
+
estimator,
|
|
4448
|
+
route,
|
|
4449
|
+
tx: l2TxForModeling ? toCoreTx(l2TxForModeling) : void 0,
|
|
4450
|
+
gasPerPubdata: ctx.gasPerPubdata,
|
|
4451
|
+
l2GasLimit: ctx.l2GasLimit,
|
|
4452
|
+
// TODO: investigate if this should be passed here; weird viem quirk
|
|
4453
|
+
overrideGasLimit,
|
|
4454
|
+
stateOverrides: input.stateOverrides
|
|
4455
|
+
});
|
|
4456
|
+
}
|
|
4457
|
+
async function determineErc20L2Gas(input) {
|
|
4458
|
+
const { ctx, l1Token } = input;
|
|
4459
|
+
const DEFAULT_SAFE_L2_GAS_LIMIT = 3000000n;
|
|
4460
|
+
if (ctx.l2GasLimit != null) {
|
|
4461
|
+
return quoteL2Gas2({
|
|
4462
|
+
ctx,
|
|
4463
|
+
route: "erc20-nonbase",
|
|
4464
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
4465
|
+
});
|
|
4466
|
+
}
|
|
4467
|
+
try {
|
|
4468
|
+
const l2NativeTokenVault = (await ctx.client.contracts()).l2NativeTokenVault;
|
|
4469
|
+
const l2TokenAddress = await ctx.client.l2.readContract({
|
|
4470
|
+
address: l2NativeTokenVault.address,
|
|
4471
|
+
abi: l2NativeTokenVault.abi,
|
|
4472
|
+
functionName: "l2TokenAddress",
|
|
4473
|
+
args: [l1Token]
|
|
4474
|
+
});
|
|
4475
|
+
if (l2TokenAddress === viem.zeroAddress) {
|
|
4476
|
+
return quoteL2Gas2({
|
|
4477
|
+
ctx,
|
|
4478
|
+
route: "erc20-nonbase",
|
|
4479
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
4480
|
+
});
|
|
4481
|
+
}
|
|
4482
|
+
const modelTx = {
|
|
4483
|
+
to: input.modelTx?.to ?? ctx.sender,
|
|
4484
|
+
from: input.modelTx?.from ?? ctx.sender,
|
|
4485
|
+
data: input.modelTx?.data ?? "0x",
|
|
4486
|
+
value: input.modelTx?.value ?? 0n
|
|
4487
|
+
};
|
|
4488
|
+
const gas = await quoteL2Gas2({
|
|
4489
|
+
ctx,
|
|
4490
|
+
route: "erc20-nonbase",
|
|
4491
|
+
l2TxForModeling: modelTx
|
|
4492
|
+
});
|
|
4493
|
+
if (!gas) {
|
|
4494
|
+
return quoteL2Gas2({
|
|
4495
|
+
ctx,
|
|
4496
|
+
route: "erc20-nonbase",
|
|
4497
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
4498
|
+
});
|
|
4499
|
+
}
|
|
4500
|
+
return gas;
|
|
4501
|
+
} catch (err) {
|
|
4502
|
+
console.warn("Failed to determine ERC20 L2 gas; defaulting to safe gas limit.", err);
|
|
4503
|
+
return quoteL2Gas2({
|
|
4504
|
+
ctx,
|
|
4505
|
+
route: "erc20-nonbase",
|
|
4506
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
4507
|
+
});
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
|
|
4511
|
+
// src/adapters/viem/resources/deposits/services/fee.ts
|
|
4341
4512
|
var { wrapAs } = createErrorHandlers("deposits");
|
|
4513
|
+
async function quoteL2BaseCost(input) {
|
|
4514
|
+
const { ctx, l2GasLimit } = input;
|
|
4515
|
+
const estimator = viemToGasEstimator(ctx.client.l1);
|
|
4516
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
4517
|
+
const gasPrice = fees.maxFeePerGas ?? fees.gasPrice ?? await estimator.getGasPrice();
|
|
4518
|
+
return wrapAs(
|
|
4519
|
+
"RPC",
|
|
4520
|
+
"deposits.fees.l2BaseCost",
|
|
4521
|
+
async () => {
|
|
4522
|
+
return await ctx.client.l1.readContract({
|
|
4523
|
+
address: ctx.bridgehub,
|
|
4524
|
+
abi: IBridgehub_default,
|
|
4525
|
+
functionName: "l2TransactionBaseCost",
|
|
4526
|
+
args: [ctx.chainIdL2, gasPrice, l2GasLimit, ctx.gasPerPubdata]
|
|
4527
|
+
});
|
|
4528
|
+
},
|
|
4529
|
+
{ ctx: { chainIdL2: ctx.chainIdL2 } }
|
|
4530
|
+
);
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
// src/core/resources/deposits/fee.ts
|
|
4534
|
+
function buildFeeBreakdown(p) {
|
|
4535
|
+
const l1MaxTotal = p.l1Gas?.maxCost ?? 0n;
|
|
4536
|
+
const l2Total = p.l2BaseCost + p.operatorTip;
|
|
4537
|
+
const l1 = {
|
|
4538
|
+
gasLimit: p.l1Gas?.gasLimit ?? 0n,
|
|
4539
|
+
maxFeePerGas: p.l1Gas?.maxFeePerGas ?? 0n,
|
|
4540
|
+
maxPriorityFeePerGas: p.l1Gas?.maxPriorityFeePerGas,
|
|
4541
|
+
maxTotal: l1MaxTotal
|
|
4542
|
+
};
|
|
4543
|
+
const l2 = {
|
|
4544
|
+
total: l2Total,
|
|
4545
|
+
baseCost: p.l2BaseCost,
|
|
4546
|
+
operatorTip: p.operatorTip,
|
|
4547
|
+
gasLimit: p.l2Gas?.gasLimit ?? 0n,
|
|
4548
|
+
maxFeePerGas: p.l2Gas?.maxFeePerGas ?? 0n,
|
|
4549
|
+
maxPriorityFeePerGas: p.l2Gas?.maxPriorityFeePerGas,
|
|
4550
|
+
gasPerPubdata: p.l2Gas?.gasPerPubdata ?? 0n
|
|
4551
|
+
};
|
|
4552
|
+
return {
|
|
4553
|
+
token: p.feeToken,
|
|
4554
|
+
maxTotal: l1MaxTotal + l2Total,
|
|
4555
|
+
mintValue: p.mintValue,
|
|
4556
|
+
l1,
|
|
4557
|
+
l2
|
|
4558
|
+
};
|
|
4559
|
+
}
|
|
4560
|
+
|
|
4561
|
+
// src/adapters/viem/resources/deposits/routes/eth.ts
|
|
4562
|
+
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
4342
4563
|
function routeEthDirect() {
|
|
4343
4564
|
return {
|
|
4344
4565
|
async build(p, ctx) {
|
|
4345
|
-
const
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
"
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
{
|
|
4357
|
-
ctx: {
|
|
4358
|
-
|
|
4566
|
+
const l2TxModel = {
|
|
4567
|
+
to: p.to ?? ctx.sender,
|
|
4568
|
+
from: ctx.sender,
|
|
4569
|
+
data: "0x",
|
|
4570
|
+
value: p.amount
|
|
4571
|
+
};
|
|
4572
|
+
const l2GasParams = await quoteL2Gas2({
|
|
4573
|
+
ctx,
|
|
4574
|
+
route: "eth-base",
|
|
4575
|
+
l2TxForModeling: l2TxModel,
|
|
4576
|
+
overrideGasLimit: ctx.l2GasLimit,
|
|
4577
|
+
stateOverrides: {
|
|
4578
|
+
[ctx.sender]: {
|
|
4579
|
+
balance: "0xffffffffffffffffffff"
|
|
4580
|
+
}
|
|
4359
4581
|
}
|
|
4360
|
-
);
|
|
4361
|
-
|
|
4582
|
+
});
|
|
4583
|
+
if (!l2GasParams) {
|
|
4584
|
+
throw new Error("Failed to estimate L2 gas for deposit.");
|
|
4585
|
+
}
|
|
4586
|
+
const baseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
4362
4587
|
const l2Contract = p.to ?? ctx.sender;
|
|
4363
4588
|
const l2Value = p.amount;
|
|
4364
4589
|
const mintValue = baseCost + ctx.operatorTip + l2Value;
|
|
4365
4590
|
const req = buildDirectRequestStruct({
|
|
4366
4591
|
chainId: ctx.chainIdL2,
|
|
4367
4592
|
mintValue,
|
|
4368
|
-
l2GasLimit:
|
|
4593
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
4369
4594
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
4370
4595
|
refundRecipient: ctx.refundRecipient,
|
|
4371
4596
|
l2Contract,
|
|
4372
4597
|
l2Value
|
|
4373
4598
|
});
|
|
4374
|
-
const sim = await
|
|
4599
|
+
const sim = await wrapAs2(
|
|
4375
4600
|
"RPC",
|
|
4376
4601
|
OP_DEPOSITS.eth.estGas,
|
|
4377
4602
|
() => ctx.client.l1.simulateContract({
|
|
@@ -4387,33 +4612,53 @@ function routeEthDirect() {
|
|
|
4387
4612
|
message: "Failed to simulate Bridgehub.requestL2TransactionDirect."
|
|
4388
4613
|
}
|
|
4389
4614
|
);
|
|
4390
|
-
const
|
|
4615
|
+
const data = viem.encodeFunctionData({
|
|
4616
|
+
abi: sim.request.abi,
|
|
4617
|
+
functionName: sim.request.functionName,
|
|
4618
|
+
args: sim.request.args
|
|
4619
|
+
});
|
|
4620
|
+
const l1TxCandidate = {
|
|
4621
|
+
to: ctx.bridgehub,
|
|
4622
|
+
data,
|
|
4623
|
+
value: mintValue,
|
|
4624
|
+
from: ctx.sender,
|
|
4625
|
+
...ctx.gasOverrides
|
|
4626
|
+
};
|
|
4627
|
+
const l1Gas = await quoteL1Gas2({
|
|
4628
|
+
ctx,
|
|
4629
|
+
tx: l1TxCandidate,
|
|
4630
|
+
overrides: ctx.gasOverrides
|
|
4631
|
+
});
|
|
4391
4632
|
const steps = [
|
|
4392
4633
|
{
|
|
4393
4634
|
key: "bridgehub:direct",
|
|
4394
4635
|
kind: "bridgehub:direct",
|
|
4395
4636
|
description: "Bridge ETH via Bridgehub.requestL2TransactionDirect",
|
|
4396
|
-
tx: { ...sim.request, ...
|
|
4637
|
+
tx: { ...sim.request, ...l1Gas }
|
|
4397
4638
|
}
|
|
4398
4639
|
];
|
|
4640
|
+
const fees = buildFeeBreakdown({
|
|
4641
|
+
feeToken: ETH_ADDRESS,
|
|
4642
|
+
l1Gas,
|
|
4643
|
+
l2Gas: l2GasParams,
|
|
4644
|
+
l2BaseCost: baseCost,
|
|
4645
|
+
operatorTip: ctx.operatorTip,
|
|
4646
|
+
mintValue
|
|
4647
|
+
});
|
|
4399
4648
|
return {
|
|
4400
4649
|
steps,
|
|
4401
4650
|
approvals: [],
|
|
4402
|
-
|
|
4651
|
+
fees
|
|
4403
4652
|
};
|
|
4404
4653
|
}
|
|
4405
4654
|
};
|
|
4406
4655
|
}
|
|
4407
|
-
|
|
4408
|
-
// src/adapters/viem/resources/deposits/routes/erc20-nonbase.ts
|
|
4409
|
-
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
4410
|
-
var BASE_COST_BUFFER_BPS = 100n;
|
|
4411
|
-
var BPS = 10000n;
|
|
4412
|
-
var withBuffer = (x) => x * (BPS + BASE_COST_BUFFER_BPS) / BPS;
|
|
4656
|
+
var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
|
|
4413
4657
|
function routeErc20NonBase() {
|
|
4414
4658
|
return {
|
|
4659
|
+
// TODO: do we even need these validations?
|
|
4415
4660
|
async preflight(p, ctx) {
|
|
4416
|
-
await
|
|
4661
|
+
await wrapAs3(
|
|
4417
4662
|
"VALIDATION",
|
|
4418
4663
|
OP_DEPOSITS.nonbase.assertNotEthAsset,
|
|
4419
4664
|
() => {
|
|
@@ -4423,18 +4668,8 @@ function routeErc20NonBase() {
|
|
|
4423
4668
|
},
|
|
4424
4669
|
{ ctx: { token: p.token } }
|
|
4425
4670
|
);
|
|
4426
|
-
const baseToken = await
|
|
4427
|
-
|
|
4428
|
-
OP_DEPOSITS.nonbase.baseToken,
|
|
4429
|
-
() => ctx.client.l1.readContract({
|
|
4430
|
-
address: ctx.bridgehub,
|
|
4431
|
-
abi: IBridgehub_default,
|
|
4432
|
-
functionName: "baseToken",
|
|
4433
|
-
args: [ctx.chainIdL2]
|
|
4434
|
-
}),
|
|
4435
|
-
{ ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 } }
|
|
4436
|
-
);
|
|
4437
|
-
await wrapAs2(
|
|
4671
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
4672
|
+
await wrapAs3(
|
|
4438
4673
|
"VALIDATION",
|
|
4439
4674
|
OP_DEPOSITS.nonbase.assertNonBaseToken,
|
|
4440
4675
|
() => {
|
|
@@ -4444,63 +4679,49 @@ function routeErc20NonBase() {
|
|
|
4444
4679
|
},
|
|
4445
4680
|
{ ctx: { depositToken: p.token, baseToken } }
|
|
4446
4681
|
);
|
|
4447
|
-
return;
|
|
4448
4682
|
},
|
|
4449
4683
|
async build(p, ctx) {
|
|
4450
|
-
const
|
|
4451
|
-
const
|
|
4452
|
-
const
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
);
|
|
4463
|
-
|
|
4464
|
-
const
|
|
4465
|
-
const
|
|
4466
|
-
"CONTRACT",
|
|
4467
|
-
OP_DEPOSITS.nonbase.baseCost,
|
|
4468
|
-
() => ctx.client.l1.readContract({
|
|
4469
|
-
address: ctx.bridgehub,
|
|
4470
|
-
abi: IBridgehub_default,
|
|
4471
|
-
functionName: "l2TransactionBaseCost",
|
|
4472
|
-
args: [ctx.chainIdL2, gasPriceForBaseCost, l2GasLimitUsed, ctx.gasPerPubdata]
|
|
4473
|
-
}),
|
|
4474
|
-
{ ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 } }
|
|
4475
|
-
);
|
|
4476
|
-
const baseCost = rawBaseCost;
|
|
4477
|
-
const mintValue = withBuffer(baseCost + ctx.operatorTip);
|
|
4684
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
4685
|
+
const baseIsEth = isETH(baseToken);
|
|
4686
|
+
const assetRouter = ctx.l1AssetRouter;
|
|
4687
|
+
const l2Gas = await determineErc20L2Gas({
|
|
4688
|
+
ctx,
|
|
4689
|
+
l1Token: p.token,
|
|
4690
|
+
modelTx: {
|
|
4691
|
+
to: p.to ?? ctx.sender,
|
|
4692
|
+
from: ctx.sender,
|
|
4693
|
+
data: "0x",
|
|
4694
|
+
value: 0n
|
|
4695
|
+
}
|
|
4696
|
+
});
|
|
4697
|
+
if (!l2Gas) throw new Error("Failed to establish L2 gas parameters.");
|
|
4698
|
+
const l2BaseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2Gas.gasLimit });
|
|
4699
|
+
const mintValue = l2BaseCost + ctx.operatorTip;
|
|
4478
4700
|
const approvals = [];
|
|
4479
4701
|
const steps = [];
|
|
4480
|
-
const depositAllowance = await
|
|
4702
|
+
const depositAllowance = await wrapAs3(
|
|
4481
4703
|
"CONTRACT",
|
|
4482
|
-
OP_DEPOSITS.nonbase.
|
|
4704
|
+
OP_DEPOSITS.nonbase.allowanceToken,
|
|
4483
4705
|
() => ctx.client.l1.readContract({
|
|
4484
4706
|
address: p.token,
|
|
4485
4707
|
abi: IERC20_default,
|
|
4486
4708
|
functionName: "allowance",
|
|
4487
|
-
args: [ctx.sender,
|
|
4709
|
+
args: [ctx.sender, assetRouter]
|
|
4488
4710
|
}),
|
|
4489
4711
|
{
|
|
4490
|
-
ctx: { where: "erc20.allowance", token: p.token, spender:
|
|
4491
|
-
message: "Failed to read
|
|
4712
|
+
ctx: { where: "erc20.allowance", token: p.token, spender: assetRouter },
|
|
4713
|
+
message: "Failed to read deposit-token allowance."
|
|
4492
4714
|
}
|
|
4493
4715
|
);
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
const approveDepReq = await wrapAs2(
|
|
4716
|
+
if (depositAllowance < p.amount) {
|
|
4717
|
+
const approveSim = await wrapAs3(
|
|
4497
4718
|
"CONTRACT",
|
|
4498
4719
|
OP_DEPOSITS.nonbase.estGas,
|
|
4499
4720
|
() => ctx.client.l1.simulateContract({
|
|
4500
4721
|
address: p.token,
|
|
4501
4722
|
abi: IERC20_default,
|
|
4502
4723
|
functionName: "approve",
|
|
4503
|
-
args: [
|
|
4724
|
+
args: [assetRouter, p.amount],
|
|
4504
4725
|
account: ctx.client.account
|
|
4505
4726
|
}),
|
|
4506
4727
|
{
|
|
@@ -4508,60 +4729,55 @@ function routeErc20NonBase() {
|
|
|
4508
4729
|
message: "Failed to simulate deposit token approve."
|
|
4509
4730
|
}
|
|
4510
4731
|
);
|
|
4511
|
-
approvals.push({ token: p.token, spender:
|
|
4732
|
+
approvals.push({ token: p.token, spender: assetRouter, amount: p.amount });
|
|
4512
4733
|
steps.push({
|
|
4513
|
-
key: `approve:${p.token}:${
|
|
4734
|
+
key: `approve:${p.token}:${assetRouter}`,
|
|
4514
4735
|
kind: "approve",
|
|
4515
4736
|
description: `Approve deposit token for amount`,
|
|
4516
|
-
tx: { ...
|
|
4737
|
+
tx: { ...approveSim.request }
|
|
4517
4738
|
});
|
|
4518
4739
|
}
|
|
4519
|
-
const baseIsEth = isETH(baseToken);
|
|
4520
|
-
let msgValue = 0n;
|
|
4521
4740
|
if (!baseIsEth) {
|
|
4522
|
-
const baseAllowance = await
|
|
4741
|
+
const baseAllowance = await wrapAs3(
|
|
4523
4742
|
"CONTRACT",
|
|
4524
|
-
OP_DEPOSITS.nonbase.
|
|
4743
|
+
OP_DEPOSITS.nonbase.allowanceBase,
|
|
4525
4744
|
() => ctx.client.l1.readContract({
|
|
4526
4745
|
address: baseToken,
|
|
4527
4746
|
abi: IERC20_default,
|
|
4528
4747
|
functionName: "allowance",
|
|
4529
|
-
args: [ctx.sender,
|
|
4748
|
+
args: [ctx.sender, assetRouter]
|
|
4530
4749
|
}),
|
|
4531
4750
|
{
|
|
4532
|
-
ctx: { where: "erc20.allowance", token: baseToken, spender:
|
|
4751
|
+
ctx: { where: "erc20.allowance", token: baseToken, spender: assetRouter },
|
|
4533
4752
|
message: "Failed to read base-token allowance."
|
|
4534
4753
|
}
|
|
4535
4754
|
);
|
|
4536
4755
|
if (baseAllowance < mintValue) {
|
|
4537
|
-
const
|
|
4756
|
+
const approveBaseSim = await wrapAs3(
|
|
4538
4757
|
"CONTRACT",
|
|
4539
4758
|
OP_DEPOSITS.nonbase.estGas,
|
|
4540
4759
|
() => ctx.client.l1.simulateContract({
|
|
4541
4760
|
address: baseToken,
|
|
4542
4761
|
abi: IERC20_default,
|
|
4543
4762
|
functionName: "approve",
|
|
4544
|
-
args: [
|
|
4763
|
+
args: [assetRouter, mintValue],
|
|
4545
4764
|
account: ctx.client.account
|
|
4546
4765
|
}),
|
|
4547
4766
|
{
|
|
4548
4767
|
ctx: { where: "l1.simulateContract", to: baseToken },
|
|
4549
|
-
message: "Failed to simulate base
|
|
4768
|
+
message: "Failed to simulate base token approve."
|
|
4550
4769
|
}
|
|
4551
4770
|
);
|
|
4552
|
-
approvals.push({ token: baseToken, spender:
|
|
4771
|
+
approvals.push({ token: baseToken, spender: assetRouter, amount: mintValue });
|
|
4553
4772
|
steps.push({
|
|
4554
|
-
key: `approve:${baseToken}:${
|
|
4773
|
+
key: `approve:${baseToken}:${assetRouter}`,
|
|
4555
4774
|
kind: "approve",
|
|
4556
4775
|
description: `Approve base token for mintValue`,
|
|
4557
|
-
tx: { ...
|
|
4776
|
+
tx: { ...approveBaseSim.request }
|
|
4558
4777
|
});
|
|
4559
4778
|
}
|
|
4560
|
-
msgValue = 0n;
|
|
4561
|
-
} else {
|
|
4562
|
-
msgValue = mintValue;
|
|
4563
4779
|
}
|
|
4564
|
-
const secondBridgeCalldata = await
|
|
4780
|
+
const secondBridgeCalldata = await wrapAs3(
|
|
4565
4781
|
"INTERNAL",
|
|
4566
4782
|
OP_DEPOSITS.nonbase.encodeCalldata,
|
|
4567
4783
|
() => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, p.to ?? ctx.sender)),
|
|
@@ -4570,44 +4786,60 @@ function routeErc20NonBase() {
|
|
|
4570
4786
|
where: "encodeSecondBridgeErc20Args",
|
|
4571
4787
|
token: p.token,
|
|
4572
4788
|
amount: p.amount.toString()
|
|
4573
|
-
}
|
|
4789
|
+
},
|
|
4790
|
+
message: "Failed to encode bridging calldata."
|
|
4574
4791
|
}
|
|
4575
4792
|
);
|
|
4576
|
-
const
|
|
4793
|
+
const requestStruct = {
|
|
4577
4794
|
chainId: ctx.chainIdL2,
|
|
4578
4795
|
mintValue,
|
|
4579
4796
|
l2Value: 0n,
|
|
4580
|
-
l2GasLimit:
|
|
4797
|
+
l2GasLimit: l2Gas.gasLimit,
|
|
4581
4798
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
4582
4799
|
refundRecipient: ctx.refundRecipient,
|
|
4583
|
-
secondBridgeAddress:
|
|
4800
|
+
secondBridgeAddress: assetRouter,
|
|
4584
4801
|
secondBridgeValue: 0n,
|
|
4585
4802
|
secondBridgeCalldata
|
|
4586
4803
|
};
|
|
4804
|
+
const msgValue = baseIsEth ? mintValue : 0n;
|
|
4805
|
+
const calldata = viem.encodeFunctionData({
|
|
4806
|
+
abi: IBridgehub_default,
|
|
4807
|
+
functionName: "requestL2TransactionTwoBridges",
|
|
4808
|
+
args: [requestStruct]
|
|
4809
|
+
});
|
|
4810
|
+
const l1TxCandidate = {
|
|
4811
|
+
to: ctx.bridgehub,
|
|
4812
|
+
data: calldata,
|
|
4813
|
+
value: msgValue,
|
|
4814
|
+
from: ctx.sender,
|
|
4815
|
+
...ctx.gasOverrides
|
|
4816
|
+
};
|
|
4817
|
+
const l1Gas = await quoteL1Gas2({
|
|
4818
|
+
ctx,
|
|
4819
|
+
tx: l1TxCandidate,
|
|
4820
|
+
overrides: ctx.gasOverrides,
|
|
4821
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
4822
|
+
});
|
|
4587
4823
|
const approvalsNeeded = approvals.length > 0;
|
|
4588
4824
|
let bridgeTx;
|
|
4589
|
-
let resolvedL1GasLimit;
|
|
4590
|
-
const gasOverride = txFeeOverrides.gas;
|
|
4591
4825
|
if (approvalsNeeded) {
|
|
4592
4826
|
bridgeTx = {
|
|
4593
4827
|
address: ctx.bridgehub,
|
|
4594
4828
|
abi: IBridgehub_default,
|
|
4595
4829
|
functionName: "requestL2TransactionTwoBridges",
|
|
4596
|
-
args: [
|
|
4830
|
+
args: [requestStruct],
|
|
4597
4831
|
value: msgValue,
|
|
4598
|
-
account: ctx.client.account
|
|
4599
|
-
...txFeeOverrides
|
|
4832
|
+
account: ctx.client.account
|
|
4600
4833
|
};
|
|
4601
|
-
resolvedL1GasLimit = gasOverride ?? ctx.l2GasLimit;
|
|
4602
4834
|
} else {
|
|
4603
|
-
const sim = await
|
|
4835
|
+
const sim = await wrapAs3(
|
|
4604
4836
|
"CONTRACT",
|
|
4605
4837
|
OP_DEPOSITS.nonbase.estGas,
|
|
4606
4838
|
() => ctx.client.l1.simulateContract({
|
|
4607
4839
|
address: ctx.bridgehub,
|
|
4608
4840
|
abi: IBridgehub_default,
|
|
4609
4841
|
functionName: "requestL2TransactionTwoBridges",
|
|
4610
|
-
args: [
|
|
4842
|
+
args: [requestStruct],
|
|
4611
4843
|
value: msgValue,
|
|
4612
4844
|
account: ctx.client.account
|
|
4613
4845
|
}),
|
|
@@ -4616,33 +4848,44 @@ function routeErc20NonBase() {
|
|
|
4616
4848
|
message: "Failed to simulate two-bridges request."
|
|
4617
4849
|
}
|
|
4618
4850
|
);
|
|
4619
|
-
bridgeTx = { ...sim.request
|
|
4620
|
-
|
|
4851
|
+
bridgeTx = { ...sim.request };
|
|
4852
|
+
}
|
|
4853
|
+
if (l1Gas) {
|
|
4854
|
+
bridgeTx = {
|
|
4855
|
+
...bridgeTx,
|
|
4856
|
+
gas: l1Gas.gasLimit,
|
|
4857
|
+
maxFeePerGas: l1Gas.maxFeePerGas,
|
|
4858
|
+
maxPriorityFeePerGas: l1Gas.maxPriorityFeePerGas
|
|
4859
|
+
};
|
|
4621
4860
|
}
|
|
4622
4861
|
steps.push({
|
|
4623
|
-
key: "bridgehub:two-bridges:nonbase",
|
|
4862
|
+
key: "bridgehub:two-bridges:erc20-nonbase",
|
|
4624
4863
|
kind: "bridgehub:two-bridges",
|
|
4625
4864
|
description: baseIsEth ? "Bridge ERC-20 (fees in ETH) via Bridgehub.requestL2TransactionTwoBridges" : "Bridge ERC-20 (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
|
|
4626
4865
|
tx: bridgeTx
|
|
4627
4866
|
});
|
|
4867
|
+
const fees = buildFeeBreakdown({
|
|
4868
|
+
feeToken: baseToken,
|
|
4869
|
+
l1Gas,
|
|
4870
|
+
l2Gas,
|
|
4871
|
+
l2BaseCost,
|
|
4872
|
+
operatorTip: ctx.operatorTip,
|
|
4873
|
+
mintValue
|
|
4874
|
+
});
|
|
4628
4875
|
return {
|
|
4629
4876
|
steps,
|
|
4630
4877
|
approvals,
|
|
4631
|
-
|
|
4878
|
+
fees
|
|
4632
4879
|
};
|
|
4633
4880
|
}
|
|
4634
4881
|
};
|
|
4635
4882
|
}
|
|
4636
|
-
|
|
4637
|
-
// src/adapters/viem/resources/deposits/routes/eth-nonbase.ts
|
|
4638
|
-
var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
|
|
4639
|
-
var BASE_COST_BUFFER_BPS2 = 100n;
|
|
4640
|
-
var BPS2 = 10000n;
|
|
4641
|
-
var withBuffer2 = (x) => x * (BPS2 + BASE_COST_BUFFER_BPS2) / BPS2;
|
|
4883
|
+
var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
|
|
4642
4884
|
function routeEthNonBase() {
|
|
4643
4885
|
return {
|
|
4886
|
+
// TODO: do we even need these validations?
|
|
4644
4887
|
async preflight(p, ctx) {
|
|
4645
|
-
await
|
|
4888
|
+
await wrapAs4(
|
|
4646
4889
|
"VALIDATION",
|
|
4647
4890
|
OP_DEPOSITS.ethNonBase.assertEthAsset,
|
|
4648
4891
|
() => {
|
|
@@ -4652,21 +4895,8 @@ function routeEthNonBase() {
|
|
|
4652
4895
|
},
|
|
4653
4896
|
{ ctx: { token: p.token } }
|
|
4654
4897
|
);
|
|
4655
|
-
const baseToken = await
|
|
4656
|
-
|
|
4657
|
-
OP_DEPOSITS.ethNonBase.baseToken,
|
|
4658
|
-
() => ctx.client.l1.readContract({
|
|
4659
|
-
address: ctx.bridgehub,
|
|
4660
|
-
abi: IBridgehub_default,
|
|
4661
|
-
functionName: "baseToken",
|
|
4662
|
-
args: [ctx.chainIdL2]
|
|
4663
|
-
}),
|
|
4664
|
-
{
|
|
4665
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
4666
|
-
message: "Failed to read base token."
|
|
4667
|
-
}
|
|
4668
|
-
);
|
|
4669
|
-
await wrapAs3(
|
|
4898
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
4899
|
+
await wrapAs4(
|
|
4670
4900
|
"VALIDATION",
|
|
4671
4901
|
OP_DEPOSITS.ethNonBase.assertNonEthBase,
|
|
4672
4902
|
() => {
|
|
@@ -4676,7 +4906,7 @@ function routeEthNonBase() {
|
|
|
4676
4906
|
},
|
|
4677
4907
|
{ ctx: { baseToken, chainIdL2: ctx.chainIdL2 } }
|
|
4678
4908
|
);
|
|
4679
|
-
const ethBal = await
|
|
4909
|
+
const ethBal = await wrapAs4(
|
|
4680
4910
|
"RPC",
|
|
4681
4911
|
OP_DEPOSITS.ethNonBase.ethBalance,
|
|
4682
4912
|
() => ctx.client.l1.getBalance({ address: ctx.sender }),
|
|
@@ -4685,7 +4915,7 @@ function routeEthNonBase() {
|
|
|
4685
4915
|
message: "Failed to read L1 ETH balance."
|
|
4686
4916
|
}
|
|
4687
4917
|
);
|
|
4688
|
-
await
|
|
4918
|
+
await wrapAs4(
|
|
4689
4919
|
"VALIDATION",
|
|
4690
4920
|
OP_DEPOSITS.ethNonBase.assertEthBalance,
|
|
4691
4921
|
() => {
|
|
@@ -4695,45 +4925,27 @@ function routeEthNonBase() {
|
|
|
4695
4925
|
},
|
|
4696
4926
|
{ ctx: { required: p.amount.toString(), balance: ethBal.toString() } }
|
|
4697
4927
|
);
|
|
4698
|
-
return;
|
|
4699
4928
|
},
|
|
4700
4929
|
async build(p, ctx) {
|
|
4701
|
-
const
|
|
4702
|
-
const
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
const rawBaseCost = await wrapAs3(
|
|
4718
|
-
"CONTRACT",
|
|
4719
|
-
OP_DEPOSITS.ethNonBase.baseCost,
|
|
4720
|
-
() => ctx.client.l1.readContract({
|
|
4721
|
-
address: ctx.bridgehub,
|
|
4722
|
-
abi: IBridgehub_default,
|
|
4723
|
-
functionName: "l2TransactionBaseCost",
|
|
4724
|
-
args: [ctx.chainIdL2, gasPriceForBaseCost, ctx.l2GasLimit, ctx.gasPerPubdata]
|
|
4725
|
-
}),
|
|
4726
|
-
{
|
|
4727
|
-
ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
|
|
4728
|
-
message: "Could not fetch L2 base cost."
|
|
4729
|
-
}
|
|
4730
|
-
);
|
|
4731
|
-
const baseCost = BigInt(rawBaseCost);
|
|
4732
|
-
const mintValueRaw = baseCost + ctx.operatorTip;
|
|
4733
|
-
const mintValue = withBuffer2(mintValueRaw);
|
|
4930
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
4931
|
+
const l2TxModel = {
|
|
4932
|
+
to: p.to ?? ctx.sender,
|
|
4933
|
+
from: ctx.sender,
|
|
4934
|
+
data: "0x",
|
|
4935
|
+
value: 0n
|
|
4936
|
+
};
|
|
4937
|
+
const l2Gas = await quoteL2Gas2({
|
|
4938
|
+
ctx,
|
|
4939
|
+
route: "eth-nonbase",
|
|
4940
|
+
l2TxForModeling: l2TxModel,
|
|
4941
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
4942
|
+
});
|
|
4943
|
+
if (!l2Gas) throw new Error("Failed to estimate L2 gas parameters.");
|
|
4944
|
+
const l2BaseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2Gas.gasLimit });
|
|
4945
|
+
const mintValue = l2BaseCost + ctx.operatorTip;
|
|
4734
4946
|
const approvals = [];
|
|
4735
4947
|
const steps = [];
|
|
4736
|
-
const allowance = await
|
|
4948
|
+
const allowance = await wrapAs4(
|
|
4737
4949
|
"CONTRACT",
|
|
4738
4950
|
OP_DEPOSITS.ethNonBase.allowanceBase,
|
|
4739
4951
|
() => ctx.client.l1.readContract({
|
|
@@ -4749,7 +4961,7 @@ function routeEthNonBase() {
|
|
|
4749
4961
|
);
|
|
4750
4962
|
const needsApprove = allowance < mintValue;
|
|
4751
4963
|
if (needsApprove) {
|
|
4752
|
-
const approveSim = await
|
|
4964
|
+
const approveSim = await wrapAs4(
|
|
4753
4965
|
"CONTRACT",
|
|
4754
4966
|
OP_DEPOSITS.ethNonBase.estGas,
|
|
4755
4967
|
() => ctx.client.l1.simulateContract({
|
|
@@ -4768,11 +4980,11 @@ function routeEthNonBase() {
|
|
|
4768
4980
|
steps.push({
|
|
4769
4981
|
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
4770
4982
|
kind: "approve",
|
|
4771
|
-
description: `Approve base token for mintValue`,
|
|
4983
|
+
description: `Approve base token for fees (mintValue)`,
|
|
4772
4984
|
tx: { ...approveSim.request }
|
|
4773
4985
|
});
|
|
4774
4986
|
}
|
|
4775
|
-
const secondBridgeCalldata = await
|
|
4987
|
+
const secondBridgeCalldata = await wrapAs4(
|
|
4776
4988
|
"INTERNAL",
|
|
4777
4989
|
OP_DEPOSITS.ethNonBase.encodeCalldata,
|
|
4778
4990
|
() => Promise.resolve(encodeSecondBridgeEthArgs(p.amount, p.to ?? ctx.sender)),
|
|
@@ -4785,11 +4997,11 @@ function routeEthNonBase() {
|
|
|
4785
4997
|
message: "Failed to encode ETH bridging calldata."
|
|
4786
4998
|
}
|
|
4787
4999
|
);
|
|
4788
|
-
const
|
|
5000
|
+
const requestStruct = {
|
|
4789
5001
|
chainId: ctx.chainIdL2,
|
|
4790
5002
|
mintValue,
|
|
4791
|
-
l2Value:
|
|
4792
|
-
l2GasLimit:
|
|
5003
|
+
l2Value: p.amount,
|
|
5004
|
+
l2GasLimit: l2Gas.gasLimit,
|
|
4793
5005
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
4794
5006
|
refundRecipient: ctx.refundRecipient,
|
|
4795
5007
|
secondBridgeAddress: ctx.l1AssetRouter,
|
|
@@ -4797,29 +5009,32 @@ function routeEthNonBase() {
|
|
|
4797
5009
|
secondBridgeCalldata
|
|
4798
5010
|
};
|
|
4799
5011
|
let bridgeTx;
|
|
4800
|
-
let
|
|
5012
|
+
let calldata;
|
|
4801
5013
|
if (needsApprove) {
|
|
4802
5014
|
bridgeTx = {
|
|
4803
5015
|
address: ctx.bridgehub,
|
|
4804
5016
|
abi: IBridgehub_default,
|
|
4805
5017
|
functionName: "requestL2TransactionTwoBridges",
|
|
4806
|
-
args: [
|
|
5018
|
+
args: [requestStruct],
|
|
4807
5019
|
value: p.amount,
|
|
4808
5020
|
// base ≠ ETH ⇒ msg.value == secondBridgeValue
|
|
4809
5021
|
account: ctx.client.account
|
|
4810
5022
|
};
|
|
4811
|
-
|
|
5023
|
+
calldata = viem.encodeFunctionData({
|
|
5024
|
+
abi: IBridgehub_default,
|
|
5025
|
+
functionName: "requestL2TransactionTwoBridges",
|
|
5026
|
+
args: [requestStruct]
|
|
5027
|
+
});
|
|
4812
5028
|
} else {
|
|
4813
|
-
const
|
|
5029
|
+
const sim = await wrapAs4(
|
|
4814
5030
|
"CONTRACT",
|
|
4815
5031
|
OP_DEPOSITS.ethNonBase.estGas,
|
|
4816
5032
|
() => ctx.client.l1.simulateContract({
|
|
4817
5033
|
address: ctx.bridgehub,
|
|
4818
5034
|
abi: IBridgehub_default,
|
|
4819
5035
|
functionName: "requestL2TransactionTwoBridges",
|
|
4820
|
-
args: [
|
|
5036
|
+
args: [requestStruct],
|
|
4821
5037
|
value: p.amount,
|
|
4822
|
-
// base ≠ ETH ⇒ msg.value == secondBridgeValue
|
|
4823
5038
|
account: ctx.client.account
|
|
4824
5039
|
}),
|
|
4825
5040
|
{
|
|
@@ -4827,8 +5042,33 @@ function routeEthNonBase() {
|
|
|
4827
5042
|
message: "Failed to simulate Bridgehub two-bridges request."
|
|
4828
5043
|
}
|
|
4829
5044
|
);
|
|
4830
|
-
|
|
4831
|
-
|
|
5045
|
+
calldata = viem.encodeFunctionData({
|
|
5046
|
+
abi: sim.request.abi,
|
|
5047
|
+
functionName: sim.request.functionName,
|
|
5048
|
+
args: sim.request.args
|
|
5049
|
+
});
|
|
5050
|
+
bridgeTx = { ...sim.request };
|
|
5051
|
+
}
|
|
5052
|
+
const l1TxCandidate = {
|
|
5053
|
+
to: ctx.bridgehub,
|
|
5054
|
+
data: calldata,
|
|
5055
|
+
value: p.amount,
|
|
5056
|
+
from: ctx.sender,
|
|
5057
|
+
...ctx.gasOverrides
|
|
5058
|
+
};
|
|
5059
|
+
const l1Gas = await quoteL1Gas2({
|
|
5060
|
+
ctx,
|
|
5061
|
+
tx: l1TxCandidate,
|
|
5062
|
+
overrides: ctx.gasOverrides,
|
|
5063
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
5064
|
+
});
|
|
5065
|
+
if (l1Gas) {
|
|
5066
|
+
bridgeTx = {
|
|
5067
|
+
...bridgeTx,
|
|
5068
|
+
gas: l1Gas.gasLimit,
|
|
5069
|
+
maxFeePerGas: l1Gas.maxFeePerGas,
|
|
5070
|
+
maxPriorityFeePerGas: l1Gas.maxPriorityFeePerGas
|
|
5071
|
+
};
|
|
4832
5072
|
}
|
|
4833
5073
|
steps.push({
|
|
4834
5074
|
key: "bridgehub:two-bridges:eth-nonbase",
|
|
@@ -4836,24 +5076,27 @@ function routeEthNonBase() {
|
|
|
4836
5076
|
description: "Bridge ETH (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
|
|
4837
5077
|
tx: bridgeTx
|
|
4838
5078
|
});
|
|
5079
|
+
const fees = buildFeeBreakdown({
|
|
5080
|
+
feeToken: baseToken,
|
|
5081
|
+
l1Gas,
|
|
5082
|
+
l2Gas,
|
|
5083
|
+
l2BaseCost,
|
|
5084
|
+
operatorTip: ctx.operatorTip,
|
|
5085
|
+
mintValue
|
|
5086
|
+
});
|
|
4839
5087
|
return {
|
|
4840
5088
|
steps,
|
|
4841
5089
|
approvals,
|
|
4842
|
-
|
|
5090
|
+
fees
|
|
4843
5091
|
};
|
|
4844
5092
|
}
|
|
4845
5093
|
};
|
|
4846
5094
|
}
|
|
4847
|
-
|
|
4848
|
-
// src/adapters/viem/resources/deposits/routes/erc20-base.ts
|
|
4849
|
-
var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
|
|
4850
|
-
var BASE_COST_BUFFER_BPS3 = 100n;
|
|
4851
|
-
var BPS3 = 10000n;
|
|
4852
|
-
var withBuffer3 = (x) => x * (BPS3 + BASE_COST_BUFFER_BPS3) / BPS3;
|
|
5095
|
+
var { wrapAs: wrapAs5 } = createErrorHandlers("deposits");
|
|
4853
5096
|
function routeErc20Base() {
|
|
4854
5097
|
return {
|
|
4855
5098
|
async preflight(p, ctx) {
|
|
4856
|
-
await
|
|
5099
|
+
await wrapAs5(
|
|
4857
5100
|
"VALIDATION",
|
|
4858
5101
|
OP_DEPOSITS.base.assertErc20Asset,
|
|
4859
5102
|
() => {
|
|
@@ -4863,21 +5106,8 @@ function routeErc20Base() {
|
|
|
4863
5106
|
},
|
|
4864
5107
|
{ ctx: { token: p.token } }
|
|
4865
5108
|
);
|
|
4866
|
-
const baseToken = await
|
|
4867
|
-
|
|
4868
|
-
OP_DEPOSITS.base.baseToken,
|
|
4869
|
-
() => ctx.client.l1.readContract({
|
|
4870
|
-
address: ctx.bridgehub,
|
|
4871
|
-
abi: IBridgehub_default,
|
|
4872
|
-
functionName: "baseToken",
|
|
4873
|
-
args: [ctx.chainIdL2]
|
|
4874
|
-
}),
|
|
4875
|
-
{
|
|
4876
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
4877
|
-
message: "Failed to read base token."
|
|
4878
|
-
}
|
|
4879
|
-
);
|
|
4880
|
-
await wrapAs4(
|
|
5109
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
5110
|
+
await wrapAs5(
|
|
4881
5111
|
"VALIDATION",
|
|
4882
5112
|
OP_DEPOSITS.base.assertMatchesBase,
|
|
4883
5113
|
() => {
|
|
@@ -4887,45 +5117,27 @@ function routeErc20Base() {
|
|
|
4887
5117
|
},
|
|
4888
5118
|
{ ctx: { baseToken, provided: p.token, chainIdL2: ctx.chainIdL2 } }
|
|
4889
5119
|
);
|
|
4890
|
-
return;
|
|
4891
5120
|
},
|
|
4892
5121
|
async build(p, ctx) {
|
|
4893
|
-
const
|
|
4894
|
-
const
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
"
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
const
|
|
4911
|
-
|
|
4912
|
-
OP_DEPOSITS.base.baseCost,
|
|
4913
|
-
() => ctx.client.l1.readContract({
|
|
4914
|
-
address: ctx.bridgehub,
|
|
4915
|
-
abi: IBridgehub_default,
|
|
4916
|
-
functionName: "l2TransactionBaseCost",
|
|
4917
|
-
args: [ctx.chainIdL2, gasPriceForBaseCost, ctx.l2GasLimit, ctx.gasPerPubdata]
|
|
4918
|
-
}),
|
|
4919
|
-
{
|
|
4920
|
-
ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
|
|
4921
|
-
message: "Could not fetch L2 base cost from Bridgehub."
|
|
4922
|
-
}
|
|
4923
|
-
);
|
|
4924
|
-
const baseCost = rawBaseCost;
|
|
4925
|
-
const l2Value = p.amount;
|
|
4926
|
-
const rawMintValue = baseCost + ctx.operatorTip + l2Value;
|
|
4927
|
-
const mintValue = withBuffer3(rawMintValue);
|
|
4928
|
-
const allowance = await wrapAs4(
|
|
5122
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
5123
|
+
const l2TxModel = {
|
|
5124
|
+
to: p.to ?? ctx.sender,
|
|
5125
|
+
from: ctx.sender,
|
|
5126
|
+
data: "0x",
|
|
5127
|
+
value: 0n
|
|
5128
|
+
};
|
|
5129
|
+
const l2Gas = await quoteL2Gas2({
|
|
5130
|
+
ctx,
|
|
5131
|
+
route: "erc20-base",
|
|
5132
|
+
l2TxForModeling: l2TxModel,
|
|
5133
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
5134
|
+
});
|
|
5135
|
+
if (!l2Gas) throw new Error("Failed to estimate L2 gas parameters.");
|
|
5136
|
+
const l2BaseCost = await quoteL2BaseCost({ ctx, l2GasLimit: l2Gas.gasLimit });
|
|
5137
|
+
const mintValue = l2BaseCost + ctx.operatorTip + p.amount;
|
|
5138
|
+
const approvals = [];
|
|
5139
|
+
const steps = [];
|
|
5140
|
+
const allowance = await wrapAs5(
|
|
4929
5141
|
"CONTRACT",
|
|
4930
5142
|
OP_DEPOSITS.base.allowance,
|
|
4931
5143
|
() => ctx.client.l1.readContract({
|
|
@@ -4939,11 +5151,9 @@ function routeErc20Base() {
|
|
|
4939
5151
|
message: "Failed to read base-token allowance."
|
|
4940
5152
|
}
|
|
4941
5153
|
);
|
|
4942
|
-
const approvals = [];
|
|
4943
|
-
const steps = [];
|
|
4944
5154
|
const needsApprove = allowance < mintValue;
|
|
4945
5155
|
if (needsApprove) {
|
|
4946
|
-
const approveSim = await
|
|
5156
|
+
const approveSim = await wrapAs5(
|
|
4947
5157
|
"CONTRACT",
|
|
4948
5158
|
OP_DEPOSITS.base.estGas,
|
|
4949
5159
|
() => ctx.client.l1.simulateContract({
|
|
@@ -4963,20 +5173,20 @@ function routeErc20Base() {
|
|
|
4963
5173
|
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
4964
5174
|
kind: "approve",
|
|
4965
5175
|
description: "Approve base token for mintValue",
|
|
4966
|
-
tx: { ...approveSim.request
|
|
5176
|
+
tx: { ...approveSim.request }
|
|
4967
5177
|
});
|
|
4968
5178
|
}
|
|
4969
5179
|
const req = buildDirectRequestStruct({
|
|
4970
5180
|
chainId: ctx.chainIdL2,
|
|
4971
5181
|
mintValue,
|
|
4972
|
-
l2GasLimit:
|
|
5182
|
+
l2GasLimit: l2Gas.gasLimit,
|
|
4973
5183
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
4974
5184
|
refundRecipient: ctx.refundRecipient,
|
|
4975
5185
|
l2Contract: p.to ?? ctx.sender,
|
|
4976
|
-
l2Value
|
|
5186
|
+
l2Value: p.amount
|
|
4977
5187
|
});
|
|
4978
5188
|
let bridgeTx;
|
|
4979
|
-
let
|
|
5189
|
+
let calldata;
|
|
4980
5190
|
if (needsApprove) {
|
|
4981
5191
|
bridgeTx = {
|
|
4982
5192
|
address: ctx.bridgehub,
|
|
@@ -4984,13 +5194,16 @@ function routeErc20Base() {
|
|
|
4984
5194
|
functionName: "requestL2TransactionDirect",
|
|
4985
5195
|
args: [req],
|
|
4986
5196
|
value: 0n,
|
|
4987
|
-
// base is ERC-20 ⇒ msg.value MUST be 0
|
|
4988
|
-
account: ctx.client.account
|
|
4989
|
-
...txFeeOverrides
|
|
5197
|
+
// base token is ERC-20 ⇒ msg.value MUST be 0
|
|
5198
|
+
account: ctx.client.account
|
|
4990
5199
|
};
|
|
4991
|
-
|
|
5200
|
+
calldata = viem.encodeFunctionData({
|
|
5201
|
+
abi: IBridgehub_default,
|
|
5202
|
+
functionName: "requestL2TransactionDirect",
|
|
5203
|
+
args: [req]
|
|
5204
|
+
});
|
|
4992
5205
|
} else {
|
|
4993
|
-
const sim = await
|
|
5206
|
+
const sim = await wrapAs5(
|
|
4994
5207
|
"RPC",
|
|
4995
5208
|
OP_DEPOSITS.base.estGas,
|
|
4996
5209
|
() => ctx.client.l1.simulateContract({
|
|
@@ -5006,8 +5219,33 @@ function routeErc20Base() {
|
|
|
5006
5219
|
message: "Failed to simulate Bridgehub.requestL2TransactionDirect."
|
|
5007
5220
|
}
|
|
5008
5221
|
);
|
|
5009
|
-
|
|
5010
|
-
|
|
5222
|
+
calldata = viem.encodeFunctionData({
|
|
5223
|
+
abi: sim.request.abi,
|
|
5224
|
+
functionName: sim.request.functionName,
|
|
5225
|
+
args: sim.request.args
|
|
5226
|
+
});
|
|
5227
|
+
bridgeTx = { ...sim.request };
|
|
5228
|
+
}
|
|
5229
|
+
const l1TxCandidate = {
|
|
5230
|
+
to: ctx.bridgehub,
|
|
5231
|
+
data: calldata,
|
|
5232
|
+
value: 0n,
|
|
5233
|
+
from: ctx.sender,
|
|
5234
|
+
...ctx.gasOverrides
|
|
5235
|
+
};
|
|
5236
|
+
const l1Gas = await quoteL1Gas2({
|
|
5237
|
+
ctx,
|
|
5238
|
+
tx: l1TxCandidate,
|
|
5239
|
+
overrides: ctx.gasOverrides,
|
|
5240
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
5241
|
+
});
|
|
5242
|
+
if (l1Gas) {
|
|
5243
|
+
bridgeTx = {
|
|
5244
|
+
...bridgeTx,
|
|
5245
|
+
gas: l1Gas.gasLimit,
|
|
5246
|
+
maxFeePerGas: l1Gas.maxFeePerGas,
|
|
5247
|
+
maxPriorityFeePerGas: l1Gas.maxPriorityFeePerGas
|
|
5248
|
+
};
|
|
5011
5249
|
}
|
|
5012
5250
|
steps.push({
|
|
5013
5251
|
key: "bridgehub:direct:erc20-base",
|
|
@@ -5015,10 +5253,18 @@ function routeErc20Base() {
|
|
|
5015
5253
|
description: "Bridge base ERC-20 via Bridgehub.requestL2TransactionDirect",
|
|
5016
5254
|
tx: bridgeTx
|
|
5017
5255
|
});
|
|
5256
|
+
const fees = buildFeeBreakdown({
|
|
5257
|
+
feeToken: baseToken,
|
|
5258
|
+
l1Gas,
|
|
5259
|
+
l2Gas,
|
|
5260
|
+
l2BaseCost,
|
|
5261
|
+
operatorTip: ctx.operatorTip,
|
|
5262
|
+
mintValue
|
|
5263
|
+
});
|
|
5018
5264
|
return {
|
|
5019
5265
|
steps,
|
|
5020
5266
|
approvals,
|
|
5021
|
-
|
|
5267
|
+
fees
|
|
5022
5268
|
};
|
|
5023
5269
|
}
|
|
5024
5270
|
};
|
|
@@ -5112,32 +5358,19 @@ function createDepositsResource(client) {
|
|
|
5112
5358
|
const ctx = await commonCtx(p, client);
|
|
5113
5359
|
const route = ctx.route;
|
|
5114
5360
|
await ROUTES[route].preflight?.(p, ctx);
|
|
5115
|
-
const { steps, approvals,
|
|
5116
|
-
const { baseCost, mintValue } = quoteExtras;
|
|
5117
|
-
const fallbackGasLimit = quoteExtras.l1GasLimit;
|
|
5118
|
-
const resolveGasLimit = () => {
|
|
5119
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
5120
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
5121
|
-
const candidate = steps[i].tx.gas;
|
|
5122
|
-
if (candidate != null) return candidate;
|
|
5123
|
-
}
|
|
5124
|
-
if (fallbackGasLimit != null) return fallbackGasLimit;
|
|
5125
|
-
return ctx.l2GasLimit;
|
|
5126
|
-
};
|
|
5127
|
-
const gasLimit = resolveGasLimit();
|
|
5361
|
+
const { steps, approvals, fees } = await ROUTES[route].build(p, ctx);
|
|
5128
5362
|
return {
|
|
5129
5363
|
route: ctx.route,
|
|
5130
5364
|
summary: {
|
|
5131
5365
|
route: ctx.route,
|
|
5132
5366
|
approvalsNeeded: approvals,
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
fees
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
}
|
|
5367
|
+
amounts: {
|
|
5368
|
+
transfer: { token: p.token, amount: p.amount }
|
|
5369
|
+
},
|
|
5370
|
+
fees,
|
|
5371
|
+
// Legacy fields (maintained for backward compatibility)
|
|
5372
|
+
baseCost: fees.l2?.baseCost,
|
|
5373
|
+
mintValue: fees.mintValue
|
|
5141
5374
|
},
|
|
5142
5375
|
steps
|
|
5143
5376
|
};
|
|
@@ -5212,7 +5445,7 @@ function createDepositsResource(client) {
|
|
|
5212
5445
|
step.tx.gas = overrides.gasLimit;
|
|
5213
5446
|
}
|
|
5214
5447
|
}
|
|
5215
|
-
if (
|
|
5448
|
+
if (!p.l1TxOverrides?.gasLimit) {
|
|
5216
5449
|
try {
|
|
5217
5450
|
const feePart = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
|
|
5218
5451
|
maxFeePerGas: step.tx.maxFeePerGas,
|
|
@@ -5435,7 +5668,7 @@ function normalizeTokenForRouting(token) {
|
|
|
5435
5668
|
function pickWithdrawRoute(args) {
|
|
5436
5669
|
const tokenNorm = normalizeTokenForRouting(args.token);
|
|
5437
5670
|
const isL2BaseAlias = tokenNorm.toLowerCase() === L2_BASE_TOKEN_ADDRESS.toLowerCase();
|
|
5438
|
-
if (isL2BaseAlias) return
|
|
5671
|
+
if (isL2BaseAlias) return "base";
|
|
5439
5672
|
return "erc20-nonbase";
|
|
5440
5673
|
}
|
|
5441
5674
|
|
|
@@ -5476,13 +5709,7 @@ async function commonCtx2(p, client) {
|
|
|
5476
5709
|
} = await client.ensureAddresses();
|
|
5477
5710
|
const chainIdL2 = BigInt(await client.l2.getChainId());
|
|
5478
5711
|
const baseIsEth = await isEthBasedChain(client.l2, l2NativeTokenVault);
|
|
5479
|
-
const
|
|
5480
|
-
const route = pickWithdrawRoute({
|
|
5481
|
-
token: p.token,
|
|
5482
|
-
baseIsEth
|
|
5483
|
-
});
|
|
5484
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
5485
|
-
const gasBufferPct = 15;
|
|
5712
|
+
const route = pickWithdrawRoute({ token: p.token});
|
|
5486
5713
|
return {
|
|
5487
5714
|
client,
|
|
5488
5715
|
bridgehub,
|
|
@@ -5495,56 +5722,162 @@ async function commonCtx2(p, client) {
|
|
|
5495
5722
|
l2NativeTokenVault,
|
|
5496
5723
|
l2BaseTokenSystem,
|
|
5497
5724
|
baseIsEth,
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5725
|
+
gasOverrides: p.l2TxOverrides
|
|
5726
|
+
};
|
|
5727
|
+
}
|
|
5728
|
+
|
|
5729
|
+
// src/core/resources/withdrawals/gas.ts
|
|
5730
|
+
function makeGasQuote2(p) {
|
|
5731
|
+
return {
|
|
5732
|
+
gasLimit: p.gasLimit,
|
|
5733
|
+
maxFeePerGas: p.maxFeePerGas,
|
|
5734
|
+
maxPriorityFeePerGas: p.maxPriorityFeePerGas,
|
|
5735
|
+
maxCost: p.gasLimit * p.maxFeePerGas
|
|
5736
|
+
};
|
|
5737
|
+
}
|
|
5738
|
+
async function fetchFees2(estimator) {
|
|
5739
|
+
try {
|
|
5740
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
5741
|
+
if (fees.maxFeePerGas != null) {
|
|
5742
|
+
return {
|
|
5743
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
5744
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? 0n
|
|
5745
|
+
};
|
|
5746
|
+
}
|
|
5747
|
+
if (fees.gasPrice != null) {
|
|
5748
|
+
return {
|
|
5749
|
+
maxFeePerGas: fees.gasPrice,
|
|
5750
|
+
maxPriorityFeePerGas: 0n
|
|
5751
|
+
};
|
|
5752
|
+
}
|
|
5753
|
+
} catch {
|
|
5754
|
+
}
|
|
5755
|
+
try {
|
|
5756
|
+
const gp = await estimator.getGasPrice();
|
|
5757
|
+
return { maxFeePerGas: gp, maxPriorityFeePerGas: 0n };
|
|
5758
|
+
} catch {
|
|
5759
|
+
return { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n };
|
|
5760
|
+
}
|
|
5761
|
+
}
|
|
5762
|
+
async function quoteL2Gas3(input) {
|
|
5763
|
+
const { estimator, tx, overrides } = input;
|
|
5764
|
+
const market = await fetchFees2(estimator);
|
|
5765
|
+
const o = overrides;
|
|
5766
|
+
const maxFeePerGas = o?.maxFeePerGas ?? (tx.maxFeePerGas != null ? BigInt(tx.maxFeePerGas) : market.maxFeePerGas);
|
|
5767
|
+
const maxPriorityFeePerGas = o?.maxPriorityFeePerGas ?? (tx.maxPriorityFeePerGas != null ? BigInt(tx.maxPriorityFeePerGas) : market.maxPriorityFeePerGas);
|
|
5768
|
+
const explicitGasLimit = o?.gasLimit ?? (tx.gasLimit != null ? BigInt(tx.gasLimit) : void 0);
|
|
5769
|
+
if (explicitGasLimit != null) {
|
|
5770
|
+
return makeGasQuote2({
|
|
5771
|
+
gasLimit: explicitGasLimit,
|
|
5772
|
+
maxFeePerGas,
|
|
5773
|
+
maxPriorityFeePerGas
|
|
5774
|
+
});
|
|
5775
|
+
}
|
|
5776
|
+
try {
|
|
5777
|
+
const est = await estimator.estimateGas(tx);
|
|
5778
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
5779
|
+
return makeGasQuote2({
|
|
5780
|
+
gasLimit: buffered,
|
|
5781
|
+
maxFeePerGas,
|
|
5782
|
+
maxPriorityFeePerGas
|
|
5783
|
+
});
|
|
5784
|
+
} catch (err) {
|
|
5785
|
+
console.warn("Failed to estimate L2 gas for withdrawal.", err);
|
|
5786
|
+
return void 0;
|
|
5787
|
+
}
|
|
5788
|
+
}
|
|
5789
|
+
|
|
5790
|
+
// src/adapters/viem/resources/withdrawals/services/gas.ts
|
|
5791
|
+
async function quoteL2Gas4(input) {
|
|
5792
|
+
const { ctx, tx } = input;
|
|
5793
|
+
const estimator = viemToGasEstimator(ctx.client.l2);
|
|
5794
|
+
return quoteL2Gas3({
|
|
5795
|
+
estimator,
|
|
5796
|
+
tx: toCoreTx(tx),
|
|
5797
|
+
overrides: ctx.gasOverrides
|
|
5798
|
+
});
|
|
5799
|
+
}
|
|
5800
|
+
|
|
5801
|
+
// src/adapters/viem/resources/withdrawals/services/fee.ts
|
|
5802
|
+
function buildFeeBreakdown2(p) {
|
|
5803
|
+
const l2Total = p.l2Gas?.maxCost ?? 0n;
|
|
5804
|
+
const l2 = {
|
|
5805
|
+
total: l2Total,
|
|
5806
|
+
gasLimit: p.l2Gas?.gasLimit ?? 0n,
|
|
5807
|
+
maxFeePerGas: p.l2Gas?.maxFeePerGas ?? 0n,
|
|
5808
|
+
maxPriorityFeePerGas: p.l2Gas?.maxPriorityFeePerGas
|
|
5809
|
+
};
|
|
5810
|
+
return {
|
|
5811
|
+
token: p.feeToken,
|
|
5812
|
+
maxTotal: l2Total,
|
|
5813
|
+
l2
|
|
5501
5814
|
};
|
|
5502
5815
|
}
|
|
5503
5816
|
|
|
5504
5817
|
// src/adapters/viem/resources/withdrawals/routes/eth.ts
|
|
5505
|
-
var { wrapAs:
|
|
5818
|
+
var { wrapAs: wrapAs6 } = createErrorHandlers("withdrawals");
|
|
5506
5819
|
function routeEthBase() {
|
|
5507
5820
|
return {
|
|
5508
5821
|
async build(p, ctx) {
|
|
5509
|
-
const
|
|
5510
|
-
const
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
account: ctx.client.account,
|
|
5521
|
-
...txFeeOverrides
|
|
5522
|
-
}),
|
|
5822
|
+
const steps = [];
|
|
5823
|
+
const data = await wrapAs6(
|
|
5824
|
+
"INTERNAL",
|
|
5825
|
+
OP_WITHDRAWALS.eth.encodeWithdraw,
|
|
5826
|
+
() => Promise.resolve(
|
|
5827
|
+
viem.encodeFunctionData({
|
|
5828
|
+
abi: IBaseToken_default,
|
|
5829
|
+
functionName: "withdraw",
|
|
5830
|
+
args: [p.to ?? ctx.sender]
|
|
5831
|
+
})
|
|
5832
|
+
),
|
|
5523
5833
|
{
|
|
5524
|
-
ctx: { where: "
|
|
5525
|
-
message: "Failed to
|
|
5834
|
+
ctx: { where: "L2BaseToken.withdraw", to: p.to ?? ctx.sender },
|
|
5835
|
+
message: "Failed to encode ETH withdraw calldata."
|
|
5526
5836
|
}
|
|
5527
5837
|
);
|
|
5528
|
-
const
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5838
|
+
const L2tx = {
|
|
5839
|
+
to: L2_BASE_TOKEN_ADDRESS,
|
|
5840
|
+
data,
|
|
5841
|
+
value: p.amount,
|
|
5842
|
+
from: ctx.sender
|
|
5843
|
+
};
|
|
5844
|
+
const l2Gas = await quoteL2Gas4({ ctx, tx: L2tx });
|
|
5845
|
+
if (l2Gas) {
|
|
5846
|
+
L2tx.gas = l2Gas.gasLimit;
|
|
5847
|
+
L2tx.maxFeePerGas = l2Gas.maxFeePerGas;
|
|
5848
|
+
L2tx.maxPriorityFeePerGas = l2Gas.maxPriorityFeePerGas;
|
|
5849
|
+
}
|
|
5850
|
+
const tx = {
|
|
5851
|
+
address: L2_BASE_TOKEN_ADDRESS,
|
|
5852
|
+
abi: IBaseToken_default,
|
|
5853
|
+
functionName: "withdraw",
|
|
5854
|
+
args: [p.to ?? ctx.sender],
|
|
5855
|
+
value: p.amount,
|
|
5856
|
+
account: ctx.client.account,
|
|
5857
|
+
...l2Gas
|
|
5858
|
+
};
|
|
5859
|
+
const fees = buildFeeBreakdown2({
|
|
5860
|
+
feeToken: L2_BASE_TOKEN_ADDRESS,
|
|
5861
|
+
l2Gas
|
|
5862
|
+
});
|
|
5863
|
+
steps.push({
|
|
5864
|
+
key: "l2-base-token:withdraw",
|
|
5865
|
+
kind: "l2-base-token:withdraw",
|
|
5866
|
+
description: "Withdraw ETH via L2 Base Token System",
|
|
5867
|
+
tx
|
|
5868
|
+
});
|
|
5869
|
+
return { steps, approvals: [], fees };
|
|
5537
5870
|
}
|
|
5538
5871
|
};
|
|
5539
5872
|
}
|
|
5540
|
-
var { wrapAs:
|
|
5873
|
+
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
5541
5874
|
function routeErc20NonBase2() {
|
|
5542
5875
|
return {
|
|
5543
5876
|
// TODO: add preflight validations here
|
|
5544
5877
|
async build(p, ctx) {
|
|
5545
|
-
const
|
|
5546
|
-
const
|
|
5547
|
-
const current = await
|
|
5878
|
+
const steps = [];
|
|
5879
|
+
const approvals = [];
|
|
5880
|
+
const current = await wrapAs7(
|
|
5548
5881
|
"CONTRACT",
|
|
5549
5882
|
OP_WITHDRAWALS.erc20.allowance,
|
|
5550
5883
|
() => ctx.client.l2.readContract({
|
|
@@ -5564,12 +5897,26 @@ function routeErc20NonBase2() {
|
|
|
5564
5897
|
message: "Failed to read L2 ERC-20 allowance."
|
|
5565
5898
|
}
|
|
5566
5899
|
);
|
|
5567
|
-
|
|
5568
|
-
const steps = [];
|
|
5569
|
-
const approvals = [];
|
|
5570
|
-
if (needsApprove) {
|
|
5900
|
+
if (current < p.amount) {
|
|
5571
5901
|
approvals.push({ token: p.token, spender: ctx.l2NativeTokenVault, amount: p.amount });
|
|
5572
|
-
const
|
|
5902
|
+
const data = viem.encodeFunctionData({
|
|
5903
|
+
abi: IERC20_default,
|
|
5904
|
+
functionName: "approve",
|
|
5905
|
+
args: [ctx.l2NativeTokenVault, p.amount]
|
|
5906
|
+
});
|
|
5907
|
+
const approveTxCandidate = {
|
|
5908
|
+
to: p.token,
|
|
5909
|
+
data,
|
|
5910
|
+
value: 0n,
|
|
5911
|
+
from: ctx.sender
|
|
5912
|
+
};
|
|
5913
|
+
const approveGas = await quoteL2Gas4({ ctx, tx: approveTxCandidate });
|
|
5914
|
+
if (approveGas) {
|
|
5915
|
+
approveTxCandidate.gas = approveGas.gasLimit;
|
|
5916
|
+
approveTxCandidate.maxFeePerGas = approveGas.maxFeePerGas;
|
|
5917
|
+
approveTxCandidate.maxPriorityFeePerGas = approveGas.maxPriorityFeePerGas;
|
|
5918
|
+
}
|
|
5919
|
+
const approveSim = await wrapAs7(
|
|
5573
5920
|
"CONTRACT",
|
|
5574
5921
|
OP_WITHDRAWALS.erc20.estGas,
|
|
5575
5922
|
() => ctx.client.l2.simulateContract({
|
|
@@ -5578,21 +5925,25 @@ function routeErc20NonBase2() {
|
|
|
5578
5925
|
functionName: "approve",
|
|
5579
5926
|
args: [ctx.l2NativeTokenVault, p.amount],
|
|
5580
5927
|
account: ctx.client.account,
|
|
5581
|
-
...
|
|
5928
|
+
...approveGas
|
|
5582
5929
|
}),
|
|
5583
5930
|
{
|
|
5584
5931
|
ctx: { where: "l2.simulateContract", to: p.token },
|
|
5585
5932
|
message: "Failed to simulate L2 ERC-20 approve."
|
|
5586
5933
|
}
|
|
5587
5934
|
);
|
|
5935
|
+
const { ...approveRequest } = approveSim.request;
|
|
5936
|
+
const approveTx = {
|
|
5937
|
+
...approveRequest
|
|
5938
|
+
};
|
|
5588
5939
|
steps.push({
|
|
5589
5940
|
key: `approve:l2:${p.token}:${ctx.l2NativeTokenVault}`,
|
|
5590
5941
|
kind: "approve:l2",
|
|
5591
5942
|
description: `Approve ${p.amount} to NativeTokenVault`,
|
|
5592
|
-
tx:
|
|
5943
|
+
tx: approveTx
|
|
5593
5944
|
});
|
|
5594
5945
|
}
|
|
5595
|
-
const ensure = await
|
|
5946
|
+
const ensure = await wrapAs7(
|
|
5596
5947
|
"CONTRACT",
|
|
5597
5948
|
OP_WITHDRAWALS.erc20.ensureRegistered,
|
|
5598
5949
|
() => ctx.client.l2.simulateContract({
|
|
@@ -5614,20 +5965,37 @@ function routeErc20NonBase2() {
|
|
|
5614
5965
|
{ type: "address", name: "l1Receiver" },
|
|
5615
5966
|
{ type: "address", name: "l2Token" }
|
|
5616
5967
|
],
|
|
5617
|
-
[p.amount,
|
|
5968
|
+
[p.amount, p.to ?? ctx.sender, p.token]
|
|
5618
5969
|
);
|
|
5970
|
+
const withdrawCalldata = viem.encodeFunctionData({
|
|
5971
|
+
abi: IL2AssetRouter_default,
|
|
5972
|
+
functionName: "withdraw",
|
|
5973
|
+
args: [assetId, assetData]
|
|
5974
|
+
});
|
|
5975
|
+
const withdrawTxCandidate = {
|
|
5976
|
+
to: ctx.l2AssetRouter,
|
|
5977
|
+
data: withdrawCalldata,
|
|
5978
|
+
value: 0n,
|
|
5979
|
+
from: ctx.sender
|
|
5980
|
+
};
|
|
5981
|
+
const withdrawGas = await quoteL2Gas4({ ctx, tx: withdrawTxCandidate });
|
|
5982
|
+
if (withdrawGas) {
|
|
5983
|
+
withdrawTxCandidate.gas = withdrawGas.gasLimit;
|
|
5984
|
+
withdrawTxCandidate.maxFeePerGas = withdrawGas.maxFeePerGas;
|
|
5985
|
+
withdrawTxCandidate.maxPriorityFeePerGas = withdrawGas.maxPriorityFeePerGas;
|
|
5986
|
+
}
|
|
5619
5987
|
let withdrawTx;
|
|
5620
|
-
if (
|
|
5988
|
+
if (current < p.amount) {
|
|
5621
5989
|
withdrawTx = {
|
|
5622
5990
|
address: ctx.l2AssetRouter,
|
|
5623
5991
|
abi: IL2AssetRouter_default,
|
|
5624
5992
|
functionName: "withdraw",
|
|
5625
5993
|
args: [assetId, assetData],
|
|
5626
5994
|
account: ctx.client.account,
|
|
5627
|
-
...
|
|
5995
|
+
...withdrawGas
|
|
5628
5996
|
};
|
|
5629
5997
|
} else {
|
|
5630
|
-
const sim = await
|
|
5998
|
+
const sim = await wrapAs7(
|
|
5631
5999
|
"CONTRACT",
|
|
5632
6000
|
OP_WITHDRAWALS.erc20.estGas,
|
|
5633
6001
|
() => ctx.client.l2.simulateContract({
|
|
@@ -5636,14 +6004,18 @@ function routeErc20NonBase2() {
|
|
|
5636
6004
|
functionName: "withdraw",
|
|
5637
6005
|
args: [assetId, assetData],
|
|
5638
6006
|
account: ctx.client.account,
|
|
5639
|
-
...
|
|
6007
|
+
...withdrawGas
|
|
5640
6008
|
}),
|
|
5641
6009
|
{
|
|
5642
6010
|
ctx: { where: "l2.simulateContract", to: ctx.l2AssetRouter },
|
|
5643
6011
|
message: "Failed to simulate L2 ERC-20 withdraw."
|
|
5644
6012
|
}
|
|
5645
6013
|
);
|
|
5646
|
-
|
|
6014
|
+
const { ...withdrawRequest } = sim.request;
|
|
6015
|
+
withdrawTx = {
|
|
6016
|
+
...withdrawRequest,
|
|
6017
|
+
...withdrawGas
|
|
6018
|
+
};
|
|
5647
6019
|
}
|
|
5648
6020
|
steps.push({
|
|
5649
6021
|
key: "l2-asset-router:withdraw",
|
|
@@ -5651,59 +6023,11 @@ function routeErc20NonBase2() {
|
|
|
5651
6023
|
description: "Burn on L2 & send L2\u2192L1 message",
|
|
5652
6024
|
tx: withdrawTx
|
|
5653
6025
|
});
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
}
|
|
5658
|
-
|
|
5659
|
-
// src/adapters/viem/resources/withdrawals/routes/eth-nonbase.ts
|
|
5660
|
-
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
5661
|
-
function routeEthNonBase2() {
|
|
5662
|
-
return {
|
|
5663
|
-
async preflight(p, ctx) {
|
|
5664
|
-
await wrapAs7(
|
|
5665
|
-
"VALIDATION",
|
|
5666
|
-
OP_WITHDRAWALS.ethNonBase.assertNonEthBase,
|
|
5667
|
-
() => {
|
|
5668
|
-
if (p.token.toLowerCase() !== L2_BASE_TOKEN_ADDRESS.toLowerCase()) {
|
|
5669
|
-
throw new Error("eth-nonbase route requires the L2 base-token alias (0x\u2026800A).");
|
|
5670
|
-
}
|
|
5671
|
-
if (ctx.baseIsEth) {
|
|
5672
|
-
throw new Error("eth-nonbase route requires chain base \u2260 ETH.");
|
|
5673
|
-
}
|
|
5674
|
-
},
|
|
5675
|
-
{ ctx: { token: p.token, baseIsEth: ctx.baseIsEth } }
|
|
5676
|
-
);
|
|
5677
|
-
},
|
|
5678
|
-
async build(p, ctx) {
|
|
5679
|
-
const toL1 = p.to ?? ctx.sender;
|
|
5680
|
-
const txFeeOverrides = buildViemFeeOverrides(ctx.fee);
|
|
5681
|
-
const sim = await wrapAs7(
|
|
5682
|
-
"CONTRACT",
|
|
5683
|
-
OP_WITHDRAWALS.ethNonBase.estGas,
|
|
5684
|
-
() => ctx.client.l2.simulateContract({
|
|
5685
|
-
address: L2_BASE_TOKEN_ADDRESS,
|
|
5686
|
-
abi: IBaseToken_default,
|
|
5687
|
-
functionName: "withdraw",
|
|
5688
|
-
args: [toL1],
|
|
5689
|
-
value: p.amount,
|
|
5690
|
-
account: ctx.client.account,
|
|
5691
|
-
...txFeeOverrides
|
|
5692
|
-
}),
|
|
5693
|
-
{
|
|
5694
|
-
ctx: { where: "l2.simulateContract", to: L2_BASE_TOKEN_ADDRESS },
|
|
5695
|
-
message: "Failed to simulate L2 base-token withdraw."
|
|
5696
|
-
}
|
|
5697
|
-
);
|
|
5698
|
-
const steps = [
|
|
5699
|
-
{
|
|
5700
|
-
key: "l2-base-token:withdraw",
|
|
5701
|
-
kind: "l2-base-token:withdraw",
|
|
5702
|
-
description: "Withdraw base token via L2 Base Token System (base \u2260 ETH)",
|
|
5703
|
-
tx: { ...sim.request, ...txFeeOverrides }
|
|
5704
|
-
}
|
|
5705
|
-
];
|
|
5706
|
-
return { steps, approvals: [], quoteExtras: {} };
|
|
6026
|
+
const fees = buildFeeBreakdown2({
|
|
6027
|
+
feeToken: await ctx.client.baseToken(ctx.chainIdL2),
|
|
6028
|
+
l2Gas: withdrawGas
|
|
6029
|
+
});
|
|
6030
|
+
return { steps, approvals, fees };
|
|
5707
6031
|
}
|
|
5708
6032
|
};
|
|
5709
6033
|
}
|
|
@@ -6058,10 +6382,8 @@ function createFinalizationServices(client) {
|
|
|
6058
6382
|
|
|
6059
6383
|
// src/adapters/viem/resources/withdrawals/index.ts
|
|
6060
6384
|
var ROUTES2 = {
|
|
6061
|
-
|
|
6385
|
+
base: routeEthBase(),
|
|
6062
6386
|
// BaseTokenSystem.withdraw, chain base = ETH
|
|
6063
|
-
"eth-nonbase": routeEthNonBase2(),
|
|
6064
|
-
// BaseTokenSystem.withdraw, chain base ≠ ETH
|
|
6065
6387
|
"erc20-nonbase": routeErc20NonBase2()
|
|
6066
6388
|
// AssetRouter.withdraw for non-base ERC-20s
|
|
6067
6389
|
};
|
|
@@ -6071,27 +6393,19 @@ function createWithdrawalsResource(client) {
|
|
|
6071
6393
|
async function buildPlan(p) {
|
|
6072
6394
|
const ctx = await commonCtx2(p, client);
|
|
6073
6395
|
await ROUTES2[ctx.route].preflight?.(p, ctx);
|
|
6074
|
-
const { steps, approvals } = await ROUTES2[ctx.route].build(p, ctx);
|
|
6075
|
-
|
|
6076
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
6077
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
6078
|
-
const candidate = steps[i].tx.gas;
|
|
6079
|
-
if (candidate != null) return candidate;
|
|
6080
|
-
}
|
|
6081
|
-
return void 0;
|
|
6082
|
-
};
|
|
6083
|
-
const gasLimit = resolveGasLimit();
|
|
6084
|
-
const summary = {
|
|
6396
|
+
const { steps, approvals, fees } = await ROUTES2[ctx.route].build(p, ctx);
|
|
6397
|
+
return {
|
|
6085
6398
|
route: ctx.route,
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6399
|
+
summary: {
|
|
6400
|
+
route: ctx.route,
|
|
6401
|
+
approvalsNeeded: approvals,
|
|
6402
|
+
amounts: {
|
|
6403
|
+
transfer: { token: p.token, amount: p.amount }
|
|
6404
|
+
},
|
|
6405
|
+
fees
|
|
6406
|
+
},
|
|
6407
|
+
steps
|
|
6093
6408
|
};
|
|
6094
|
-
return { route: ctx.route, summary, steps };
|
|
6095
6409
|
}
|
|
6096
6410
|
const finalizeCache = /* @__PURE__ */ new Map();
|
|
6097
6411
|
const quote = (p) => wrap2(OP_WITHDRAWALS.quote, async () => (await buildPlan(p)).summary, {
|
|
@@ -6125,7 +6439,7 @@ function createWithdrawalsResource(client) {
|
|
|
6125
6439
|
}
|
|
6126
6440
|
if (overrides.gasLimit != null) step.tx.gas = overrides.gasLimit;
|
|
6127
6441
|
}
|
|
6128
|
-
if (
|
|
6442
|
+
if (!p.l2TxOverrides?.gasLimit) {
|
|
6129
6443
|
try {
|
|
6130
6444
|
const feePart = step.tx.maxFeePerGas != null && step.tx.maxPriorityFeePerGas != null ? {
|
|
6131
6445
|
maxFeePerGas: step.tx.maxFeePerGas,
|