diff --git a/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go b/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go index 25a9e3ab9..d0ffdc961 100644 --- a/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go +++ b/services/wallet/router/pathprocessor/mock_pathprocessor/processor.go @@ -1,10 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. // Source: services/wallet/router/pathprocessor/processor.go -// -// Generated by this command: -// -// mockgen -package=mock_pathprocessor -destination=services/wallet/router/pathprocessor/mock_pathprocessor/processor.go -source=services/wallet/router/pathprocessor/processor.go -// // Package mock_pathprocessor is a generated GoMock package. package mock_pathprocessor @@ -13,13 +8,13 @@ import ( big "math/big" reflect "reflect" - gomock "go.uber.org/mock/gomock" - common "github.com/ethereum/go-ethereum/common" types "github.com/ethereum/go-ethereum/core/types" + gomock "go.uber.org/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" + transactions "github.com/status-im/status-go/transactions" ) // MockPathProcessor is a mock of PathProcessor interface. @@ -55,7 +50,7 @@ func (m *MockPathProcessor) AvailableFor(params pathprocessor.ProcessorInputPara } // AvailableFor indicates an expected call of AvailableFor. -func (mr *MockPathProcessorMockRecorder) AvailableFor(params any) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) AvailableFor(params interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AvailableFor", reflect.TypeOf((*MockPathProcessor)(nil).AvailableFor), params) } @@ -71,11 +66,27 @@ func (m *MockPathProcessor) BuildTransaction(sendArgs *pathprocessor.MultipathPr } // BuildTransaction indicates an expected call of BuildTransaction. -func (mr *MockPathProcessorMockRecorder) BuildTransaction(sendArgs, lastUsedNonce any) *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, lastUsedNonce) } +// BuildTransactionV2 mocks base method. +func (m *MockPathProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*types.Transaction, uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BuildTransactionV2", sendArgs, lastUsedNonce) + ret0, _ := ret[0].(*types.Transaction) + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// BuildTransactionV2 indicates an expected call of BuildTransactionV2. +func (mr *MockPathProcessorMockRecorder) BuildTransactionV2(sendArgs, lastUsedNonce interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildTransactionV2", reflect.TypeOf((*MockPathProcessor)(nil).BuildTransactionV2), sendArgs, lastUsedNonce) +} + // CalculateAmountOut mocks base method. func (m *MockPathProcessor) CalculateAmountOut(params pathprocessor.ProcessorInputParams) (*big.Int, error) { m.ctrl.T.Helper() @@ -86,7 +97,7 @@ func (m *MockPathProcessor) CalculateAmountOut(params pathprocessor.ProcessorInp } // CalculateAmountOut indicates an expected call of CalculateAmountOut. -func (mr *MockPathProcessorMockRecorder) CalculateAmountOut(params any) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) CalculateAmountOut(params interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateAmountOut", reflect.TypeOf((*MockPathProcessor)(nil).CalculateAmountOut), params) } @@ -102,7 +113,7 @@ func (m *MockPathProcessor) CalculateFees(params pathprocessor.ProcessorInputPar } // CalculateFees indicates an expected call of CalculateFees. -func (mr *MockPathProcessorMockRecorder) CalculateFees(params any) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) CalculateFees(params interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateFees", reflect.TypeOf((*MockPathProcessor)(nil).CalculateFees), params) } @@ -117,7 +128,7 @@ func (m *MockPathProcessor) EstimateGas(params pathprocessor.ProcessorInputParam } // EstimateGas indicates an expected call of EstimateGas. -func (mr *MockPathProcessorMockRecorder) EstimateGas(params any) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) EstimateGas(params interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGas", reflect.TypeOf((*MockPathProcessor)(nil).EstimateGas), params) } @@ -132,7 +143,7 @@ func (m *MockPathProcessor) GetContractAddress(params pathprocessor.ProcessorInp } // GetContractAddress indicates an expected call of GetContractAddress. -func (mr *MockPathProcessorMockRecorder) GetContractAddress(params any) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) GetContractAddress(params interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContractAddress", reflect.TypeOf((*MockPathProcessor)(nil).GetContractAddress), params) } @@ -161,7 +172,7 @@ func (m *MockPathProcessor) PackTxInputData(params pathprocessor.ProcessorInputP } // PackTxInputData indicates an expected call of PackTxInputData. -func (mr *MockPathProcessorMockRecorder) PackTxInputData(params any) *gomock.Call { +func (mr *MockPathProcessorMockRecorder) PackTxInputData(params interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PackTxInputData", reflect.TypeOf((*MockPathProcessor)(nil).PackTxInputData), params) } @@ -177,7 +188,7 @@ func (m *MockPathProcessor) Send(sendArgs *pathprocessor.MultipathProcessorTxArg } // Send indicates an expected call of Send. -func (mr *MockPathProcessorMockRecorder) Send(sendArgs, lastUsedNonce, verifiedAccount any) *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, lastUsedNonce, verifiedAccount) } diff --git a/services/wallet/router/pathprocessor/processor.go b/services/wallet/router/pathprocessor/processor.go index b9e539f91..0b5275daf 100644 --- a/services/wallet/router/pathprocessor/processor.go +++ b/services/wallet/router/pathprocessor/processor.go @@ -10,6 +10,7 @@ import ( "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/params" "github.com/status-im/status-go/services/wallet/token" + "github.com/status-im/status-go/transactions" ) type PathProcessor interface { @@ -31,6 +32,8 @@ type PathProcessor interface { GetContractAddress(params ProcessorInputParams) (common.Address, 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) + // BuildTransactionV2 builds the transaction based on SendTxArgs, returns the transaction and the used nonce (lastUsedNonce is -1 if it's the first tx) + BuildTransactionV2(sendArgs *transactions.SendTxArgs, 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 3e187f07f..5811c26e5 100644 --- a/services/wallet/router/pathprocessor/processor_bridge_celar.go +++ b/services/wallet/router/pathprocessor/processor_bridge_celar.go @@ -302,6 +302,7 @@ func (s *CelerBridgeProcessor) GetContractAddress(params ProcessorInputParams) ( return common.Address{}, ErrContractNotFound } +// TODO: remove this struct once mobile switches to the new approach func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (*ethTypes.Transaction, error) { fromChain := s.rpcClient.NetworkManager.Find(sendArgs.ChainID) if fromChain == nil { @@ -364,6 +365,68 @@ func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, s return tx, nil } +func (s *CelerBridgeProcessor) sendOrBuildV2(sendArgs *transactions.SendTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (*ethTypes.Transaction, error) { + fromChain := s.rpcClient.NetworkManager.Find(sendArgs.FromChainID) + if fromChain == nil { + return nil, ErrNetworkNotFound + } + token := s.tokenManager.FindToken(fromChain, sendArgs.FromTokenID) + if token == nil { + return nil, ErrTokenNotFound + } + addrs, err := s.GetContractAddress(ProcessorInputParams{ + FromChain: fromChain, + }) + if err != nil { + return nil, createBridgeCellerErrorResponse(err) + } + + backend, err := s.rpcClient.EthClient(sendArgs.FromChainID) + if err != nil { + return nil, createBridgeCellerErrorResponse(err) + } + contract, err := celer.NewCeler(addrs, backend) + if err != nil { + return nil, createBridgeCellerErrorResponse(err) + } + + if lastUsedNonce >= 0 { + lastUsedNonceHexUtil := hexutil.Uint64(uint64(lastUsedNonce) + 1) + sendArgs.Nonce = &lastUsedNonceHexUtil + } + + var tx *ethTypes.Transaction + txOpts := sendArgs.ToTransactOpts(signerFn) + if token.IsNative() { + tx, err = contract.SendNative( + txOpts, + common.Address(*sendArgs.To), + (*big.Int)(sendArgs.Value), + sendArgs.FromChainID, + uint64(time.Now().UnixMilli()), + maxSlippage, + ) + } else { + tx, err = contract.Send( + txOpts, + common.Address(*sendArgs.To), + token.Address, + (*big.Int)(sendArgs.Value), + sendArgs.FromChainID, + uint64(time.Now().UnixMilli()), + maxSlippage, + ) + } + if err != nil { + return tx, createBridgeCellerErrorResponse(err) + } + err = s.transactor.StoreAndTrackPendingTx(txOpts.From, sendArgs.FromTokenID, sendArgs.FromChainID, sendArgs.MultiTransactionID, tx) + if err != nil { + return tx, createBridgeCellerErrorResponse(err) + } + return tx, nil +} + 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 { @@ -378,6 +441,11 @@ func (s *CelerBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxAr return tx, tx.Nonce(), err } +func (s *CelerBridgeProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := s.sendOrBuildV2(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), err +} + func (s *CelerBridgeProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { amt, err := s.estimateAmt(params.FromChain, params.ToChain, params.AmountIn, params.FromToken.Symbol) if err != nil { diff --git a/services/wallet/router/pathprocessor/processor_bridge_hop.go b/services/wallet/router/pathprocessor/processor_bridge_hop.go index 6753d450a..1273294d1 100644 --- a/services/wallet/router/pathprocessor/processor_bridge_hop.go +++ b/services/wallet/router/pathprocessor/processor_bridge_hop.go @@ -282,6 +282,7 @@ func (h *HopBridgeProcessor) GetContractAddress(params ProcessorInputParams) (co return address, createBridgeHopErrorResponse(err) } +// TODO: remove this struct once mobile switches to the new approach 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 { @@ -349,6 +350,73 @@ func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, sig return tx, nil } +func (h *HopBridgeProcessor) sendOrBuildV2(sendArgs *transactions.SendTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { + fromChain := h.networkManager.Find(sendArgs.FromChainID) + if fromChain == nil { + return tx, fmt.Errorf("ChainID not supported %d", sendArgs.FromChainID) + } + + token := h.tokenManager.FindToken(fromChain, sendArgs.FromTokenID) + + var nonce uint64 + if lastUsedNonce < 0 { + nonce, err = h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.From) + if err != nil { + return tx, createBridgeHopErrorResponse(err) + } + } else { + nonce = uint64(lastUsedNonce) + 1 + } + + argNonce := hexutil.Uint64(nonce) + sendArgs.Nonce = &argNonce + + txOpts := sendArgs.ToTransactOpts(signerFn) + if token.IsNative() { + txOpts.Value = (*big.Int)(sendArgs.Value) + } + + ethClient, err := h.contractMaker.RPCClient.EthClient(fromChain.ChainID) + if err != nil { + return tx, createBridgeHopErrorResponse(err) + } + + contractAddress, contractType, err := hop.GetContractAddress(fromChain.ChainID, sendArgs.FromTokenID) + if err != nil { + return tx, createBridgeHopErrorResponse(err) + } + + bonderKey := makeKey(sendArgs.FromChainID, sendArgs.ToChainID, "", "") + bonderFeeIns, ok := h.bonderFee.Load(bonderKey) + if !ok { + return nil, ErrNoBonderFeeFound + } + bonderFee := bonderFeeIns.(*BonderFee) + + switch contractType { + case hop.CctpL1Bridge: + tx, err = h.sendCctpL1BridgeTx(contractAddress, ethClient, sendArgs.ToChainID, common.Address(*sendArgs.To), txOpts, bonderFee) + case hop.L1Bridge: + tx, err = h.sendL1BridgeTx(contractAddress, ethClient, sendArgs.ToChainID, common.Address(*sendArgs.To), txOpts, token, bonderFee) + case hop.L2AmmWrapper: + tx, err = h.sendL2AmmWrapperTx(contractAddress, ethClient, sendArgs.ToChainID, common.Address(*sendArgs.To), txOpts, bonderFee) + case hop.CctpL2Bridge: + tx, err = h.sendCctpL2BridgeTx(contractAddress, ethClient, sendArgs.ToChainID, common.Address(*sendArgs.To), txOpts, bonderFee) + case hop.L2Bridge: + tx, err = h.sendL2BridgeTx(contractAddress, ethClient, sendArgs.ToChainID, common.Address(*sendArgs.To), txOpts, bonderFee) + default: + return tx, ErrContractTypeNotSupported + } + if err != nil { + return tx, createBridgeHopErrorResponse(err) + } + err = h.transactor.StoreAndTrackPendingTx(txOpts.From, sendArgs.FromTokenID, sendArgs.FromChainID, sendArgs.MultiTransactionID, tx) + if err != nil { + return tx, createBridgeHopErrorResponse(err) + } + return tx, nil +} + 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 { @@ -362,6 +430,11 @@ func (h *HopBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs return tx, tx.Nonce(), createBridgeHopErrorResponse(err) } +func (h *HopBridgeProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := h.sendOrBuildV2(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), createBridgeHopErrorResponse(err) +} + func (h *HopBridgeProcessor) CalculateFees(params ProcessorInputParams) (*big.Int, *big.Int, error) { bonderKey := makeKey(params.FromChain.ChainID, params.ToChain.ChainID, "", "") if params.TestsMode { diff --git a/services/wallet/router/pathprocessor/processor_ens_public_key.go b/services/wallet/router/pathprocessor/processor_ens_public_key.go index b0134439c..72b47a3ed 100644 --- a/services/wallet/router/pathprocessor/processor_ens_public_key.go +++ b/services/wallet/router/pathprocessor/processor_ens_public_key.go @@ -111,6 +111,10 @@ func (s *ENSPublicKeyProcessor) BuildTransaction(sendArgs *MultipathProcessorTxA return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } +func (s *ENSPublicKeyProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.FromChainID, *sendArgs, lastUsedNonce) +} + func (s *ENSPublicKeyProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { return params.AmountIn, nil } diff --git a/services/wallet/router/pathprocessor/processor_ens_register.go b/services/wallet/router/pathprocessor/processor_ens_register.go index fef94839d..895ca753a 100644 --- a/services/wallet/router/pathprocessor/processor_ens_register.go +++ b/services/wallet/router/pathprocessor/processor_ens_register.go @@ -147,6 +147,10 @@ func (s *ENSRegisterProcessor) BuildTransaction(sendArgs *MultipathProcessorTxAr return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } +func (s *ENSRegisterProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.FromChainID, *sendArgs, lastUsedNonce) +} + func (s *ENSRegisterProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { return params.AmountIn, nil } diff --git a/services/wallet/router/pathprocessor/processor_ens_release.go b/services/wallet/router/pathprocessor/processor_ens_release.go index 6f0d56aa2..e269e7a29 100644 --- a/services/wallet/router/pathprocessor/processor_ens_release.go +++ b/services/wallet/router/pathprocessor/processor_ens_release.go @@ -110,6 +110,10 @@ func (s *ENSReleaseProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArg return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } +func (s *ENSReleaseProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.FromChainID, *sendArgs, lastUsedNonce) +} + func (s *ENSReleaseProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { return params.AmountIn, nil } diff --git a/services/wallet/router/pathprocessor/processor_erc1155.go b/services/wallet/router/pathprocessor/processor_erc1155.go index 4ccc795d4..9d3e06326 100644 --- a/services/wallet/router/pathprocessor/processor_erc1155.go +++ b/services/wallet/router/pathprocessor/processor_erc1155.go @@ -108,6 +108,7 @@ func (s *ERC1155Processor) EstimateGas(params ProcessorInputParams) (uint64, err return uint64(increasedEstimation), nil } +// TODO: remove this struct once mobile switches to the new approach 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 { @@ -150,6 +151,54 @@ func (s *ERC1155Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signe return tx, nil } +func (s *ERC1155Processor) sendOrBuildV2(sendArgs *transactions.SendTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { + ethClient, err := s.rpcClient.EthClient(sendArgs.FromChainID) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + + contract, err := ierc1155.NewIerc1155(common.Address(sendArgs.ToContractAddress), ethClient) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + + id, err := walletCommon.GetTokenIdFromSymbol(sendArgs.FromTokenID) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + + var nonce uint64 + if lastUsedNonce < 0 { + nonce, err = s.transactor.NextNonce(s.rpcClient, sendArgs.FromChainID, sendArgs.From) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + } else { + nonce = uint64(lastUsedNonce) + 1 + } + + argNonce := hexutil.Uint64(nonce) + sendArgs.Nonce = &argNonce + txOpts := sendArgs.ToTransactOpts(signerFn) + from := common.Address(sendArgs.From) + tx, err = contract.SafeTransferFrom( + txOpts, + from, + common.Address(*sendArgs.To), + id, + sendArgs.Value.ToInt(), + []byte{}, + ) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + err = s.transactor.StoreAndTrackPendingTx(from, sendArgs.FromTokenID, sendArgs.FromChainID, sendArgs.MultiTransactionID, tx) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + return tx, nil +} + 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 { @@ -163,6 +212,11 @@ func (s *ERC1155Processor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, return tx, tx.Nonce(), err } +func (s *ERC1155Processor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := s.sendOrBuildV2(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), err +} + func (s *ERC1155Processor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { return params.AmountIn, nil } diff --git a/services/wallet/router/pathprocessor/processor_erc721.go b/services/wallet/router/pathprocessor/processor_erc721.go index eeb4bf38e..d4124fc28 100644 --- a/services/wallet/router/pathprocessor/processor_erc721.go +++ b/services/wallet/router/pathprocessor/processor_erc721.go @@ -146,6 +146,7 @@ func (s *ERC721Processor) EstimateGas(params ProcessorInputParams) (uint64, erro return uint64(increasedEstimation), nil } +// TODO: remove this struct once mobile switches to the new approach func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { from := common.Address(sendArgs.ERC721TransferTx.From) @@ -157,7 +158,8 @@ func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signer FromAddr: from, ToAddr: sendArgs.ERC721TransferTx.Recipient, FromToken: &token.Token{ - Symbol: sendArgs.ERC721TransferTx.TokenID.String(), + Symbol: sendArgs.ERC721TransferTx.TokenID.String(), + Address: common.Address(*sendArgs.ERC721TransferTx.To), }, } err = s.checkIfFunctionExists(inputParams, functionNameSafeTransferFrom) @@ -207,6 +209,76 @@ func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signer return tx, nil } +func (s *ERC721Processor) sendOrBuildV2(sendArgs *transactions.SendTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { + from := common.Address(sendArgs.From) + to := common.Address(*sendArgs.To) + + useSafeTransferFrom := true + inputParams := ProcessorInputParams{ + FromChain: ¶ms.Network{ + ChainID: sendArgs.FromChainID, + }, + FromAddr: from, + ToAddr: to, + FromToken: &token.Token{ + Symbol: sendArgs.FromTokenID, + Address: common.Address(sendArgs.ToContractAddress), + }, + } + err = s.checkIfFunctionExists(inputParams, functionNameSafeTransferFrom) + if err != nil { + useSafeTransferFrom = false + } + + ethClient, err := s.rpcClient.EthClient(sendArgs.FromChainID) + if err != nil { + return tx, createERC721ErrorResponse(err) + } + + contract, err := collectibles.NewCollectibles(common.Address(sendArgs.ToContractAddress), ethClient) + if err != nil { + return tx, createERC721ErrorResponse(err) + } + + id, err := walletCommon.GetTokenIdFromSymbol(sendArgs.FromTokenID) + if err != nil { + return tx, createERC1155ErrorResponse(err) + } + + var nonce uint64 + if lastUsedNonce < 0 { + nonce, err = s.transactor.NextNonce(s.rpcClient, sendArgs.FromChainID, sendArgs.From) + if err != nil { + return tx, createERC721ErrorResponse(err) + } + } else { + nonce = uint64(lastUsedNonce) + 1 + } + + argNonce := hexutil.Uint64(nonce) + sendArgs.Nonce = &argNonce + txOpts := sendArgs.ToTransactOpts(signerFn) + if useSafeTransferFrom { + tx, err = contract.SafeTransferFrom(txOpts, + from, + to, + id) + } else { + tx, err = contract.TransferFrom(txOpts, + from, + to, + id) + } + if err != nil { + return tx, createERC721ErrorResponse(err) + } + err = s.transactor.StoreAndTrackPendingTx(from, sendArgs.FromTokenID, sendArgs.FromChainID, sendArgs.MultiTransactionID, tx) + if err != nil { + return tx, createERC721ErrorResponse(err) + } + return tx, nil +} + 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 { @@ -220,6 +292,11 @@ func (s *ERC721Processor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, l return tx, tx.Nonce(), err } +func (s *ERC721Processor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + tx, err := s.sendOrBuildV2(sendArgs, nil, lastUsedNonce) + return tx, tx.Nonce(), err +} + func (s *ERC721Processor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { return params.AmountIn, nil } diff --git a/services/wallet/router/pathprocessor/processor_stickers_buy.go b/services/wallet/router/pathprocessor/processor_stickers_buy.go index 8e83dbd1a..d723e33b2 100644 --- a/services/wallet/router/pathprocessor/processor_stickers_buy.go +++ b/services/wallet/router/pathprocessor/processor_stickers_buy.go @@ -139,6 +139,10 @@ func (s *StickersBuyProcessor) BuildTransaction(sendArgs *MultipathProcessorTxAr return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } +func (s *StickersBuyProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.FromChainID, *sendArgs, lastUsedNonce) +} + func (s *StickersBuyProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { return params.AmountIn, nil } diff --git a/services/wallet/router/pathprocessor/processor_swap_paraswap.go b/services/wallet/router/pathprocessor/processor_swap_paraswap.go index 991c2a591..21d6050de 100644 --- a/services/wallet/router/pathprocessor/processor_swap_paraswap.go +++ b/services/wallet/router/pathprocessor/processor_swap_paraswap.go @@ -208,6 +208,7 @@ func (s *SwapParaswapProcessor) GetContractAddress(params ProcessorInputParams) return priceRoute.TokenTransferProxy, nil } +// TODO: remove this struct once mobile switches to the new approach func (s *SwapParaswapProcessor) prepareTransaction(sendArgs *MultipathProcessorTxArgs) error { slippageBP := uint(sendArgs.SwapTx.SlippagePercentage * 100) // convert to basis points @@ -254,6 +255,51 @@ func (s *SwapParaswapProcessor) prepareTransaction(sendArgs *MultipathProcessorT return nil } +func (s *SwapParaswapProcessor) prepareTransactionV2(sendArgs *transactions.SendTxArgs) error { + slippageBP := uint(sendArgs.SlippagePercentage * 100) // convert to basis points + + key := makeKey(sendArgs.FromChainID, sendArgs.ToChainID, sendArgs.FromTokenID, sendArgs.ToTokenID) + priceRouteIns, ok := s.priceRoute.Load(key) + if !ok { + return ErrPriceRouteNotFound + } + priceRoute := priceRouteIns.(*paraswap.Route) + + tx, err := s.paraswapClient.BuildTransaction(context.Background(), priceRoute.SrcTokenAddress, priceRoute.SrcTokenDecimals, priceRoute.SrcAmount.Int, + priceRoute.DestTokenAddress, priceRoute.DestTokenDecimals, priceRoute.DestAmount.Int, slippageBP, + common.Address(sendArgs.From), common.Address(*sendArgs.To), + priceRoute.RawPriceRoute, priceRoute.Side) + if err != nil { + return createSwapParaswapErrorResponse(err) + } + + value, ok := new(big.Int).SetString(tx.Value, 10) + if !ok { + return ErrConvertingAmountToBigInt + } + + gas, err := strconv.ParseUint(tx.Gas, 10, 64) + if err != nil { + return createSwapParaswapErrorResponse(err) + } + + gasPrice, ok := new(big.Int).SetString(tx.GasPrice, 10) + if !ok { + return ErrConvertingAmountToBigInt + } + + sendArgs.FromChainID = tx.ChainID + toAddr := types.HexToAddress(tx.To) + sendArgs.From = types.HexToAddress(tx.From) + sendArgs.To = &toAddr + sendArgs.Value = (*hexutil.Big)(value) + sendArgs.Gas = (*hexutil.Uint64)(&gas) + sendArgs.GasPrice = (*hexutil.Big)(gasPrice) + sendArgs.Data = types.Hex2Bytes(tx.Data) + + return nil +} + func (s *SwapParaswapProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { err := s.prepareTransaction(sendArgs) if err != nil { @@ -262,6 +308,14 @@ func (s *SwapParaswapProcessor) BuildTransaction(sendArgs *MultipathProcessorTxA return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, sendArgs.SwapTx.SendTxArgs, lastUsedNonce) } +func (s *SwapParaswapProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + err := s.prepareTransactionV2(sendArgs) + if err != nil { + return nil, 0, createSwapParaswapErrorResponse(err) + } + return s.transactor.ValidateAndBuildTransaction(sendArgs.FromChainID, *sendArgs, lastUsedNonce) +} + func (s *SwapParaswapProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types.Hash, uint64, error) { err := s.prepareTransaction(sendArgs) if err != nil { diff --git a/services/wallet/router/pathprocessor/processor_transfer.go b/services/wallet/router/pathprocessor/processor_transfer.go index 4fa056eb4..7e1e3faa6 100644 --- a/services/wallet/router/pathprocessor/processor_transfer.go +++ b/services/wallet/router/pathprocessor/processor_transfer.go @@ -53,7 +53,7 @@ func (s *TransferProcessor) CalculateFees(params ProcessorInputParams) (*big.Int func (s *TransferProcessor) PackTxInputData(params ProcessorInputParams) ([]byte, error) { if params.FromToken.IsNative() { - return []byte("eth_sendRawTransaction"), nil + return []byte{}, nil } else { abi, err := abi.JSON(strings.NewReader(ierc20.IERC20ABI)) if err != nil { @@ -122,6 +122,10 @@ func (s *TransferProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce) } +func (s *TransferProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { + return s.transactor.ValidateAndBuildTransaction(sendArgs.FromChainID, *sendArgs, lastUsedNonce) +} + func (s *TransferProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { return params.AmountIn, nil }