feat: Community token received notification (#4515)
This commit is contained in:
parent
a8357dceac
commit
846a4e2363
|
@ -35,6 +35,7 @@ const (
|
|||
ActivityCenterNotificationTypeSetSignerFailed
|
||||
ActivityCenterNotificationTypeSetSignerDeclined
|
||||
ActivityCenterNotificationTypeShareAccounts
|
||||
ActivityCenterNotificationTypeCommunityTokenReceived
|
||||
)
|
||||
|
||||
type ActivityCenterMembershipStatus int
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue