From 40a89e758987112d9496f1f96d3a72cc1078d46b Mon Sep 17 00:00:00 2001 From: Shubham Damkondwar Date: Fri, 13 Mar 2026 23:58:50 +0530 Subject: [PATCH] feat: add support for L1 fee buffers in gas calculations for multiple coin families CECHO-354 TICKET: CECHO-354 --- .gitignore | 1 + .../abstract-eth/src/abstractEthLikeNewCoins.ts | 14 +++++++++----- modules/abstract-eth/src/ethLikeToken.ts | 8 ++++---- modules/abstract-eth/src/lib/constants.ts | 8 ++++++++ modules/abstract-eth/src/lib/index.ts | 1 + modules/statics/src/tokenConfig.ts | 2 +- 6 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 modules/abstract-eth/src/lib/constants.ts diff --git a/.gitignore b/.gitignore index 028dd2ee8e..0ca92b500e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules/ +.worktrees/ .idea/ *.iml lerna-debug.log diff --git a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts index a29761ffde..10ee40ee17 100644 --- a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts +++ b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts @@ -72,6 +72,7 @@ import { AbstractEthLikeCoin } from './abstractEthLikeCoin'; import { EthLikeToken } from './ethLikeToken'; import { calculateForwarderV1Address, + coinFamiliesWithL1Fees, decodeTransferData, ERC1155TransferBuilder, ERC721TransferBuilder, @@ -1516,10 +1517,9 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin { const backupKeyBalance = await this.queryAddressBalance(backupKeyAddress, params.apiKey); let totalGasNeeded = gasPrice.mul(gasLimit); - // On optimism chain, L1 fees is to be paid as well apart from L2 fees - // So we are adding the amount that can be used up as l1 fees - if (this.staticsCoin?.family === 'opeth') { - totalGasNeeded = totalGasNeeded.add(new optionalDeps.ethUtil.BN(ethGasConfigs.opethGasL1Fees)); + // On L2 chains with L1 data fees, add buffer for L1 fees + if (this.staticsCoin?.family !== undefined && coinFamiliesWithL1Fees.includes(this.staticsCoin.family)) { + totalGasNeeded = totalGasNeeded.add(new optionalDeps.ethUtil.BN(ethGasConfigs.l1GasFeeBuffer)); } const weiToGwei = 10 ** 9; @@ -2515,7 +2515,11 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin { async validateBalanceAndGetTxAmount(baseAddress: string, gasPrice: BN, gasLimit: BN, apiKey?: string) { const baseAddressBalance = await this.queryAddressBalance(baseAddress, apiKey); - const totalGasNeeded = gasPrice.mul(gasLimit); + let totalGasNeeded = gasPrice.mul(gasLimit); + // On L2 chains with L1 data fees, add buffer for L1 fees + if (this.staticsCoin?.family !== undefined && coinFamiliesWithL1Fees.includes(this.staticsCoin.family)) { + totalGasNeeded = totalGasNeeded.add(new optionalDeps.ethUtil.BN(ethGasConfigs.l1GasFeeBuffer)); + } const weiToGwei = new BN(10 ** 9); if (baseAddressBalance.lt(totalGasNeeded)) { throw new Error( diff --git a/modules/abstract-eth/src/ethLikeToken.ts b/modules/abstract-eth/src/ethLikeToken.ts index 830006e1e4..6e3e09d79c 100644 --- a/modules/abstract-eth/src/ethLikeToken.ts +++ b/modules/abstract-eth/src/ethLikeToken.ts @@ -8,6 +8,7 @@ import { BigNumber } from 'bignumber.js'; import { BitGoBase, CoinConstructor, NamedCoinConstructor, getIsUnsignedSweep, Util } from '@bitgo/sdk-core'; import { + coinFamiliesWithL1Fees, TransactionBuilder as EthLikeTransactionBuilder, TransferBuilder as EthLikeTransferBuilder, KeyPair as KeyPairLib, @@ -276,10 +277,9 @@ export class EthLikeToken extends AbstractEthLikeNewCoins { let totalGasNeeded = gasPrice.mul(gasLimit); - // On optimism chain, L1 fees is to be paid as well apart from L2 fees - // So we are adding the amount that can be used up as l1 fees - if (this.staticsCoin?.family === 'opeth') { - totalGasNeeded = totalGasNeeded.add(new optionalDeps.ethUtil.BN(ethGasConfigs.opethGasL1Fees)); + // On L2 chains with L1 data fees, add buffer for L1 fees + if (this.staticsCoin?.family !== undefined && coinFamiliesWithL1Fees.includes(this.staticsCoin.family)) { + totalGasNeeded = totalGasNeeded.add(new optionalDeps.ethUtil.BN(ethGasConfigs.l1GasFeeBuffer)); } const weiToGwei = 10 ** 9; diff --git a/modules/abstract-eth/src/lib/constants.ts b/modules/abstract-eth/src/lib/constants.ts new file mode 100644 index 0000000000..e4ba6c1668 --- /dev/null +++ b/modules/abstract-eth/src/lib/constants.ts @@ -0,0 +1,8 @@ +import { CoinFamily } from '@bitgo/statics'; + +/** L2 coin families that incur L1 data fees during recovery transactions */ +export const coinFamiliesWithL1Fees: ReadonlyArray = [ + CoinFamily.OPETH, + CoinFamily.DOGEOS, + CoinFamily.MORPHETH, +]; diff --git a/modules/abstract-eth/src/lib/index.ts b/modules/abstract-eth/src/lib/index.ts index f685804a50..86eb9024e5 100644 --- a/modules/abstract-eth/src/lib/index.ts +++ b/modules/abstract-eth/src/lib/index.ts @@ -1,3 +1,4 @@ +export * from './constants'; export * from './contractCall'; export * from './iface'; export * from './keyPair'; diff --git a/modules/statics/src/tokenConfig.ts b/modules/statics/src/tokenConfig.ts index dc678d06bc..21d8755c31 100644 --- a/modules/statics/src/tokenConfig.ts +++ b/modules/statics/src/tokenConfig.ts @@ -344,7 +344,7 @@ export const ethGasConfigs = { minimumGasLimit: 30000, // minimum gas limit a user can set for a send maximumGasLimit: 20000000, // Customers cannot set gas limits beyond this amount newEthLikeCoinsMinGasLimit: 400000, // minimum gas limit a user can set for a send for eth like coins like arbitrum, optimism, etc - opethGasL1Fees: 1000000000000000, // Buffer for opeth L1 gas fees + l1GasFeeBuffer: 1000000000000000, // Buffer for L1 data fees }; function getStellarTokenConfig(coin: StellarCoin): StellarTokenConfig {