diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 40366c5b998..65fdf72e440 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/utils" + commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -26,6 +27,7 @@ type ArbConfig interface { LimitMax() uint64 BumpPercent() uint16 BumpMin() *assets.Wei + LimitMultiplier() float32 } //go:generate mockery --quiet --name ethClient --output ./mocks/ --case=underscore --structname ETHClient @@ -134,7 +136,9 @@ func (a *arbitrumEstimator) GetLegacyGas(ctx context.Context, calldata []byte, l } } perL2Tx, perL1CalldataUnit := a.getPricesInArbGas() - chainSpecificGasLimit = l2GasLimit + uint64(perL2Tx) + uint64(len(calldata))*uint64(perL1CalldataUnit) + originalGasLimit := l2GasLimit + uint64(perL2Tx) + uint64(len(calldata))*uint64(perL1CalldataUnit) + chainSpecificGasLimit, err = commonfee.ApplyMultiplier(originalGasLimit, a.cfg.LimitMultiplier()) + a.logger.Debugw("GetLegacyGas", "l2GasLimit", l2GasLimit, "calldataLen", len(calldata), "perL2Tx", perL2Tx, "perL1CalldataUnit", perL1CalldataUnit, "chainSpecificGasLimit", chainSpecificGasLimit) }) diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index 3c46b466e87..855d090cb84 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -23,9 +23,10 @@ import ( ) type arbConfig struct { - v uint64 - bumpPercent uint16 - bumpMin *assets.Wei + v uint64 + bumpPercent uint16 + bumpMin *assets.Wei + limitMultiplier float32 } func (a *arbConfig) LimitMax() uint64 { @@ -40,6 +41,10 @@ func (a *arbConfig) BumpMin() *assets.Wei { return a.bumpMin } +func (a *arbConfig) LimitMultiplier() float32 { + return a.limitMultiplier +} + func TestArbitrumEstimator(t *testing.T) { t.Parallel() @@ -50,6 +55,7 @@ func TestArbitrumEstimator(t *testing.T) { const gasPriceBufferPercentage = 50 const bumpPercent = 10 var bumpMin = assets.NewWei(big.NewInt(1)) + const limitMultiplier = 1 t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { rpcClient := mocks.NewRPCClient(t) @@ -78,7 +84,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin, limitMultiplier: limitMultiplier}, rpcClient, ethClient) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) @@ -209,7 +215,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(b.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin, limitMultiplier: limitMultiplier}, rpcClient, ethClient) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) @@ -243,7 +249,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(b.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin, limitMultiplier: limitMultiplier}, rpcClient, ethClient) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.Error(t, err, "expected error but got (%s, %d)", gasPrice, chainSpecificGasLimit) diff --git a/core/chains/evm/gas/cmd/arbgas/main.go b/core/chains/evm/gas/cmd/arbgas/main.go index dc107a50b52..7c7491d65aa 100644 --- a/core/chains/evm/gas/cmd/arbgas/main.go +++ b/core/chains/evm/gas/cmd/arbgas/main.go @@ -67,9 +67,10 @@ func withEstimator(ctx context.Context, lggr logger.SugaredLogger, url string, f var _ gas.ArbConfig = &config{} type config struct { - max uint64 - bumpPercent uint16 - bumpMin *assets.Wei + max uint64 + bumpPercent uint16 + bumpMin *assets.Wei + limitMultiplier float32 } func (c *config) LimitMax() uint64 { @@ -83,3 +84,7 @@ func (c *config) BumpPercent() uint16 { func (c *config) BumpMin() *assets.Wei { return c.bumpMin } + +func (c *config) LimitMultiplier() float32 { + return c.limitMultiplier +} diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index edc1b0f92fa..2007e8ebceb 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -16,6 +16,7 @@ import ( bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink/v2/common/fee" + commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -29,6 +30,7 @@ var ( type suggestedPriceConfig interface { BumpPercent() uint16 BumpMin() *assets.Wei + LimitMultiplier() float32 } //go:generate mockery --quiet --name rpcClient --output ./mocks/ --case=underscore --structname RPCClient @@ -165,7 +167,7 @@ func (*SuggestedPriceEstimator) BumpDynamicFee(_ context.Context, _ DynamicFee, } func (o *SuggestedPriceEstimator) GetLegacyGas(ctx context.Context, _ []byte, GasLimit uint64, maxGasPriceWei *assets.Wei, opts ...feetypes.Opt) (gasPrice *assets.Wei, chainSpecificGasLimit uint64, err error) { - chainSpecificGasLimit = GasLimit + chainSpecificGasLimit, err = commonfee.ApplyMultiplier(GasLimit, o.cfg.LimitMultiplier()) ok := o.IfStarted(func() { if slices.Contains(opts, feetypes.OptForceRefetch) { err = o.forceRefresh(ctx) @@ -193,7 +195,7 @@ func (o *SuggestedPriceEstimator) GetLegacyGas(ctx context.Context, _ []byte, Ga // The only reason bumping logic would be called on the SuggestedPriceEstimator is if there was a significant price spike // between the last price update and when the tx was submitted. Refreshing the price helps ensure the latest market changes are accounted for. func (o *SuggestedPriceEstimator) BumpLegacyGas(ctx context.Context, originalFee *assets.Wei, feeLimit uint64, maxGasPriceWei *assets.Wei, _ []EvmPriorAttempt) (newGasPrice *assets.Wei, chainSpecificGasLimit uint64, err error) { - chainSpecificGasLimit = feeLimit + chainSpecificGasLimit, err = commonfee.ApplyMultiplier(feeLimit, o.cfg.LimitMultiplier()) ok := o.IfStarted(func() { // Immediately return error if original fee is greater than or equal to the max gas price // Prevents a loop of resubmitting the attempt with the max gas price diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index 0d52d6ab1b9..f925752f7e0 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -26,7 +26,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { calldata := []byte{0x00, 0x00, 0x01, 0x02, 0x03} const gasLimit uint64 = 80000 - cfg := &gas.MockGasEstimatorConfig{BumpPercentF: 10, BumpMinF: assets.NewWei(big.NewInt(1)), BumpThresholdF: 1} + cfg := &gas.MockGasEstimatorConfig{BumpPercentF: 10, BumpMinF: assets.NewWei(big.NewInt(1)), BumpThresholdF: 1, LimitMultiplierF: 1} t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) @@ -142,7 +142,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { (*big.Int)(res).SetInt64(40) }) - testCfg := &gas.MockGasEstimatorConfig{BumpPercentF: 1, BumpMinF: assets.NewWei(big.NewInt(1)), BumpThresholdF: 1} + testCfg := &gas.MockGasEstimatorConfig{BumpPercentF: 1, BumpMinF: assets.NewWei(big.NewInt(1)), BumpThresholdF: 1, LimitMultiplierF: 1} o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, testCfg) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(10), gasLimit, maxGasPrice, nil)