status-go/services/wallet/service.go

209 lines
6.5 KiB
Go
Raw Normal View History

package wallet
import (
2023-01-17 09:56:16 +00:00
"context"
"database/sql"
2023-02-20 09:32:45 +00:00
"time"
"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"
2022-05-10 07:48:05 +00:00
"github.com/status-im/status-go/multiaccounts/accounts"
2022-07-15 08:53:56 +00:00
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/rpc"
2022-09-13 07:10:59 +00:00
"github.com/status-im/status-go/services/ens"
"github.com/status-im/status-go/services/stickers"
"github.com/status-im/status-go/services/wallet/collectibles"
"github.com/status-im/status-go/services/wallet/currency"
feat: retrieve balance history for tokens and cache it to DB 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
2022-11-15 12:14:41 +00:00
"github.com/status-im/status-go/services/wallet/history"
2023-02-21 09:05:16 +00:00
"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/thirdparty/coingecko"
2023-02-21 09:05:16 +00:00
"github.com/status-im/status-go/services/wallet/thirdparty/cryptocompare"
"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
2022-09-13 07:10:59 +00:00
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/transfer"
2022-12-01 09:19:32 +00:00
"github.com/status-im/status-go/services/wallet/walletevent"
2022-07-15 08:53:56 +00:00
"github.com/status-im/status-go/transactions"
)
2023-02-23 13:55:57 +00:00
type Connection struct {
Up bool `json:"up"`
LastCheckedAt int64 `json:"lastCheckedAt"`
}
2023-01-17 09:56:16 +00:00
type ConnectedResult struct {
2023-02-20 09:32:45 +00:00
Blockchains map[uint64]Connection `json:"blockchains"`
2023-02-21 09:05:16 +00:00
Market Connection `json:"market"`
Collectibles map[uint64]Connection `json:"collectibles"`
2023-01-17 09:56:16 +00:00
}
// NewService initializes service instance.
2022-07-15 08:53:56 +00:00
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,
2022-09-13 07:10:59 +00:00
ens *ens.Service,
stickers *stickers.Service,
nftMetadataProvider thirdparty.NFTMetadataProvider,
2022-07-15 08:53:56 +00:00
) *Service {
cryptoOnRampManager := NewCryptoOnRampManager(&CryptoOnRampOptions{
dataSourceType: DataSourceStatic,
})
2022-12-01 09:19:32 +00:00
walletFeed := &event.Feed{}
signals := &walletevent.SignalsTransmitter{
Publisher: walletFeed,
}
2022-09-13 07:10:59 +00:00
tokenManager := token.NewTokenManager(db, rpcClient, rpcClient.NetworkManager)
2021-09-10 18:08:22 +00:00
savedAddressesManager := &SavedAddressesManager{db: db}
transactionManager := transfer.NewTransactionManager(db, gethManager, transactor, config, accountsDB)
transferController := transfer.NewTransferController(db, rpcClient, accountFeed, walletFeed, transactionManager)
2023-02-21 09:05:16 +00:00
cryptoCompare := cryptocompare.NewClient()
coingecko := coingecko.NewClient()
marketManager := market.NewManager(cryptoCompare, coingecko)
2023-02-21 09:05:16 +00:00
reader := NewReader(rpcClient, tokenManager, marketManager, accountsDB, walletFeed)
history := history.NewService(db, walletFeed, rpcClient, tokenManager, marketManager)
currency := currency.NewService(db, walletFeed, tokenManager, marketManager)
collectiblesManager := collectibles.NewManager(rpcClient, nftMetadataProvider, openseaAPIKey)
return &Service{
2022-05-10 07:48:05 +00:00
db: db,
accountsDB: accountsDB,
rpcClient: rpcClient,
2021-09-10 18:08:22 +00:00
tokenManager: tokenManager,
savedAddressesManager: savedAddressesManager,
transactionManager: transactionManager,
transferController: transferController,
cryptoOnRampManager: cryptoOnRampManager,
collectiblesManager: collectiblesManager,
2022-03-29 21:12:05 +00:00
feesManager: &FeeManager{rpcClient},
gethManager: gethManager,
2023-02-21 09:05:16 +00:00
marketManager: marketManager,
2022-09-13 07:10:59 +00:00
transactor: transactor,
ens: ens,
stickers: stickers,
feed: accountFeed,
2022-12-01 09:19:32 +00:00
signals: signals,
reader: reader,
feat: retrieve balance history for tokens and cache it to DB 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
2022-11-15 12:14:41 +00:00
history: history,
currency: currency,
}
}
// Service is a wallet service.
type Service struct {
2022-05-10 07:48:05 +00:00
db *sql.DB
accountsDB *accounts.Database
rpcClient *rpc.Client
2021-09-10 18:08:22 +00:00
savedAddressesManager *SavedAddressesManager
2022-10-25 14:50:32 +00:00
tokenManager *token.Manager
transactionManager *transfer.TransactionManager
2021-09-10 18:08:22 +00:00
cryptoOnRampManager *CryptoOnRampManager
transferController *transfer.Controller
2022-03-29 21:12:05 +00:00
feesManager *FeeManager
2023-02-21 09:05:16 +00:00
marketManager *market.Manager
2021-09-10 18:08:22 +00:00
started bool
collectiblesManager *collectibles.Manager
gethManager *account.GethManager
2022-09-13 07:10:59 +00:00
transactor *transactions.Transactor
ens *ens.Service
stickers *stickers.Service
feed *event.Feed
2022-12-01 09:19:32 +00:00
signals *walletevent.SignalsTransmitter
reader *Reader
feat: retrieve balance history for tokens and cache it to DB 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
2022-11-15 12:14:41 +00:00
history *history.Service
currency *currency.Service
}
// Start signals transmitter.
func (s *Service) Start() error {
2022-12-01 09:19:32 +00:00
s.transferController.Start()
s.currency.Start()
2022-12-01 09:19:32 +00:00
err := s.signals.Start()
s.history.Start()
s.started = true
return err
}
// GetFeed returns signals feed.
func (s *Service) GetFeed() *event.Feed {
return s.transferController.TransferFeed
}
2022-12-01 09:19:32 +00:00
// Stop reactor and close db.
func (s *Service) Stop() error {
log.Info("wallet will be stopped")
2022-12-01 09:19:32 +00:00
s.signals.Stop()
s.transferController.Stop()
s.currency.Stop()
2022-12-01 09:19:32 +00:00
s.reader.Stop()
feat: retrieve balance history for tokens and cache it to DB 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
2022-11-15 12:14:41 +00:00
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
}
2023-01-17 09:56:16 +00:00
func (s *Service) CheckConnected(ctx context.Context) *ConnectedResult {
2023-02-20 09:32:45 +00:00
networks, err := s.rpcClient.NetworkManager.Get(false)
blockchains := make(map[uint64]Connection)
if err == nil {
for _, network := range networks {
ethClient, err := s.rpcClient.EthClient(network.ChainID)
if err != nil {
blockchains[network.ChainID] = Connection{
Up: true,
LastCheckedAt: time.Now().Unix(),
}
}
blockchains[network.ChainID] = Connection{
Up: ethClient.IsConnected,
LastCheckedAt: ethClient.LastCheckedAt,
}
2023-02-23 13:55:57 +00:00
}
2023-01-17 09:56:16 +00:00
}
2023-02-21 09:05:16 +00:00
collectibles := make(map[uint64]Connection)
for chainID, client := range opensea.OpenseaClientInstances {
collectibles[chainID] = Connection{
2023-02-23 13:55:57 +00:00
Up: client.IsConnected,
LastCheckedAt: client.LastCheckedAt,
}
2023-01-17 09:56:16 +00:00
}
return &ConnectedResult{
2023-02-20 09:32:45 +00:00
Blockchains: blockchains,
2023-02-21 09:05:16 +00:00
Collectibles: collectibles,
Market: Connection{
Up: s.marketManager.IsConnected,
LastCheckedAt: s.marketManager.LastCheckedAt,
2023-02-23 13:55:57 +00:00
},
2023-01-17 09:56:16 +00:00
}
}