feat: Fetch community data for tokens (#4497)

This commit is contained in:
Cuteivist 2023-12-22 10:43:19 +01:00 committed by GitHub
parent 54f3cf8af0
commit dac7a0daf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 84 additions and 24 deletions

View File

@ -455,7 +455,7 @@ func NewMessenger(
if c.tokenManager != nil { if c.tokenManager != nil {
managerOptions = append(managerOptions, communities.WithTokenManager(c.tokenManager)) managerOptions = append(managerOptions, communities.WithTokenManager(c.tokenManager))
} else if c.rpcClient != nil { } else if c.rpcClient != nil {
tokenManager := token.NewTokenManager(c.walletDb, c.rpcClient, community.NewManager(database, c.httpServer), c.rpcClient.NetworkManager, database, c.httpServer) tokenManager := token.NewTokenManager(c.walletDb, c.rpcClient, community.NewManager(database, c.httpServer, nil), c.rpcClient.NetworkManager, database, c.httpServer)
managerOptions = append(managerOptions, communities.WithTokenManager(communities.NewDefaultTokenManager(tokenManager))) managerOptions = append(managerOptions, communities.WithTokenManager(communities.NewDefaultTokenManager(tokenManager)))
} }

View File

@ -2,22 +2,39 @@ package community
import ( import (
"database/sql" "database/sql"
"encoding/json"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/server" "github.com/status-im/status-go/server"
"github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/walletevent"
)
// These events are used to notify the UI of state changes
const (
EventCommmunityDataUpdated walletevent.EventType = "wallet-community-data-updated"
) )
type Manager struct { type Manager struct {
db *DataDB db *DataDB
communityInfoProvider thirdparty.CommunityInfoProvider communityInfoProvider thirdparty.CommunityInfoProvider
mediaServer *server.MediaServer mediaServer *server.MediaServer
feed *event.Feed
} }
func NewManager(db *sql.DB, mediaServer *server.MediaServer) *Manager { type Data struct {
ID string `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
Image string `json:"image,omitempty"`
}
func NewManager(db *sql.DB, mediaServer *server.MediaServer, feed *event.Feed) *Manager {
return &Manager{ return &Manager{
db: NewDataDB(db), db: NewDataDB(db),
mediaServer: mediaServer, mediaServer: mediaServer,
feed: feed,
} }
} }
@ -58,7 +75,43 @@ func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.Community
} }
return nil, err return nil, err
} }
err = cm.setCommunityInfo(communityID, communityInfo) err = cm.setCommunityInfo(communityID, communityInfo)
return communityInfo, err return communityInfo, err
} }
func (cm *Manager) FetchCommunityMetadataAsync(communityID string) {
go func() {
communityInfo, err := cm.FetchCommunityInfo(communityID)
if err != nil {
log.Error("FetchCommunityInfo failed", "communityID", communityID, "err", err)
return
}
cm.signalUpdatedCommunityMetadata(communityID, communityInfo)
}()
}
func (cm *Manager) signalUpdatedCommunityMetadata(communityID string, communityInfo *thirdparty.CommunityInfo) {
if communityInfo == nil {
return
}
data := Data{
ID: communityID,
Name: communityInfo.CommunityName,
Color: communityInfo.CommunityColor,
Image: communityInfo.CommunityImage, // TODO make media server url after merging community token media server changes
}
payload, err := json.Marshal(data)
if err != nil {
log.Error("Error marshaling response: %v", err)
return
}
event := walletevent.Event{
Type: EventCommmunityDataUpdated,
Message: string(payload),
}
cm.feed.Send(event)
}

View File

@ -14,6 +14,7 @@ import (
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
"github.com/status-im/status-go/rpc" "github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/services/wallet/async" "github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/community"
"github.com/status-im/status-go/services/wallet/market" "github.com/status-im/status-go/services/wallet/market"
"github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/transfer" "github.com/status-im/status-go/services/wallet/transfer"
@ -46,11 +47,12 @@ func belongsToMandatoryTokens(symbol string) bool {
return false return false
} }
func NewReader(rpcClient *rpc.Client, tokenManager *token.Manager, marketManager *market.Manager, accountsDB *accounts.Database, persistence *Persistence, walletFeed *event.Feed) *Reader { func NewReader(rpcClient *rpc.Client, tokenManager *token.Manager, marketManager *market.Manager, communityManager *community.Manager, accountsDB *accounts.Database, persistence *Persistence, walletFeed *event.Feed) *Reader {
return &Reader{ return &Reader{
rpcClient: rpcClient, rpcClient: rpcClient,
tokenManager: tokenManager, tokenManager: tokenManager,
marketManager: marketManager, marketManager: marketManager,
communityManager: communityManager,
accountsDB: accountsDB, accountsDB: accountsDB,
persistence: persistence, persistence: persistence,
walletFeed: walletFeed, walletFeed: walletFeed,
@ -62,6 +64,7 @@ type Reader struct {
rpcClient *rpc.Client rpcClient *rpc.Client
tokenManager *token.Manager tokenManager *token.Manager
marketManager *market.Manager marketManager *market.Manager
communityManager *community.Manager
accountsDB *accounts.Database accountsDB *accounts.Database
persistence *Persistence persistence *Persistence
walletFeed *event.Feed walletFeed *event.Feed
@ -103,7 +106,7 @@ type Token struct {
PegSymbol string `json:"pegSymbol"` PegSymbol string `json:"pegSymbol"`
Verified bool `json:"verified"` Verified bool `json:"verified"`
Image string `json:"image,omitempty"` Image string `json:"image,omitempty"`
CommunityData *token.CommunityData `json:"community_data,omitempty"` CommunityData *community.Data `json:"community_data,omitempty"`
} }
func splitVerifiedTokens(tokens []*token.Token) ([]*token.Token, []*token.Token) { func splitVerifiedTokens(tokens []*token.Token) ([]*token.Token, []*token.Token) {
@ -389,6 +392,8 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
return nil, err return nil, err
} }
communities := make(map[string]bool)
for address, tokens := range result { for address, tokens := range result {
for index, token := range tokens { for index, token := range tokens {
marketValuesPerCurrency := make(map[string]TokenMarketValues) marketValuesPerCurrency := make(map[string]TokenMarketValues)
@ -409,6 +414,10 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
} }
} }
if token.CommunityData != nil {
communities[token.CommunityData.ID] = true
}
if _, ok := tokenDetails[token.Symbol]; !ok { if _, ok := tokenDetails[token.Symbol]; !ok {
continue continue
} }
@ -422,6 +431,10 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
r.lastWalletTokenUpdateTimestamp.Store(time.Now().Unix()) r.lastWalletTokenUpdateTimestamp.Store(time.Now().Unix())
for communityID := range communities {
r.communityManager.FetchCommunityMetadataAsync(communityID)
}
return result, r.persistence.SaveTokens(result) return result, r.persistence.SaveTokens(result)
} }

View File

@ -99,7 +99,7 @@ func NewService(
}) })
}) })
communityManager := community.NewManager(db, mediaServer) communityManager := community.NewManager(db, mediaServer, feed)
balanceCacher := balance.NewCacherWithTTL(5 * time.Minute) balanceCacher := balance.NewCacherWithTTL(5 * time.Minute)
tokenManager := token.NewTokenManager(db, rpcClient, communityManager, rpcClient.NetworkManager, appDB, mediaServer) tokenManager := token.NewTokenManager(db, rpcClient, communityManager, rpcClient.NetworkManager, appDB, mediaServer)
savedAddressesManager := &SavedAddressesManager{db: db} savedAddressesManager := &SavedAddressesManager{db: db}
@ -110,7 +110,7 @@ func NewService(
cryptoCompare := cryptocompare.NewClient() cryptoCompare := cryptocompare.NewClient()
coingecko := coingecko.NewClient() coingecko := coingecko.NewClient()
marketManager := market.NewManager(cryptoCompare, coingecko, feed) marketManager := market.NewManager(cryptoCompare, coingecko, feed)
reader := NewReader(rpcClient, tokenManager, marketManager, accountsDB, NewPersistence(db), feed) reader := NewReader(rpcClient, tokenManager, marketManager, communityManager, accountsDB, NewPersistence(db), feed)
history := history.NewService(db, accountsDB, feed, rpcClient, tokenManager, marketManager, balanceCacher.Cache()) history := history.NewService(db, accountsDB, feed, rpcClient, tokenManager, marketManager, balanceCacher.Cache())
currency := currency.NewService(db, feed, tokenManager, marketManager) currency := currency.NewService(db, feed, tokenManager, marketManager)
blockChainState := NewBlockChainState(rpcClient, accountsDB) blockChainState := NewBlockChainState(rpcClient, accountsDB)

View File

@ -49,18 +49,11 @@ type Token struct {
PegSymbol string `json:"pegSymbol"` PegSymbol string `json:"pegSymbol"`
Image string `json:"image,omitempty"` Image string `json:"image,omitempty"`
CommunityData *CommunityData `json:"community_data,omitempty"` CommunityData *community.Data `json:"community_data,omitempty"`
Verified bool `json:"verified"` Verified bool `json:"verified"`
TokenListID string `json:"tokenListId"` TokenListID string `json:"tokenListId"`
} }
type CommunityData struct {
ID string `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
Image string `json:"image,omitempty"`
}
func (t *Token) IsNative() bool { func (t *Token) IsNative() bool {
return t.Address == nativeChainAddress return t.Address == nativeChainAddress
} }
@ -551,7 +544,7 @@ func (tm *Manager) getTokensFromDB(query string, args ...any) ([]*Token, error)
break break
} }
token.CommunityData = &CommunityData{ token.CommunityData = &community.Data{
ID: communityID, ID: communityID,
} }
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/wallet/community"
"github.com/status-im/status-go/t/helpers" "github.com/status-im/status-go/t/helpers"
"github.com/status-im/status-go/walletdatabase" "github.com/status-im/status-go/walletdatabase"
) )
@ -97,7 +98,7 @@ func TestCommunityTokens(t *testing.T) {
Symbol: "COM", Symbol: "COM",
Decimals: 12, Decimals: 12,
ChainID: 777, ChainID: 777,
CommunityData: &CommunityData{ CommunityData: &community.Data{
ID: "random_community_id", ID: "random_community_id",
}, },
} }

View File

@ -937,7 +937,8 @@ func TestFindBlocksCommand(t *testing.T) {
} }
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db) client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
client.SetClient(tc.NetworkID(), tc) client.SetClient(tc.NetworkID(), tc)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil), network.NewManager(appdb), appdb, mediaServer) tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager.SetTokens([]*token.Token{ tokenManager.SetTokens([]*token.Token{
{ {
Address: tokenTXXAddress, Address: tokenTXXAddress,
@ -1062,7 +1063,7 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) {
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db) client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
client.SetClient(tc.NetworkID(), tc) client.SetClient(tc.NetworkID(), tc)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil), network.NewManager(appdb), appdb, mediaServer) tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager.SetTokens([]*token.Token{ tokenManager.SetTokens([]*token.Token{
{ {
@ -1182,7 +1183,7 @@ func TestFetchNewBlocksCommand_findBlocksWithEthTransfers(t *testing.T) {
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db) client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
client.SetClient(tc.NetworkID(), tc) client.SetClient(tc.NetworkID(), tc)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil), network.NewManager(appdb), appdb, mediaServer) tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager.SetTokens([]*token.Token{ tokenManager.SetTokens([]*token.Token{
{ {
@ -1259,8 +1260,7 @@ func TestFetchNewBlocksCommand(t *testing.T) {
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db) client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
client.SetClient(tc.NetworkID(), tc) client.SetClient(tc.NetworkID(), tc)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager.SetTokens([]*token.Token{ tokenManager.SetTokens([]*token.Token{
{ {