feat: Community token received notification (#4515)

This commit is contained in:
Cuteivist 2024-01-04 13:22:06 +01:00 committed by GitHub
parent a8357dceac
commit 846a4e2363
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 126 additions and 23 deletions

View File

@ -35,6 +35,7 @@ const (
ActivityCenterNotificationTypeSetSignerFailed
ActivityCenterNotificationTypeSetSignerDeclined
ActivityCenterNotificationTypeShareAccounts
ActivityCenterNotificationTypeCommunityTokenReceived
)
type ActivityCenterMembershipStatus int

View File

@ -456,7 +456,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, community.NewManager(database, c.httpServer, nil), 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, nil)
managerOptions = append(managerOptions, communities.WithTokenManager(communities.NewDefaultTokenManager(tokenManager)))
}

View File

@ -1669,6 +1669,11 @@ func (api *PublicAPI) RegisterReceivedOwnershipNotification(communityID string)
return api.service.messenger.CreateResponseWithACNotification(communityID, protocol.ActivityCenterNotificationTypeOwnershipReceived, false)
}
// Returns response with AC notification when community token is received
func (api *PublicAPI) RegisterReceivedCommunityTokenNotification(communityID string) (*protocol.MessengerResponse, error) {
return api.service.messenger.CreateResponseWithACNotification(communityID, protocol.ActivityCenterNotificationTypeCommunityTokenReceived, false)
}
// Returns response with AC notification when setting signer is failed
func (api *PublicAPI) RegisterSetSignerFailedNotification(communityID string) (*protocol.MessengerResponse, error) {
return api.service.messenger.CreateResponseWithACNotification(communityID, protocol.ActivityCenterNotificationTypeSetSignerFailed, false)

View File

@ -49,7 +49,7 @@ func (cm *Manager) GetCommunityInfo(id string) (*thirdparty.CommunityInfo, *Info
return nil, nil, err
}
if cm.mediaServer != nil && communityInfo != nil && len(communityInfo.CommunityImagePayload) > 0 {
communityInfo.CommunityImage = cm.mediaServer.MakeWalletCommunityImagesURL(id)
communityInfo.CommunityImage = cm.GetCommunityImageURL(id)
}
return communityInfo, state, err
}
@ -81,16 +81,30 @@ func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.Community
func (cm *Manager) FetchCommunityMetadataAsync(communityID string) {
go func() {
communityInfo, err := cm.FetchCommunityInfo(communityID)
communityInfo, err := cm.FetchCommunityMetadata(communityID)
if err != nil {
log.Error("FetchCommunityInfo failed", "communityID", communityID, "err", err)
return
}
cm.signalUpdatedCommunityMetadata(communityID, communityInfo)
}()
}
func (cm *Manager) FetchCommunityMetadata(communityID string) (*thirdparty.CommunityInfo, error) {
communityInfo, err := cm.FetchCommunityInfo(communityID)
if err != nil {
return nil, err
}
_ = cm.setCommunityInfo(communityID, communityInfo)
return communityInfo, err
}
func (cm *Manager) GetCommunityImageURL(communityID string) string {
if cm.mediaServer != nil {
return cm.mediaServer.MakeWalletCommunityImagesURL(communityID)
}
return ""
}
func (cm *Manager) signalUpdatedCommunityMetadata(communityID string, communityInfo *thirdparty.CommunityInfo) {
if communityInfo == nil {
return
@ -99,7 +113,7 @@ func (cm *Manager) signalUpdatedCommunityMetadata(communityID string, communityI
ID: communityID,
Name: communityInfo.CommunityName,
Color: communityInfo.CommunityColor,
Image: communityInfo.CommunityImage, // TODO make media server url after merging community token media server changes
Image: cm.GetCommunityImageURL(communityID),
}
payload, err := json.Marshal(data)

View File

@ -101,7 +101,7 @@ func NewService(
communityManager := community.NewManager(db, mediaServer, feed)
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, feed)
savedAddressesManager := &SavedAddressesManager{db: db}
transactionManager := transfer.NewTransactionManager(db, gethManager, transactor, config, accountsDB, pendingTxManager, feed)
transferController := transfer.NewTransferController(db, accountsDB, rpcClient, accountFeed, feed, transactionManager, pendingTxManager,

View File

@ -3,6 +3,7 @@ package token
import (
"context"
"database/sql"
"encoding/json"
"errors"
"math/big"
"strconv"
@ -13,6 +14,7 @@ import (
"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/event"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/contracts"
"github.com/status-im/status-go/contracts/community-tokens/assets"
@ -29,6 +31,11 @@ import (
"github.com/status-im/status-go/services/utils"
"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/walletevent"
)
const (
EventCommunityTokenReceived walletevent.EventType = "wallet-community-token-received"
)
var requestTimeout = 20 * time.Second
@ -54,6 +61,17 @@ type Token struct {
TokenListID string `json:"tokenListId"`
}
type ReceivedToken struct {
Address common.Address `json:"address"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Image string `json:"image,omitempty"`
ChainID uint64 `json:"chainId"`
CommunityData *community.Data `json:"community_data,omitempty"`
Balance *big.Int `json:"balance"`
TxHash common.Hash `json:"txHash"`
}
func (t *Token) IsNative() bool {
return t.Address == nativeChainAddress
}
@ -84,6 +102,7 @@ type Manager struct {
communityTokensDB *communitytokens.Database
communityManager *community.Manager
mediaServer *server.MediaServer
walletFeed *event.Feed
tokens []*Token
@ -112,6 +131,7 @@ func NewTokenManager(
networkManager *network.Manager,
appDB *sql.DB,
mediaServer *server.MediaServer,
walletFeed *event.Feed,
) *Manager {
maker, _ := contracts.NewContractMaker(RPCClient)
stores := []store{newUniswapStore(), newDefaultStore()}
@ -148,6 +168,7 @@ func NewTokenManager(
communityTokensDB: communitytokens.NewCommunityTokensDatabase(appDB),
tokens: tokens,
mediaServer: mediaServer,
walletFeed: walletFeed,
}
}
@ -349,6 +370,10 @@ func (tm *Manager) discoverTokenCommunityID(ctx context.Context, token *Token, a
}
communityID := eth_node_types.EncodeHex(communityIDHex)
token.CommunityData = &community.Data{
ID: communityID,
}
_, err = update.Exec(communityID, token.ChainID, token.Address)
if err != nil {
log.Error("Cannot update community id", err)
@ -549,15 +574,7 @@ func (tm *Manager) getTokensFromDB(query string, args ...any) ([]*Token, error)
}
}
if tm.communityManager != nil && token.CommunityData != nil {
communityInfo, _, err := tm.communityManager.GetCommunityInfo(token.CommunityData.ID)
if err == nil && communityInfo != nil {
// Fetched data from cache. Cache is refreshed during every wallet token list call.
token.CommunityData.Name = communityInfo.CommunityName
token.CommunityData.Color = communityInfo.CommunityColor
token.CommunityData.Image = communityInfo.CommunityImage
}
}
_ = tm.fillCommunityData(token)
rst = append(rst, token)
}
@ -785,3 +802,64 @@ func (tm *Manager) GetBalancesAtByChain(parent context.Context, clients map[uint
}
return response, group.Error()
}
func (tm *Manager) SignalCommunityTokenReceived(address common.Address, txHash common.Hash, value *big.Int, t *Token) {
if tm.walletFeed == nil || t == nil || t.CommunityData == nil {
return
}
if len(t.CommunityData.Name) == 0 {
_ = tm.fillCommunityData(t)
}
if len(t.CommunityData.Name) == 0 && tm.communityManager != nil {
communityData, _ := tm.communityManager.FetchCommunityMetadata(t.CommunityData.ID)
if communityData != nil {
t.CommunityData.Name = communityData.CommunityName
t.CommunityData.Color = communityData.CommunityColor
t.CommunityData.Image = tm.communityManager.GetCommunityImageURL(t.CommunityData.ID)
}
}
receivedToken := ReceivedToken{
Address: t.Address,
Name: t.Name,
Symbol: t.Symbol,
Image: t.Image,
ChainID: t.ChainID,
CommunityData: t.CommunityData,
Balance: value,
TxHash: txHash,
}
encodedMessage, err := json.Marshal(receivedToken)
if err != nil {
return
}
tm.walletFeed.Send(walletevent.Event{
Type: EventCommunityTokenReceived,
ChainID: t.ChainID,
Accounts: []common.Address{
address,
},
Message: string(encodedMessage),
})
}
func (tm *Manager) fillCommunityData(token *Token) error {
if token == nil || token.CommunityData == nil || tm.communityManager == nil {
return nil
}
communityInfo, _, err := tm.communityManager.GetCommunityInfo(token.CommunityData.ID)
if err != nil {
return err
}
if err == nil && communityInfo != nil {
// Fetched data from cache. Cache is refreshed during every wallet token list call.
token.CommunityData.Name = communityInfo.CommunityName
token.CommunityData.Color = communityInfo.CommunityColor
token.CommunityData.Image = communityInfo.CommunityImage
}
return nil
}

View File

@ -420,8 +420,13 @@ func (c *transfersCommand) processUnknownErc20CommunityTransactions(ctx context.
if tx.Type == w_common.Erc20Transfer && tx.Transaction.To() != nil {
// Find token in db or if this is a community token, find its metadata
token := c.tokenManager.FindOrCreateTokenByAddress(ctx, tx.NetworkID, *tx.Transaction.To())
if token != nil && (token.Verified || token.CommunityData != nil) {
_ = c.tokenManager.MarkAsPreviouslyOwnedToken(token, tx.Address)
if token != nil {
if token.Verified || token.CommunityData != nil {
_ = c.tokenManager.MarkAsPreviouslyOwnedToken(token, tx.Address)
}
if token.CommunityData != nil {
go c.tokenManager.SignalCommunityTokenReceived(tx.Address, tx.ID, tx.Transaction.Value(), token)
}
}
}
}

View File

@ -937,8 +937,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, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil)
tokenManager.SetTokens([]*token.Token{
{
Address: tokenTXXAddress,
@ -1063,7 +1062,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, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil)
tokenManager.SetTokens([]*token.Token{
{
@ -1183,7 +1182,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, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil)
tokenManager.SetTokens([]*token.Token{
{
@ -1260,7 +1259,8 @@ 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, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil)
tokenManager.SetTokens([]*token.Token{
{