feat(wallet)_: enrich status changed and tx update signals' payload with tx route data
This commit is contained in:
parent
0994cc4865
commit
ffc4243622
|
@ -1,8 +1,12 @@
|
||||||
package responses
|
package responses
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/status-im/status-go/errors"
|
"github.com/status-im/status-go/errors"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"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"
|
"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 {
|
if sendArgs.To != nil {
|
||||||
addr = *sendArgs.To
|
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{
|
return &RouterSentTransaction{
|
||||||
FromAddress: sendArgs.From,
|
FromAddress: sendArgs.From,
|
||||||
ToAddress: addr,
|
ToAddress: addr,
|
||||||
|
@ -72,3 +85,23 @@ func NewRouterSentTransaction(sendArgs *wallettypes.SendTxArgs, hash types.Hash,
|
||||||
ApprovalTx: approvalTx,
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
|
||||||
"github.com/status-im/status-go/logutils"
|
"github.com/status-im/status-go/logutils"
|
||||||
|
|
||||||
status_common "github.com/status-im/status-go/common"
|
status_common "github.com/status-im/status-go/common"
|
||||||
|
@ -81,7 +80,7 @@ func (m *Manager) BuildTransactionsFromRoute(ctx context.Context, buildInputPara
|
||||||
|
|
||||||
m.buildInputParams = buildInputParams
|
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)
|
// notify client that sending transactions started (has 3 steps, building txs, signing txs, sending txs)
|
||||||
signal.SendWalletEvent(signal.RouterSendingTransactionsStarted, response.SendDetails)
|
signal.SendWalletEvent(signal.RouterSendingTransactionsStarted, response.SendDetails)
|
||||||
|
@ -143,7 +142,7 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFields(response.SendDetails, routeInputParams)
|
response.SendDetails.UpdateFields(routeInputParams)
|
||||||
|
|
||||||
err = m.transactionManager.ValidateAndAddSignaturesToRouterTransactions(sendInputParams.Signatures)
|
err = m.transactionManager.ValidateAndAddSignaturesToRouterTransactions(sendInputParams.Signatures)
|
||||||
if err != nil {
|
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -55,6 +55,14 @@ func (db *DB) GetRouteData(uuid string) (*wallettypes.RouteData, error) {
|
||||||
return getRouteData(db.db, uuid)
|
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 {
|
func putRouteInputParams(creator sqlite.StatementCreator, p *requests.RouteInputParams) error {
|
||||||
q := sq.Replace("route_input_parameters").
|
q := sq.Replace("route_input_parameters").
|
||||||
SetMap(sq.Eq{"route_input_params_json": &sqlite.JSONBlob{Data: p}})
|
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
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,20 @@ func Test_PutRouteData(t *testing.T) {
|
||||||
readRouteData, err := routeDB.GetRouteData(routeData.RouteInputParams.Uuid)
|
readRouteData, err := routeDB.GetRouteData(routeData.RouteInputParams.Uuid)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualExportedValues(t, routeData, readRouteData)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,16 +66,16 @@ type SendTxArgs struct {
|
||||||
|
|
||||||
// additional data - version SendTxArgsVersion0
|
// additional data - version SendTxArgsVersion0
|
||||||
MultiTransactionID wallet_common.MultiTransactionIDType `json:"multiTransactionID"`
|
MultiTransactionID wallet_common.MultiTransactionIDType `json:"multiTransactionID"`
|
||||||
Symbol string `json:"-"`
|
Symbol string `json:"symbol"`
|
||||||
// additional data - version SendTxArgsVersion1
|
// additional data - version SendTxArgsVersion1
|
||||||
ValueIn *hexutil.Big `json:"-"`
|
ValueIn *hexutil.Big `json:"valueIn"`
|
||||||
ValueOut *hexutil.Big `json:"-"`
|
ValueOut *hexutil.Big `json:"valueOut"`
|
||||||
FromChainID uint64 `json:"-"`
|
FromChainID uint64 `json:"fromChainID"`
|
||||||
ToChainID uint64 `json:"-"`
|
ToChainID uint64 `json:"toChainID"`
|
||||||
FromTokenID string `json:"-"`
|
FromTokenID string `json:"fromTokenID"`
|
||||||
ToTokenID string `json:"-"`
|
ToTokenID string `json:"toTokenID"`
|
||||||
ToContractAddress types.Address `json:"-"` // represents address of the contract that needs to be used in order to send assets, like ERC721 or ERC1155 tx
|
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 float32 `json:"slippagePercentage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid checks whether this structure is filled in correctly.
|
// Valid checks whether this structure is filled in correctly.
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
ethrpc "github.com/ethereum/go-ethereum/rpc"
|
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/logutils"
|
||||||
"github.com/status-im/status-go/rpc"
|
"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/bigint"
|
||||||
"github.com/status-im/status-go/services/wallet/common"
|
"github.com/status-im/status-go/services/wallet/common"
|
||||||
wallet_common "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"
|
"github.com/status-im/status-go/services/wallet/walletevent"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,21 +66,29 @@ type TxIdentity struct {
|
||||||
Hash eth.Hash `json:"hash"`
|
Hash eth.Hash `json:"hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TxDetails struct {
|
||||||
|
SendDetails *responses.SendDetails `json:"sendDetails"`
|
||||||
|
SentTransactions []*responses.RouterSentTransaction `json:"sentTransactions"`
|
||||||
|
}
|
||||||
|
|
||||||
type PendingTxUpdatePayload struct {
|
type PendingTxUpdatePayload struct {
|
||||||
TxIdentity
|
TxIdentity
|
||||||
|
TxDetails
|
||||||
Deleted bool `json:"deleted"`
|
Deleted bool `json:"deleted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatusChangedPayload struct {
|
type StatusChangedPayload struct {
|
||||||
TxIdentity
|
TxIdentity
|
||||||
|
TxDetails
|
||||||
Status TxStatus `json:"status"`
|
Status TxStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PendingTxTracker implements StatusService in common/status_node_service.go
|
// PendingTxTracker implements StatusService in common/status_node_service.go
|
||||||
type PendingTxTracker struct {
|
type PendingTxTracker struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
trackedTxDB *DB
|
routeExecutionStorage *storage.DB
|
||||||
rpcClient rpc.ClientInterface
|
trackedTxDB *DB
|
||||||
|
rpcClient rpc.ClientInterface
|
||||||
|
|
||||||
rpcFilter *rpcfilters.Service
|
rpcFilter *rpcfilters.Service
|
||||||
eventFeed *event.Feed
|
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 {
|
func NewPendingTxTracker(db *sql.DB, rpcClient rpc.ClientInterface, rpcFilter *rpcfilters.Service, eventFeed *event.Feed, checkInterval time.Duration) *PendingTxTracker {
|
||||||
tm := &PendingTxTracker{
|
tm := &PendingTxTracker{
|
||||||
db: db,
|
db: db,
|
||||||
trackedTxDB: NewDB(db),
|
routeExecutionStorage: storage.NewDB(db),
|
||||||
rpcClient: rpcClient,
|
trackedTxDB: NewDB(db),
|
||||||
eventFeed: eventFeed,
|
rpcClient: rpcClient,
|
||||||
rpcFilter: rpcFilter,
|
eventFeed: eventFeed,
|
||||||
logger: logutils.ZapLogger().Named("PendingTxTracker"),
|
rpcFilter: rpcFilter,
|
||||||
|
logger: logutils.ZapLogger().Named("PendingTxTracker"),
|
||||||
}
|
}
|
||||||
tm.taskRunner = NewConditionalRepeater(checkInterval, func(ctx context.Context) bool {
|
tm.taskRunner = NewConditionalRepeater(checkInterval, func(ctx context.Context) bool {
|
||||||
return tm.fetchAndUpdateDB(ctx)
|
return tm.fetchAndUpdateDB(ctx)
|
||||||
|
@ -335,6 +347,37 @@ func (tm *PendingTxTracker) updateDBStatus(ctx context.Context, chainID common.C
|
||||||
return res, nil
|
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) {
|
func (tm *PendingTxTracker) emitNotifications(chainID common.ChainID, changes []txStatusRes) {
|
||||||
if tm.eventFeed != nil {
|
if tm.eventFeed != nil {
|
||||||
for _, change := range changes {
|
for _, change := range changes {
|
||||||
|
@ -346,6 +389,8 @@ func (tm *PendingTxTracker) emitNotifications(chainID common.ChainID, changes []
|
||||||
Status: change.Status,
|
Status: change.Status,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tm.updateTxDetails(&payload.TxDetails, chainID.ToUint(), ethTypes.Hash(change.hash))
|
||||||
|
|
||||||
jsonPayload, err := json.Marshal(payload)
|
jsonPayload, err := json.Marshal(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tm.logger.Error("Failed to marshal pending transaction status", zap.Stringer("hash", change.hash), zap.Error(err))
|
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) {
|
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)
|
jsonPayload, err := json.Marshal(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tm.logger.Error("Failed to marshal PendingTxUpdatePayload", zap.Stringer("hash", payload.Hash), zap.Error(err))
|
tm.logger.Error("Failed to marshal PendingTxUpdatePayload", zap.Stringer("hash", payload.Hash), zap.Error(err))
|
||||||
|
|
Loading…
Reference in New Issue