feat: refresh balances when Eth or ERC20 transfer is detected

This commit is contained in:
Dario Gabriel Lipicar 2023-11-27 18:28:16 -03:00 committed by dlipicar
parent 5de4057a6a
commit 8b539cd400
3 changed files with 124 additions and 31 deletions

View File

@ -330,7 +330,8 @@ func (c *Controller) startWalletEventsWatcher() {
walletEventCb := func(event walletevent.Event) {
// EventRecentHistoryReady ?
if event.Type != transfer.EventInternalERC721TransferDetected {
if event.Type != transfer.EventInternalERC721TransferDetected &&
event.Type != transfer.EventInternalERC1155TransferDetected {
return
}

View File

@ -4,6 +4,7 @@ import (
"context"
"math"
"math/big"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
@ -15,6 +16,7 @@ import (
"github.com/status-im/status-go/services/wallet/async"
"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/transfer"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/walletevent"
@ -24,6 +26,12 @@ import (
const EventWalletTickReload walletevent.EventType = "wallet-tick-reload"
const EventWalletTickCheckConnected walletevent.EventType = "wallet-tick-check-connected"
const (
walletTickReloadPeriod = 10 * time.Minute
activityReloadDelay = 30 // Wait this many seconds after activity is detected before triggering a wallet reload
activityReloadMarginSeconds = 30 // Trigger a wallet reload if activity is detected this many seconds before the last reload
)
func getFixedCurrencies() []string {
return []string{"USD"}
}
@ -40,23 +48,27 @@ func belongsToMandatoryTokens(symbol string) bool {
func NewReader(rpcClient *rpc.Client, tokenManager *token.Manager, marketManager *market.Manager, accountsDB *accounts.Database, persistence *Persistence, walletFeed *event.Feed) *Reader {
return &Reader{
rpcClient,
tokenManager,
marketManager,
accountsDB,
persistence,
walletFeed,
nil}
rpcClient: rpcClient,
tokenManager: tokenManager,
marketManager: marketManager,
accountsDB: accountsDB,
persistence: persistence,
walletFeed: walletFeed,
lastWalletTokenUpdateTimestamp: atomic.Int64{},
}
}
type Reader struct {
rpcClient *rpc.Client
tokenManager *token.Manager
marketManager *market.Manager
accountsDB *accounts.Database
persistence *Persistence
walletFeed *event.Feed
cancel context.CancelFunc
rpcClient *rpc.Client
tokenManager *token.Manager
marketManager *market.Manager
accountsDB *accounts.Database
persistence *Persistence
walletFeed *event.Feed
cancel context.CancelFunc
walletEventsWatcher *walletevent.Watcher
lastWalletTokenUpdateTimestamp atomic.Int64
reloadDelayTimer *time.Timer
}
type TokenMarketValues struct {
@ -138,17 +150,17 @@ func (r *Reader) Start() error {
ctx, cancel := context.WithCancel(context.Background())
r.cancel = cancel
r.startWalletEventsWatcher()
go func() {
ticker := time.NewTicker(10 * time.Minute)
ticker := time.NewTicker(walletTickReloadPeriod)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
r.walletFeed.Send(walletevent.Event{
Type: EventWalletTickReload,
})
r.triggerWalletReload()
}
}
}()
@ -159,6 +171,64 @@ func (r *Reader) Stop() {
if r.cancel != nil {
r.cancel()
}
r.stopWalletEventsWatcher()
r.cancelDelayedWalletReload()
r.lastWalletTokenUpdateTimestamp.Store(0)
}
func (r *Reader) triggerWalletReload() {
r.cancelDelayedWalletReload()
r.walletFeed.Send(walletevent.Event{
Type: EventWalletTickReload,
})
}
func (r *Reader) triggerDelayedWalletReload() {
r.cancelDelayedWalletReload()
r.reloadDelayTimer = time.AfterFunc(time.Duration(activityReloadDelay)*time.Second, r.triggerWalletReload)
}
func (r *Reader) cancelDelayedWalletReload() {
if r.reloadDelayTimer != nil {
r.reloadDelayTimer.Stop()
r.reloadDelayTimer = nil
}
}
func (r *Reader) startWalletEventsWatcher() {
if r.walletEventsWatcher != nil {
return
}
// Respond to ETH/Token transfers
walletEventCb := func(event walletevent.Event) {
if event.Type != transfer.EventInternalETHTransferDetected &&
event.Type != transfer.EventInternalERC20TransferDetected {
return
}
timecheck := r.lastWalletTokenUpdateTimestamp.Load() - activityReloadMarginSeconds
if event.At > timecheck {
r.triggerDelayedWalletReload()
}
}
r.walletEventsWatcher = walletevent.NewWatcher(r.walletFeed, walletEventCb)
r.walletEventsWatcher.Start()
}
func (r *Reader) stopWalletEventsWatcher() {
if r.walletEventsWatcher != nil {
r.walletEventsWatcher.Stop()
r.walletEventsWatcher = nil
}
}
func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address) (map[common.Address][]Token, error) {
@ -348,6 +418,8 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
}
}
r.lastWalletTokenUpdateTimestamp.Store(time.Now().Unix())
return result, r.persistence.SaveTokens(result)
}

View File

@ -32,8 +32,11 @@ const (
// EventNonArchivalNodeDetected emitted when a connection to a non archival node is detected
EventNonArchivalNodeDetected walletevent.EventType = "non-archival-node-detected"
// EventInternalERC721TransferDetected emitted when ERC721 transfer is detected
EventInternalERC721TransferDetected walletevent.EventType = walletevent.InternalEventTypePrefix + "erc721-transfer-detected"
// Internal events emitted when different kinds of transfers are detected
EventInternalETHTransferDetected walletevent.EventType = walletevent.InternalEventTypePrefix + "eth-transfer-detected"
EventInternalERC20TransferDetected walletevent.EventType = walletevent.InternalEventTypePrefix + "erc20-transfer-detected"
EventInternalERC721TransferDetected walletevent.EventType = walletevent.InternalEventTypePrefix + "erc721-transfer-detected"
EventInternalERC1155TransferDetected walletevent.EventType = walletevent.InternalEventTypePrefix + "erc1155-transfer-detected"
numberOfBlocksCheckedPerIteration = 40
noBlockLimit = 0
@ -248,7 +251,10 @@ func (c *transfersCommand) Run(ctx context.Context) (err error) {
c.fetchedTransfers = append(c.fetchedTransfers, allTransfers...)
c.notifyOfNewTransfers(blockNum, allTransfers)
c.notifyOfNewERC721Transfers(allTransfers)
c.notifyOfLatestTransfers(allTransfers, w_common.EthTransfer)
c.notifyOfLatestTransfers(allTransfers, w_common.Erc20Transfer)
c.notifyOfLatestTransfers(allTransfers, w_common.Erc721Transfer)
c.notifyOfLatestTransfers(allTransfers, w_common.Erc1155Transfer)
log.Debug("transfersCommand block end", "chain", c.chainClient.NetworkID(), "address", c.address,
"block", blockNum, "tranfers.len", len(allTransfers), "fetchedTransfers.len", len(c.fetchedTransfers))
@ -438,23 +444,37 @@ func (c *transfersCommand) notifyOfNewTransfers(blockNum *big.Int, transfers []T
}
}
func (c *transfersCommand) notifyOfNewERC721Transfers(transfers []Transfer) {
func transferTypeToEventType(transferType w_common.Type) walletevent.EventType {
switch transferType {
case w_common.EthTransfer:
return EventInternalETHTransferDetected
case w_common.Erc20Transfer:
return EventInternalERC20TransferDetected
case w_common.Erc721Transfer:
return EventInternalERC721TransferDetected
case w_common.Erc1155Transfer:
return EventInternalERC1155TransferDetected
default:
return ""
}
}
func (c *transfersCommand) notifyOfLatestTransfers(transfers []Transfer, transferType w_common.Type) {
if c.feed != nil {
// Internal event for ERC721 transfers
latestERC721TransferTimestamp := uint64(0)
latestTransferTimestamp := uint64(0)
for _, transfer := range transfers {
if transfer.Type == w_common.Erc721Transfer {
if transfer.Timestamp > latestERC721TransferTimestamp {
latestERC721TransferTimestamp = transfer.Timestamp
if transfer.Type == transferType {
if transfer.Timestamp > latestTransferTimestamp {
latestTransferTimestamp = transfer.Timestamp
}
}
}
if latestERC721TransferTimestamp > 0 {
if latestTransferTimestamp > 0 {
c.feed.Send(walletevent.Event{
Type: EventInternalERC721TransferDetected,
Type: transferTypeToEventType(transferType),
Accounts: []common.Address{c.address},
ChainID: c.chainClient.NetworkID(),
At: int64(latestERC721TransferTimestamp),
At: int64(latestTransferTimestamp),
})
}
}