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 {