feat: Fetch community data for tokens (#4497)
This commit is contained in:
parent
54f3cf8af0
commit
dac7a0daf9
|
@ -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)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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{
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue