feat: refresh balances when Eth or ERC20 transfer is detected
This commit is contained in:
parent
5de4057a6a
commit
8b539cd400
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue