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 {
|
type transfersCommand struct {
|
||||||
db *Database
|
db *Database
|
||||||
blockDAO *BlockDAO
|
blockDAO *BlockDAO
|
||||||
eth *ETHDownloader
|
eth *ETHDownloader
|
||||||
blockNums []*big.Int
|
blockNums []*big.Int
|
||||||
address common.Address
|
address common.Address
|
||||||
chainClient chain.ClientInterface
|
chainClient chain.ClientInterface
|
||||||
blocksLimit int
|
blocksLimit int
|
||||||
transactionManager *TransactionManager
|
pendingTxManager *transactions.PendingTxTracker
|
||||||
pendingTxManager *transactions.PendingTxTracker
|
tokenManager *token.Manager
|
||||||
tokenManager *token.Manager
|
feed *event.Feed
|
||||||
feed *event.Feed
|
|
||||||
|
|
||||||
// result
|
// result
|
||||||
fetchedTransfers []Transfer
|
fetchedTransfers []Transfer
|
||||||
|
@ -274,13 +273,6 @@ func (c *transfersCommand) Run(ctx context.Context) (err error) {
|
||||||
logutils.ZapLogger().Error("saveAndConfirmPending error", zap.Error(err))
|
logutils.ZapLogger().Error("saveAndConfirmPending error", zap.Error(err))
|
||||||
return 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 {
|
} else {
|
||||||
// If no transfers found, that is suspecting, because downloader returned this block as containing transfers
|
// If no transfers found, that is suspecting, because downloader returned this block as containing transfers
|
||||||
logutils.ZapLogger().Error("no transfers found in block",
|
logutils.ZapLogger().Error("no transfers found in block",
|
||||||
|
@ -422,73 +414,6 @@ func (c *transfersCommand) confirmPendingTransactions(tx *sql.Tx, allTransfers [
|
||||||
return notifyFunctions
|
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) {
|
func (c *transfersCommand) processUnknownErc20CommunityTransactions(ctx context.Context, allTransfers []Transfer) {
|
||||||
for _, tx := range allTransfers {
|
for _, tx := range allTransfers {
|
||||||
// To can be nil in case of erc20 contract creation
|
// 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) {
|
func (c *transfersCommand) notifyOfNewTransfers(blockNum *big.Int, transfers []Transfer) {
|
||||||
if c.feed != nil {
|
if c.feed != nil {
|
||||||
if len(transfers) > 0 {
|
if len(transfers) > 0 {
|
||||||
|
@ -591,16 +486,15 @@ func (c *transfersCommand) notifyOfLatestTransfers(transfers []Transfer, transfe
|
||||||
}
|
}
|
||||||
|
|
||||||
type loadTransfersCommand struct {
|
type loadTransfersCommand struct {
|
||||||
accounts []common.Address
|
accounts []common.Address
|
||||||
db *Database
|
db *Database
|
||||||
blockDAO *BlockDAO
|
blockDAO *BlockDAO
|
||||||
chainClient chain.ClientInterface
|
chainClient chain.ClientInterface
|
||||||
blocksByAddress map[common.Address][]*big.Int
|
blocksByAddress map[common.Address][]*big.Int
|
||||||
transactionManager *TransactionManager
|
pendingTxManager *transactions.PendingTxTracker
|
||||||
pendingTxManager *transactions.PendingTxTracker
|
blocksLimit int
|
||||||
blocksLimit int
|
tokenManager *token.Manager
|
||||||
tokenManager *token.Manager
|
feed *event.Feed
|
||||||
feed *event.Feed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *loadTransfersCommand) Command() async.Command {
|
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).
|
// in `transferCommand` with exponential backoff instead of `loadTransfersCommand` (issue #4608).
|
||||||
func (c *loadTransfersCommand) Run(parent context.Context) (err error) {
|
func (c *loadTransfersCommand) Run(parent context.Context) (err error) {
|
||||||
return loadTransfers(parent, c.blockDAO, c.db, c.chainClient, c.blocksLimit, c.blocksByAddress,
|
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,
|
func loadTransfers(ctx context.Context, blockDAO *BlockDAO, db *Database,
|
||||||
chainClient chain.ClientInterface, blocksLimitPerAccount int, blocksByAddress map[common.Address][]*big.Int,
|
chainClient chain.ClientInterface, blocksLimitPerAccount int, blocksByAddress map[common.Address][]*big.Int,
|
||||||
transactionManager *TransactionManager, pendingTxManager *transactions.PendingTxTracker,
|
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager, feed *event.Feed) error {
|
||||||
tokenManager *token.Manager, feed *event.Feed) error {
|
|
||||||
|
|
||||||
logutils.ZapLogger().Debug("loadTransfers start",
|
logutils.ZapLogger().Debug("loadTransfers start",
|
||||||
zap.Uint64("chain", chainClient.NetworkID()),
|
zap.Uint64("chain", chainClient.NetworkID()),
|
||||||
|
@ -646,11 +539,10 @@ func loadTransfers(ctx context.Context, blockDAO *BlockDAO, db *Database,
|
||||||
signer: types.LatestSignerForChainID(chainClient.ToBigInt()),
|
signer: types.LatestSignerForChainID(chainClient.ToBigInt()),
|
||||||
db: db,
|
db: db,
|
||||||
},
|
},
|
||||||
blockNums: blocksByAddress[address],
|
blockNums: blocksByAddress[address],
|
||||||
transactionManager: transactionManager,
|
pendingTxManager: pendingTxManager,
|
||||||
pendingTxManager: pendingTxManager,
|
tokenManager: tokenManager,
|
||||||
tokenManager: tokenManager,
|
feed: feed,
|
||||||
feed: feed,
|
|
||||||
}
|
}
|
||||||
group.Add(transfers.Command())
|
group.Add(transfers.Command())
|
||||||
}
|
}
|
||||||
|
@ -692,31 +584,3 @@ func uniqueHeaderPerBlockHash(allHeaders []*DBHeader) []*DBHeader {
|
||||||
|
|
||||||
return uniqHeaders
|
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() {
|
go func() {
|
||||||
defer gocommon.LogOnPanic()
|
defer gocommon.LogOnPanic()
|
||||||
_ = loadTransfers(ctx, c.blockDAO, c.db, c.chainClient, noBlockLimit,
|
_ = 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,
|
func newLoadBlocksAndTransfersCommand(accounts []common.Address, db *Database, accountsDB *accounts.Database,
|
||||||
blockDAO *BlockDAO, blockRangesSeqDAO BlockRangeDAOer, chainClient chain.ClientInterface, feed *event.Feed,
|
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,
|
tokenManager *token.Manager, balanceCacher balance.Cacher, omitHistory bool,
|
||||||
blockChainState *blockchainstate.BlockChainState) *loadBlocksAndTransfersCommand {
|
blockChainState *blockchainstate.BlockChainState) *loadBlocksAndTransfersCommand {
|
||||||
|
|
||||||
return &loadBlocksAndTransfersCommand{
|
return &loadBlocksAndTransfersCommand{
|
||||||
accounts: accounts,
|
accounts: accounts,
|
||||||
db: db,
|
db: db,
|
||||||
blockRangeDAO: blockRangesSeqDAO,
|
blockRangeDAO: blockRangesSeqDAO,
|
||||||
accountsDB: accountsDB,
|
accountsDB: accountsDB,
|
||||||
blockDAO: blockDAO,
|
blockDAO: blockDAO,
|
||||||
chainClient: chainClient,
|
chainClient: chainClient,
|
||||||
feed: feed,
|
feed: feed,
|
||||||
balanceCacher: balanceCacher,
|
balanceCacher: balanceCacher,
|
||||||
transactionManager: transactionManager,
|
pendingTxManager: pendingTxManager,
|
||||||
pendingTxManager: pendingTxManager,
|
tokenManager: tokenManager,
|
||||||
tokenManager: tokenManager,
|
blocksLoadedCh: make(chan []*DBHeader, 100),
|
||||||
blocksLoadedCh: make(chan []*DBHeader, 100),
|
omitHistory: omitHistory,
|
||||||
omitHistory: omitHistory,
|
contractMaker: tokenManager.ContractMaker,
|
||||||
contractMaker: tokenManager.ContractMaker,
|
blockChainState: blockChainState,
|
||||||
blockChainState: blockChainState,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,13 +1122,12 @@ type loadBlocksAndTransfersCommand struct {
|
||||||
feed *event.Feed
|
feed *event.Feed
|
||||||
balanceCacher balance.Cacher
|
balanceCacher balance.Cacher
|
||||||
// nonArchivalRPCNode bool // TODO Make use of it
|
// nonArchivalRPCNode bool // TODO Make use of it
|
||||||
transactionManager *TransactionManager
|
pendingTxManager *transactions.PendingTxTracker
|
||||||
pendingTxManager *transactions.PendingTxTracker
|
tokenManager *token.Manager
|
||||||
tokenManager *token.Manager
|
blocksLoadedCh chan []*DBHeader
|
||||||
blocksLoadedCh chan []*DBHeader
|
omitHistory bool
|
||||||
omitHistory bool
|
contractMaker *contracts.ContractMaker
|
||||||
contractMaker *contracts.ContractMaker
|
blockChainState *blockchainstate.BlockChainState
|
||||||
blockChainState *blockchainstate.BlockChainState
|
|
||||||
|
|
||||||
// Not to be set by the caller
|
// 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
|
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() {
|
go func() {
|
||||||
defer gocommon.LogOnPanic()
|
defer gocommon.LogOnPanic()
|
||||||
txCommand := &loadTransfersCommand{
|
txCommand := &loadTransfersCommand{
|
||||||
accounts: c.accounts,
|
accounts: c.accounts,
|
||||||
db: c.db,
|
db: c.db,
|
||||||
blockDAO: c.blockDAO,
|
blockDAO: c.blockDAO,
|
||||||
chainClient: c.chainClient,
|
chainClient: c.chainClient,
|
||||||
transactionManager: c.transactionManager,
|
pendingTxManager: c.pendingTxManager,
|
||||||
pendingTxManager: c.pendingTxManager,
|
tokenManager: c.tokenManager,
|
||||||
tokenManager: c.tokenManager,
|
blocksByAddress: blocksMap,
|
||||||
blocksByAddress: blocksMap,
|
feed: c.feed,
|
||||||
feed: c.feed,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group.Add(txCommand.Command())
|
group.Add(txCommand.Command())
|
||||||
|
|
|
@ -1335,7 +1335,6 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) {
|
||||||
|
|
||||||
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||||
require.NoError(t, err)
|
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)
|
mediaServer, err := server.NewMediaServer(appdb, nil, nil, db)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -1395,20 +1394,19 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
cmd := &loadBlocksAndTransfersCommand{
|
cmd := &loadBlocksAndTransfersCommand{
|
||||||
accounts: []common.Address{address},
|
accounts: []common.Address{address},
|
||||||
db: wdb,
|
db: wdb,
|
||||||
blockRangeDAO: &BlockRangeSequentialDAO{wdb.client},
|
blockRangeDAO: &BlockRangeSequentialDAO{wdb.client},
|
||||||
blockDAO: &BlockDAO{db},
|
blockDAO: &BlockDAO{db},
|
||||||
accountsDB: accDB,
|
accountsDB: accDB,
|
||||||
chainClient: tc,
|
chainClient: tc,
|
||||||
feed: &event.Feed{},
|
feed: &event.Feed{},
|
||||||
balanceCacher: balance.NewCacherWithTTL(5 * time.Minute),
|
balanceCacher: balance.NewCacherWithTTL(5 * time.Minute),
|
||||||
transactionManager: tm,
|
pendingTxManager: tracker,
|
||||||
pendingTxManager: tracker,
|
tokenManager: tokenManager,
|
||||||
tokenManager: tokenManager,
|
blocksLoadedCh: blockChannel,
|
||||||
blocksLoadedCh: blockChannel,
|
omitHistory: true,
|
||||||
omitHistory: true,
|
contractMaker: tokenManager.ContractMaker,
|
||||||
contractMaker: tokenManager.ContractMaker,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tc.prepareBalanceHistory(int(tc.currentBlock))
|
tc.prepareBalanceHistory(int(tc.currentBlock))
|
||||||
|
|
|
@ -48,36 +48,34 @@ type HistoryFetcher interface {
|
||||||
|
|
||||||
// Reactor listens to new blocks and stores transfers into the database.
|
// Reactor listens to new blocks and stores transfers into the database.
|
||||||
type Reactor struct {
|
type Reactor struct {
|
||||||
db *Database
|
db *Database
|
||||||
blockDAO *BlockDAO
|
blockDAO *BlockDAO
|
||||||
blockRangesSeqDAO *BlockRangeSequentialDAO
|
blockRangesSeqDAO *BlockRangeSequentialDAO
|
||||||
accountsDB *accounts.Database
|
accountsDB *accounts.Database
|
||||||
feed *event.Feed
|
feed *event.Feed
|
||||||
transactionManager *TransactionManager
|
pendingTxManager *transactions.PendingTxTracker
|
||||||
pendingTxManager *transactions.PendingTxTracker
|
tokenManager *token.Manager
|
||||||
tokenManager *token.Manager
|
strategy HistoryFetcher
|
||||||
strategy HistoryFetcher
|
balanceCacher balance.Cacher
|
||||||
balanceCacher balance.Cacher
|
omitHistory bool
|
||||||
omitHistory bool
|
blockChainState *blockchainstate.BlockChainState
|
||||||
blockChainState *blockchainstate.BlockChainState
|
chainIDs []uint64
|
||||||
chainIDs []uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReactor(db *Database, blockDAO *BlockDAO, blockRangesSeqDAO *BlockRangeSequentialDAO, accountsDB *accounts.Database, feed *event.Feed, tm *TransactionManager,
|
func NewReactor(db *Database, blockDAO *BlockDAO, blockRangesSeqDAO *BlockRangeSequentialDAO, accountsDB *accounts.Database, feed *event.Feed, tm *TransactionManager,
|
||||||
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
|
pendingTxManager *transactions.PendingTxTracker, tokenManager *token.Manager,
|
||||||
balanceCacher balance.Cacher, omitHistory bool, blockChainState *blockchainstate.BlockChainState) *Reactor {
|
balanceCacher balance.Cacher, omitHistory bool, blockChainState *blockchainstate.BlockChainState) *Reactor {
|
||||||
return &Reactor{
|
return &Reactor{
|
||||||
db: db,
|
db: db,
|
||||||
accountsDB: accountsDB,
|
accountsDB: accountsDB,
|
||||||
blockDAO: blockDAO,
|
blockDAO: blockDAO,
|
||||||
blockRangesSeqDAO: blockRangesSeqDAO,
|
blockRangesSeqDAO: blockRangesSeqDAO,
|
||||||
feed: feed,
|
feed: feed,
|
||||||
transactionManager: tm,
|
pendingTxManager: pendingTxManager,
|
||||||
pendingTxManager: pendingTxManager,
|
tokenManager: tokenManager,
|
||||||
tokenManager: tokenManager,
|
balanceCacher: balanceCacher,
|
||||||
balanceCacher: balanceCacher,
|
omitHistory: omitHistory,
|
||||||
omitHistory: omitHistory,
|
blockChainState: blockChainState,
|
||||||
blockChainState: blockChainState,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +112,6 @@ func (r *Reactor) createFetchStrategy(chainClients map[uint64]chain.ClientInterf
|
||||||
r.blockRangesSeqDAO,
|
r.blockRangesSeqDAO,
|
||||||
r.accountsDB,
|
r.accountsDB,
|
||||||
r.feed,
|
r.feed,
|
||||||
r.transactionManager,
|
|
||||||
r.pendingTxManager,
|
r.pendingTxManager,
|
||||||
r.tokenManager,
|
r.tokenManager,
|
||||||
chainClients,
|
chainClients,
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, blockRangesSeqDAO *BlockRangeSequentialDAO, accountsDB *accounts.Database, feed *event.Feed,
|
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,
|
tokenManager *token.Manager,
|
||||||
chainClients map[uint64]chain.ClientInterface,
|
chainClients map[uint64]chain.ClientInterface,
|
||||||
accounts []common.Address,
|
accounts []common.Address,
|
||||||
|
@ -31,45 +31,43 @@ func NewSequentialFetchStrategy(db *Database, blockDAO *BlockDAO, blockRangesSeq
|
||||||
) *SequentialFetchStrategy {
|
) *SequentialFetchStrategy {
|
||||||
|
|
||||||
return &SequentialFetchStrategy{
|
return &SequentialFetchStrategy{
|
||||||
db: db,
|
db: db,
|
||||||
blockDAO: blockDAO,
|
blockDAO: blockDAO,
|
||||||
blockRangesSeqDAO: blockRangesSeqDAO,
|
blockRangesSeqDAO: blockRangesSeqDAO,
|
||||||
accountsDB: accountsDB,
|
accountsDB: accountsDB,
|
||||||
feed: feed,
|
feed: feed,
|
||||||
transactionManager: transactionManager,
|
pendingTxManager: pendingTxManager,
|
||||||
pendingTxManager: pendingTxManager,
|
tokenManager: tokenManager,
|
||||||
tokenManager: tokenManager,
|
chainClients: chainClients,
|
||||||
chainClients: chainClients,
|
accounts: accounts,
|
||||||
accounts: accounts,
|
balanceCacher: balanceCacher,
|
||||||
balanceCacher: balanceCacher,
|
omitHistory: omitHistory,
|
||||||
omitHistory: omitHistory,
|
blockChainState: blockChainState,
|
||||||
blockChainState: blockChainState,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SequentialFetchStrategy struct {
|
type SequentialFetchStrategy struct {
|
||||||
db *Database
|
db *Database
|
||||||
blockDAO *BlockDAO
|
blockDAO *BlockDAO
|
||||||
blockRangesSeqDAO *BlockRangeSequentialDAO
|
blockRangesSeqDAO *BlockRangeSequentialDAO
|
||||||
accountsDB *accounts.Database
|
accountsDB *accounts.Database
|
||||||
feed *event.Feed
|
feed *event.Feed
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
group *async.Group
|
group *async.Group
|
||||||
transactionManager *TransactionManager
|
pendingTxManager *transactions.PendingTxTracker
|
||||||
pendingTxManager *transactions.PendingTxTracker
|
tokenManager *token.Manager
|
||||||
tokenManager *token.Manager
|
chainClients map[uint64]chain.ClientInterface
|
||||||
chainClients map[uint64]chain.ClientInterface
|
accounts []common.Address
|
||||||
accounts []common.Address
|
balanceCacher balance.Cacher
|
||||||
balanceCacher balance.Cacher
|
omitHistory bool
|
||||||
omitHistory bool
|
blockChainState *blockchainstate.BlockChainState
|
||||||
blockChainState *blockchainstate.BlockChainState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SequentialFetchStrategy) newCommand(chainClient chain.ClientInterface,
|
func (s *SequentialFetchStrategy) newCommand(chainClient chain.ClientInterface,
|
||||||
accounts []common.Address) async.Commander {
|
accounts []common.Address) async.Commander {
|
||||||
|
|
||||||
return newLoadBlocksAndTransfersCommand(accounts, s.db, s.accountsDB, s.blockDAO, s.blockRangesSeqDAO, chainClient, s.feed,
|
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 {
|
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