From c39baa80d22fb0a4bad57194e6e6175556cc1a4b Mon Sep 17 00:00:00 2001 From: saledjenic <86303051+saledjenic@users.noreply.github.com> Date: Tue, 13 Aug 2024 12:17:08 +0200 Subject: [PATCH] chore_: cherry-pick #5658: improvements on resolving nonce (#5690) * chore_: unused `BuildTx` function removed from the processor interface and types that are implement it Since the `BuildTx` function is not used anywhere, it's removed from the code. * fix_: resolving nonce improvements When the app sends more than a single tx from the same account on the same chain, some chains do not return appropriate nonce (they do not consider pending txs), because of that we place more tx with the same nonce, where all but the first one fail. Changes in this PR keep track of nonces being used in the same sending/bridging flow, which means for the first tx from the multi txs the app asks the chain for the nonce, and every next nonce is resolved by incrementing the last used nonce by 1. --- api/geth_backend.go | 6 +- services/communitytokens/estimations.go | 2 +- .../mock_pathprocessor/processor.go | 91 ++++++++++--------- .../wallet/router/pathprocessor/processor.go | 10 +- .../pathprocessor/processor_bridge_celar.go | 41 +++------ .../pathprocessor/processor_bridge_hop.go | 48 ++++------ .../pathprocessor/processor_ens_public_key.go | 29 +----- .../pathprocessor/processor_ens_register.go | 29 +----- .../pathprocessor/processor_ens_release.go | 29 +----- .../router/pathprocessor/processor_erc1155.go | 53 ++++------- .../router/pathprocessor/processor_erc721.go | 52 ++++------- .../pathprocessor/processor_stickers_buy.go | 29 +----- .../pathprocessor/processor_swap_paraswap.go | 33 ++----- .../pathprocessor/processor_transfer.go | 48 +--------- services/wallet/transfer/helpers.go | 11 ++- .../wallet/transfer/transaction_manager.go | 2 +- .../transfer/transaction_manager_internal.go | 11 ++- ...ansaction_manager_multitransaction_test.go | 10 +- .../transfer/transaction_manager_test.go | 4 +- services/web3provider/signature.go | 2 +- transactions/mock_transactor/transactor.go | 42 +++++---- transactions/transactor.go | 46 ++++++---- transactions/transactor_test.go | 16 ++-- 23 files changed, 231 insertions(+), 413 deletions(-) diff --git a/api/geth_backend.go b/api/geth_backend.go index dc751c17d..69b00be78 100644 --- a/api/geth_backend.go +++ b/api/geth_backend.go @@ -2223,7 +2223,8 @@ func (b *GethStatusBackend) SendTransaction(sendArgs transactions.SendTxArgs, pa return hash, err } - return b.transactor.SendTransaction(sendArgs, verifiedAccount) + hash, _, err = b.transactor.SendTransaction(sendArgs, verifiedAccount, -1) + return hash, err } func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs transactions.SendTxArgs, password string) (hash types.Hash, err error) { @@ -2232,7 +2233,8 @@ func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs return hash, err } - return b.transactor.SendTransactionWithChainID(chainID, sendArgs, verifiedAccount) + hash, _, err = b.transactor.SendTransactionWithChainID(chainID, sendArgs, -1, verifiedAccount) + return hash, err } func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.SendTxArgs, sig []byte) (hash types.Hash, err error) { diff --git a/services/communitytokens/estimations.go b/services/communitytokens/estimations.go index 5b1816ca0..c9b85bb5d 100644 --- a/services/communitytokens/estimations.go +++ b/services/communitytokens/estimations.go @@ -388,7 +388,7 @@ func (s *Service) suggestedFeesToSendTxArgs(from common.Address, to *common.Addr } func (s *Service) estimateL1Fee(ctx context.Context, chainID uint64, sendArgs transactions.SendTxArgs) (uint64, error) { - transaction, err := s.transactor.ValidateAndBuildTransaction(chainID, sendArgs) + transaction, _, err := s.transactor.ValidateAndBuildTransaction(chainID, sendArgs, -1) if err != nil { return 0, err } diff --git a/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go b/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go index 45a051ad1..fd217c338 100644 --- a/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go +++ b/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go @@ -8,10 +8,9 @@ import ( big "math/big" reflect "reflect" - gomock "github.com/golang/mock/gomock" - common "github.com/ethereum/go-ethereum/common" types "github.com/ethereum/go-ethereum/core/types" + gomock "github.com/golang/mock/gomock" account "github.com/status-im/status-go/account" types0 "github.com/status-im/status-go/eth-node/types" pathprocessor "github.com/status-im/status-go/services/wallet/router/pathprocessor" @@ -56,33 +55,19 @@ func (mr *MockPathProcessorMockRecorder) AvailableFor(params interface{}) *gomoc } // BuildTransaction mocks base method. -func (m *MockPathProcessor) BuildTransaction(sendArgs *pathprocessor.MultipathProcessorTxArgs) (*types.Transaction, error) { +func (m *MockPathProcessor) BuildTransaction(sendArgs *pathprocessor.MultipathProcessorTxArgs, lastUsedNonce int64) (*types.Transaction, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BuildTransaction", sendArgs) + ret := m.ctrl.Call(m, "BuildTransaction", sendArgs, lastUsedNonce) ret0, _ := ret[0].(*types.Transaction) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // BuildTransaction indicates an expected call of BuildTransaction. -func (mr *MockPathProcessorMockRecorder) BuildTransaction(sendArgs interface{}) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) BuildTransaction(sendArgs, lastUsedNonce interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildTransaction", reflect.TypeOf((*MockPathProcessor)(nil).BuildTransaction), sendArgs) -} - -// BuildTx mocks base method. -func (m *MockPathProcessor) BuildTx(params pathprocessor.ProcessorInputParams) (*types.Transaction, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BuildTx", params) - ret0, _ := ret[0].(*types.Transaction) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// BuildTx indicates an expected call of BuildTx. -func (mr *MockPathProcessorMockRecorder) BuildTx(params interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildTx", reflect.TypeOf((*MockPathProcessor)(nil).BuildTx), params) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildTransaction", reflect.TypeOf((*MockPathProcessor)(nil).BuildTransaction), sendArgs, lastUsedNonce) } // CalculateAmountOut mocks base method. @@ -116,18 +101,6 @@ func (mr *MockPathProcessorMockRecorder) CalculateFees(params interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateFees", reflect.TypeOf((*MockPathProcessor)(nil).CalculateFees), params) } -// Clear mocks base method. -func (m *MockPathProcessor) Clear() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Clear") -} - -// Clear indicates an expected call of Clear. -func (mr *MockPathProcessorMockRecorder) Clear() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clear", reflect.TypeOf((*MockPathProcessor)(nil).Clear)) -} - // EstimateGas mocks base method. func (m *MockPathProcessor) EstimateGas(params pathprocessor.ProcessorInputParams) (uint64, error) { m.ctrl.T.Helper() @@ -188,16 +161,52 @@ func (mr *MockPathProcessorMockRecorder) PackTxInputData(params interface{}) *go } // Send mocks base method. -func (m *MockPathProcessor) Send(sendArgs *pathprocessor.MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (types0.Hash, error) { +func (m *MockPathProcessor) Send(sendArgs *pathprocessor.MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types0.Hash, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Send", sendArgs, verifiedAccount) + ret := m.ctrl.Call(m, "Send", sendArgs, lastUsedNonce, verifiedAccount) ret0, _ := ret[0].(types0.Hash) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // Send indicates an expected call of Send. -func (mr *MockPathProcessorMockRecorder) Send(sendArgs, verifiedAccount interface{}) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) Send(sendArgs, lastUsedNonce, verifiedAccount interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockPathProcessor)(nil).Send), sendArgs, verifiedAccount) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockPathProcessor)(nil).Send), sendArgs, lastUsedNonce, verifiedAccount) +} + +// MockPathProcessorClearable is a mock of PathProcessorClearable interface. +type MockPathProcessorClearable struct { + ctrl *gomock.Controller + recorder *MockPathProcessorClearableMockRecorder +} + +// MockPathProcessorClearableMockRecorder is the mock recorder for MockPathProcessorClearable. +type MockPathProcessorClearableMockRecorder struct { + mock *MockPathProcessorClearable +} + +// NewMockPathProcessorClearable creates a new mock instance. +func NewMockPathProcessorClearable(ctrl *gomock.Controller) *MockPathProcessorClearable { + mock := &MockPathProcessorClearable{ctrl: ctrl} + mock.recorder = &MockPathProcessorClearableMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPathProcessorClearable) EXPECT() *MockPathProcessorClearableMockRecorder { + return m.recorder +} + +// Clear mocks base method. +func (m *MockPathProcessorClearable) Clear() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Clear") +} + +// Clear indicates an expected call of Clear. +func (mr *MockPathProcessorClearableMockRecorder) Clear() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clear", reflect.TypeOf((*MockPathProcessorClearable)(nil).Clear)) } diff --git a/services/wallet/router/pathprocessor/processor.go b/services/wallet/router/pathprocessor/processor.go index a82fa9d94..d337439b4 100644 --- a/services/wallet/router/pathprocessor/processor.go +++ b/services/wallet/router/pathprocessor/processor.go @@ -25,14 +25,12 @@ type PathProcessor interface { EstimateGas(params ProcessorInputParams) (uint64, error) // CalculateAmountOut calculates the amount out CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) - // Send sends the tx - Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (types.Hash, error) + // Send sends the tx, returns the hash and the used nonce (lastUsedNonce is -1 if it's the first tx) + Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types.Hash, uint64, error) // GetContractAddress returns the contract address GetContractAddress(params ProcessorInputParams) (common.Address, error) - // BuildTransaction builds the transaction based on MultipathProcessorTxArgs - BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) - // BuildTx builds the transaction based on ProcessorInputParams - BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) + // BuildTransaction builds the transaction based on MultipathProcessorTxArgs, returns the transaction and the used nonce (lastUsedNonce is -1 if it's the first tx) + BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) } type PathProcessorClearable interface { diff --git a/services/wallet/router/pathprocessor/processor_bridge_celar.go b/services/wallet/router/pathprocessor/processor_bridge_celar.go index 38afb41a3..1b11513d1 100644 --- a/services/wallet/router/pathprocessor/processor_bridge_celar.go +++ b/services/wallet/router/pathprocessor/processor_bridge_celar.go @@ -283,27 +283,6 @@ func (s *CelerBridgeProcessor) EstimateGas(params ProcessorInputParams) (uint64, return uint64(increasedEstimation), nil } -func (s *CelerBridgeProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - sendArgs := &MultipathProcessorTxArgs{ - CbridgeTx: &CelerBridgeTxArgs{ - SendTxArgs: transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(params.AmountIn), - Data: types.HexBytes("0x0"), - }, - ChainID: params.ToChain.ChainID, - Symbol: params.FromToken.Symbol, - Recipient: params.ToAddr, - Amount: (*hexutil.Big)(params.AmountIn), - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) -} - func (s *CelerBridgeProcessor) GetContractAddress(params ProcessorInputParams) (common.Address, error) { transferConfig, err := s.getTransferConfig(params.FromChain.IsTest) if err != nil { @@ -322,7 +301,7 @@ func (s *CelerBridgeProcessor) GetContractAddress(params ProcessorInputParams) ( return common.Address{}, ErrContractNotFound } -func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn) (*ethTypes.Transaction, error) { +func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (*ethTypes.Transaction, error) { fromChain := s.rpcClient.NetworkManager.Find(sendArgs.ChainID) if fromChain == nil { return nil, ErrNetworkNotFound @@ -347,6 +326,11 @@ func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, s return nil, createBridgeCellerErrorResponse(err) } + if lastUsedNonce >= 0 { + lastUsedNonceHexUtil := hexutil.Uint64(uint64(lastUsedNonce) + 1) + sendArgs.CbridgeTx.Nonce = &lastUsedNonceHexUtil + } + var tx *ethTypes.Transaction txOpts := sendArgs.CbridgeTx.ToTransactOpts(signerFn) if token.IsNative() { @@ -379,17 +363,18 @@ func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, s return tx, nil } -func (s *CelerBridgeProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (types.Hash, error) { - tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.CbridgeTx.From, verifiedAccount)) +func (s *CelerBridgeProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types.Hash, uint64, error) { + tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.CbridgeTx.From, verifiedAccount), lastUsedNonce) if err != nil { - return types.HexToHash(""), createBridgeCellerErrorResponse(err) + return types.HexToHash(""), 0, createBridgeCellerErrorResponse(err) } - return types.Hash(tx.Hash()), nil + return types.Hash(tx.Hash()), tx.Nonce(), nil } -func (s *CelerBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.sendOrBuild(sendArgs, nil) +func (s *CelerBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := s.sendOrBuild(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), err } func (s *CelerBridgeProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_bridge_hop.go b/services/wallet/router/pathprocessor/processor_bridge_hop.go index c27354888..6c28e26e3 100644 --- a/services/wallet/router/pathprocessor/processor_bridge_hop.go +++ b/services/wallet/router/pathprocessor/processor_bridge_hop.go @@ -277,34 +277,12 @@ func (h *HopBridgeProcessor) EstimateGas(params ProcessorInputParams) (uint64, e return uint64(increasedEstimation), nil } -func (h *HopBridgeProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - sendArgs := &MultipathProcessorTxArgs{ - HopTx: &HopBridgeTxArgs{ - SendTxArgs: transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(params.AmountIn), - Data: types.HexBytes("0x0"), - }, - Symbol: params.FromToken.Symbol, - Recipient: params.ToAddr, - Amount: (*hexutil.Big)(params.AmountIn), - BonderFee: (*hexutil.Big)(params.BonderFee), - ChainID: params.ToChain.ChainID, - }, - ChainID: params.FromChain.ChainID, - } - - return h.BuildTransaction(sendArgs) -} - func (h *HopBridgeProcessor) GetContractAddress(params ProcessorInputParams) (common.Address, error) { address, _, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol) return address, createBridgeHopErrorResponse(err) } -func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) { +func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { fromChain := h.networkManager.Find(sendArgs.HopTx.ChainID) if fromChain == nil { return tx, fmt.Errorf("ChainID not supported %d", sendArgs.HopTx.ChainID) @@ -312,9 +290,14 @@ func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, sig token := h.tokenManager.FindToken(fromChain, sendArgs.HopTx.Symbol) - nonce, err := h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.HopTx.From) - if err != nil { - return tx, createBridgeHopErrorResponse(err) + var nonce uint64 + if lastUsedNonce < 0 { + nonce, err = h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.HopTx.From) + if err != nil { + return tx, createBridgeHopErrorResponse(err) + } + } else { + nonce = uint64(lastUsedNonce) + 1 } argNonce := hexutil.Uint64(nonce) @@ -366,16 +349,17 @@ func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, sig return tx, nil } -func (h *HopBridgeProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - tx, err := h.sendOrBuild(sendArgs, getSigner(sendArgs.HopTx.ChainID, sendArgs.HopTx.From, verifiedAccount)) +func (h *HopBridgeProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error) { + tx, err := h.sendOrBuild(sendArgs, getSigner(sendArgs.HopTx.ChainID, sendArgs.HopTx.From, verifiedAccount), lastUsedNonce) if err != nil { - return types.Hash{}, createBridgeHopErrorResponse(err) + return types.Hash{}, 0, createBridgeHopErrorResponse(err) } - return types.Hash(tx.Hash()), nil + return types.Hash(tx.Hash()), tx.Nonce(), nil } -func (h *HopBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return h.sendOrBuild(sendArgs, nil) +func (h *HopBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := h.sendOrBuild(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), createBridgeHopErrorResponse(err) } func (h *HopBridgeProcessor) CalculateFees(params ProcessorInputParams) (*big.Int, *big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_ens_public_key.go b/services/wallet/router/pathprocessor/processor_ens_public_key.go index bbc2c90b3..71913bc33 100644 --- a/services/wallet/router/pathprocessor/processor_ens_public_key.go +++ b/services/wallet/router/pathprocessor/processor_ens_public_key.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/status-im/status-go/account" "github.com/status-im/status-go/contracts" @@ -104,32 +103,12 @@ func (s *ENSPublicKeyProcessor) EstimateGas(params ProcessorInputParams) (uint64 return uint64(increasedEstimation), nil } -func (s *ENSPublicKeyProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - inputData, err := s.PackTxInputData(params) - if err != nil { - return nil, createENSPublicKeyErrorResponse(err) - } - - sendArgs := &MultipathProcessorTxArgs{ - TransferTx: &transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(ZeroBigIntValue), - Data: inputData, - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) +func (s *ENSPublicKeyProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) { + return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce, verifiedAccount) } -func (s *ENSPublicKeyProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount) -} - -func (s *ENSPublicKeyProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx) +func (s *ENSPublicKeyProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } func (s *ENSPublicKeyProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_ens_register.go b/services/wallet/router/pathprocessor/processor_ens_register.go index eac6e0c96..2eed73c2c 100644 --- a/services/wallet/router/pathprocessor/processor_ens_register.go +++ b/services/wallet/router/pathprocessor/processor_ens_register.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/status-im/status-go/account" "github.com/status-im/status-go/contracts" @@ -140,32 +139,12 @@ func (s *ENSRegisterProcessor) EstimateGas(params ProcessorInputParams) (uint64, return uint64(increasedEstimation), nil } -func (s *ENSRegisterProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - inputData, err := s.PackTxInputData(params) - if err != nil { - return nil, createENSRegisterProcessorErrorResponse(err) - } - - sendArgs := &MultipathProcessorTxArgs{ - TransferTx: &transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(ZeroBigIntValue), - Data: inputData, - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) +func (s *ENSRegisterProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) { + return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce, verifiedAccount) } -func (s *ENSRegisterProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount) -} - -func (s *ENSRegisterProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx) +func (s *ENSRegisterProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } func (s *ENSRegisterProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_ens_release.go b/services/wallet/router/pathprocessor/processor_ens_release.go index 76a61dec5..70772b8f6 100644 --- a/services/wallet/router/pathprocessor/processor_ens_release.go +++ b/services/wallet/router/pathprocessor/processor_ens_release.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/status-im/status-go/account" "github.com/status-im/status-go/contracts" @@ -103,32 +102,12 @@ func (s *ENSReleaseProcessor) EstimateGas(params ProcessorInputParams) (uint64, return uint64(increasedEstimation), nil } -func (s *ENSReleaseProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - inputData, err := s.PackTxInputData(params) - if err != nil { - return nil, createENSReleaseErrorResponse(err) - } - - sendArgs := &MultipathProcessorTxArgs{ - TransferTx: &transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(ZeroBigIntValue), - Data: inputData, - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) +func (s *ENSReleaseProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) { + return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce, verifiedAccount) } -func (s *ENSReleaseProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount) -} - -func (s *ENSReleaseProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx) +func (s *ENSReleaseProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } func (s *ENSReleaseProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_erc1155.go b/services/wallet/router/pathprocessor/processor_erc1155.go index 4dd6e6b03..b4e68710c 100644 --- a/services/wallet/router/pathprocessor/processor_erc1155.go +++ b/services/wallet/router/pathprocessor/processor_erc1155.go @@ -108,34 +108,7 @@ func (s *ERC1155Processor) EstimateGas(params ProcessorInputParams) (uint64, err return uint64(increasedEstimation), nil } -func (s *ERC1155Processor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - contractAddress := types.Address(params.FromToken.Address) - - // We store ERC1155 Token ID using big.Int.String() in token.Symbol - tokenID, success := new(big.Int).SetString(params.FromToken.Symbol, 10) - if !success { - return nil, createERC1155ErrorResponse(fmt.Errorf("failed to convert ERC1155's Symbol %s to big.Int", params.FromToken.Symbol)) - } - - sendArgs := &MultipathProcessorTxArgs{ - ERC1155TransferTx: &ERC1155TxArgs{ - SendTxArgs: transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &contractAddress, - Value: (*hexutil.Big)(params.AmountIn), - Data: types.HexBytes("0x0"), - }, - TokenID: (*hexutil.Big)(tokenID), - Recipient: params.ToAddr, - Amount: (*hexutil.Big)(params.AmountIn), - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) -} - -func (s *ERC1155Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) { +func (s *ERC1155Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { ethClient, err := s.rpcClient.EthClient(sendArgs.ChainID) if err != nil { return tx, createERC1155ErrorResponse(err) @@ -146,9 +119,14 @@ func (s *ERC1155Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signe return tx, createERC1155ErrorResponse(err) } - nonce, err := s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC1155TransferTx.From) - if err != nil { - return tx, createERC1155ErrorResponse(err) + var nonce uint64 + if lastUsedNonce < 0 { + nonce, err = s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC1155TransferTx.From) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + } else { + nonce = uint64(lastUsedNonce) + 1 } argNonce := hexutil.Uint64(nonce) @@ -172,16 +150,17 @@ func (s *ERC1155Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signe return tx, nil } -func (s *ERC1155Processor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC1155TransferTx.From, verifiedAccount)) +func (s *ERC1155Processor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) { + tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC1155TransferTx.From, verifiedAccount), lastUsedNonce) if err != nil { - return hash, createERC1155ErrorResponse(err) + return hash, 0, createERC1155ErrorResponse(err) } - return types.Hash(tx.Hash()), nil + return types.Hash(tx.Hash()), tx.Nonce(), nil } -func (s *ERC1155Processor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.sendOrBuild(sendArgs, nil) +func (s *ERC1155Processor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := s.sendOrBuild(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), err } func (s *ERC1155Processor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_erc721.go b/services/wallet/router/pathprocessor/processor_erc721.go index b8f14557f..fe5f74f7c 100644 --- a/services/wallet/router/pathprocessor/processor_erc721.go +++ b/services/wallet/router/pathprocessor/processor_erc721.go @@ -106,33 +106,7 @@ func (s *ERC721Processor) EstimateGas(params ProcessorInputParams) (uint64, erro return uint64(increasedEstimation), nil } -func (s *ERC721Processor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - contractAddress := types.Address(params.FromToken.Address) - - // We store ERC721 Token ID using big.Int.String() in token.Symbol - tokenID, success := new(big.Int).SetString(params.FromToken.Symbol, 10) - if !success { - return nil, createERC721ErrorResponse(fmt.Errorf("failed to convert ERC721's Symbol %s to big.Int", params.FromToken.Symbol)) - } - - sendArgs := &MultipathProcessorTxArgs{ - ERC721TransferTx: &ERC721TxArgs{ - SendTxArgs: transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &contractAddress, - Value: (*hexutil.Big)(params.AmountIn), - Data: types.HexBytes("0x0"), - }, - TokenID: (*hexutil.Big)(tokenID), - Recipient: params.ToAddr, - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) -} - -func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) { +func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { ethClient, err := s.rpcClient.EthClient(sendArgs.ChainID) if err != nil { return tx, createERC721ErrorResponse(err) @@ -143,9 +117,14 @@ func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signer return tx, createERC721ErrorResponse(err) } - nonce, err := s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From) - if err != nil { - return tx, createERC721ErrorResponse(err) + var nonce uint64 + if lastUsedNonce < 0 { + nonce, err = s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From) + if err != nil { + return tx, createERC721ErrorResponse(err) + } + } else { + nonce = uint64(lastUsedNonce) + 1 } argNonce := hexutil.Uint64(nonce) @@ -165,16 +144,17 @@ func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signer return tx, nil } -func (s *ERC721Processor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC721TransferTx.From, verifiedAccount)) +func (s *ERC721Processor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) { + tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC721TransferTx.From, verifiedAccount), lastUsedNonce) if err != nil { - return hash, createERC721ErrorResponse(err) + return hash, 0, createERC721ErrorResponse(err) } - return types.Hash(tx.Hash()), nil + return types.Hash(tx.Hash()), tx.Nonce(), nil } -func (s *ERC721Processor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.sendOrBuild(sendArgs, nil) +func (s *ERC721Processor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := s.sendOrBuild(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), err } func (s *ERC721Processor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_stickers_buy.go b/services/wallet/router/pathprocessor/processor_stickers_buy.go index c8433adfe..540ad3b6e 100644 --- a/services/wallet/router/pathprocessor/processor_stickers_buy.go +++ b/services/wallet/router/pathprocessor/processor_stickers_buy.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/status-im/status-go/account" "github.com/status-im/status-go/contracts" @@ -132,32 +131,12 @@ func (s *StickersBuyProcessor) EstimateGas(params ProcessorInputParams) (uint64, return uint64(increasedEstimation), nil } -func (s *StickersBuyProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - inputData, err := s.PackTxInputData(params) - if err != nil { - return nil, createStickersBuyErrorResponse(err) - } - - sendArgs := &MultipathProcessorTxArgs{ - TransferTx: &transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(ZeroBigIntValue), - Data: inputData, - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) +func (s *StickersBuyProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) { + return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce, verifiedAccount) } -func (s *StickersBuyProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount) -} - -func (s *StickersBuyProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx) +func (s *StickersBuyProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } func (s *StickersBuyProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_swap_paraswap.go b/services/wallet/router/pathprocessor/processor_swap_paraswap.go index e6e247a31..649e02ac6 100644 --- a/services/wallet/router/pathprocessor/processor_swap_paraswap.go +++ b/services/wallet/router/pathprocessor/processor_swap_paraswap.go @@ -209,27 +209,6 @@ func (s *SwapParaswapProcessor) GetContractAddress(params ProcessorInputParams) return } -func (s *SwapParaswapProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - sendArgs := &MultipathProcessorTxArgs{ - SwapTx: &SwapParaswapTxArgs{ - SendTxArgs: transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(params.AmountIn), - Data: types.HexBytes("0x0"), - Symbol: params.FromToken.Symbol, - }, - ChainID: params.FromChain.ChainID, - ChainIDTo: params.ToChain.ChainID, - TokenIDFrom: params.FromToken.Symbol, - TokenIDTo: params.ToToken.Symbol, - }, - } - - return s.BuildTransaction(sendArgs) -} - func (s *SwapParaswapProcessor) prepareTransaction(sendArgs *MultipathProcessorTxArgs) error { slippageBP := uint(sendArgs.SwapTx.SlippagePercentage * 100) // convert to basis points @@ -276,21 +255,21 @@ func (s *SwapParaswapProcessor) prepareTransaction(sendArgs *MultipathProcessorT return nil } -func (s *SwapParaswapProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { +func (s *SwapParaswapProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { err := s.prepareTransaction(sendArgs) if err != nil { - return nil, createSwapParaswapErrorResponse(err) + return nil, 0, createSwapParaswapErrorResponse(err) } - return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, sendArgs.SwapTx.SendTxArgs) + return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, sendArgs.SwapTx.SendTxArgs, lastUsedNonce) } -func (s *SwapParaswapProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (types.Hash, error) { +func (s *SwapParaswapProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types.Hash, uint64, error) { err := s.prepareTransaction(sendArgs) if err != nil { - return types.Hash{}, createSwapParaswapErrorResponse(err) + return types.Hash{}, 0, createSwapParaswapErrorResponse(err) } - return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, sendArgs.SwapTx.SendTxArgs, verifiedAccount) + return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, sendArgs.SwapTx.SendTxArgs, lastUsedNonce, verifiedAccount) } func (s *SwapParaswapProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/router/pathprocessor/processor_transfer.go b/services/wallet/router/pathprocessor/processor_transfer.go index 15bb974c7..33baf256b 100644 --- a/services/wallet/router/pathprocessor/processor_transfer.go +++ b/services/wallet/router/pathprocessor/processor_transfer.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/status-im/status-go/account" "github.com/status-im/status-go/contracts/ierc20" @@ -114,51 +113,12 @@ func (s *TransferProcessor) EstimateGas(params ProcessorInputParams) (uint64, er return uint64(increasedEstimation), nil } -func (s *TransferProcessor) BuildTx(params ProcessorInputParams) (*ethTypes.Transaction, error) { - toAddr := types.Address(params.ToAddr) - if params.FromToken.IsNative() { - sendArgs := &MultipathProcessorTxArgs{ - TransferTx: &transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(params.AmountIn), - Data: types.HexBytes("0x0"), - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) - } - abi, err := abi.JSON(strings.NewReader(ierc20.IERC20ABI)) - if err != nil { - return nil, createTransferErrorResponse(err) - } - input, err := abi.Pack("transfer", - params.ToAddr, - params.AmountIn, - ) - if err != nil { - return nil, createTransferErrorResponse(err) - } - sendArgs := &MultipathProcessorTxArgs{ - TransferTx: &transactions.SendTxArgs{ - From: types.Address(params.FromAddr), - To: &toAddr, - Value: (*hexutil.Big)(ZeroBigIntValue), - Data: input, - }, - ChainID: params.FromChain.ChainID, - } - - return s.BuildTransaction(sendArgs) +func (s *TransferProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types.Hash, uint64, error) { + return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce, verifiedAccount) } -func (s *TransferProcessor) Send(sendArgs *MultipathProcessorTxArgs, verifiedAccount *account.SelectedExtKey) (types.Hash, error) { - return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount) -} - -func (s *TransferProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs) (*ethTypes.Transaction, error) { - return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx) +func (s *TransferProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } func (s *TransferProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { diff --git a/services/wallet/transfer/helpers.go b/services/wallet/transfer/helpers.go index 6a8ee9547..8733bea22 100644 --- a/services/wallet/transfer/helpers.go +++ b/services/wallet/transfer/helpers.go @@ -158,12 +158,21 @@ func sendTransactions(data []*pathprocessor.MultipathProcessorTxArgs, pathProces map[uint64][]types.Hash, error) { hashes := make(map[uint64][]types.Hash) + usedNonces := make(map[uint64]int64) for _, tx := range data { - hash, err := pathProcessors[tx.Name].Send(tx, account) + + lastUsedNonce := int64(-1) + if nonce, ok := usedNonces[tx.ChainID]; ok { + lastUsedNonce = nonce + } + + hash, usedNonce, err := pathProcessors[tx.Name].Send(tx, lastUsedNonce, account) if err != nil { return nil, err // TODO: One of transfers within transaction could have been sent. Need to notify user about it } + hashes[tx.ChainID] = append(hashes[tx.ChainID], hash) + usedNonces[tx.ChainID] = int64(usedNonce) } return hashes, nil } diff --git a/services/wallet/transfer/transaction_manager.go b/services/wallet/transfer/transaction_manager.go index 184cb9718..c839d4f6c 100644 --- a/services/wallet/transfer/transaction_manager.go +++ b/services/wallet/transfer/transaction_manager.go @@ -182,7 +182,7 @@ func (tm *TransactionManager) BuildTransaction(chainID uint64, sendArgs transact return nil, err } - txBeingSigned, err := tm.transactor.ValidateAndBuildTransaction(chainID, sendArgs) + txBeingSigned, _, err := tm.transactor.ValidateAndBuildTransaction(chainID, sendArgs, -1) if err != nil { return nil, err } diff --git a/services/wallet/transfer/transaction_manager_internal.go b/services/wallet/transfer/transaction_manager_internal.go index 507283af6..f50991d13 100644 --- a/services/wallet/transfer/transaction_manager_internal.go +++ b/services/wallet/transfer/transaction_manager_internal.go @@ -11,8 +11,15 @@ import ( func (tm *TransactionManager) buildTransactions(pathProcessors map[string]pathprocessor.PathProcessor) ([]string, error) { tm.transactionsForKeycardSigning = make(map[common.Hash]*TransactionDescription) var hashes []string + usedNonces := make(map[uint64]int64) for _, bridgeTx := range tm.multipathTransactionsData { - builtTx, err := pathProcessors[bridgeTx.Name].BuildTransaction(bridgeTx) + + lastUsedNonce := int64(-1) + if nonce, ok := usedNonces[bridgeTx.ChainID]; ok { + lastUsedNonce = nonce + } + + builtTx, usedNonce, err := pathProcessors[bridgeTx.Name].BuildTransaction(bridgeTx, lastUsedNonce) if err != nil { return hashes, err } @@ -26,6 +33,8 @@ func (tm *TransactionManager) buildTransactions(pathProcessors map[string]pathpr builtTx: builtTx, } + usedNonces[bridgeTx.ChainID] = int64(usedNonce) + hashes = append(hashes, txHash.String()) } diff --git a/services/wallet/transfer/transaction_manager_multitransaction_test.go b/services/wallet/transfer/transaction_manager_multitransaction_test.go index e54c3694e..f90bc9737 100644 --- a/services/wallet/transfer/transaction_manager_multitransaction_test.go +++ b/services/wallet/transfer/transaction_manager_multitransaction_test.go @@ -166,7 +166,7 @@ func TestSendTransactionsETHSuccess(t *testing.T) { // Verify that the SendTransactionWithChainID method is called for each transaction with proper arguments // Return values are not checked, because they must be checked in Transactor tests for _, tx := range expectedData { - transactor.EXPECT().SendTransactionWithChainID(tx.ChainID, *(tx.TransferTx), account).Return(types.Hash{}, nil) + transactor.EXPECT().SendTransactionWithChainID(tx.ChainID, *(tx.TransferTx), int64(-1), account).Return(types.Hash{}, uint64(0), nil) } // Call the SendTransactions method @@ -182,7 +182,7 @@ func TestSendTransactionsApproveSuccess(t *testing.T) { // Verify that the SendTransactionWithChainID method is called for each transaction with proper arguments // Return values are not checked, because they must be checked in Transactor tests for _, tx := range expectedData { - transactor.EXPECT().SendTransactionWithChainID(tx.ChainID, *(tx.TransferTx), account).Return(types.Hash{}, nil) + transactor.EXPECT().SendTransactionWithChainID(tx.ChainID, *(tx.TransferTx), int64(-1), account).Return(types.Hash{}, uint64(0), nil) } // Call the SendTransactions method @@ -205,7 +205,7 @@ func TestSendTransactionsETHFailOnBridge(t *testing.T) { expectedErr := transactions.ErrInvalidTxSender // Any error to verify // In case of bridge error, verify that the error is returned - transferBridge.EXPECT().Send(gomock.Any(), gomock.Any()).Return(types.Hash{}, transactions.ErrInvalidTxSender) + transferBridge.EXPECT().Send(gomock.Any(), int64(-1), gomock.Any()).Return(types.Hash{}, uint64(0), transactions.ErrInvalidTxSender) // Call the SendTransactions method _, err := tm.SendTransactions(context.Background(), multiTransaction, data, bridges, account) @@ -220,8 +220,8 @@ func TestSendTransactionsETHFailOnTransactor(t *testing.T) { // Verify that the SendTransactionWithChainID method is called for each transaction with proper arguments // Return values are not checked, because they must be checked in Transactor tests. Only error propagation matters here expectedErr := transactions.ErrInvalidTxSender // Any error to verify - transactor.EXPECT().SendTransactionWithChainID(expectedData[0].ChainID, *(expectedData[0].TransferTx), account).Return(types.Hash{}, nil) - transactor.EXPECT().SendTransactionWithChainID(expectedData[1].ChainID, *(expectedData[1].TransferTx), account).Return(types.Hash{}, expectedErr) + transactor.EXPECT().SendTransactionWithChainID(expectedData[0].ChainID, *(expectedData[0].TransferTx), int64(-1), account).Return(types.Hash{}, uint64(0), nil) + transactor.EXPECT().SendTransactionWithChainID(expectedData[1].ChainID, *(expectedData[1].TransferTx), int64(-1), account).Return(types.Hash{}, uint64(0), expectedErr) // Call the SendTransactions method _, err := tm.SendTransactions(context.Background(), multiTransaction, data, bridges, account) diff --git a/services/wallet/transfer/transaction_manager_test.go b/services/wallet/transfer/transaction_manager_test.go index b13ac6b61..11e7f9e29 100644 --- a/services/wallet/transfer/transaction_manager_test.go +++ b/services/wallet/transfer/transaction_manager_test.go @@ -280,7 +280,7 @@ func TestBuildTransaction(t *testing.T) { } expectedTx := gethtypes.NewTransaction(nonce, common.Address(*sendArgs.To), sendArgs.Value.ToInt(), gas, sendArgs.GasPrice.ToInt(), nil) - transactor.EXPECT().ValidateAndBuildTransaction(chainID, sendArgs).Return(expectedTx, nil) + transactor.EXPECT().ValidateAndBuildTransaction(chainID, sendArgs, int64(-1)).Return(expectedTx, uint64(0), nil) response, err := manager.BuildTransaction(chainID, sendArgs) require.NoError(t, err) @@ -334,7 +334,7 @@ func TestBuildTransaction_InvalidSendTxArgs(t *testing.T) { } expectedErr := fmt.Errorf("invalid SendTxArgs") - transactor.EXPECT().ValidateAndBuildTransaction(chainID, sendArgs).Return(nil, expectedErr) + transactor.EXPECT().ValidateAndBuildTransaction(chainID, sendArgs, int64(-1)).Return(nil, uint64(0), expectedErr) tx, err := manager.BuildTransaction(chainID, sendArgs) require.Equal(t, expectedErr, err) require.Nil(t, tx) diff --git a/services/web3provider/signature.go b/services/web3provider/signature.go index 6f20d7c0d..1a4dd989e 100644 --- a/services/web3provider/signature.go +++ b/services/web3provider/signature.go @@ -79,7 +79,7 @@ func (api *API) sendTransaction(chainID uint64, sendArgs transactions.SendTxArgs return hash, err } - hash, err = api.s.transactor.SendTransactionWithChainID(chainID, sendArgs, verifiedAccount) + hash, _, err = api.s.transactor.SendTransactionWithChainID(chainID, sendArgs, -1, verifiedAccount) if err != nil { return } diff --git a/transactions/mock_transactor/transactor.go b/transactions/mock_transactor/transactor.go index 09982e599..e927f7997 100644 --- a/transactions/mock_transactor/transactor.go +++ b/transactions/mock_transactor/transactor.go @@ -8,10 +8,9 @@ import ( big "math/big" reflect "reflect" - gomock "github.com/golang/mock/gomock" - common "github.com/ethereum/go-ethereum/common" types "github.com/ethereum/go-ethereum/core/types" + gomock "github.com/golang/mock/gomock" account "github.com/status-im/status-go/account" types0 "github.com/status-im/status-go/eth-node/types" params "github.com/status-im/status-go/params" @@ -118,33 +117,35 @@ func (mr *MockTransactorIfaceMockRecorder) SendRawTransaction(chainID, rawTx int } // SendTransaction mocks base method. -func (m *MockTransactorIface) SendTransaction(sendArgs transactions.SendTxArgs, verifiedAccount *account.SelectedExtKey) (types0.Hash, error) { +func (m *MockTransactorIface) SendTransaction(sendArgs transactions.SendTxArgs, verifiedAccount *account.SelectedExtKey, lastUsedNonce int64) (types0.Hash, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendTransaction", sendArgs, verifiedAccount) + ret := m.ctrl.Call(m, "SendTransaction", sendArgs, verifiedAccount, lastUsedNonce) ret0, _ := ret[0].(types0.Hash) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // SendTransaction indicates an expected call of SendTransaction. -func (mr *MockTransactorIfaceMockRecorder) SendTransaction(sendArgs, verifiedAccount interface{}) *gomock.Call { +func (mr *MockTransactorIfaceMockRecorder) SendTransaction(sendArgs, verifiedAccount, lastUsedNonce interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransaction", reflect.TypeOf((*MockTransactorIface)(nil).SendTransaction), sendArgs, verifiedAccount) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransaction", reflect.TypeOf((*MockTransactorIface)(nil).SendTransaction), sendArgs, verifiedAccount, lastUsedNonce) } // SendTransactionWithChainID mocks base method. -func (m *MockTransactorIface) SendTransactionWithChainID(chainID uint64, sendArgs transactions.SendTxArgs, verifiedAccount *account.SelectedExtKey) (types0.Hash, error) { +func (m *MockTransactorIface) SendTransactionWithChainID(chainID uint64, sendArgs transactions.SendTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types0.Hash, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendTransactionWithChainID", chainID, sendArgs, verifiedAccount) + ret := m.ctrl.Call(m, "SendTransactionWithChainID", chainID, sendArgs, lastUsedNonce, verifiedAccount) ret0, _ := ret[0].(types0.Hash) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // SendTransactionWithChainID indicates an expected call of SendTransactionWithChainID. -func (mr *MockTransactorIfaceMockRecorder) SendTransactionWithChainID(chainID, sendArgs, verifiedAccount interface{}) *gomock.Call { +func (mr *MockTransactorIfaceMockRecorder) SendTransactionWithChainID(chainID, sendArgs, lastUsedNonce, verifiedAccount interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransactionWithChainID", reflect.TypeOf((*MockTransactorIface)(nil).SendTransactionWithChainID), chainID, sendArgs, verifiedAccount) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransactionWithChainID", reflect.TypeOf((*MockTransactorIface)(nil).SendTransactionWithChainID), chainID, sendArgs, lastUsedNonce, verifiedAccount) } // SendTransactionWithSignature mocks base method. @@ -177,16 +178,17 @@ func (mr *MockTransactorIfaceMockRecorder) StoreAndTrackPendingTx(from, symbol, } // ValidateAndBuildTransaction mocks base method. -func (m *MockTransactorIface) ValidateAndBuildTransaction(chainID uint64, sendArgs transactions.SendTxArgs) (*types.Transaction, error) { +func (m *MockTransactorIface) ValidateAndBuildTransaction(chainID uint64, sendArgs transactions.SendTxArgs, lastUsedNonce int64) (*types.Transaction, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateAndBuildTransaction", chainID, sendArgs) + ret := m.ctrl.Call(m, "ValidateAndBuildTransaction", chainID, sendArgs, lastUsedNonce) ret0, _ := ret[0].(*types.Transaction) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // ValidateAndBuildTransaction indicates an expected call of ValidateAndBuildTransaction. -func (mr *MockTransactorIfaceMockRecorder) ValidateAndBuildTransaction(chainID, sendArgs interface{}) *gomock.Call { +func (mr *MockTransactorIfaceMockRecorder) ValidateAndBuildTransaction(chainID, sendArgs, lastUsedNonce interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAndBuildTransaction", reflect.TypeOf((*MockTransactorIface)(nil).ValidateAndBuildTransaction), chainID, sendArgs) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAndBuildTransaction", reflect.TypeOf((*MockTransactorIface)(nil).ValidateAndBuildTransaction), chainID, sendArgs, lastUsedNonce) } diff --git a/transactions/transactor.go b/transactions/transactor.go index 66395748f..1dee6d799 100644 --- a/transactions/transactor.go +++ b/transactions/transactor.go @@ -48,9 +48,9 @@ func (e *ErrBadNonce) Error() string { type TransactorIface interface { NextNonce(rpcClient rpc.ClientInterface, chainID uint64, from types.Address) (uint64, error) EstimateGas(network *params.Network, from common.Address, to common.Address, value *big.Int, input []byte) (uint64, error) - SendTransaction(sendArgs SendTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) - SendTransactionWithChainID(chainID uint64, sendArgs SendTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) - ValidateAndBuildTransaction(chainID uint64, sendArgs SendTxArgs) (tx *gethtypes.Transaction, err error) + SendTransaction(sendArgs SendTxArgs, verifiedAccount *account.SelectedExtKey, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) + SendTransactionWithChainID(chainID uint64, sendArgs SendTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error) + ValidateAndBuildTransaction(chainID uint64, sendArgs SendTxArgs, lastUsedNonce int64) (tx *gethtypes.Transaction, nonce uint64, err error) AddSignatureToTransaction(chainID uint64, tx *gethtypes.Transaction, sig []byte) (*gethtypes.Transaction, error) SendRawTransaction(chainID uint64, rawTx string) error BuildTransactionWithSignature(chainID uint64, args SendTxArgs, sig []byte) (*gethtypes.Transaction, error) @@ -139,21 +139,21 @@ func (t *Transactor) EstimateGas(network *params.Network, from common.Address, t } // SendTransaction is an implementation of eth_sendTransaction. It queues the tx to the sign queue. -func (t *Transactor) SendTransaction(sendArgs SendTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - hash, err = t.validateAndPropagate(t.rpcWrapper, verifiedAccount, sendArgs) +func (t *Transactor) SendTransaction(sendArgs SendTxArgs, verifiedAccount *account.SelectedExtKey, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) { + hash, nonce, err = t.validateAndPropagate(t.rpcWrapper, verifiedAccount, sendArgs, lastUsedNonce) return } -func (t *Transactor) SendTransactionWithChainID(chainID uint64, sendArgs SendTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { +func (t *Transactor) SendTransactionWithChainID(chainID uint64, sendArgs SendTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error) { wrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID) - hash, err = t.validateAndPropagate(wrapper, verifiedAccount, sendArgs) + hash, nonce, err = t.validateAndPropagate(wrapper, verifiedAccount, sendArgs, lastUsedNonce) return } -func (t *Transactor) ValidateAndBuildTransaction(chainID uint64, sendArgs SendTxArgs) (tx *gethtypes.Transaction, err error) { +func (t *Transactor) ValidateAndBuildTransaction(chainID uint64, sendArgs SendTxArgs, lastUsedNonce int64) (tx *gethtypes.Transaction, nonce uint64, err error) { wrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID) - tx, err = t.validateAndBuildTransaction(wrapper, sendArgs) - return + tx, err = t.validateAndBuildTransaction(wrapper, sendArgs, lastUsedNonce) + return tx, tx.Nonce(), err } func (t *Transactor) AddSignatureToTransaction(chainID uint64, tx *gethtypes.Transaction, sig []byte) (*gethtypes.Transaction, error) { @@ -361,7 +361,7 @@ func (t *Transactor) validateAccount(args SendTxArgs, selectedAccount *account.S return nil } -func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args SendTxArgs) (tx *gethtypes.Transaction, err error) { +func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args SendTxArgs, lastUsedNonce int64) (tx *gethtypes.Transaction, err error) { if !args.Valid() { return tx, ErrInvalidSendTxArgs } @@ -370,9 +370,14 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args Se if args.Nonce != nil { nonce = uint64(*args.Nonce) } else { - nonce, err = t.NextNonce(rpcWrapper.RPCClient, rpcWrapper.chainID, args.From) - if err != nil { - return tx, err + // some chains, like arbitrum doesn't count pending txs in the nonce, so we need to calculate it manually + if lastUsedNonce < 0 { + nonce, err = t.NextNonce(rpcWrapper.RPCClient, rpcWrapper.chainID, args.From) + if err != nil { + return tx, err + } + } else { + nonce = uint64(lastUsedNonce) + 1 } } @@ -433,23 +438,24 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args Se return tx, nil } -func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccount *account.SelectedExtKey, args SendTxArgs) (hash types.Hash, err error) { +func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccount *account.SelectedExtKey, args SendTxArgs, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) { if err = t.validateAccount(args, selectedAccount); err != nil { - return hash, err + return hash, nonce, err } - tx, err := t.validateAndBuildTransaction(rpcWrapper, args) + tx, err := t.validateAndBuildTransaction(rpcWrapper, args, lastUsedNonce) if err != nil { - return hash, err + return hash, nonce, err } chainID := big.NewInt(int64(rpcWrapper.chainID)) signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(chainID), selectedAccount.AccountKey.PrivateKey) if err != nil { - return hash, err + return hash, nonce, err } - return t.sendTransaction(rpcWrapper, common.Address(args.From), args.Symbol, args.MultiTransactionID, signedTx) + hash, err = t.sendTransaction(rpcWrapper, common.Address(args.From), args.Symbol, args.MultiTransactionID, signedTx) + return hash, tx.Nonce(), err } func (t *Transactor) buildTransaction(args SendTxArgs) *gethtypes.Transaction { diff --git a/transactions/transactor_test.go b/transactions/transactor_test.go index 68bac9e39..8ff005713 100644 --- a/transactions/transactor_test.go +++ b/transactions/transactor_test.go @@ -207,7 +207,7 @@ func (s *TransactorSuite) TestGasValues() { } s.setupTransactionPoolAPI(args, testNonce, testNonce, selectedAccount, nil) - hash, err := s.manager.SendTransaction(args, selectedAccount) + hash, _, err := s.manager.SendTransaction(args, selectedAccount, -1) s.NoError(err) s.False(reflect.DeepEqual(hash, common.Hash{})) }) @@ -256,7 +256,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { } s.setupBuildTransactionMocks(args, selectedAccount) - tx, err := s.manager.ValidateAndBuildTransaction(chainID, args) + tx, _, err := s.manager.ValidateAndBuildTransaction(chainID, args, -1) s.NoError(err) s.Equal(tx.Gas(), uint64(gas), "The gas shouldn't be estimated, but should use the gas from the Tx") s.Equal(tx.GasFeeCap(), expectedGasPrice, "The maxFeePerGas should be the same as in the original Tx") @@ -275,7 +275,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { } s.setupBuildTransactionMocks(args, selectedAccount) - tx, err := s.manager.ValidateAndBuildTransaction(chainID, args) + tx, _, err := s.manager.ValidateAndBuildTransaction(chainID, args, -1) s.NoError(err) s.Equal(tx.Gas(), expectedGas, "The gas should be estimated if not present in the original Tx") s.Equal(tx.Nonce(), expectedNonce, "The nonce should be added if not present in the original Tx") @@ -298,7 +298,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { } s.setupBuildTransactionMocks(args, selectedAccount) - tx, err := s.manager.ValidateAndBuildTransaction(chainID, args) + tx, _, err := s.manager.ValidateAndBuildTransaction(chainID, args, -1) s.NoError(err) s.Equal(tx.Gas(), uint64(gas), "The gas shouldn't be estimated, but should use the gas from the Tx") s.Equal(tx.GasPrice(), expectedGasPrice, "The gasPrice should be the same as in the original Tx") @@ -314,7 +314,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { } s.setupBuildTransactionMocks(args, selectedAccount) - tx, err := s.manager.ValidateAndBuildTransaction(chainID, args) + tx, _, err := s.manager.ValidateAndBuildTransaction(chainID, args, -1) s.NoError(err) s.Equal(tx.Gas(), expectedGas, "The gas should be estimated if not present in the original Tx") s.Equal(tx.GasPrice(), expectedGasPrice, "The gasPrice should be estimated if not present in the original Tx") @@ -333,7 +333,7 @@ func (s *TransactorSuite) TestArgsValidation() { selectedAccount := &account.SelectedExtKey{ Address: account.FromAddress(utils.TestConfig.Account1.WalletAddress), } - _, err := s.manager.SendTransaction(args, selectedAccount) + _, _, err := s.manager.SendTransaction(args, selectedAccount, -1) s.EqualError(err, ErrInvalidSendTxArgs.Error()) } @@ -346,14 +346,14 @@ func (s *TransactorSuite) TestAccountMismatch() { var err error // missing account - _, err = s.manager.SendTransaction(args, nil) + _, _, err = s.manager.SendTransaction(args, nil, -1) s.EqualError(err, account.ErrNoAccountSelected.Error()) // mismatched accounts selectedAccount := &account.SelectedExtKey{ Address: account.FromAddress(utils.TestConfig.Account2.WalletAddress), } - _, err = s.manager.SendTransaction(args, selectedAccount) + _, _, err = s.manager.SendTransaction(args, selectedAccount, -1) s.EqualError(err, ErrInvalidTxSender.Error()) }