diff --git a/pkg/crypto/signer.go b/pkg/crypto/signer.go index 4156e697503..6a82101eff0 100644 --- a/pkg/crypto/signer.go +++ b/pkg/crypto/signer.go @@ -90,7 +90,7 @@ func (d *defaultSigner) Sign(data []byte) (signature []byte, err error) { // SignTx signs an ethereum transaction. func (d *defaultSigner) SignTx(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - txSigner := types.NewEIP155Signer(chainID) + txSigner := types.NewLondonSigner(chainID) hash := txSigner.Hash(transaction).Bytes() // isCompressedKey is false here so we get the expected v value (27 or 28) signature, err := d.sign(hash, false) diff --git a/pkg/node/chain.go b/pkg/node/chain.go index 368a1979310..fe45038f5c1 100644 --- a/pkg/node/chain.go +++ b/pkg/node/chain.go @@ -399,6 +399,9 @@ func (m noOpChainBackend) PendingNonceAt(context.Context, common.Address) (uint6 func (m noOpChainBackend) SuggestGasPrice(context.Context) (*big.Int, error) { panic("chain no op: SuggestGasPrice") } +func (m noOpChainBackend) SuggestGasTipCap(context.Context) (*big.Int, error) { + panic("chain no op: SuggestGasPrice") +} func (m noOpChainBackend) EstimateGas(context.Context, ethereum.CallMsg) (uint64, error) { panic("chain no op: EstimateGas") } diff --git a/pkg/postage/postagecontract/contract.go b/pkg/postage/postagecontract/contract.go index c1547ac3385..37babc52b4d 100644 --- a/pkg/postage/postagecontract/contract.go +++ b/pkg/postage/postagecontract/contract.go @@ -96,7 +96,7 @@ func (c *postageContract) sendApproveTransaction(ctx context.Context, amount *bi GasLimit: 65000, Value: big.NewInt(0), Description: approveDescription, - }, 0) + }, transaction.DefaultTipBoostPercent) if err != nil { return nil, err } @@ -123,7 +123,7 @@ func (c *postageContract) sendTransaction(ctx context.Context, callData []byte, Description: desc, } - txHash, err := c.transactionService.Send(ctx, request, 0) + txHash, err := c.transactionService.Send(ctx, request, transaction.DefaultTipBoostPercent) if err != nil { return nil, err } diff --git a/pkg/settlement/swap/chequebook/cashout.go b/pkg/settlement/swap/chequebook/cashout.go index a7d00d87f40..157af01ad56 100644 --- a/pkg/settlement/swap/chequebook/cashout.go +++ b/pkg/settlement/swap/chequebook/cashout.go @@ -149,7 +149,7 @@ func (s *cashoutService) CashCheque(ctx context.Context, chequebook, recipient c Description: "cheque cashout", } - txHash, err := s.transactionService.Send(ctx, request, 0) + txHash, err := s.transactionService.Send(ctx, request, transaction.DefaultTipBoostPercent) if err != nil { return common.Hash{}, err } diff --git a/pkg/settlement/swap/chequebook/chequebook.go b/pkg/settlement/swap/chequebook/chequebook.go index 845f9aac201..347f6a7bfe7 100644 --- a/pkg/settlement/swap/chequebook/chequebook.go +++ b/pkg/settlement/swap/chequebook/chequebook.go @@ -334,7 +334,7 @@ func (s *service) Withdraw(ctx context.Context, amount *big.Int) (hash common.Ha Description: fmt.Sprintf("chequebook withdrawal of %d BZZ", amount), } - txHash, err := s.transactionService.Send(ctx, request, 0) + txHash, err := s.transactionService.Send(ctx, request, transaction.DefaultTipBoostPercent) if err != nil { return common.Hash{}, err } diff --git a/pkg/settlement/swap/chequebook/factory.go b/pkg/settlement/swap/chequebook/factory.go index ad890b95491..6b4cc106b6f 100644 --- a/pkg/settlement/swap/chequebook/factory.go +++ b/pkg/settlement/swap/chequebook/factory.go @@ -87,7 +87,7 @@ func (c *factory) Deploy(ctx context.Context, issuer common.Address, defaultHard Description: "chequebook deployment", } - txHash, err := c.transactionService.Send(ctx, request, 0) + txHash, err := c.transactionService.Send(ctx, request, transaction.DefaultTipBoostPercent) if err != nil { return common.Hash{}, err } diff --git a/pkg/settlement/swap/erc20/erc20.go b/pkg/settlement/swap/erc20/erc20.go index 4866350a81c..677ac35b8fb 100644 --- a/pkg/settlement/swap/erc20/erc20.go +++ b/pkg/settlement/swap/erc20/erc20.go @@ -83,7 +83,7 @@ func (c *erc20Service) Transfer(ctx context.Context, address common.Address, val Description: "token transfer", } - txHash, err := c.transactionService.Send(ctx, request, 0) + txHash, err := c.transactionService.Send(ctx, request, transaction.DefaultTipBoostPercent) if err != nil { return common.Hash{}, err } diff --git a/pkg/storageincentives/staking/contract.go b/pkg/storageincentives/staking/contract.go index d0df5c44932..b22fc8d6f3f 100644 --- a/pkg/storageincentives/staking/contract.go +++ b/pkg/storageincentives/staking/contract.go @@ -106,7 +106,7 @@ func (s *contract) sendTransaction(ctx context.Context, callData []byte, desc st Description: desc, } - txHash, err := s.transactionService.Send(ctx, request, 0) + txHash, err := s.transactionService.Send(ctx, request, transaction.DefaultTipBoostPercent) if err != nil { return nil, err } diff --git a/pkg/transaction/backend.go b/pkg/transaction/backend.go index d1e8686cb41..c574bebebce 100644 --- a/pkg/transaction/backend.go +++ b/pkg/transaction/backend.go @@ -26,6 +26,7 @@ type Backend interface { HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) SuggestGasPrice(ctx context.Context) (*big.Int, error) + SuggestGasTipCap(ctx context.Context) (*big.Int, error) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) SendTransaction(ctx context.Context, tx *types.Transaction) error TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) diff --git a/pkg/transaction/backendmock/backend.go b/pkg/transaction/backendmock/backend.go index aa43f7ef062..8ce38614b6e 100644 --- a/pkg/transaction/backendmock/backend.go +++ b/pkg/transaction/backendmock/backend.go @@ -19,6 +19,7 @@ type backendMock struct { codeAt func(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) sendTransaction func(ctx context.Context, tx *types.Transaction) error suggestGasPrice func(ctx context.Context) (*big.Int, error) + suggestGasTipCap func(ctx context.Context) (*big.Int, error) estimateGas func(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) pendingNonceAt func(ctx context.Context, account common.Address) (uint64, error) @@ -130,6 +131,9 @@ func (m *backendMock) NonceAt(ctx context.Context, account common.Address, block } func (m *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + if m.suggestGasPrice != nil { + return m.suggestGasTipCap(ctx) + } return nil, errors.New("not implemented") } @@ -181,6 +185,12 @@ func WithSuggestGasPriceFunc(f func(ctx context.Context) (*big.Int, error)) Opti }) } +func WithSuggestGasTipCapFunc(f func(ctx context.Context) (*big.Int, error)) Option { + return optionFunc(func(s *backendMock) { + s.suggestGasTipCap = f + }) +} + func WithEstimateGasFunc(f func(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error)) Option { return optionFunc(func(s *backendMock) { s.estimateGas = f diff --git a/pkg/transaction/transaction.go b/pkg/transaction/transaction.go index 7e65f36eefe..fb3fa106596 100644 --- a/pkg/transaction/transaction.go +++ b/pkg/transaction/transaction.go @@ -43,7 +43,7 @@ var ( // minGasPrice determines the minimum gas price // threshold (in wei) for the creation of a transaction. -var minGasPrice = big.NewInt(1000) +const DefaultTipBoostPercent = 20 // TxRequest describes a request for a transaction that can be executed. type TxRequest struct { @@ -71,7 +71,7 @@ type StoredTransaction struct { type Service interface { io.Closer // Send creates a transaction based on the request (with gasprice increased by provided percentage) and sends it. - Send(ctx context.Context, request *TxRequest, priceBoostPercent int) (txHash common.Hash, err error) + Send(ctx context.Context, request *TxRequest, tipCapBoostPercent int) (txHash common.Hash, err error) // Call simulate a transaction based on the request. Call(ctx context.Context, request *TxRequest) (result []byte, err error) // WaitForReceipt waits until either the transaction with the given hash has been mined or the context is cancelled. @@ -140,7 +140,7 @@ func NewService(logger log.Logger, backend Backend, signer crypto.Signer, store } // Send creates and signs a transaction based on the request and sends it. -func (t *transactionService) Send(ctx context.Context, request *TxRequest, priceBoostPercent int) (txHash common.Hash, err error) { +func (t *transactionService) Send(ctx context.Context, request *TxRequest, tipCapBoostPercent int) (txHash common.Hash, err error) { loggerV1 := t.logger.V(1).Register() t.lock.Lock() @@ -151,7 +151,7 @@ func (t *transactionService) Send(ctx context.Context, request *TxRequest, price return common.Hash{}, err } - tx, err := t.prepareTransaction(ctx, request, nonce, priceBoostPercent) + tx, err := t.prepareTransaction(ctx, request, nonce, tipCapBoostPercent) if err != nil { return common.Hash{}, err } @@ -254,7 +254,7 @@ func (t *transactionService) StoredTransaction(txHash common.Hash) (*StoredTrans } // prepareTransaction creates a signable transaction based on a request. -func (t *transactionService) prepareTransaction(ctx context.Context, request *TxRequest, nonce uint64, boostPercent int) (tx *types.Transaction, err error) { +func (t *transactionService) prepareTransaction(ctx context.Context, request *TxRequest, nonce uint64, tipPercent int) (tx *types.Transaction, err error) { var gasLimit uint64 if request.GasLimit == 0 { gasLimit, err = t.backend.EstimateGas(ctx, ethereum.CallMsg{ @@ -272,25 +272,43 @@ func (t *transactionService) prepareTransaction(ctx context.Context, request *Tx gasLimit = request.GasLimit } + /* + Transactions are EIP 1559 dynamic transactions where there are three fee related fields: + 1. base fee is the price that will be burned as part of the transaction. + 2. max fee is the max price we are willing to spend as gas price. + 3. max priority fee is max price want to give to the miner to prioritize the transaction. + as an example: + if base fee is 15, max fee is 20, and max priority is 3, gas price will be 15 + 3 = 18 + if base is 15, max fee is 20, and max priority fee is 10, + gas price will be 15 + 10 = 25, but since 25 > 20, gas price is 20. + notice that gas price does not exceed 20 as defined by max fee. + */ + gasPrice := request.GasPrice if gasPrice == nil { - gasPriceSuggested, err := t.backend.SuggestGasPrice(ctx) - gasPrice = new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(boostPercent)+100), gasPriceSuggested), big.NewInt(100)) + gasPrice, err = t.backend.SuggestGasPrice(ctx) if err != nil { return nil, err } } - if gasPrice.Cmp(minGasPrice) < 0 { - return nil, ErrGasPriceTooLow + + gasTipCap, err := t.backend.SuggestGasTipCap(ctx) + if err != nil { + return nil, err } - return types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: request.To, - Value: request.Value, - Gas: gasLimit, - GasPrice: gasPrice, - Data: request.Data, + gasTipCap = new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(tipPercent)+100), gasTipCap), big.NewInt(100)) + gasFeeCap := new(big.Int).Add(gasTipCap, gasPrice) + + return types.NewTx(&types.DynamicFeeTx{ + Nonce: nonce, + ChainID: t.chainID, + To: request.To, + Value: request.Value, + Gas: gasLimit, + GasTipCap: gasTipCap, + GasFeeCap: gasFeeCap, + Data: request.Data, }), nil } @@ -385,13 +403,15 @@ func (t *transactionService) ResendTransaction(ctx context.Context, txHash commo return err } - tx := types.NewTx(&types.LegacyTx{ - Nonce: storedTransaction.Nonce, - To: storedTransaction.To, - Value: storedTransaction.Value, - Gas: storedTransaction.GasLimit, - GasPrice: storedTransaction.GasPrice, - Data: storedTransaction.Data, + tx := types.NewTx(&types.DynamicFeeTx{ + Nonce: storedTransaction.Nonce, + ChainID: t.chainID, + To: storedTransaction.To, + Value: storedTransaction.Value, + Gas: storedTransaction.GasLimit, + GasTipCap: storedTransaction.GasPrice, + GasFeeCap: storedTransaction.GasPrice, + Data: storedTransaction.Data, }) signedTx, err := t.signer.SignTx(tx, t.chainID) @@ -425,13 +445,15 @@ func (t *transactionService) CancelTransaction(ctx context.Context, originalTxHa return common.Hash{}, ErrGasPriceTooLow } - signedTx, err := t.signer.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: storedTransaction.Nonce, - To: &t.sender, - Value: big.NewInt(0), - Gas: 21000, - GasPrice: gasPrice, - Data: []byte{}, + signedTx, err := t.signer.SignTx(types.NewTx(&types.DynamicFeeTx{ + Nonce: storedTransaction.Nonce, + ChainID: t.chainID, + To: &t.sender, + Value: big.NewInt(0), + Gas: 21000, + GasTipCap: gasPrice, + GasFeeCap: gasPrice, + Data: []byte{}, }), t.chainID) if err != nil { return common.Hash{}, err diff --git a/pkg/transaction/transaction_test.go b/pkg/transaction/transaction_test.go index 12920b02aeb..557c5e59d4a 100644 --- a/pkg/transaction/transaction_test.go +++ b/pkg/transaction/transaction_test.go @@ -31,10 +31,9 @@ func nonceKey(sender common.Address) string { func signerMockForTransaction(t *testing.T, signedTx *types.Transaction, sender common.Address, signerChainID *big.Int) crypto.Signer { t.Helper() - return signermock.New( signermock.WithSignTxFunc(func(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - if transaction.Type() != 0 { + if transaction.Type() != 2 { t.Fatalf("wrong transaction type. wanted 0, got %d", transaction.Type()) } if signedTx.To() == nil { @@ -90,13 +89,15 @@ func TestTransactionSend(t *testing.T) { t.Run("send", func(t *testing.T) { t.Parallel() - signedTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: value, - Gas: estimatedGasLimit, - GasPrice: suggestedGasPrice, - Data: txData, + signedTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: value, + Gas: estimatedGasLimit, + GasTipCap: suggestedGasPrice, + GasFeeCap: suggestedGasPrice, + Data: txData, }) request := &transaction.TxRequest{ To: &recipient, @@ -133,6 +134,9 @@ func TestTransactionSend(t *testing.T) { backendmock.WithPendingNonceAtFunc(func(ctx context.Context, account common.Address) (uint64, error) { return nonce - 1, nil }), + backendmock.WithSuggestGasTipCapFunc(func(ctx context.Context) (*big.Int, error) { + return big.NewInt(0), nil + }), ), signerMockForTransaction(t, signedTx, sender, chainID), store, @@ -211,13 +215,20 @@ func TestTransactionSend(t *testing.T) { t.Run("sendWithBoost", func(t *testing.T) { t.Parallel() - signedTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: value, - Gas: estimatedGasLimit, - GasPrice: big.NewInt(0).Div(new(big.Int).Mul(suggestedGasPrice, big.NewInt(15)), big.NewInt(10)), - Data: txData, + price := big.NewInt(0).Div(new(big.Int).Mul(suggestedGasPrice, big.NewInt(25)), big.NewInt(10)) + + // tip is the same as suggestedGasPrice and boost is 50% + // so final gas price will be 2.5x suggestedGasPrice + + signedTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: value, + Gas: estimatedGasLimit, + GasTipCap: suggestedGasPrice, + GasFeeCap: price, + Data: txData, }) request := &transaction.TxRequest{ To: &recipient, @@ -253,6 +264,9 @@ func TestTransactionSend(t *testing.T) { backendmock.WithPendingNonceAtFunc(func(ctx context.Context, account common.Address) (uint64, error) { return nonce - 1, nil }), + backendmock.WithSuggestGasTipCapFunc(func(ctx context.Context) (*big.Int, error) { + return suggestedGasPrice, nil + }), ), signerMockForTransaction(t, signedTx, sender, chainID), store, @@ -307,8 +321,8 @@ func TestTransactionSend(t *testing.T) { t.Fatalf("got wrong gas limit in stored transaction. wanted %d, got %d", estimatedGasLimit, storedTransaction.GasLimit) } - if new(big.Int).Div(new(big.Int).Mul(suggestedGasPrice, big.NewInt(15)), big.NewInt(10)).Cmp(storedTransaction.GasPrice) != 0 { - t.Fatalf("got wrong gas price in stored transaction. wanted %d, got %d", suggestedGasPrice, storedTransaction.GasPrice) + if want := new(big.Int).Div(new(big.Int).Mul(suggestedGasPrice, big.NewInt(25)), big.NewInt(10)); want.Cmp(storedTransaction.GasPrice) != 0 { + t.Fatalf("got wrong gas price in stored transaction. wanted %d, got %d", want, storedTransaction.GasPrice) } if storedTransaction.Nonce != nonce { @@ -331,13 +345,15 @@ func TestTransactionSend(t *testing.T) { t.Run("send_no_nonce", func(t *testing.T) { t.Parallel() - signedTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: value, - Gas: estimatedGasLimit, - GasPrice: suggestedGasPrice, - Data: txData, + signedTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: value, + Gas: estimatedGasLimit, + GasTipCap: suggestedGasPrice, + GasFeeCap: suggestedGasPrice, + Data: txData, }) request := &transaction.TxRequest{ To: &recipient, @@ -369,6 +385,9 @@ func TestTransactionSend(t *testing.T) { backendmock.WithPendingNonceAtFunc(func(ctx context.Context, account common.Address) (uint64, error) { return nonce, nil }), + backendmock.WithSuggestGasTipCapFunc(func(ctx context.Context) (*big.Int, error) { + return big.NewInt(0), nil + }), ), signerMockForTransaction(t, signedTx, sender, chainID), store, @@ -403,13 +422,15 @@ func TestTransactionSend(t *testing.T) { t.Parallel() nextNonce := nonce + 5 - signedTx := types.NewTx(&types.LegacyTx{ - Nonce: nextNonce, - To: &recipient, - Value: value, - Gas: estimatedGasLimit, - GasPrice: suggestedGasPrice, - Data: txData, + signedTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nextNonce, + To: &recipient, + Value: value, + Gas: estimatedGasLimit, + GasTipCap: suggestedGasPrice, + GasFeeCap: suggestedGasPrice, + Data: txData, }) request := &transaction.TxRequest{ To: &recipient, @@ -445,6 +466,9 @@ func TestTransactionSend(t *testing.T) { backendmock.WithPendingNonceAtFunc(func(ctx context.Context, account common.Address) (uint64, error) { return nextNonce, nil }), + backendmock.WithSuggestGasTipCapFunc(func(ctx context.Context) (*big.Int, error) { + return big.NewInt(0), nil + }), ), signerMockForTransaction(t, signedTx, sender, chainID), store, @@ -550,13 +574,15 @@ func TestTransactionResend(t *testing.T) { store := storemock.NewStateStore() defer store.Close() - signedTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: value, - Gas: gasLimit, - GasPrice: gasPrice, - Data: data, + signedTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: value, + Gas: gasLimit, + GasTipCap: gasPrice, + GasFeeCap: gasPrice, + Data: data, }) err := store.Put(transaction.StoredTransactionKey(signedTx.Hash()), transaction.StoredTransaction{ @@ -611,13 +637,15 @@ func TestTransactionCancel(t *testing.T) { store := storemock.NewStateStore() t.Cleanup(func() { store.Close() }) - signedTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: value, - Gas: gasLimit, - GasPrice: gasPrice, - Data: data, + signedTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: value, + Gas: gasLimit, + GasTipCap: gasPrice, + GasFeeCap: gasPrice, + Data: data, }) err := store.Put(transaction.StoredTransactionKey(signedTx.Hash()), transaction.StoredTransaction{ Nonce: nonce, @@ -634,13 +662,17 @@ func TestTransactionCancel(t *testing.T) { t.Run("ok", func(t *testing.T) { t.Parallel() - cancelTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: big.NewInt(0), - Gas: 21000, - GasPrice: new(big.Int).Add(gasPrice, big.NewInt(1)), - Data: []byte{}, + price := new(big.Int).Add(gasPrice, big.NewInt(1)) + + cancelTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: big.NewInt(0), + Gas: 21000, + GasTipCap: price, + GasFeeCap: price, + Data: []byte{}, }) transactionService, err := transaction.NewService(logger, @@ -676,13 +708,15 @@ func TestTransactionCancel(t *testing.T) { t.Parallel() customGasPrice := big.NewInt(5) - cancelTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: big.NewInt(0), - Gas: 21000, - GasPrice: customGasPrice, - Data: []byte{}, + cancelTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: big.NewInt(0), + Gas: 21000, + GasTipCap: customGasPrice, + GasFeeCap: customGasPrice, + Data: []byte{}, }) transactionService, err := transaction.NewService(logger, @@ -719,13 +753,15 @@ func TestTransactionCancel(t *testing.T) { t.Parallel() customGasPrice := big.NewInt(0) - cancelTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: &recipient, - Value: big.NewInt(0), - Gas: 21000, - GasPrice: customGasPrice, - Data: []byte{}, + cancelTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: big.NewInt(0), + Gas: 21000, + GasTipCap: customGasPrice, + GasFeeCap: customGasPrice, + Data: []byte{}, }) transactionService, err := transaction.NewService(logger, diff --git a/pkg/transaction/wrapped/wrapped.go b/pkg/transaction/wrapped/wrapped.go index c4e5b82d953..24d8e3d5a0c 100644 --- a/pkg/transaction/wrapped/wrapped.go +++ b/pkg/transaction/wrapped/wrapped.go @@ -147,6 +147,17 @@ func (b *wrappedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) return gasPrice, nil } +func (b *wrappedBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + b.metrics.TotalRPCCalls.Inc() + b.metrics.SuggestGasPriceCalls.Inc() + gasTipCap, err := b.backend.SuggestGasTipCap(ctx) + if err != nil { + b.metrics.TotalRPCErrors.Inc() + return nil, err + } + return gasTipCap, nil +} + func (b *wrappedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { b.metrics.TotalRPCCalls.Inc() b.metrics.EstimateGasCalls.Inc()