feat: Fetch community token image (#4440)
This commit is contained in:
parent
575a421786
commit
dfe6baed9b
|
@ -1,6 +1,7 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -73,6 +74,7 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
setSettingsNotifier(accDB, settingsFeed)
|
||||
|
||||
services := []common.StatusService{}
|
||||
|
@ -99,7 +101,7 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
|||
// Wallet Service is used by wakuExtSrvc/wakuV2ExtSrvc
|
||||
// Keep this initialization before the other two
|
||||
if config.WalletConfig.Enabled {
|
||||
walletService := b.walletService(accDB, accountsFeed, settingsFeed, &b.walletFeed)
|
||||
walletService := b.walletService(accDB, b.appDB, accountsFeed, settingsFeed, &b.walletFeed)
|
||||
services = append(services, walletService)
|
||||
}
|
||||
|
||||
|
@ -522,10 +524,10 @@ func (b *StatusNode) SetWalletCollectibleCommunityInfoProvider(provider thirdpar
|
|||
}
|
||||
}
|
||||
|
||||
func (b *StatusNode) walletService(accountsDB *accounts.Database, accountsFeed *event.Feed, settingsFeed *event.Feed, walletFeed *event.Feed) *wallet.Service {
|
||||
func (b *StatusNode) walletService(accountsDB *accounts.Database, appDB *sql.DB, accountsFeed *event.Feed, settingsFeed *event.Feed, walletFeed *event.Feed) *wallet.Service {
|
||||
if b.walletSrvc == nil {
|
||||
b.walletSrvc = wallet.NewService(
|
||||
b.walletDB, accountsDB, b.rpcClient, accountsFeed, settingsFeed, b.gethAccountManager, b.transactor, b.config,
|
||||
b.walletDB, accountsDB, appDB, b.rpcClient, accountsFeed, settingsFeed, b.gethAccountManager, b.transactor, b.config,
|
||||
b.ensService(b.timeSourceNow()),
|
||||
b.stickersService(accountsDB),
|
||||
b.pendingTracker,
|
||||
|
|
|
@ -459,7 +459,7 @@ func NewMessenger(
|
|||
if c.tokenManager != nil {
|
||||
managerOptions = append(managerOptions, communities.WithTokenManager(c.tokenManager))
|
||||
} else if c.rpcClient != nil {
|
||||
tokenManager := token.NewTokenManager(c.walletDb, c.rpcClient, c.rpcClient.NetworkManager)
|
||||
tokenManager := token.NewTokenManager(c.walletDb, c.rpcClient, c.rpcClient.NetworkManager, database)
|
||||
managerOptions = append(managerOptions, communities.WithTokenManager(communities.NewDefaultTokenManager(tokenManager)))
|
||||
}
|
||||
|
||||
|
|
|
@ -45,3 +45,22 @@ func (db *Database) GetTokenPrivilegesLevel(chainID uint64, contractAddress stri
|
|||
}
|
||||
return result, fmt.Errorf("can't find privileges level: chainId %v, contractAddress %v", chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (db *Database) GetCommunityERC20Metadata() ([]*token.CommunityToken, error) {
|
||||
rows, err := db.db.Query(`SELECT community_id, address, name, symbol, chain_id, image_base64 FROM community_tokens WHERE type = ?`, protobuf.CommunityTokenType_ERC20)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []*token.CommunityToken
|
||||
for rows.Next() {
|
||||
token := token.CommunityToken{}
|
||||
err := rows.Scan(&token.CommunityID, &token.Address, &token.Name, &token.Symbol, &token.ChainID, &token.Base64Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, &token)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func TestKeycardPairingsFile(t *testing.T) {
|
|||
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||
require.NoError(t, err)
|
||||
|
||||
service := NewService(db, accountsDb, &rpc.Client{NetworkManager: network.NewManager(db)}, nil, nil, nil, nil, ¶ms.NodeConfig{}, nil, nil, nil, nil)
|
||||
service := NewService(db, accountsDb, appDB, &rpc.Client{NetworkManager: network.NewManager(db)}, nil, nil, nil, nil, ¶ms.NodeConfig{}, nil, nil, nil, nil)
|
||||
|
||||
data, err := service.KeycardPairings().GetPairingsJSONFileContent()
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -102,7 +102,8 @@ type Token struct {
|
|||
MarketValuesPerCurrency map[string]TokenMarketValues `json:"marketValuesPerCurrency"`
|
||||
PegSymbol string `json:"pegSymbol"`
|
||||
Verified bool `json:"verified"`
|
||||
CommunityID string `json:"communityId"`
|
||||
Image string `json:"image,omitempty"`
|
||||
CommunityData *token.CommunityData `json:"community_data,omitempty"`
|
||||
}
|
||||
|
||||
func splitVerifiedTokens(tokens []*token.Token) ([]*token.Token, []*token.Token) {
|
||||
|
@ -325,11 +326,6 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
|
|||
continue
|
||||
}
|
||||
|
||||
var communityID string
|
||||
if tokens[0].CommunityID != nil {
|
||||
communityID = *tokens[0].CommunityID
|
||||
}
|
||||
|
||||
walletToken := Token{
|
||||
Name: tokens[0].Name,
|
||||
Symbol: symbol,
|
||||
|
@ -337,7 +333,8 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
|
|||
Decimals: decimals,
|
||||
PegSymbol: token.GetTokenPegSymbol(symbol),
|
||||
Verified: tokens[0].Verified,
|
||||
CommunityID: communityID,
|
||||
CommunityData: tokens[0].CommunityData,
|
||||
Image: tokens[0].Image,
|
||||
}
|
||||
|
||||
tokenSymbols = append(tokenSymbols, symbol)
|
||||
|
|
|
@ -45,6 +45,7 @@ const (
|
|||
func NewService(
|
||||
db *sql.DB,
|
||||
accountsDB *accounts.Database,
|
||||
appDB *sql.DB,
|
||||
rpcClient *rpc.Client,
|
||||
accountFeed *event.Feed,
|
||||
settingsFeed *event.Feed,
|
||||
|
@ -96,7 +97,7 @@ func NewService(
|
|||
})
|
||||
|
||||
balanceCacher := balance.NewCacherWithTTL(5 * time.Minute)
|
||||
tokenManager := token.NewTokenManager(db, rpcClient, rpcClient.NetworkManager)
|
||||
tokenManager := token.NewTokenManager(db, rpcClient, rpcClient.NetworkManager, appDB)
|
||||
savedAddressesManager := &SavedAddressesManager{db: db}
|
||||
transactionManager := transfer.NewTransactionManager(db, gethManager, transactor, config, accountsDB, pendingTxManager, feed)
|
||||
transferController := transfer.NewTransferController(db, accountsDB, rpcClient, accountFeed, feed, transactionManager, pendingTxManager,
|
||||
|
|
|
@ -19,9 +19,11 @@ import (
|
|||
"github.com/status-im/status-go/contracts/ierc20"
|
||||
eth_node_types "github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/protocol/communities/token"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/rpc/chain"
|
||||
"github.com/status-im/status-go/rpc/network"
|
||||
"github.com/status-im/status-go/services/communitytokens"
|
||||
"github.com/status-im/status-go/services/utils"
|
||||
"github.com/status-im/status-go/services/wallet/async"
|
||||
)
|
||||
|
@ -42,10 +44,18 @@ type Token struct {
|
|||
// ISO 4217 alphabetic code. For example, an empty string means it is not
|
||||
// pegged, while "USD" means it's pegged to the United States Dollar.
|
||||
PegSymbol string `json:"pegSymbol"`
|
||||
Image string `json:"image,omitempty"`
|
||||
|
||||
CommunityID *string `json:"communityId,omitempty"`
|
||||
Verified bool `json:"verified"`
|
||||
TokenListID string `json:"tokenListId"`
|
||||
CommunityData *CommunityData `json:"community_data,omitempty"`
|
||||
Verified bool `json:"verified"`
|
||||
TokenListID string `json:"tokenListId"`
|
||||
}
|
||||
|
||||
type CommunityData struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Color string `json:"color"`
|
||||
ImageURL *string `json:"image_url,omitempty"`
|
||||
}
|
||||
|
||||
func (t *Token) IsNative() bool {
|
||||
|
@ -70,11 +80,12 @@ type ManagerInterface interface {
|
|||
|
||||
// Manager is used for accessing token store. It changes the token store based on overridden tokens
|
||||
type Manager struct {
|
||||
db *sql.DB
|
||||
RPCClient *rpc.Client
|
||||
contractMaker *contracts.ContractMaker
|
||||
networkManager *network.Manager
|
||||
stores []store // Set on init, not changed afterwards
|
||||
db *sql.DB
|
||||
RPCClient *rpc.Client
|
||||
contractMaker *contracts.ContractMaker
|
||||
networkManager *network.Manager
|
||||
stores []store // Set on init, not changed afterwards
|
||||
communityTokensDB *communitytokens.Database
|
||||
|
||||
tokens []*Token
|
||||
|
||||
|
@ -100,6 +111,7 @@ func NewTokenManager(
|
|||
db *sql.DB,
|
||||
RPCClient *rpc.Client,
|
||||
networkManager *network.Manager,
|
||||
appDB *sql.DB,
|
||||
) *Manager {
|
||||
maker, _ := contracts.NewContractMaker(RPCClient)
|
||||
stores := []store{newUniswapStore(), newDefaultStore()}
|
||||
|
@ -127,12 +139,13 @@ func NewTokenManager(
|
|||
}
|
||||
|
||||
return &Manager{
|
||||
db: db,
|
||||
RPCClient: RPCClient,
|
||||
contractMaker: maker,
|
||||
networkManager: networkManager,
|
||||
stores: stores,
|
||||
tokens: tokens,
|
||||
db: db,
|
||||
RPCClient: RPCClient,
|
||||
contractMaker: maker,
|
||||
networkManager: networkManager,
|
||||
stores: stores,
|
||||
communityTokensDB: communitytokens.NewCommunityTokensDatabase(appDB),
|
||||
tokens: tokens,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,7 +290,7 @@ func (tm *Manager) FindOrCreateTokenByAddress(ctx context.Context, chainID uint6
|
|||
}
|
||||
|
||||
func (tm *Manager) discoverTokenCommunityID(ctx context.Context, token *Token, address common.Address) {
|
||||
if token == nil || token.CommunityID != nil {
|
||||
if token == nil || token.CommunityData != nil {
|
||||
// Token is invalid or is alrady discovered. Nothing to do here.
|
||||
return
|
||||
}
|
||||
|
@ -482,6 +495,13 @@ func (tm *Manager) DiscoverToken(ctx context.Context, chainID uint64, address co
|
|||
}
|
||||
|
||||
func (tm *Manager) getTokensFromDB(query string, args ...any) ([]*Token, error) {
|
||||
|
||||
communityTokens := []*token.CommunityToken{}
|
||||
if tm.communityTokensDB != nil {
|
||||
// Error is skipped because it's only returning optional metadata
|
||||
communityTokens, _ = tm.communityTokensDB.GetCommunityERC20Metadata()
|
||||
}
|
||||
|
||||
rows, err := tm.db.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -498,7 +518,18 @@ func (tm *Manager) getTokensFromDB(query string, args ...any) ([]*Token, error)
|
|||
}
|
||||
|
||||
if communityIDDB.Valid {
|
||||
token.CommunityID = &communityIDDB.String
|
||||
communityID := communityIDDB.String
|
||||
for _, communityToken := range communityTokens {
|
||||
if communityToken.CommunityID != communityID || uint64(communityToken.ChainID) != token.ChainID || communityToken.Symbol != token.Symbol {
|
||||
continue
|
||||
}
|
||||
token.Image = communityToken.Base64Image
|
||||
break
|
||||
}
|
||||
|
||||
token.CommunityData = &CommunityData{
|
||||
ID: communityID,
|
||||
}
|
||||
}
|
||||
|
||||
rst = append(rst, token)
|
||||
|
|
|
@ -17,16 +17,28 @@ func setupTestTokenDB(t *testing.T) (*Manager, func()) {
|
|||
require.NoError(t, err)
|
||||
|
||||
return &Manager{
|
||||
db: db,
|
||||
RPCClient: nil,
|
||||
contractMaker: nil,
|
||||
networkManager: nil,
|
||||
stores: nil,
|
||||
db: db,
|
||||
RPCClient: nil,
|
||||
contractMaker: nil,
|
||||
networkManager: nil,
|
||||
stores: nil,
|
||||
communityTokensDB: nil,
|
||||
}, func() {
|
||||
require.NoError(t, db.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func upsertCommunityToken(t *testing.T, token *Token, manager *Manager) {
|
||||
require.NotNil(t, token.CommunityData)
|
||||
|
||||
err := manager.UpsertCustom(*token)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Community ID is only discovered by calling contract, so must be updated manually
|
||||
_, err = manager.db.Exec("UPDATE tokens SET community_id = ? WHERE address = ?", token.CommunityData.ID, token.Address)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCustoms(t *testing.T) {
|
||||
manager, stop := setupTestTokenDB(t)
|
||||
defer stop()
|
||||
|
@ -59,6 +71,50 @@ func TestCustoms(t *testing.T) {
|
|||
require.Equal(t, 0, len(rst))
|
||||
}
|
||||
|
||||
func TestCommunityTokens(t *testing.T) {
|
||||
manager, stop := setupTestTokenDB(t)
|
||||
defer stop()
|
||||
|
||||
rst, err := manager.GetCustoms(true)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, rst)
|
||||
|
||||
token := Token{
|
||||
Address: common.Address{1},
|
||||
Name: "Zilliqa",
|
||||
Symbol: "ZIL",
|
||||
Decimals: 12,
|
||||
ChainID: 777,
|
||||
}
|
||||
|
||||
err = manager.UpsertCustom(token)
|
||||
require.NoError(t, err)
|
||||
|
||||
communityToken := Token{
|
||||
Address: common.Address{2},
|
||||
Name: "Communitia",
|
||||
Symbol: "COM",
|
||||
Decimals: 12,
|
||||
ChainID: 777,
|
||||
CommunityData: &CommunityData{
|
||||
ID: "random_community_id",
|
||||
},
|
||||
}
|
||||
|
||||
upsertCommunityToken(t, &communityToken, manager)
|
||||
|
||||
rst, err = manager.GetCustoms(false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(rst))
|
||||
require.Equal(t, token, *rst[0])
|
||||
require.Equal(t, communityToken, *rst[1])
|
||||
|
||||
rst, err = manager.GetCustoms(true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(rst))
|
||||
require.Equal(t, communityToken, *rst[0])
|
||||
}
|
||||
|
||||
func toTokenMap(tokens []*Token) storeMap {
|
||||
tokenMap := storeMap{}
|
||||
|
||||
|
|
|
@ -930,7 +930,7 @@ func TestFindBlocksCommand(t *testing.T) {
|
|||
}
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb))
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb), appdb)
|
||||
tokenManager.SetTokens([]*token.Token{
|
||||
{
|
||||
Address: tokenTXXAddress,
|
||||
|
@ -1052,7 +1052,7 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) {
|
|||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb))
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb), appdb)
|
||||
|
||||
tokenManager.SetTokens([]*token.Token{
|
||||
{
|
||||
|
@ -1169,7 +1169,7 @@ func TestFetchNewBlocksCommand_findBlocksWithEthTransfers(t *testing.T) {
|
|||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb))
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb), appdb)
|
||||
|
||||
tokenManager.SetTokens([]*token.Token{
|
||||
{
|
||||
|
@ -1243,7 +1243,7 @@ func TestFetchNewBlocksCommand(t *testing.T) {
|
|||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb))
|
||||
tokenManager := token.NewTokenManager(db, client, network.NewManager(appdb), appdb)
|
||||
|
||||
tokenManager.SetTokens([]*token.Token{
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue