mirror of
https://github.com/status-im/status-go.git
synced 2025-01-18 10:42:07 +00:00
a2ff03c79e
Extends wallet module with the history package with the following components: BalanceDB (balance_db.go) - Keeps track of balance information (token count, block, block timestamp) for a token identity (chain, address, currency) - The cached data is stored in `balance_history` table. - Uniqueness constrained is enforced by the `balance_history_identify_entry` UNIQUE index. - Optimal DB fetching is ensured by the `balance_history_filter_entries` index Balance (balance.go) - Provides two stages: - Fetch of balance history using RPC calls (Balance.update function) - Retrieving of cached balance data from the DB it exists (Balance.get function) - Fetching and retrieving of data is done for specific time intervals defined by TimeInterval "enumeration" - Update process is done for a token identity by the Balance.Update function - The granularity of data points returned is defined by the constant increment step define in `timeIntervalToStride` for each time interval. - The `blocksStride` values have a common divisor to have cache hit between time intervals. Service (service.go) - Main APIs - StartBalanceHistory: Regularly updates balance history for all enabled networks, available accounts and provided tokens. - GetBalanceHistory: retrieves cached token count for a token identity (chain, address, currency) for multiple chains - UpdateVisibleTokens: will set the list of tokens to have historical balance fetched. This is a simplification to limit tokens to a small list that make sense Fetch balance history for ECR20 tokens - Add token.Manager.GetTokenBalanceAt to fetch balance of a specific block number of ECR20. - Add tokenChainClientSource concrete implementation of DataSource to fetch balance of ECR20 tokens. - Chose the correct DataSource implementation based on the token "is native" property. Tests Tests are implemented using a mock of `DataSource` interface used to intercept the RPC calls. Notes: - the timestamp used for retrieving block balance is constant Closes status-desktop: #8175, #8226, #8862
171 lines
5.1 KiB
Go
171 lines
5.1 KiB
Go
package wallet
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
|
|
"github.com/ethereum/go-ethereum/event"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
gethrpc "github.com/ethereum/go-ethereum/rpc"
|
|
|
|
"github.com/status-im/status-go/account"
|
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
|
"github.com/status-im/status-go/params"
|
|
"github.com/status-im/status-go/rpc"
|
|
"github.com/status-im/status-go/services/ens"
|
|
"github.com/status-im/status-go/services/stickers"
|
|
"github.com/status-im/status-go/services/wallet/chain"
|
|
"github.com/status-im/status-go/services/wallet/history"
|
|
"github.com/status-im/status-go/services/wallet/token"
|
|
"github.com/status-im/status-go/services/wallet/transfer"
|
|
"github.com/status-im/status-go/services/wallet/walletevent"
|
|
"github.com/status-im/status-go/transactions"
|
|
)
|
|
|
|
type ConnectedResult struct {
|
|
Infura map[uint64]bool `json:"infura"`
|
|
CryptoCompare bool `json:"cryptoCompare"`
|
|
Opensea map[uint64]bool `json:"opensea"`
|
|
}
|
|
|
|
// NewService initializes service instance.
|
|
func NewService(
|
|
db *sql.DB,
|
|
accountsDB *accounts.Database,
|
|
rpcClient *rpc.Client,
|
|
accountFeed *event.Feed,
|
|
openseaAPIKey string,
|
|
gethManager *account.GethManager,
|
|
transactor *transactions.Transactor,
|
|
config *params.NodeConfig,
|
|
ens *ens.Service,
|
|
stickers *stickers.Service,
|
|
) *Service {
|
|
cryptoOnRampManager := NewCryptoOnRampManager(&CryptoOnRampOptions{
|
|
dataSourceType: DataSourceStatic,
|
|
})
|
|
walletFeed := &event.Feed{}
|
|
signals := &walletevent.SignalsTransmitter{
|
|
Publisher: walletFeed,
|
|
}
|
|
tokenManager := token.NewTokenManager(db, rpcClient, rpcClient.NetworkManager)
|
|
savedAddressesManager := &SavedAddressesManager{db: db}
|
|
transactionManager := &TransactionManager{db: db, transactor: transactor, gethManager: gethManager, config: config, accountsDB: accountsDB}
|
|
transferController := transfer.NewTransferController(db, rpcClient, accountFeed, walletFeed)
|
|
cryptoCompare := NewCryptoCompare()
|
|
priceManager := NewPriceManager(db, cryptoCompare)
|
|
reader := NewReader(rpcClient, tokenManager, priceManager, cryptoCompare, accountsDB, walletFeed)
|
|
history := history.NewService(db, walletFeed, rpcClient, tokenManager)
|
|
return &Service{
|
|
db: db,
|
|
accountsDB: accountsDB,
|
|
rpcClient: rpcClient,
|
|
tokenManager: tokenManager,
|
|
savedAddressesManager: savedAddressesManager,
|
|
transactionManager: transactionManager,
|
|
transferController: transferController,
|
|
cryptoOnRampManager: cryptoOnRampManager,
|
|
openseaAPIKey: openseaAPIKey,
|
|
feesManager: &FeeManager{rpcClient},
|
|
gethManager: gethManager,
|
|
priceManager: priceManager,
|
|
transactor: transactor,
|
|
ens: ens,
|
|
stickers: stickers,
|
|
feed: accountFeed,
|
|
signals: signals,
|
|
reader: reader,
|
|
cryptoCompare: cryptoCompare,
|
|
history: history,
|
|
}
|
|
}
|
|
|
|
// Service is a wallet service.
|
|
type Service struct {
|
|
db *sql.DB
|
|
accountsDB *accounts.Database
|
|
rpcClient *rpc.Client
|
|
savedAddressesManager *SavedAddressesManager
|
|
tokenManager *token.Manager
|
|
transactionManager *TransactionManager
|
|
cryptoOnRampManager *CryptoOnRampManager
|
|
transferController *transfer.Controller
|
|
feesManager *FeeManager
|
|
priceManager *PriceManager
|
|
started bool
|
|
openseaAPIKey string
|
|
gethManager *account.GethManager
|
|
transactor *transactions.Transactor
|
|
ens *ens.Service
|
|
stickers *stickers.Service
|
|
feed *event.Feed
|
|
signals *walletevent.SignalsTransmitter
|
|
reader *Reader
|
|
cryptoCompare *CryptoCompare
|
|
history *history.Service
|
|
}
|
|
|
|
// Start signals transmitter.
|
|
func (s *Service) Start() error {
|
|
s.transferController.Start()
|
|
err := s.signals.Start()
|
|
s.started = true
|
|
return err
|
|
}
|
|
|
|
// GetFeed returns signals feed.
|
|
func (s *Service) GetFeed() *event.Feed {
|
|
return s.transferController.TransferFeed
|
|
}
|
|
|
|
// Stop reactor and close db.
|
|
func (s *Service) Stop() error {
|
|
log.Info("wallet will be stopped")
|
|
s.signals.Stop()
|
|
s.transferController.Stop()
|
|
s.reader.Stop()
|
|
s.history.Stop()
|
|
s.started = false
|
|
log.Info("wallet stopped")
|
|
return nil
|
|
}
|
|
|
|
// APIs returns list of available RPC APIs.
|
|
func (s *Service) APIs() []gethrpc.API {
|
|
return []gethrpc.API{
|
|
{
|
|
Namespace: "wallet",
|
|
Version: "0.1.0",
|
|
Service: NewAPI(s),
|
|
Public: true,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Protocols returns list of p2p protocols.
|
|
func (s *Service) Protocols() []p2p.Protocol {
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) IsStarted() bool {
|
|
return s.started
|
|
}
|
|
|
|
func (s *Service) CheckConnected(ctx context.Context) *ConnectedResult {
|
|
infura := make(map[uint64]bool)
|
|
for chainID, client := range chain.ChainClientInstances {
|
|
infura[chainID] = client.IsConnected
|
|
}
|
|
|
|
opensea := make(map[uint64]bool)
|
|
for chainID, client := range OpenseaClientInstances {
|
|
opensea[chainID] = client.IsConnected
|
|
}
|
|
return &ConnectedResult{
|
|
Infura: infura,
|
|
Opensea: opensea,
|
|
CryptoCompare: s.cryptoCompare.IsConnected,
|
|
}
|
|
}
|