From c27c773c27a10d0dd7742d324455ca7143829065 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Thu, 12 Dec 2024 16:03:00 +0100 Subject: [PATCH] chore(wallet)_: from and to chains added to send details From and to chains added to SendDetails type that can be used on the client side if the sending fails that we can display appropriate ephemeral notifications, saying sending from which chain has failed. --- .../wallet/responses/router_transactions.go | 8 +++++- services/wallet/routeexecution/manager.go | 23 +++++++++++---- services/wallet/router/routes/route.go | 13 +++++++++ .../transfer/transaction_manager_route.go | 28 ++++++++++--------- transactions/pendingtxtracker.go | 2 +- 5 files changed, 53 insertions(+), 21 deletions(-) diff --git a/services/wallet/responses/router_transactions.go b/services/wallet/responses/router_transactions.go index be26dcc56..9a533c504 100644 --- a/services/wallet/responses/router_transactions.go +++ b/services/wallet/responses/router_transactions.go @@ -15,6 +15,8 @@ type SendDetails struct { SendType int `json:"sendType"` FromAddress types.Address `json:"fromAddress"` ToAddress types.Address `json:"toAddress"` + FromChain uint64 `json:"fromChain"` // this chain should be used only if en error occurred while sending a transaction + ToChain uint64 `json:"toChain"` // this chain should be used only if en error occurred while sending a transaction FromToken string `json:"fromToken"` ToToken string `json:"toToken"` FromAmount string `json:"fromAmount"` // total amount @@ -88,7 +90,7 @@ func NewRouterSentTransaction(sendArgs *wallettypes.SendTxArgs, hash types.Hash, } } -func (sd *SendDetails) UpdateFields(inputParams requests.RouteInputParams) { +func (sd *SendDetails) UpdateFields(inputParams requests.RouteInputParams, fromChain uint64, toChain uint64) { sd.SendType = int(inputParams.SendType) sd.FromAddress = types.Address(inputParams.AddrFrom) sd.ToAddress = types.Address(inputParams.AddrTo) @@ -106,4 +108,8 @@ func (sd *SendDetails) UpdateFields(inputParams requests.RouteInputParams) { if inputParams.PackID != nil { sd.PackID = inputParams.PackID.String() } + + // Set chain IDs, in case of an error while sending a transaction + sd.FromChain = fromChain + sd.ToChain = toChain } diff --git a/services/wallet/routeexecution/manager.go b/services/wallet/routeexecution/manager.go index fab5684c1..c4f3460b5 100644 --- a/services/wallet/routeexecution/manager.go +++ b/services/wallet/routeexecution/manager.go @@ -20,6 +20,7 @@ import ( "github.com/status-im/status-go/services/wallet/routeexecution/storage" "github.com/status-im/status-go/services/wallet/router" pathProcessorCommon "github.com/status-im/status-go/services/wallet/router/pathprocessor/common" + "github.com/status-im/status-go/services/wallet/router/routes" "github.com/status-im/status-go/services/wallet/router/sendtype" "github.com/status-im/status-go/services/wallet/transfer" "github.com/status-im/status-go/services/wallet/walletevent" @@ -88,12 +89,14 @@ func (m *Manager) BuildTransactionsFromRoute(ctx context.Context, buildInputPara m.buildInputParams = buildInputParams - response.SendDetails.UpdateFields(routeInputParams) + fromChainID, toChainID := route.GetFirstPathChains() + + response.SendDetails.UpdateFields(routeInputParams, fromChainID, toChainID) // notify client that sending transactions started (has 3 steps, building txs, signing txs, sending txs) signal.SendWalletEvent(signal.RouterSendingTransactionsStarted, response.SendDetails) - response.SigningDetails, err = m.transactionManager.BuildTransactionsFromRoute( + response.SigningDetails, fromChainID, toChainID, err = m.transactionManager.BuildTransactionsFromRoute( route, m.router.GetPathProcessors(), transfer.BuildRouteExtraParams{ @@ -105,6 +108,9 @@ func (m *Manager) BuildTransactionsFromRoute(ctx context.Context, buildInputPara SlippagePercentage: buildInputParams.SlippagePercentage, }, ) + if err != nil { + response.SendDetails.UpdateFields(routeInputParams, fromChainID, toChainID) + } }() } @@ -114,6 +120,7 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send var ( err error + route routes.Route routeInputParams requests.RouteInputParams ) response := &responses.RouterSentTransactions{ @@ -150,16 +157,19 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send m.eventFeed.Send(event) }() - _, routeInputParams = m.router.GetBestRouteAndAssociatedInputParams() + route, routeInputParams = m.router.GetBestRouteAndAssociatedInputParams() if routeInputParams.Uuid != sendInputParams.Uuid { err = ErrCannotResolveRouteId return } - response.SendDetails.UpdateFields(routeInputParams) + fromChainID, toChainID := route.GetFirstPathChains() - err = m.transactionManager.ValidateAndAddSignaturesToRouterTransactions(sendInputParams.Signatures) + response.SendDetails.UpdateFields(routeInputParams, fromChainID, toChainID) + + fromChainID, toChainID, err = m.transactionManager.ValidateAndAddSignaturesToRouterTransactions(sendInputParams.Signatures) if err != nil { + response.SendDetails.UpdateFields(routeInputParams, fromChainID, toChainID) return } @@ -194,8 +204,9 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send } ////////////////////////////////////////////////////////////////////////////// - response.SentTransactions, err = m.transactionManager.SendRouterTransactions(ctx, multiTx) + response.SentTransactions, fromChainID, toChainID, err = m.transactionManager.SendRouterTransactions(ctx, multiTx) if err != nil { + response.SendDetails.UpdateFields(routeInputParams, fromChainID, toChainID) log.Error("Error sending router transactions", "error", err) // TODO #16556: Handle partially successful Tx sends? // Don't return, store whichever transactions were successfully sent diff --git a/services/wallet/router/routes/route.go b/services/wallet/router/routes/route.go index 56057f066..dcd30d193 100644 --- a/services/wallet/router/routes/route.go +++ b/services/wallet/router/routes/route.go @@ -17,6 +17,19 @@ func (r Route) Copy() Route { return newRoute } +// GetFirstPathChains returns the chain IDs (from and to) of the first path in the route +// If certain tx fails or succeeds status--go will send from/to chains along with other tx details to client to let +// thc client know about failed/successful tx. But if an error occurs before the first path, during the preparation +// of the route, the client will not have the chain IDs to know where the tx was supposed to be sent. This function +// is used to get the chain IDs of the first path in the route to send them to the client in case of an error. +func (r Route) GetFirstPathChains() (uint64, uint64) { + if len(r) == 0 { + return 0, 0 + } + + return r[0].FromChain.ChainID, r[0].ToChain.ChainID +} + func FindBestRoute(routes []Route, tokenPrice float64, nativeTokenPrice float64) Route { var best Route bestCost := big.NewFloat(math.Inf(1)) diff --git a/services/wallet/transfer/transaction_manager_route.go b/services/wallet/transfer/transaction_manager_route.go index 4fa38b6b3..4330e1f15 100644 --- a/services/wallet/transfer/transaction_manager_route.go +++ b/services/wallet/transfer/transaction_manager_route.go @@ -214,19 +214,19 @@ func buildTxForPath(transactor transactions.TransactorIface, path *routes.Path, } func (tm *TransactionManager) BuildTransactionsFromRoute(route routes.Route, pathProcessors map[string]pathprocessor.PathProcessor, - params BuildRouteExtraParams) (*responses.SigningDetails, error) { + params BuildRouteExtraParams) (*responses.SigningDetails, uint64, uint64, error) { if len(route) == 0 { - return nil, ErrNoRoute + return nil, 0, 0, ErrNoRoute } accFrom, err := tm.accountsDB.GetAccountByAddress(types.Address(params.AddressFrom)) if err != nil { - return nil, err + return nil, 0, 0, err } keypair, err := tm.accountsDB.GetKeypairByKeyUID(accFrom.KeyUID) if err != nil { - return nil, err + return nil, 0, 0, err } response := &responses.SigningDetails{ @@ -246,7 +246,7 @@ func (tm *TransactionManager) BuildTransactionsFromRoute(route routes.Route, pat if path.ApprovalRequired && !tm.ApprovalPlacedForPath(path.ProcessorName) { txDetails.ApprovalTxData, err = buildApprovalTxForPath(tm.transactor, path, params.AddressFrom, usedNonces, signer) if err != nil { - return nil, err + return nil, path.FromChain.ChainID, path.ToChain.ChainID, err } response.Hashes = append(response.Hashes, txDetails.ApprovalTxData.HashToSign) @@ -259,12 +259,12 @@ func (tm *TransactionManager) BuildTransactionsFromRoute(route routes.Route, pat // build tx for the path txDetails.TxData, err = buildTxForPath(tm.transactor, path, pathProcessors, usedNonces, signer, params) if err != nil { - return nil, err + return nil, path.FromChain.ChainID, path.ToChain.ChainID, err } response.Hashes = append(response.Hashes, txDetails.TxData.HashToSign) } - return response, nil + return response, 0, 0, nil } func getSignatureForTxHash(txHash string, signatures map[string]requests.SignatureDetails) ([]byte, error) { @@ -309,9 +309,9 @@ func validateAndAddSignature(txData *wallettypes.TransactionData, signatures map return nil } -func (tm *TransactionManager) ValidateAndAddSignaturesToRouterTransactions(signatures map[string]requests.SignatureDetails) error { +func (tm *TransactionManager) ValidateAndAddSignaturesToRouterTransactions(signatures map[string]requests.SignatureDetails) (uint64, uint64, error) { if len(tm.routerTransactions) == 0 { - return ErrNoTrsansactionsBeingBuilt + return 0, 0, ErrNoTrsansactionsBeingBuilt } // check if all transactions have been signed @@ -319,16 +319,16 @@ func (tm *TransactionManager) ValidateAndAddSignaturesToRouterTransactions(signa for _, desc := range tm.routerTransactions { err = validateAndAddSignature(desc.ApprovalTxData, signatures) if err != nil { - return err + return desc.RouterPath.FromChain.ChainID, desc.RouterPath.ToChain.ChainID, err } err = validateAndAddSignature(desc.TxData, signatures) if err != nil { - return err + return desc.RouterPath.FromChain.ChainID, desc.RouterPath.ToChain.ChainID, err } } - return nil + return 0, 0, nil } func addSignatureAndSendTransaction( @@ -355,11 +355,13 @@ func addSignatureAndSendTransaction( return responses.NewRouterSentTransaction(txData.TxArgs, txData.SentHash, isApproval), nil } -func (tm *TransactionManager) SendRouterTransactions(ctx context.Context, multiTx *MultiTransaction) (transactions []*responses.RouterSentTransaction, err error) { +func (tm *TransactionManager) SendRouterTransactions(ctx context.Context, multiTx *MultiTransaction) (transactions []*responses.RouterSentTransaction, fromChainID uint64, toChainID uint64, err error) { transactions = make([]*responses.RouterSentTransaction, 0) // send transactions for _, desc := range tm.routerTransactions { + fromChainID = desc.RouterPath.FromChain.ChainID + toChainID = desc.RouterPath.ToChain.ChainID if desc.ApprovalTxData != nil && !desc.IsApprovalPlaced() { var response *responses.RouterSentTransaction response, err = addSignatureAndSendTransaction(tm.transactor, desc.ApprovalTxData, multiTx.ID, true) diff --git a/transactions/pendingtxtracker.go b/transactions/pendingtxtracker.go index e0f1ca049..bca766394 100644 --- a/transactions/pendingtxtracker.go +++ b/transactions/pendingtxtracker.go @@ -358,7 +358,7 @@ func (tm *PendingTxTracker) updateTxDetails(txDetails *TxDetails, chainID uint64 } if routeData != nil { if routeData.RouteInputParams != nil { - txDetails.SendDetails.UpdateFields(*routeData.RouteInputParams) + txDetails.SendDetails.UpdateFields(*routeData.RouteInputParams, 0, 0) } for _, pd := range routeData.PathsData {