feat: Save previously owned tokens (#4482)

This commit is contained in:
Cuteivist 2023-12-21 15:12:50 +01:00 committed by GitHub
parent 5d644bdf94
commit 313375e215
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 5 deletions

View File

@ -250,6 +250,11 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
availableNetworks = append(availableNetworks, network)
}
cachedTokens, err := r.GetCachedWalletTokensWithoutMarketData()
if err != nil {
return nil, err
}
chainIDs := make([]uint64, 0)
for _, network := range availableNetworks {
chainIDs = append(chainIDs, network.ChainID)
@ -296,7 +301,7 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
for symbol, tokens := range getTokenBySymbols(tokenList) {
balancesPerChain := make(map[uint64]ChainBalance)
decimals := tokens[0].Decimals
anyPositiveBalance := false
isVisible := false
for _, token := range tokens {
hexBalance := balances[token.ChainID][address][token.Address]
balance := big.NewFloat(0.0)
@ -310,8 +315,8 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
if client, ok := clients[token.ChainID]; ok {
hasError = err != nil || !client.GetIsConnected()
}
if !anyPositiveBalance {
anyPositiveBalance = balance.Cmp(big.NewFloat(0.0)) > 0
if !isVisible {
isVisible = balance.Cmp(big.NewFloat(0.0)) > 0 || r.isCachedToken(cachedTokens, address, token.Symbol, token.ChainID)
}
balancesPerChain[token.ChainID] = ChainBalance{
RawBalance: hexBalance.ToInt().String(),
@ -322,7 +327,7 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
}
}
if !anyPositiveBalance && !belongsToMandatoryTokens(symbol) {
if !isVisible && !belongsToMandatoryTokens(symbol) {
continue
}
@ -420,6 +425,21 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
return result, r.persistence.SaveTokens(result)
}
func (r *Reader) isCachedToken(cachedTokens map[common.Address][]Token, address common.Address, symbol string, chainID uint64) bool {
if tokens, ok := cachedTokens[address]; ok {
for _, t := range tokens {
if t.Symbol != symbol {
continue
}
_, ok := t.BalancesPerChain[chainID]
if ok {
return true
}
}
}
return false
}
// GetCachedWalletTokensWithoutMarketData returns the latest fetched balances, minus
// price information
func (r *Reader) GetCachedWalletTokensWithoutMarketData() (map[common.Address][]Token, error) {

View File

@ -3,6 +3,7 @@ package token
import (
"context"
"database/sql"
"errors"
"math/big"
"strconv"
"strings"
@ -293,6 +294,22 @@ func (tm *Manager) FindOrCreateTokenByAddress(ctx context.Context, chainID uint6
return token
}
func (tm *Manager) MarkAsPreviouslyOwnedToken(token *Token, owner common.Address) error {
if token == nil {
return errors.New("token is nil")
}
if (owner == common.Address{}) {
return errors.New("owner is nil")
}
count := 0
err := tm.db.QueryRow(`SELECT EXISTS(SELECT 1 FROM token_balances WHERE user_address = ? AND token_address = ? AND chain_id = ?)`, owner.Hex(), token.Address.Hex(), token.ChainID).Scan(&count)
if err != nil || count > 0 {
return err
}
_, err = tm.db.Exec(`INSERT INTO token_balances(user_address,token_name,token_symbol,token_address,token_decimals,chain_id,token_decimals,raw_balance,balance) VALUES (?,?,?,?,?,?,?,?,?)`, owner.Hex(), token.Name, token.Symbol, token.Address.Hex(), token.Decimals, token.ChainID, 0, "0", "0")
return err
}
func (tm *Manager) discoverTokenCommunityID(ctx context.Context, token *Token, address common.Address) {
if token == nil || token.CommunityData != nil {
// Token is invalid or is alrady discovered. Nothing to do here.

View File

@ -193,3 +193,52 @@ func TestTokenOverride(t *testing.T) {
require.Equal(t, common.Address{33}, tokenMap[2][common.Address{33}].Address)
require.Equal(t, common.Address{4}, tokenMap[2][common.Address{4}].Address)
}
func TestMarkAsPreviouslyOwnedToken(t *testing.T) {
manager, stop := setupTestTokenDB(t)
defer stop()
owner := common.HexToAddress("0x1234567890abcdef")
token := &Token{
Address: common.HexToAddress("0xabcdef1234567890"),
Name: "TestToken",
Symbol: "TT",
Decimals: 18,
ChainID: 1,
}
err := manager.MarkAsPreviouslyOwnedToken(nil, owner)
require.Error(t, err)
err = manager.MarkAsPreviouslyOwnedToken(token, common.Address{})
require.Error(t, err)
err = manager.MarkAsPreviouslyOwnedToken(token, owner)
require.NoError(t, err)
// Verify that the token balance was inserted correctly
var count int
err = manager.db.QueryRow(`SELECT count(*) FROM token_balances`).Scan(&count)
require.NoError(t, err)
require.Equal(t, 1, count)
token.Name = "123"
err = manager.MarkAsPreviouslyOwnedToken(token, owner)
require.NoError(t, err)
// Not updated because already exists
err = manager.db.QueryRow(`SELECT count(*) FROM token_balances`).Scan(&count)
require.NoError(t, err)
require.Equal(t, 1, count)
token.ChainID = 2
err = manager.MarkAsPreviouslyOwnedToken(token, owner)
require.NoError(t, err)
// Same token on different chains counts as different token
err = manager.db.QueryRow(`SELECT count(*) FROM token_balances`).Scan(&count)
require.NoError(t, err)
require.Equal(t, 2, count)
}

View File

@ -354,6 +354,20 @@ func setMultiTxID(tx Transaction, multiTxID MultiTransactionIDType) {
}
}
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 {
@ -370,6 +384,7 @@ func (c *transfersCommand) checkAndProcessSwapMultiTx(ctx context.Context, tx Tr
return false, err
}
setMultiTxID(tx, id)
c.markMultiTxTokensAsPreviouslyOwned(ctx, multiTransaction, subTx.Address)
return true, nil
}
}
@ -390,6 +405,7 @@ func (c *transfersCommand) checkAndProcessBridgeMultiTx(ctx context.Context, tx
if multiTransaction != nil {
setMultiTxID(tx, MultiTransactionIDType(multiTransaction.ID))
c.markMultiTxTokensAsPreviouslyOwned(ctx, multiTransaction, subTx.Address)
return true, nil
}
}
@ -403,7 +419,10 @@ func (c *transfersCommand) processUnknownErc20CommunityTransactions(ctx context.
// To can be nil in case of erc20 contract creation
if tx.Type == w_common.Erc20Transfer && tx.Transaction.To() != nil {
// Find token in db or if this is a community token, find its metadata
_ = c.tokenManager.FindOrCreateTokenByAddress(ctx, tx.NetworkID, *tx.Transaction.To())
token := c.tokenManager.FindOrCreateTokenByAddress(ctx, tx.NetworkID, *tx.Transaction.To())
if token != nil && (token.Verified || token.CommunityData != nil) {
_ = c.tokenManager.MarkAsPreviouslyOwnedToken(token, tx.Address)
}
}
}
}