From fb687af5ad4b71d450eff429b42176e87102ba8d Mon Sep 17 00:00:00 2001 From: Gaston Ponti Date: Tue, 3 Dec 2024 18:55:04 -0300 Subject: [PATCH] Fix gas estimator for txs with feeCurrency + Value (#282) * Fix gas estimator for txs with feeCurrency + Value --------- Co-authored-by: Maximilian Langenfeld <15726643+ezdac@users.noreply.github.com> --- eth/gasestimator/gasestimator.go | 22 ++++++++++++++-------- internal/ethapi/api.go | 13 ++++++++----- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index f35a33eea9..2ebbbf1f1c 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -50,7 +50,7 @@ type Options struct { // Estimate returns the lowest possible gas limit that allows the transaction to // run successfully with the provided context options. It returns an error if the // transaction would always revert, or if there are unexpected failures. -func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uint64, exchangeRates common.ExchangeRates, balance *big.Int) (uint64, []byte, error) { +func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uint64, exchangeRates common.ExchangeRates, feeCurrencyBalance *big.Int) (uint64, []byte, error) { // Binary search the gas limit, as it may need to be higher than the amount used var ( lo uint64 // lowest-known gas limit where tx execution fails @@ -72,7 +72,8 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin } // Recap the highest gas limit with account's available balance. if feeCap.BitLen() != 0 { - available := balance + celoBalance := opts.State.GetBalance(call.From).ToBig() + available := celoBalance if call.FeeCurrency != nil { if !call.IsFeeCurrencyDenominated() { // CIP-66, prices are given in native token. @@ -83,12 +84,17 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin return 0, nil, err } } - } else { - if call.Value != nil { - if call.Value.Cmp(available) >= 0 { + available = feeCurrencyBalance + } + if call.Value != nil { + if call.Value.Cmp(celoBalance) > 0 { + return 0, nil, core.ErrInsufficientFundsForTransfer + } + if call.FeeCurrency == nil { + available.Sub(available, call.Value) + if available.Cmp(big.NewInt(0)) <= 0 { return 0, nil, core.ErrInsufficientFundsForTransfer } - available.Sub(available, call.Value) } } @@ -114,8 +120,8 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin if transfer == nil { transfer = new(big.Int) } - log.Debug("Gas estimation capped by limited funds", "original", hi, "balance", balance, - "sent", transfer, "maxFeePerGas", feeCap, "fundable", allowance, + log.Debug("Gas estimation capped by limited funds", "original", hi, "celo balance", celoBalance, + "feeCurrency balance", feeCurrencyBalance, "sent", transfer, "maxFeePerGas", feeCap, "fundable", allowance, "feeCurrency", call.FeeCurrency, "maxFeeInFeeCurrency", call.MaxFeeInFeeCurrency, ) hi = allowance.Uint64() diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index cec1f83a4d..ee686d83cf 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1330,14 +1330,17 @@ func DoEstimateGas(ctx context.Context, b CeloBackend, args TransactionArgs, blo call := args.ToMessage(header.BaseFee, exchangeRates) - // Celo specific: get balance - balance, err := b.GetFeeBalance(ctx, blockNrOrHash, call.From, args.FeeCurrency) - if err != nil { - return 0, err + // Celo specific: get balance of fee currency if fee currency is specified + feeCurrencyBalance := new(big.Int) + if args.FeeCurrency != nil { + feeCurrencyBalance, err = b.GetFeeBalance(ctx, blockNrOrHash, call.From, args.FeeCurrency) + if err != nil { + return 0, err + } } // Run the gas estimation and wrap any revertals into a custom return - estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap, exchangeRates, balance) + estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap, exchangeRates, feeCurrencyBalance) if err != nil { if len(revert) > 0 { return 0, newRevertError(revert)