chore_: remove detection of external swaps and bridges
This commit is contained in:
parent
c08e922f65
commit
5d4838a752
|
@ -1,221 +0,0 @@
|
|||
package transfer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/status-im/status-go/rpc/chain"
|
||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/token"
|
||||
)
|
||||
|
||||
// TODO: Find proper way to uniquely match Origin and Destination transactions (some sort of hash or uniqueID)
|
||||
// Current approach is not failsafe (for example, if multiple identical bridge operations are triggered
|
||||
// at the same time)
|
||||
// Recipient + Relayer + Data should match in both Origin and Destination transactions
|
||||
func getHopBridgeFromL1CrossTxID(recipient common.Address, relayer common.Address, logData []byte) string {
|
||||
return fmt.Sprintf("FromL1_%s_%s_%s", recipient.String(), relayer.String(), hex.EncodeToString(logData))
|
||||
}
|
||||
|
||||
func getHopBridgeFromL2CrossTxID(transferID *big.Int) string {
|
||||
return fmt.Sprintf("FromL2_0x%s", transferID.Text(16))
|
||||
}
|
||||
|
||||
type originTxParams struct {
|
||||
fromNetworkID uint64
|
||||
fromTxHash common.Hash
|
||||
fromAddress common.Address
|
||||
fromAsset string
|
||||
fromAmount *big.Int
|
||||
toNetworkID uint64
|
||||
toAddress common.Address
|
||||
crossTxID string
|
||||
timestamp uint64
|
||||
}
|
||||
|
||||
func upsertHopBridgeOriginTx(ctx context.Context, transactionManager *TransactionManager, params originTxParams) (*MultiTransaction, error) {
|
||||
// Try to find "destination" half of the multiTx
|
||||
multiTx, err := transactionManager.GetBridgeDestinationMultiTransaction(ctx, params.toNetworkID, params.crossTxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if multiTx == nil {
|
||||
multiTx = NewMultiTransaction(
|
||||
/* Timestamp: */ params.timestamp, // Common data
|
||||
/* FromNetworkID: */ params.fromNetworkID, // Data from "origin" transaction
|
||||
/* ToNetworkID: */ params.toNetworkID, // Data from "origin" transaction
|
||||
/* FromTxHash: */ params.fromTxHash, // Data from "origin" transaction
|
||||
/* ToTxHash: */ common.Hash{},
|
||||
/* FromAddress: */ params.fromAddress, // Data from "origin" transaction
|
||||
/* ToAddress: */ params.toAddress, // Data from "origin" transaction
|
||||
/* FromAsset: */ params.fromAsset, // Data from "origin" transaction
|
||||
/* ToAsset: */ params.fromAsset, // To be replaced by "destination" transaction, need to be non-null
|
||||
/* FromAmount: */ (*hexutil.Big)(params.fromAmount), // Data from "origin" transaction
|
||||
/* ToAmount: */ (*hexutil.Big)(params.fromAmount), // To be replaced by "destination" transaction, need to be non-null
|
||||
/* Type: */ MultiTransactionBridge, // Common data
|
||||
/* CrossTxID: */ params.crossTxID, // Common data
|
||||
)
|
||||
|
||||
_, err := transactionManager.InsertMultiTransaction(multiTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
multiTx.FromNetworkID = params.fromNetworkID
|
||||
multiTx.FromTxHash = params.fromTxHash
|
||||
multiTx.FromAddress = params.fromAddress
|
||||
multiTx.FromAsset = params.fromAsset
|
||||
multiTx.FromAmount = (*hexutil.Big)(params.fromAmount)
|
||||
multiTx.Timestamp = params.timestamp
|
||||
|
||||
err := transactionManager.UpdateMultiTransaction(multiTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return multiTx, nil
|
||||
}
|
||||
|
||||
type destinationTxParams struct {
|
||||
toNetworkID uint64
|
||||
toTxHash common.Hash
|
||||
toAddress common.Address
|
||||
toAsset string
|
||||
toAmount *big.Int
|
||||
crossTxID string
|
||||
timestamp uint64
|
||||
}
|
||||
|
||||
func upsertHopBridgeDestinationTx(ctx context.Context, transactionManager *TransactionManager, params destinationTxParams) (*MultiTransaction, error) {
|
||||
// Try to find "origin" half of the multiTx
|
||||
multiTx, err := transactionManager.GetBridgeOriginMultiTransaction(ctx, params.toNetworkID, params.crossTxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if multiTx == nil {
|
||||
multiTx = NewMultiTransaction(
|
||||
/* Timestamp: */ params.timestamp, // Common data
|
||||
/* FromNetworkID: */ 0, // not set
|
||||
/* ToNetworkID: */ params.toNetworkID, // Data from "destination" transaction
|
||||
/* FromTxHash: */ common.Hash{},
|
||||
/* ToTxHash: */ params.toTxHash, // Data from "destination" transaction
|
||||
/* FromAddress: */ params.toAddress, // To be replaced by "origin" transaction, need to be non-null
|
||||
/* ToAddress: */ params.toAddress, // Data from "destination" transaction
|
||||
/* FromAsset: */ params.toAsset, // To be replaced by "origin" transaction, need to be non-null
|
||||
/* ToAsset: */ params.toAsset, // Data from "destination" transaction
|
||||
/* FromAmount: */ (*hexutil.Big)(params.toAmount), // To be replaced by "origin" transaction, need to be non-null
|
||||
/* ToAmount: */ (*hexutil.Big)(params.toAmount), // Data from "destination" transaction
|
||||
/* Type: */ MultiTransactionBridge, // Common data
|
||||
/* CrossTxID: */ params.crossTxID, // Common data
|
||||
)
|
||||
|
||||
_, err := transactionManager.InsertMultiTransaction(multiTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
multiTx.ToTxHash = params.toTxHash
|
||||
multiTx.ToAsset = params.toAsset
|
||||
multiTx.ToAmount = (*hexutil.Big)(params.toAmount)
|
||||
multiTx.Timestamp = params.timestamp
|
||||
|
||||
err := transactionManager.UpdateMultiTransaction(multiTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return multiTx, nil
|
||||
}
|
||||
|
||||
func buildHopBridgeMultitransaction(ctx context.Context, client chain.ClientInterface, transactionManager *TransactionManager, tokenManager *token.Manager, subTx *Transfer) (*MultiTransaction, error) {
|
||||
// Identify if it's from/to transaction
|
||||
switch w_common.GetEventType(subTx.Log) {
|
||||
case w_common.HopBridgeTransferSentToL2EventType:
|
||||
// L1->L2 Origin transaction
|
||||
toChainID, recipient, relayer, fromAmount, err := w_common.ParseHopBridgeTransferSentToL2Log(subTx.Log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := originTxParams{
|
||||
fromNetworkID: subTx.NetworkID,
|
||||
fromTxHash: subTx.Receipt.TxHash,
|
||||
fromAddress: subTx.From,
|
||||
fromAsset: "ETH",
|
||||
fromAmount: fromAmount,
|
||||
toNetworkID: toChainID,
|
||||
toAddress: recipient,
|
||||
crossTxID: getHopBridgeFromL1CrossTxID(recipient, relayer, subTx.Log.Data),
|
||||
timestamp: subTx.Timestamp,
|
||||
}
|
||||
|
||||
return upsertHopBridgeOriginTx(ctx, transactionManager, params)
|
||||
|
||||
case w_common.HopBridgeTransferFromL1CompletedEventType:
|
||||
// L1->L2 Destination transaction
|
||||
recipient, relayer, toAmount, err := w_common.ParseHopBridgeTransferFromL1CompletedLog(subTx.Log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := destinationTxParams{
|
||||
toNetworkID: subTx.NetworkID,
|
||||
toTxHash: subTx.Receipt.TxHash,
|
||||
toAddress: recipient,
|
||||
toAsset: "ETH",
|
||||
toAmount: toAmount,
|
||||
crossTxID: getHopBridgeFromL1CrossTxID(recipient, relayer, subTx.Log.Data),
|
||||
timestamp: subTx.Timestamp,
|
||||
}
|
||||
|
||||
return upsertHopBridgeDestinationTx(ctx, transactionManager, params)
|
||||
|
||||
case w_common.HopBridgeTransferSentEventType:
|
||||
// L2->L1 / L2->L2 Origin transaction
|
||||
transferID, toChainID, recipient, fromAmount, _, _, _, _, _, err := w_common.ParseHopBridgeTransferSentLog(subTx.Log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := originTxParams{
|
||||
fromNetworkID: subTx.NetworkID,
|
||||
fromTxHash: subTx.Receipt.TxHash,
|
||||
fromAddress: subTx.From,
|
||||
fromAsset: "ETH",
|
||||
fromAmount: fromAmount,
|
||||
toNetworkID: toChainID,
|
||||
toAddress: recipient,
|
||||
crossTxID: getHopBridgeFromL2CrossTxID(transferID),
|
||||
timestamp: subTx.Timestamp,
|
||||
}
|
||||
|
||||
return upsertHopBridgeOriginTx(ctx, transactionManager, params)
|
||||
|
||||
case w_common.HopBridgeWithdrawalBondedEventType:
|
||||
// L2->L1 / L2->L2 Destination transaction
|
||||
transferID, toAmount, err := w_common.ParseHopWithdrawalBondedLog(subTx.Log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := destinationTxParams{
|
||||
toNetworkID: subTx.NetworkID,
|
||||
toTxHash: subTx.Receipt.TxHash,
|
||||
toAddress: subTx.Address,
|
||||
toAsset: "ETH",
|
||||
toAmount: toAmount,
|
||||
crossTxID: getHopBridgeFromL2CrossTxID(transferID),
|
||||
timestamp: subTx.Timestamp,
|
||||
}
|
||||
|
||||
return upsertHopBridgeDestinationTx(ctx, transactionManager, params)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
|
@ -201,17 +201,16 @@ func (c *erc20HistoricalCommand) Run(ctx context.Context) (err error) {
|
|||
}
|
||||
|
||||
type transfersCommand struct {
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
eth *ETHDownloader
|
||||
blockNums []*big.Int
|
||||
address common.Address
|
||||
chainClient chain.ClientInterface
|
||||
blocksLimit int
|
||||
transactionManager *TransactionManager
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
feed *event.Feed
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
eth *ETHDownloader
|
||||
blockNums []*big.Int
|
||||
address common.Address
|
||||
chainClient chain.ClientInterface
|
||||
blocksLimit int
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
feed *event.Feed
|
||||
|
||||
// result
|
||||
fetchedTransfers []Transfer
|
||||
|
@ -274,13 +273,6 @@ func (c *transfersCommand) Run(ctx context.Context) (err error) {
|
|||
logutils.ZapLogger().Error("saveAndConfirmPending error", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if multi transaction needs to be created
|
||||
err = c.processMultiTransactions(ctx, allTransfers)
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Error("processMultiTransactions error", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// If no transfers found, that is suspecting, because downloader returned this block as containing transfers
|
||||
logutils.ZapLogger().Error("no transfers found in block",
|
||||
|
@ -422,73 +414,6 @@ func (c *transfersCommand) confirmPendingTransactions(tx *sql.Tx, allTransfers [
|
|||
return notifyFunctions
|
||||
}
|
||||
|
||||
// Mark all subTxs of a given Tx with the same multiTxID
|
||||
func setMultiTxID(tx Transaction, multiTxID w_common.MultiTransactionIDType) {
|
||||
for _, subTx := range tx {
|
||||
subTx.MultiTransactionID = multiTxID
|
||||
}
|
||||
}
|
||||
|
||||
func (c *transfersCommand) markMultiTxTokensAsPreviouslyOwned(ctx context.Context, multiTransaction *MultiTransaction, ownerAddress common.Address) {
|
||||
if multiTransaction == nil {
|
||||
return
|
||||
}
|
||||
if len(multiTransaction.ToAsset) > 0 && multiTransaction.ToNetworkID > 0 {
|
||||
token := c.tokenManager.GetToken(multiTransaction.ToNetworkID, multiTransaction.ToAsset)
|
||||
_, _ = c.tokenManager.MarkAsPreviouslyOwnedToken(token, ownerAddress)
|
||||
}
|
||||
if len(multiTransaction.FromAsset) > 0 && multiTransaction.FromNetworkID > 0 {
|
||||
token := c.tokenManager.GetToken(multiTransaction.FromNetworkID, multiTransaction.FromAsset)
|
||||
_, _ = c.tokenManager.MarkAsPreviouslyOwnedToken(token, ownerAddress)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *transfersCommand) checkAndProcessSwapMultiTx(ctx context.Context, tx Transaction) (bool, error) {
|
||||
for _, subTx := range tx {
|
||||
switch subTx.Type {
|
||||
// If the Tx contains any uniswapV2Swap/uniswapV3Swap subTx, generate a Swap multiTx
|
||||
case w_common.UniswapV2Swap, w_common.UniswapV3Swap:
|
||||
multiTransaction, err := buildUniswapSwapMultitransaction(ctx, c.chainClient, c.tokenManager, subTx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if multiTransaction != nil {
|
||||
id, err := c.transactionManager.InsertMultiTransaction(multiTransaction)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
setMultiTxID(tx, id)
|
||||
c.markMultiTxTokensAsPreviouslyOwned(ctx, multiTransaction, subTx.Address)
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *transfersCommand) checkAndProcessBridgeMultiTx(ctx context.Context, tx Transaction) (bool, error) {
|
||||
for _, subTx := range tx {
|
||||
switch subTx.Type {
|
||||
// If the Tx contains any hopBridge subTx, create/update Bridge multiTx
|
||||
case w_common.HopBridgeFrom, w_common.HopBridgeTo:
|
||||
multiTransaction, err := buildHopBridgeMultitransaction(ctx, c.chainClient, c.transactionManager, c.tokenManager, subTx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if multiTransaction != nil {
|
||||
setMultiTxID(tx, multiTransaction.ID)
|
||||
c.markMultiTxTokensAsPreviouslyOwned(ctx, multiTransaction, subTx.Address)
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *transfersCommand) processUnknownErc20CommunityTransactions(ctx context.Context, allTransfers []Transfer) {
|
||||
for _, tx := range allTransfers {
|
||||
// To can be nil in case of erc20 contract creation
|
||||
|
@ -508,36 +433,6 @@ func (c *transfersCommand) processUnknownErc20CommunityTransactions(ctx context.
|
|||
}
|
||||
}
|
||||
|
||||
func (c *transfersCommand) processMultiTransactions(ctx context.Context, allTransfers []Transfer) error {
|
||||
txByTxHash := subTransactionListToTransactionsByTxHash(allTransfers)
|
||||
|
||||
// Detect / Generate multitransactions
|
||||
// Iterate over all detected transactions
|
||||
for _, tx := range txByTxHash {
|
||||
// Check if already matched to a multi transaction
|
||||
if tx[0].MultiTransactionID > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Then check for a Swap transaction
|
||||
txProcessed, err := c.checkAndProcessSwapMultiTx(ctx, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if txProcessed {
|
||||
continue
|
||||
}
|
||||
|
||||
// Then check for a Bridge transaction
|
||||
_, err = c.checkAndProcessBridgeMultiTx(ctx, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *transfersCommand) notifyOfNewTransfers(blockNum *big.Int, transfers []Transfer) {
|
||||
if c.feed != nil {
|
||||
if len(transfers) > 0 {
|
||||
|
@ -591,16 +486,15 @@ func (c *transfersCommand) notifyOfLatestTransfers(transfers []Transfer, transfe
|
|||
}
|
||||
|
||||
type loadTransfersCommand struct {
|
||||
accounts []common.Address
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
chainClient chain.ClientInterface
|
||||
blocksByAddress map[common.Address][]*big.Int
|
||||
transactionManager *TransactionManager
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
blocksLimit int
|
||||
tokenManager *token.Manager
|
||||
feed *event.Feed
|
||||
accounts []common.Address
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
chainClient chain.ClientInterface
|
||||
blocksByAddress map[common.Address][]*big.Int
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
blocksLimit int
|
||||
tokenManager *token.Manager
|
||||
feed *event.Feed
|
||||
}
|
||||
|
||||
func (c *loadTransfersCommand) Command() async.Command {
|
||||
|
@ -617,13 +511,12 @@ func (c *loadTransfersCommand) Command() async.Command {
|
|||
// in `transferCommand` with exponential backoff instead of `loadTransfersCommand` (issue #4608).
|
||||
func (c *loadTransfersCommand) Run(parent context.Context) (err error) {
|
||||
return loadTransfers(parent, c.blockDAO, c.db, c.chainClient, c.blocksLimit, c.blocksByAddress,
|
||||
c.transactionManager, c.pendingTxManager, c.tokenManager, c.feed)
|
||||
c.pendingTxManager, c.tokenManager, c.feed)
|
||||
}
|
||||
|
||||
func loadTransfers(ctx context.Context, blockDAO *BlockDAO, db *Database,
|
||||
chainClient chain.ClientInterface, blocksLimitPerAccount int, blocksByAddress map[common.Address][]*big.Int,
|
||||
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker,
|
||||
tokenManager *token.Manager, feed *event.Feed) error {
|
||||
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager, feed *event.Feed) error {
|
||||
|
||||
logutils.ZapLogger().Debug("loadTransfers start",
|
||||
zap.Uint64("chain", chainClient.NetworkID()),
|
||||
|
@ -646,11 +539,10 @@ func loadTransfers(ctx context.Context, blockDAO *BlockDAO, db *Database,
|
|||
signer: types.LatestSignerForChainID(chainClient.ToBigInt()),
|
||||
db: db,
|
||||
},
|
||||
blockNums: blocksByAddress[address],
|
||||
transactionManager: transactionManager,
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
feed: feed,
|
||||
blockNums: blocksByAddress[address],
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
feed: feed,
|
||||
}
|
||||
group.Add(transfers.Command())
|
||||
}
|
||||
|
@ -692,31 +584,3 @@ func uniqueHeaderPerBlockHash(allHeaders []*DBHeader) []*DBHeader {
|
|||
|
||||
return uniqHeaders
|
||||
}
|
||||
|
||||
// Organize subTransactions by Transaction Hash
|
||||
func subTransactionListToTransactionsByTxHash(subTransactions []Transfer) map[common.Hash]Transaction {
|
||||
rst := map[common.Hash]Transaction{}
|
||||
|
||||
for index := range subTransactions {
|
||||
subTx := &subTransactions[index]
|
||||
txHash := subTx.Transaction.Hash()
|
||||
|
||||
if _, ok := rst[txHash]; !ok {
|
||||
rst[txHash] = make([]*Transfer, 0)
|
||||
}
|
||||
rst[txHash] = append(rst[txHash], subTx)
|
||||
}
|
||||
|
||||
return rst
|
||||
}
|
||||
|
||||
func IsTransferDetectionEvent(ev walletevent.EventType) bool {
|
||||
if ev == EventInternalETHTransferDetected ||
|
||||
ev == EventInternalERC20TransferDetected ||
|
||||
ev == EventInternalERC721TransferDetected ||
|
||||
ev == EventInternalERC1155TransferDetected {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -1081,7 +1081,7 @@ func (c *loadBlocksAndTransfersCommand) startTransfersLoop(ctx context.Context)
|
|||
go func() {
|
||||
defer gocommon.LogOnPanic()
|
||||
_ = loadTransfers(ctx, c.blockDAO, c.db, c.chainClient, noBlockLimit,
|
||||
blocksByAddress, c.transactionManager, c.pendingTxManager, c.tokenManager, c.feed)
|
||||
blocksByAddress, c.pendingTxManager, c.tokenManager, c.feed)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
@ -1090,26 +1090,25 @@ func (c *loadBlocksAndTransfersCommand) startTransfersLoop(ctx context.Context)
|
|||
|
||||
func newLoadBlocksAndTransfersCommand(accounts []common.Address, db *Database, accountsDB *accounts.Database,
|
||||
blockDAO *BlockDAO, blockRangesSeqDAO BlockRangeDAOer, chainClient chain.ClientInterface, feed *event.Feed,
|
||||
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker,
|
||||
pendingTxManager *transactions.PendingTxTracker,
|
||||
tokenManager *token.Manager, balanceCacher balance.Cacher, omitHistory bool,
|
||||
blockChainState *blockchainstate.BlockChainState) *loadBlocksAndTransfersCommand {
|
||||
|
||||
return &loadBlocksAndTransfersCommand{
|
||||
accounts: accounts,
|
||||
db: db,
|
||||
blockRangeDAO: blockRangesSeqDAO,
|
||||
accountsDB: accountsDB,
|
||||
blockDAO: blockDAO,
|
||||
chainClient: chainClient,
|
||||
feed: feed,
|
||||
balanceCacher: balanceCacher,
|
||||
transactionManager: transactionManager,
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
blocksLoadedCh: make(chan []*DBHeader, 100),
|
||||
omitHistory: omitHistory,
|
||||
contractMaker: tokenManager.ContractMaker,
|
||||
blockChainState: blockChainState,
|
||||
accounts: accounts,
|
||||
db: db,
|
||||
blockRangeDAO: blockRangesSeqDAO,
|
||||
accountsDB: accountsDB,
|
||||
blockDAO: blockDAO,
|
||||
chainClient: chainClient,
|
||||
feed: feed,
|
||||
balanceCacher: balanceCacher,
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
blocksLoadedCh: make(chan []*DBHeader, 100),
|
||||
omitHistory: omitHistory,
|
||||
contractMaker: tokenManager.ContractMaker,
|
||||
blockChainState: blockChainState,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1123,13 +1122,12 @@ type loadBlocksAndTransfersCommand struct {
|
|||
feed *event.Feed
|
||||
balanceCacher balance.Cacher
|
||||
// nonArchivalRPCNode bool // TODO Make use of it
|
||||
transactionManager *TransactionManager
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
blocksLoadedCh chan []*DBHeader
|
||||
omitHistory bool
|
||||
contractMaker *contracts.ContractMaker
|
||||
blockChainState *blockchainstate.BlockChainState
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
blocksLoadedCh chan []*DBHeader
|
||||
omitHistory bool
|
||||
contractMaker *contracts.ContractMaker
|
||||
blockChainState *blockchainstate.BlockChainState
|
||||
|
||||
// Not to be set by the caller
|
||||
transfersLoaded map[common.Address]bool // For event RecentHistoryReady to be sent only once per account during app lifetime
|
||||
|
@ -1446,15 +1444,14 @@ func (c *loadBlocksAndTransfersCommand) startFetchingTransfersForLoadedBlocks(gr
|
|||
go func() {
|
||||
defer gocommon.LogOnPanic()
|
||||
txCommand := &loadTransfersCommand{
|
||||
accounts: c.accounts,
|
||||
db: c.db,
|
||||
blockDAO: c.blockDAO,
|
||||
chainClient: c.chainClient,
|
||||
transactionManager: c.transactionManager,
|
||||
pendingTxManager: c.pendingTxManager,
|
||||
tokenManager: c.tokenManager,
|
||||
blocksByAddress: blocksMap,
|
||||
feed: c.feed,
|
||||
accounts: c.accounts,
|
||||
db: c.db,
|
||||
blockDAO: c.blockDAO,
|
||||
chainClient: c.chainClient,
|
||||
pendingTxManager: c.pendingTxManager,
|
||||
tokenManager: c.tokenManager,
|
||||
blocksByAddress: blocksMap,
|
||||
feed: c.feed,
|
||||
}
|
||||
|
||||
group.Add(txCommand.Command())
|
||||
|
|
|
@ -1335,7 +1335,6 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) {
|
|||
|
||||
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||
require.NoError(t, err)
|
||||
tm := &TransactionManager{NewMultiTransactionDB(db), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
|
||||
mediaServer, err := server.NewMediaServer(appdb, nil, nil, db)
|
||||
require.NoError(t, err)
|
||||
|
@ -1395,20 +1394,19 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
cmd := &loadBlocksAndTransfersCommand{
|
||||
accounts: []common.Address{address},
|
||||
db: wdb,
|
||||
blockRangeDAO: &BlockRangeSequentialDAO{wdb.client},
|
||||
blockDAO: &BlockDAO{db},
|
||||
accountsDB: accDB,
|
||||
chainClient: tc,
|
||||
feed: &event.Feed{},
|
||||
balanceCacher: balance.NewCacherWithTTL(5 * time.Minute),
|
||||
transactionManager: tm,
|
||||
pendingTxManager: tracker,
|
||||
tokenManager: tokenManager,
|
||||
blocksLoadedCh: blockChannel,
|
||||
omitHistory: true,
|
||||
contractMaker: tokenManager.ContractMaker,
|
||||
accounts: []common.Address{address},
|
||||
db: wdb,
|
||||
blockRangeDAO: &BlockRangeSequentialDAO{wdb.client},
|
||||
blockDAO: &BlockDAO{db},
|
||||
accountsDB: accDB,
|
||||
chainClient: tc,
|
||||
feed: &event.Feed{},
|
||||
balanceCacher: balance.NewCacherWithTTL(5 * time.Minute),
|
||||
pendingTxManager: tracker,
|
||||
tokenManager: tokenManager,
|
||||
blocksLoadedCh: blockChannel,
|
||||
omitHistory: true,
|
||||
contractMaker: tokenManager.ContractMaker,
|
||||
}
|
||||
|
||||
tc.prepareBalanceHistory(int(tc.currentBlock))
|
||||
|
|
|
@ -48,36 +48,34 @@ type HistoryFetcher interface {
|
|||
|
||||
// Reactor listens to new blocks and stores transfers into the database.
|
||||
type Reactor struct {
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
blockRangesSeqDAO *BlockRangeSequentialDAO
|
||||
accountsDB *accounts.Database
|
||||
feed *event.Feed
|
||||
transactionManager *TransactionManager
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
strategy HistoryFetcher
|
||||
balanceCacher balance.Cacher
|
||||
omitHistory bool
|
||||
blockChainState *blockchainstate.BlockChainState
|
||||
chainIDs []uint64
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
blockRangesSeqDAO *BlockRangeSequentialDAO
|
||||
accountsDB *accounts.Database
|
||||
feed *event.Feed
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
strategy HistoryFetcher
|
||||
balanceCacher balance.Cacher
|
||||
omitHistory bool
|
||||
blockChainState *blockchainstate.BlockChainState
|
||||
chainIDs []uint64
|
||||
}
|
||||
|
||||
func NewReactor(db *Database, blockDAO *BlockDAO, blockRangesSeqDAO *BlockRangeSequentialDAO, accountsDB *accounts.Database, feed *event.Feed, tm *TransactionManager,
|
||||
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
|
||||
balanceCacher balance.Cacher, omitHistory bool, blockChainState *blockchainstate.BlockChainState) *Reactor {
|
||||
return &Reactor{
|
||||
db: db,
|
||||
accountsDB: accountsDB,
|
||||
blockDAO: blockDAO,
|
||||
blockRangesSeqDAO: blockRangesSeqDAO,
|
||||
feed: feed,
|
||||
transactionManager: tm,
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
balanceCacher: balanceCacher,
|
||||
omitHistory: omitHistory,
|
||||
blockChainState: blockChainState,
|
||||
db: db,
|
||||
accountsDB: accountsDB,
|
||||
blockDAO: blockDAO,
|
||||
blockRangesSeqDAO: blockRangesSeqDAO,
|
||||
feed: feed,
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
balanceCacher: balanceCacher,
|
||||
omitHistory: omitHistory,
|
||||
blockChainState: blockChainState,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +112,6 @@ func (r *Reactor) createFetchStrategy(chainClients map[uint64]chain.ClientInterf
|
|||
r.blockRangesSeqDAO,
|
||||
r.accountsDB,
|
||||
r.feed,
|
||||
r.transactionManager,
|
||||
r.pendingTxManager,
|
||||
r.tokenManager,
|
||||
chainClients,
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, blockRangesSeqDAO *BlockRangeSequentialDAO, accountsDB *accounts.Database, feed *event.Feed,
|
||||
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker,
|
||||
pendingTxManager *transactions.PendingTxTracker,
|
||||
tokenManager *token.Manager,
|
||||
chainClients map[uint64]chain.ClientInterface,
|
||||
accounts []common.Address,
|
||||
|
@ -31,45 +31,43 @@ func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, blockRangesSeq
|
|||
) *SequentialFetchStrategy {
|
||||
|
||||
return &SequentialFetchStrategy{
|
||||
db: db,
|
||||
blockDAO: blockDAO,
|
||||
blockRangesSeqDAO: blockRangesSeqDAO,
|
||||
accountsDB: accountsDB,
|
||||
feed: feed,
|
||||
transactionManager: transactionManager,
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
chainClients: chainClients,
|
||||
accounts: accounts,
|
||||
balanceCacher: balanceCacher,
|
||||
omitHistory: omitHistory,
|
||||
blockChainState: blockChainState,
|
||||
db: db,
|
||||
blockDAO: blockDAO,
|
||||
blockRangesSeqDAO: blockRangesSeqDAO,
|
||||
accountsDB: accountsDB,
|
||||
feed: feed,
|
||||
pendingTxManager: pendingTxManager,
|
||||
tokenManager: tokenManager,
|
||||
chainClients: chainClients,
|
||||
accounts: accounts,
|
||||
balanceCacher: balanceCacher,
|
||||
omitHistory: omitHistory,
|
||||
blockChainState: blockChainState,
|
||||
}
|
||||
}
|
||||
|
||||
type SequentialFetchStrategy struct {
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
blockRangesSeqDAO *BlockRangeSequentialDAO
|
||||
accountsDB *accounts.Database
|
||||
feed *event.Feed
|
||||
mu sync.Mutex
|
||||
group *async.Group
|
||||
transactionManager *TransactionManager
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
chainClients map[uint64]chain.ClientInterface
|
||||
accounts []common.Address
|
||||
balanceCacher balance.Cacher
|
||||
omitHistory bool
|
||||
blockChainState *blockchainstate.BlockChainState
|
||||
db *Database
|
||||
blockDAO *BlockDAO
|
||||
blockRangesSeqDAO *BlockRangeSequentialDAO
|
||||
accountsDB *accounts.Database
|
||||
feed *event.Feed
|
||||
mu sync.Mutex
|
||||
group *async.Group
|
||||
pendingTxManager *transactions.PendingTxTracker
|
||||
tokenManager *token.Manager
|
||||
chainClients map[uint64]chain.ClientInterface
|
||||
accounts []common.Address
|
||||
balanceCacher balance.Cacher
|
||||
omitHistory bool
|
||||
blockChainState *blockchainstate.BlockChainState
|
||||
}
|
||||
|
||||
func (s *SequentialFetchStrategy) newCommand(chainClient chain.ClientInterface,
|
||||
accounts []common.Address) async.Commander {
|
||||
|
||||
return newLoadBlocksAndTransfersCommand(accounts, s.db, s.accountsDB, s.blockDAO, s.blockRangesSeqDAO, chainClient, s.feed,
|
||||
s.transactionManager, s.pendingTxManager, s.tokenManager, s.balanceCacher, s.omitHistory, s.blockChainState)
|
||||
s.pendingTxManager, s.tokenManager, s.balanceCacher, s.omitHistory, s.blockChainState)
|
||||
}
|
||||
|
||||
func (s *SequentialFetchStrategy) start() error {
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
package transfer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
uniswapv2 "github.com/status-im/status-go/contracts/uniswapV2"
|
||||
uniswapv3 "github.com/status-im/status-go/contracts/uniswapV3"
|
||||
"github.com/status-im/status-go/rpc/chain"
|
||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/token"
|
||||
)
|
||||
|
||||
const ETHSymbol string = "ETH"
|
||||
const WETHSymbol string = "WETH"
|
||||
|
||||
func fetchUniswapV2PairInfo(ctx context.Context, client chain.ClientInterface, pairAddress common.Address) (*common.Address, *common.Address, error) {
|
||||
caller, err := uniswapv2.NewUniswapv2Caller(pairAddress, client)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
token0Address, err := caller.Token0(&bind.CallOpts{
|
||||
Context: ctx,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
token1Address, err := caller.Token1(&bind.CallOpts{
|
||||
Context: ctx,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &token0Address, &token1Address, nil
|
||||
}
|
||||
|
||||
func fetchUniswapV3PoolInfo(ctx context.Context, client chain.ClientInterface, poolAddress common.Address) (*common.Address, *common.Address, error) {
|
||||
caller, err := uniswapv3.NewUniswapv3Caller(poolAddress, client)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
token0Address, err := caller.Token0(&bind.CallOpts{
|
||||
Context: ctx,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
token1Address, err := caller.Token1(&bind.CallOpts{
|
||||
Context: ctx,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &token0Address, &token1Address, nil
|
||||
}
|
||||
|
||||
func identifyUniswapV2Asset(tokenManager *token.Manager, chainID uint64, amount0 *big.Int, contractAddress0 common.Address, amount1 *big.Int, contractAddress1 common.Address) (token *token.Token, amount *big.Int, err error) {
|
||||
// Either amount0 or amount1 should be 0
|
||||
if amount1.Sign() == 0 && amount0.Sign() != 0 {
|
||||
token = tokenManager.FindTokenByAddress(chainID, contractAddress0)
|
||||
if token == nil {
|
||||
err = fmt.Errorf("couldn't find symbol for token0 %v", contractAddress0)
|
||||
return
|
||||
}
|
||||
amount = amount0
|
||||
} else if amount0.Sign() == 0 && amount1.Sign() != 0 {
|
||||
token = tokenManager.FindTokenByAddress(chainID, contractAddress1)
|
||||
if token == nil {
|
||||
err = fmt.Errorf("couldn't find symbol for token1 %v", contractAddress1)
|
||||
return
|
||||
}
|
||||
amount = amount1
|
||||
} else {
|
||||
err = fmt.Errorf("couldn't identify token %v %v %v %v", contractAddress0, amount0, contractAddress1, amount1)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func fetchUniswapV2Info(ctx context.Context, client chain.ClientInterface, tokenManager *token.Manager, log *types.Log) (fromAsset string, fromAmount *hexutil.Big, toAsset string, toAmount *hexutil.Big, err error) {
|
||||
pairAddress, _, _, amount0In, amount1In, amount0Out, amount1Out, err := w_common.ParseUniswapV2Log(log)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
token0ContractAddress, token1ContractAddress, err := fetchUniswapV2PairInfo(ctx, client, pairAddress)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fromToken, fromAmountInt, err := identifyUniswapV2Asset(tokenManager, client.NetworkID(), amount0In, *token0ContractAddress, amount1In, *token1ContractAddress)
|
||||
if err != nil {
|
||||
// "Soft" error, allow to continue with unknown asset
|
||||
fromAsset = ""
|
||||
fromAmount = (*hexutil.Big)(big.NewInt(0))
|
||||
} else {
|
||||
fromAsset = fromToken.Symbol
|
||||
fromAmount = (*hexutil.Big)(fromAmountInt)
|
||||
}
|
||||
|
||||
toToken, toAmountInt, err := identifyUniswapV2Asset(tokenManager, client.NetworkID(), amount0Out, *token0ContractAddress, amount1Out, *token1ContractAddress)
|
||||
if err != nil {
|
||||
// "Soft" error, allow to continue with unknown asset
|
||||
toAsset = ""
|
||||
toAmount = (*hexutil.Big)(big.NewInt(0))
|
||||
} else {
|
||||
toAsset = toToken.Symbol
|
||||
toAmount = (*hexutil.Big)(toAmountInt)
|
||||
}
|
||||
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
func identifyUniswapV3Assets(tokenManager *token.Manager, chainID uint64, amount0 *big.Int, contractAddress0 common.Address, amount1 *big.Int, contractAddress1 common.Address) (fromToken *token.Token, fromAmount *big.Int, toToken *token.Token, toAmount *big.Int, err error) {
|
||||
token0 := tokenManager.FindTokenByAddress(chainID, contractAddress0)
|
||||
if token0 == nil {
|
||||
err = fmt.Errorf("couldn't find symbol for token0 %v", contractAddress0)
|
||||
return
|
||||
}
|
||||
|
||||
token1 := tokenManager.FindTokenByAddress(chainID, contractAddress1)
|
||||
if token1 == nil {
|
||||
err = fmt.Errorf("couldn't find symbol for token1 %v", contractAddress1)
|
||||
return
|
||||
}
|
||||
|
||||
// amount0 and amount1 are the balance deltas of the pool
|
||||
// The positive amount is how much the sender spent
|
||||
// The negative amount is how much the recipent got
|
||||
if amount0.Sign() > 0 && amount1.Sign() < 0 {
|
||||
fromToken = token0
|
||||
fromAmount = amount0
|
||||
toToken = token1
|
||||
toAmount = new(big.Int).Neg(amount1)
|
||||
} else if amount0.Sign() < 0 && amount1.Sign() > 0 {
|
||||
fromToken = token1
|
||||
fromAmount = amount1
|
||||
toToken = token0
|
||||
toAmount = new(big.Int).Neg(amount0)
|
||||
} else {
|
||||
err = fmt.Errorf("couldn't identify tokens %v %v %v %v", contractAddress0, amount0, contractAddress1, amount1)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func fetchUniswapV3Info(ctx context.Context, client chain.ClientInterface, tokenManager *token.Manager, log *types.Log) (fromAsset string, fromAmount *hexutil.Big, toAsset string, toAmount *hexutil.Big, err error) {
|
||||
poolAddress, _, _, amount0, amount1, err := w_common.ParseUniswapV3Log(log)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
token0ContractAddress, token1ContractAddress, err := fetchUniswapV3PoolInfo(ctx, client, poolAddress)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fromToken, fromAmountInt, toToken, toAmountInt, err := identifyUniswapV3Assets(tokenManager, client.NetworkID(), amount0, *token0ContractAddress, amount1, *token1ContractAddress)
|
||||
if err != nil {
|
||||
// "Soft" error, allow to continue with unknown asset
|
||||
err = nil
|
||||
fromAsset = ""
|
||||
fromAmount = (*hexutil.Big)(big.NewInt(0))
|
||||
toAsset = ""
|
||||
toAmount = (*hexutil.Big)(big.NewInt(0))
|
||||
} else {
|
||||
fromAsset = fromToken.Symbol
|
||||
fromAmount = (*hexutil.Big)(fromAmountInt)
|
||||
toAsset = toToken.Symbol
|
||||
toAmount = (*hexutil.Big)(toAmountInt)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func fetchUniswapInfo(ctx context.Context, client chain.ClientInterface, tokenManager *token.Manager, log *types.Log, logType w_common.EventType) (fromAsset string, fromAmount *hexutil.Big, toAsset string, toAmount *hexutil.Big, err error) {
|
||||
switch logType {
|
||||
case w_common.UniswapV2SwapEventType:
|
||||
return fetchUniswapV2Info(ctx, client, tokenManager, log)
|
||||
case w_common.UniswapV3SwapEventType:
|
||||
return fetchUniswapV3Info(ctx, client, tokenManager, log)
|
||||
}
|
||||
err = fmt.Errorf("wrong log type %s", logType)
|
||||
return
|
||||
}
|
||||
|
||||
// Build a Swap multitransaction from a list containing one or several uniswapV2/uniswapV3 subTxs
|
||||
// We only care about the first and last swap to identify the input/output token and amounts
|
||||
func buildUniswapSwapMultitransaction(ctx context.Context, client chain.ClientInterface, tokenManager *token.Manager, transfer *Transfer) (*MultiTransaction, error) {
|
||||
multiTransaction := MultiTransaction{
|
||||
Type: MultiTransactionSwap,
|
||||
FromNetworkID: transfer.NetworkID,
|
||||
FromTxHash: transfer.Receipt.TxHash,
|
||||
FromAddress: transfer.Address,
|
||||
ToNetworkID: transfer.NetworkID,
|
||||
ToTxHash: transfer.Receipt.TxHash,
|
||||
ToAddress: transfer.Address,
|
||||
Timestamp: transfer.Timestamp,
|
||||
}
|
||||
|
||||
var firstSwapLog, lastSwapLog *types.Log
|
||||
var firstSwapLogType, lastSwapLogType w_common.EventType
|
||||
hasWETHDepositLog := false
|
||||
hasWETHWithdrawalLog := false
|
||||
|
||||
for _, ethlog := range transfer.Receipt.Logs {
|
||||
logType := w_common.GetEventType(ethlog)
|
||||
switch logType {
|
||||
case w_common.WETHDepositEventType:
|
||||
hasWETHDepositLog = true
|
||||
case w_common.WETHWithdrawalEventType:
|
||||
hasWETHWithdrawalLog = true
|
||||
case w_common.UniswapV2SwapEventType, w_common.UniswapV3SwapEventType:
|
||||
if firstSwapLog == nil {
|
||||
firstSwapLog = ethlog
|
||||
firstSwapLogType = logType
|
||||
}
|
||||
lastSwapLog = ethlog
|
||||
lastSwapLogType = logType
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
multiTransaction.FromAsset, multiTransaction.FromAmount, multiTransaction.ToAsset, multiTransaction.ToAmount, err = fetchUniswapInfo(ctx, client, tokenManager, firstSwapLog, firstSwapLogType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if firstSwapLog != lastSwapLog {
|
||||
_, _, multiTransaction.ToAsset, multiTransaction.ToAmount, err = fetchUniswapInfo(ctx, client, tokenManager, lastSwapLog, lastSwapLogType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// WETH and ETH have same decimals value, no need to change From/To Amount
|
||||
if multiTransaction.FromAsset == WETHSymbol && hasWETHDepositLog {
|
||||
multiTransaction.FromAsset = ETHSymbol
|
||||
}
|
||||
|
||||
if multiTransaction.ToAsset == WETHSymbol && hasWETHWithdrawalLog {
|
||||
multiTransaction.ToAsset = ETHSymbol
|
||||
}
|
||||
|
||||
return &multiTransaction, nil
|
||||
}
|
Loading…
Reference in New Issue