feat(wallet)_: enrich status changed and tx update signals' payload with tx route data

This commit is contained in:
Sale Djenic 2024-11-06 11:14:25 +01:00
parent 0994cc4865
commit ffc4243622
6 changed files with 143 additions and 41 deletions

View File

@ -1,8 +1,12 @@
package responses
import (
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/errors"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/services/wallet/requests"
"github.com/status-im/status-go/services/wallet/wallettypes"
)
@ -59,6 +63,15 @@ func NewRouterSentTransaction(sendArgs *wallettypes.SendTxArgs, hash types.Hash,
if sendArgs.To != nil {
addr = *sendArgs.To
}
if sendArgs.Value == nil {
sendArgs.Value = (*hexutil.Big)(big.NewInt(0))
}
if sendArgs.ValueIn == nil {
sendArgs.ValueIn = (*hexutil.Big)(big.NewInt(0))
}
if sendArgs.ValueOut == nil {
sendArgs.ValueOut = (*hexutil.Big)(big.NewInt(0))
}
return &RouterSentTransaction{
FromAddress: sendArgs.From,
ToAddress: addr,
@ -72,3 +85,23 @@ func NewRouterSentTransaction(sendArgs *wallettypes.SendTxArgs, hash types.Hash,
ApprovalTx: approvalTx,
}
}
func (sd *SendDetails) UpdateFields(inputParams requests.RouteInputParams) {
sd.SendType = int(inputParams.SendType)
sd.FromAddress = types.Address(inputParams.AddrFrom)
sd.ToAddress = types.Address(inputParams.AddrTo)
sd.FromToken = inputParams.TokenID
sd.ToToken = inputParams.ToTokenID
if inputParams.AmountIn != nil {
sd.FromAmount = inputParams.AmountIn.String()
}
if inputParams.AmountOut != nil {
sd.ToAmount = inputParams.AmountOut.String()
}
sd.OwnerTokenBeingSent = inputParams.TokenIDIsOwnerToken
sd.Username = inputParams.Username
sd.PublicKey = inputParams.PublicKey
if inputParams.PackID != nil {
sd.PackID = inputParams.PackID.String()
}
}

View File

@ -10,7 +10,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/logutils"
status_common "github.com/status-im/status-go/common"
@ -81,7 +80,7 @@ func (m *Manager) BuildTransactionsFromRoute(ctx context.Context, buildInputPara
m.buildInputParams = buildInputParams
updateFields(response.SendDetails, routeInputParams)
response.SendDetails.UpdateFields(routeInputParams)
// notify client that sending transactions started (has 3 steps, building txs, signing txs, sending txs)
signal.SendWalletEvent(signal.RouterSendingTransactionsStarted, response.SendDetails)
@ -143,7 +142,7 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send
return
}
updateFields(response.SendDetails, routeInputParams)
response.SendDetails.UpdateFields(routeInputParams)
err = m.transactionManager.ValidateAndAddSignaturesToRouterTransactions(sendInputParams.Signatures)
if err != nil {
@ -219,23 +218,3 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send
}
}()
}
func updateFields(sd *responses.SendDetails, inputParams requests.RouteInputParams) {
sd.SendType = int(inputParams.SendType)
sd.FromAddress = types.Address(inputParams.AddrFrom)
sd.ToAddress = types.Address(inputParams.AddrTo)
sd.FromToken = inputParams.TokenID
sd.ToToken = inputParams.ToTokenID
if inputParams.AmountIn != nil {
sd.FromAmount = inputParams.AmountIn.String()
}
if inputParams.AmountOut != nil {
sd.ToAmount = inputParams.AmountOut.String()
}
sd.OwnerTokenBeingSent = inputParams.TokenIDIsOwnerToken
sd.Username = inputParams.Username
sd.PublicKey = inputParams.PublicKey
if inputParams.PackID != nil {
sd.PackID = inputParams.PackID.String()
}
}

View File

@ -55,6 +55,14 @@ func (db *DB) GetRouteData(uuid string) (*wallettypes.RouteData, error) {
return getRouteData(db.db, uuid)
}
func (db *DB) GetRouteDataByHash(chainID uint64, txHash types.Hash) (*wallettypes.RouteData, error) {
uuid, err := getUuidForTxOnChain(db.db, chainID, txHash)
if err != nil {
return nil, err
}
return db.GetRouteData(uuid)
}
func putRouteInputParams(creator sqlite.StatementCreator, p *requests.RouteInputParams) error {
q := sq.Replace("route_input_parameters").
SetMap(sq.Eq{"route_input_params_json": &sqlite.JSONBlob{Data: p}})
@ -394,3 +402,24 @@ func getPathTransaction(creator sqlite.StatementCreator, uuid string, pathIdx in
return tx, nil
}
func getUuidForTxOnChain(creator sqlite.StatementCreator, chainID uint64, txHash types.Hash) (string, error) {
var uuid string
q := sq.Select("uuid").
From("route_path_transactions").
Where(sq.Eq{"chain_id": chainID, "tx_hash": txHash[:]})
query, args, err := q.ToSql()
if err != nil {
return uuid, err
}
stmt, err := creator.Prepare(query)
if err != nil {
return uuid, err
}
defer stmt.Close()
err = stmt.QueryRow(args...).Scan(&uuid)
return uuid, err
}

View File

@ -44,6 +44,20 @@ func Test_PutRouteData(t *testing.T) {
readRouteData, err := routeDB.GetRouteData(routeData.RouteInputParams.Uuid)
require.NoError(t, err)
require.EqualExportedValues(t, routeData, readRouteData)
for _, pathData := range routeData.PathsData {
if pathData.IsTxPlaced() {
readRouteData, err = routeDB.GetRouteDataByHash(pathData.RouterPath.FromChain.ChainID, pathData.TxData.SentHash)
require.NoError(t, err)
require.EqualExportedValues(t, routeData, readRouteData)
}
if pathData.IsApprovalPlaced() {
readRouteData, err = routeDB.GetRouteDataByHash(pathData.RouterPath.FromChain.ChainID, pathData.ApprovalTxData.SentHash)
require.NoError(t, err)
require.EqualExportedValues(t, routeData, readRouteData)
}
}
})
}
}

View File

@ -66,16 +66,16 @@ type SendTxArgs struct {
// additional data - version SendTxArgsVersion0
MultiTransactionID wallet_common.MultiTransactionIDType `json:"multiTransactionID"`
Symbol string `json:"-"`
Symbol string `json:"symbol"`
// additional data - version SendTxArgsVersion1
ValueIn *hexutil.Big `json:"-"`
ValueOut *hexutil.Big `json:"-"`
FromChainID uint64 `json:"-"`
ToChainID uint64 `json:"-"`
FromTokenID string `json:"-"`
ToTokenID string `json:"-"`
ToContractAddress types.Address `json:"-"` // represents address of the contract that needs to be used in order to send assets, like ERC721 or ERC1155 tx
SlippagePercentage float32 `json:"-"`
ValueIn *hexutil.Big `json:"valueIn"`
ValueOut *hexutil.Big `json:"valueOut"`
FromChainID uint64 `json:"fromChainID"`
ToChainID uint64 `json:"toChainID"`
FromTokenID string `json:"fromTokenID"`
ToTokenID string `json:"toTokenID"`
ToContractAddress types.Address `json:"toContractAddress"` // represents address of the contract that needs to be used in order to send assets, like ERC721 or ERC1155 tx
SlippagePercentage float32 `json:"slippagePercentage"`
}
// Valid checks whether this structure is filled in correctly.

View File

@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
ethrpc "github.com/ethereum/go-ethereum/rpc"
ethTypes "github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/logutils"
"github.com/status-im/status-go/rpc"
@ -24,6 +25,8 @@ import (
"github.com/status-im/status-go/services/wallet/bigint"
"github.com/status-im/status-go/services/wallet/common"
wallet_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/responses"
"github.com/status-im/status-go/services/wallet/routeexecution/storage"
"github.com/status-im/status-go/services/wallet/walletevent"
)
@ -63,21 +66,29 @@ type TxIdentity struct {
Hash eth.Hash `json:"hash"`
}
type TxDetails struct {
SendDetails *responses.SendDetails `json:"sendDetails"`
SentTransactions []*responses.RouterSentTransaction `json:"sentTransactions"`
}
type PendingTxUpdatePayload struct {
TxIdentity
TxDetails
Deleted bool `json:"deleted"`
}
type StatusChangedPayload struct {
TxIdentity
TxDetails
Status TxStatus `json:"status"`
}
// PendingTxTracker implements StatusService in common/status_node_service.go
type PendingTxTracker struct {
db *sql.DB
trackedTxDB *DB
rpcClient rpc.ClientInterface
db *sql.DB
routeExecutionStorage *storage.DB
trackedTxDB *DB
rpcClient rpc.ClientInterface
rpcFilter *rpcfilters.Service
eventFeed *event.Feed
@ -88,12 +99,13 @@ type PendingTxTracker struct {
func NewPendingTxTracker(db *sql.DB, rpcClient rpc.ClientInterface, rpcFilter *rpcfilters.Service, eventFeed *event.Feed, checkInterval time.Duration) *PendingTxTracker {
tm := &PendingTxTracker{
db: db,
trackedTxDB: NewDB(db),
rpcClient: rpcClient,
eventFeed: eventFeed,
rpcFilter: rpcFilter,
logger: logutils.ZapLogger().Named("PendingTxTracker"),
db: db,
routeExecutionStorage: storage.NewDB(db),
trackedTxDB: NewDB(db),
rpcClient: rpcClient,
eventFeed: eventFeed,
rpcFilter: rpcFilter,
logger: logutils.ZapLogger().Named("PendingTxTracker"),
}
tm.taskRunner = NewConditionalRepeater(checkInterval, func(ctx context.Context) bool {
return tm.fetchAndUpdateDB(ctx)
@ -335,6 +347,37 @@ func (tm *PendingTxTracker) updateDBStatus(ctx context.Context, chainID common.C
return res, nil
}
func (tm *PendingTxTracker) updateTxDetails(txDetails *TxDetails, chainID uint64, txHash ethTypes.Hash) {
if txDetails == nil {
txDetails = &TxDetails{}
}
txDetails.SendDetails = &responses.SendDetails{}
routeData, err := tm.routeExecutionStorage.GetRouteDataByHash(chainID, txHash)
if err != nil {
tm.logger.Warn("Missing tx data ", zap.Stringer("hash", txHash), zap.Error(err))
}
if routeData != nil {
if routeData.RouteInputParams != nil {
txDetails.SendDetails.UpdateFields(*routeData.RouteInputParams)
}
for _, pd := range routeData.PathsData {
if pd.IsApprovalPlaced() && pd.ApprovalTxData.SentHash == txHash {
txDetails.SentTransactions = append(txDetails.SentTransactions, responses.NewRouterSentTransaction(
pd.ApprovalTxData.TxArgs,
pd.ApprovalTxData.SentHash,
true))
}
if pd.IsTxPlaced() && pd.TxData.SentHash == txHash {
txDetails.SentTransactions = append(txDetails.SentTransactions, responses.NewRouterSentTransaction(
pd.TxData.TxArgs,
pd.TxData.SentHash,
false))
}
}
}
}
func (tm *PendingTxTracker) emitNotifications(chainID common.ChainID, changes []txStatusRes) {
if tm.eventFeed != nil {
for _, change := range changes {
@ -346,6 +389,8 @@ func (tm *PendingTxTracker) emitNotifications(chainID common.ChainID, changes []
Status: change.Status,
}
tm.updateTxDetails(&payload.TxDetails, chainID.ToUint(), ethTypes.Hash(change.hash))
jsonPayload, err := json.Marshal(payload)
if err != nil {
tm.logger.Error("Failed to marshal pending transaction status", zap.Stringer("hash", change.hash), zap.Error(err))
@ -688,6 +733,8 @@ func (tm *PendingTxTracker) addPending(transaction *PendingTransaction) error {
}
func (tm *PendingTxTracker) notifyPendingTransactionListeners(payload PendingTxUpdatePayload, addresses []eth.Address, timestamp uint64) {
tm.updateTxDetails(&payload.TxDetails, payload.ChainID.ToUint(), ethTypes.Hash(payload.Hash))
jsonPayload, err := json.Marshal(payload)
if err != nil {
tm.logger.Error("Failed to marshal PendingTxUpdatePayload", zap.Stringer("hash", payload.Hash), zap.Error(err))