chore(wallet)_: tests for wallet.Reader fetching balances

chore(wallet)_: split getWalletTokenBalances into multiple functions

Removed some unused balances methods from wallet API

chore(wallet)_: refactored FetchOrGetWalletTokenBalances

- getWalletTokenBalances only returns cached ones
- update of balances is done in a separate method

chore(wallet)_: fix isVisible in getWalletTokenBalances is overwritten

It is overwritten and in some cases its value is desrespected

chore(wallet)_: simplify getWalletTokenBalance even further

chore(wallet)_: remove accountsDB from wallet.Reader

Call GetTestNetworkEnabled from NetworkManager instead

chore(wallet)_: remove rpc.Client from wallet.Reader.

Added GetActiveNetworks() method for NetworkManager
Removed adding native tokens from networks, as this is done already
in NetworkManager

chore(wallet)_: moved Persistence to token package

As it works with token_balances table, moved Persistence to token package.
Fixed TokenManager's Mark/Get previously owned tokens to use persistence
storage instead of direct SQL calls.
Introduced StorageToken that aggregates Token type, because when
Persistence moved to token package, names clash

test(wallet)_: tests for wallet.Reader.FetchorGetCachedBalances
This commit is contained in:
Ivan Belyakov 2024-06-06 20:57:29 +01:00 committed by Andrea Maria Piana
parent d2f4cae18f
commit bd816f1e29
18 changed files with 2715 additions and 389 deletions

View File

@ -339,6 +339,10 @@ mock: ##@other Regenerate mocks
mockgen -package=peer -destination=services/peer/discoverer_mock.go -source=services/peer/service.go
mockgen -package=mock_transactor -destination=transactions/mock_transactor/transactor.go -source=transactions/transactor.go
mockgen -package=mock_pathprocessor -destination=services/wallet/router/pathprocessor/mock_pathprocessor/processor.go -source=services/wallet/router/pathprocessor/processor.go
mockgen -package=mock_bridge -destination=services/wallet/bridge/mock_bridge/bridge.go -source=services/wallet/bridge/bridge.go
mockgen -package=mock_client -destination=rpc/chain/mock/client/client.go -source=rpc/chain/client.go
mockgen -package=mock_token -destination=services/wallet/token/mock/token/tokenmanager.go -source=services/wallet/token/token.go
mockgen -package=mock_balance_persistence -destination=services/wallet/token/mock/balance_persistence/balance_persistence.go -source=services/wallet/token/balance_persistence.go
docker-test: ##@tests Run tests in a docker container with golang.
docker run --privileged --rm -it -v "$(PWD):$(DOCKER_TEST_WORKDIR)" -w "$(DOCKER_TEST_WORKDIR)" $(DOCKER_TEST_IMAGE) go test ${ARGS}

View File

@ -467,7 +467,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, nil, nil, nil)
tokenManager := token.NewTokenManager(c.walletDb, c.rpcClient, community.NewManager(database, c.httpServer, nil), c.rpcClient.NetworkManager, database, c.httpServer, nil, nil, nil, token.NewPersistence(c.walletDb))
managerOptions = append(managerOptions, communities.WithTokenManager(communities.NewDefaultTokenManager(tokenManager)))
}

View File

@ -0,0 +1,917 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: rpc/chain/client.go
// Package mock_client is a generated GoMock package.
package mock_client
import (
context "context"
big "math/big"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
ethereum "github.com/ethereum/go-ethereum"
common "github.com/ethereum/go-ethereum/common"
types "github.com/ethereum/go-ethereum/core/types"
rpc "github.com/ethereum/go-ethereum/rpc"
chain "github.com/status-im/status-go/rpc/chain"
)
// MockBatchCallClient is a mock of BatchCallClient interface.
type MockBatchCallClient struct {
ctrl *gomock.Controller
recorder *MockBatchCallClientMockRecorder
}
// MockBatchCallClientMockRecorder is the mock recorder for MockBatchCallClient.
type MockBatchCallClientMockRecorder struct {
mock *MockBatchCallClient
}
// NewMockBatchCallClient creates a new mock instance.
func NewMockBatchCallClient(ctrl *gomock.Controller) *MockBatchCallClient {
mock := &MockBatchCallClient{ctrl: ctrl}
mock.recorder = &MockBatchCallClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockBatchCallClient) EXPECT() *MockBatchCallClientMockRecorder {
return m.recorder
}
// BatchCallContext mocks base method.
func (m *MockBatchCallClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BatchCallContext", ctx, b)
ret0, _ := ret[0].(error)
return ret0
}
// BatchCallContext indicates an expected call of BatchCallContext.
func (mr *MockBatchCallClientMockRecorder) BatchCallContext(ctx, b interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchCallContext", reflect.TypeOf((*MockBatchCallClient)(nil).BatchCallContext), ctx, b)
}
// MockChainInterface is a mock of ChainInterface interface.
type MockChainInterface struct {
ctrl *gomock.Controller
recorder *MockChainInterfaceMockRecorder
}
// MockChainInterfaceMockRecorder is the mock recorder for MockChainInterface.
type MockChainInterfaceMockRecorder struct {
mock *MockChainInterface
}
// NewMockChainInterface creates a new mock instance.
func NewMockChainInterface(ctrl *gomock.Controller) *MockChainInterface {
mock := &MockChainInterface{ctrl: ctrl}
mock.recorder = &MockChainInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockChainInterface) EXPECT() *MockChainInterfaceMockRecorder {
return m.recorder
}
// BalanceAt mocks base method.
func (m *MockChainInterface) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BalanceAt", ctx, account, blockNumber)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BalanceAt indicates an expected call of BalanceAt.
func (mr *MockChainInterfaceMockRecorder) BalanceAt(ctx, account, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BalanceAt", reflect.TypeOf((*MockChainInterface)(nil).BalanceAt), ctx, account, blockNumber)
}
// BatchCallContext mocks base method.
func (m *MockChainInterface) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BatchCallContext", ctx, b)
ret0, _ := ret[0].(error)
return ret0
}
// BatchCallContext indicates an expected call of BatchCallContext.
func (mr *MockChainInterfaceMockRecorder) BatchCallContext(ctx, b interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchCallContext", reflect.TypeOf((*MockChainInterface)(nil).BatchCallContext), ctx, b)
}
// BlockByHash mocks base method.
func (m *MockChainInterface) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlockByHash", ctx, hash)
ret0, _ := ret[0].(*types.Block)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BlockByHash indicates an expected call of BlockByHash.
func (mr *MockChainInterfaceMockRecorder) BlockByHash(ctx, hash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockChainInterface)(nil).BlockByHash), ctx, hash)
}
// BlockByNumber mocks base method.
func (m *MockChainInterface) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlockByNumber", ctx, number)
ret0, _ := ret[0].(*types.Block)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BlockByNumber indicates an expected call of BlockByNumber.
func (mr *MockChainInterfaceMockRecorder) BlockByNumber(ctx, number interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockChainInterface)(nil).BlockByNumber), ctx, number)
}
// BlockNumber mocks base method.
func (m *MockChainInterface) BlockNumber(ctx context.Context) (uint64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlockNumber", ctx)
ret0, _ := ret[0].(uint64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BlockNumber indicates an expected call of BlockNumber.
func (mr *MockChainInterfaceMockRecorder) BlockNumber(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockNumber", reflect.TypeOf((*MockChainInterface)(nil).BlockNumber), ctx)
}
// CallBlockHashByTransaction mocks base method.
func (m *MockChainInterface) CallBlockHashByTransaction(ctx context.Context, blockNumber *big.Int, index uint) (common.Hash, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CallBlockHashByTransaction", ctx, blockNumber, index)
ret0, _ := ret[0].(common.Hash)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CallBlockHashByTransaction indicates an expected call of CallBlockHashByTransaction.
func (mr *MockChainInterfaceMockRecorder) CallBlockHashByTransaction(ctx, blockNumber, index interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallBlockHashByTransaction", reflect.TypeOf((*MockChainInterface)(nil).CallBlockHashByTransaction), ctx, blockNumber, index)
}
// CallContext mocks base method.
func (m *MockChainInterface) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
m.ctrl.T.Helper()
varargs := []interface{}{ctx, result, method}
for _, a := range args {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "CallContext", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// CallContext indicates an expected call of CallContext.
func (mr *MockChainInterfaceMockRecorder) CallContext(ctx, result, method interface{}, args ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx, result, method}, args...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContext", reflect.TypeOf((*MockChainInterface)(nil).CallContext), varargs...)
}
// CallContract mocks base method.
func (m *MockChainInterface) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CallContract", ctx, call, blockNumber)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CallContract indicates an expected call of CallContract.
func (mr *MockChainInterfaceMockRecorder) CallContract(ctx, call, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContract", reflect.TypeOf((*MockChainInterface)(nil).CallContract), ctx, call, blockNumber)
}
// CodeAt mocks base method.
func (m *MockChainInterface) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CodeAt", ctx, contract, blockNumber)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CodeAt indicates an expected call of CodeAt.
func (mr *MockChainInterfaceMockRecorder) CodeAt(ctx, contract, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CodeAt", reflect.TypeOf((*MockChainInterface)(nil).CodeAt), ctx, contract, blockNumber)
}
// FilterLogs mocks base method.
func (m *MockChainInterface) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FilterLogs", ctx, q)
ret0, _ := ret[0].([]types.Log)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FilterLogs indicates an expected call of FilterLogs.
func (mr *MockChainInterfaceMockRecorder) FilterLogs(ctx, q interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterLogs", reflect.TypeOf((*MockChainInterface)(nil).FilterLogs), ctx, q)
}
// GetBaseFeeFromBlock mocks base method.
func (m *MockChainInterface) GetBaseFeeFromBlock(ctx context.Context, blockNumber *big.Int) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBaseFeeFromBlock", ctx, blockNumber)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBaseFeeFromBlock indicates an expected call of GetBaseFeeFromBlock.
func (mr *MockChainInterfaceMockRecorder) GetBaseFeeFromBlock(ctx, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaseFeeFromBlock", reflect.TypeOf((*MockChainInterface)(nil).GetBaseFeeFromBlock), ctx, blockNumber)
}
// HeaderByHash mocks base method.
func (m *MockChainInterface) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HeaderByHash", ctx, hash)
ret0, _ := ret[0].(*types.Header)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// HeaderByHash indicates an expected call of HeaderByHash.
func (mr *MockChainInterfaceMockRecorder) HeaderByHash(ctx, hash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockChainInterface)(nil).HeaderByHash), ctx, hash)
}
// HeaderByNumber mocks base method.
func (m *MockChainInterface) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HeaderByNumber", ctx, number)
ret0, _ := ret[0].(*types.Header)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// HeaderByNumber indicates an expected call of HeaderByNumber.
func (mr *MockChainInterfaceMockRecorder) HeaderByNumber(ctx, number interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockChainInterface)(nil).HeaderByNumber), ctx, number)
}
// NetworkID mocks base method.
func (m *MockChainInterface) NetworkID() uint64 {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NetworkID")
ret0, _ := ret[0].(uint64)
return ret0
}
// NetworkID indicates an expected call of NetworkID.
func (mr *MockChainInterfaceMockRecorder) NetworkID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkID", reflect.TypeOf((*MockChainInterface)(nil).NetworkID))
}
// NonceAt mocks base method.
func (m *MockChainInterface) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NonceAt", ctx, account, blockNumber)
ret0, _ := ret[0].(uint64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// NonceAt indicates an expected call of NonceAt.
func (mr *MockChainInterfaceMockRecorder) NonceAt(ctx, account, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NonceAt", reflect.TypeOf((*MockChainInterface)(nil).NonceAt), ctx, account, blockNumber)
}
// ToBigInt mocks base method.
func (m *MockChainInterface) ToBigInt() *big.Int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ToBigInt")
ret0, _ := ret[0].(*big.Int)
return ret0
}
// ToBigInt indicates an expected call of ToBigInt.
func (mr *MockChainInterfaceMockRecorder) ToBigInt() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToBigInt", reflect.TypeOf((*MockChainInterface)(nil).ToBigInt))
}
// TransactionByHash mocks base method.
func (m *MockChainInterface) TransactionByHash(ctx context.Context, hash common.Hash) (*types.Transaction, bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TransactionByHash", ctx, hash)
ret0, _ := ret[0].(*types.Transaction)
ret1, _ := ret[1].(bool)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// TransactionByHash indicates an expected call of TransactionByHash.
func (mr *MockChainInterfaceMockRecorder) TransactionByHash(ctx, hash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByHash", reflect.TypeOf((*MockChainInterface)(nil).TransactionByHash), ctx, hash)
}
// TransactionReceipt mocks base method.
func (m *MockChainInterface) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TransactionReceipt", ctx, txHash)
ret0, _ := ret[0].(*types.Receipt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// TransactionReceipt indicates an expected call of TransactionReceipt.
func (mr *MockChainInterfaceMockRecorder) TransactionReceipt(ctx, txHash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionReceipt", reflect.TypeOf((*MockChainInterface)(nil).TransactionReceipt), ctx, txHash)
}
// MockClientInterface is a mock of ClientInterface interface.
type MockClientInterface struct {
ctrl *gomock.Controller
recorder *MockClientInterfaceMockRecorder
}
// MockClientInterfaceMockRecorder is the mock recorder for MockClientInterface.
type MockClientInterfaceMockRecorder struct {
mock *MockClientInterface
}
// NewMockClientInterface creates a new mock instance.
func NewMockClientInterface(ctrl *gomock.Controller) *MockClientInterface {
mock := &MockClientInterface{ctrl: ctrl}
mock.recorder = &MockClientInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockClientInterface) EXPECT() *MockClientInterfaceMockRecorder {
return m.recorder
}
// BalanceAt mocks base method.
func (m *MockClientInterface) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BalanceAt", ctx, account, blockNumber)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BalanceAt indicates an expected call of BalanceAt.
func (mr *MockClientInterfaceMockRecorder) BalanceAt(ctx, account, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BalanceAt", reflect.TypeOf((*MockClientInterface)(nil).BalanceAt), ctx, account, blockNumber)
}
// BatchCallContext mocks base method.
func (m *MockClientInterface) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BatchCallContext", ctx, b)
ret0, _ := ret[0].(error)
return ret0
}
// BatchCallContext indicates an expected call of BatchCallContext.
func (mr *MockClientInterfaceMockRecorder) BatchCallContext(ctx, b interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchCallContext", reflect.TypeOf((*MockClientInterface)(nil).BatchCallContext), ctx, b)
}
// BlockByHash mocks base method.
func (m *MockClientInterface) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlockByHash", ctx, hash)
ret0, _ := ret[0].(*types.Block)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BlockByHash indicates an expected call of BlockByHash.
func (mr *MockClientInterfaceMockRecorder) BlockByHash(ctx, hash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockClientInterface)(nil).BlockByHash), ctx, hash)
}
// BlockByNumber mocks base method.
func (m *MockClientInterface) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlockByNumber", ctx, number)
ret0, _ := ret[0].(*types.Block)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BlockByNumber indicates an expected call of BlockByNumber.
func (mr *MockClientInterfaceMockRecorder) BlockByNumber(ctx, number interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockClientInterface)(nil).BlockByNumber), ctx, number)
}
// BlockNumber mocks base method.
func (m *MockClientInterface) BlockNumber(ctx context.Context) (uint64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlockNumber", ctx)
ret0, _ := ret[0].(uint64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BlockNumber indicates an expected call of BlockNumber.
func (mr *MockClientInterfaceMockRecorder) BlockNumber(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockNumber", reflect.TypeOf((*MockClientInterface)(nil).BlockNumber), ctx)
}
// CallBlockHashByTransaction mocks base method.
func (m *MockClientInterface) CallBlockHashByTransaction(ctx context.Context, blockNumber *big.Int, index uint) (common.Hash, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CallBlockHashByTransaction", ctx, blockNumber, index)
ret0, _ := ret[0].(common.Hash)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CallBlockHashByTransaction indicates an expected call of CallBlockHashByTransaction.
func (mr *MockClientInterfaceMockRecorder) CallBlockHashByTransaction(ctx, blockNumber, index interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallBlockHashByTransaction", reflect.TypeOf((*MockClientInterface)(nil).CallBlockHashByTransaction), ctx, blockNumber, index)
}
// CallContext mocks base method.
func (m *MockClientInterface) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
m.ctrl.T.Helper()
varargs := []interface{}{ctx, result, method}
for _, a := range args {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "CallContext", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// CallContext indicates an expected call of CallContext.
func (mr *MockClientInterfaceMockRecorder) CallContext(ctx, result, method interface{}, args ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx, result, method}, args...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContext", reflect.TypeOf((*MockClientInterface)(nil).CallContext), varargs...)
}
// CallContract mocks base method.
func (m *MockClientInterface) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CallContract", ctx, call, blockNumber)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CallContract indicates an expected call of CallContract.
func (mr *MockClientInterfaceMockRecorder) CallContract(ctx, call, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContract", reflect.TypeOf((*MockClientInterface)(nil).CallContract), ctx, call, blockNumber)
}
// CodeAt mocks base method.
func (m *MockClientInterface) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CodeAt", ctx, contract, blockNumber)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CodeAt indicates an expected call of CodeAt.
func (mr *MockClientInterfaceMockRecorder) CodeAt(ctx, contract, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CodeAt", reflect.TypeOf((*MockClientInterface)(nil).CodeAt), ctx, contract, blockNumber)
}
// EstimateGas mocks base method.
func (m *MockClientInterface) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EstimateGas", ctx, call)
ret0, _ := ret[0].(uint64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EstimateGas indicates an expected call of EstimateGas.
func (mr *MockClientInterfaceMockRecorder) EstimateGas(ctx, call interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGas", reflect.TypeOf((*MockClientInterface)(nil).EstimateGas), ctx, call)
}
// FilterLogs mocks base method.
func (m *MockClientInterface) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FilterLogs", ctx, q)
ret0, _ := ret[0].([]types.Log)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FilterLogs indicates an expected call of FilterLogs.
func (mr *MockClientInterfaceMockRecorder) FilterLogs(ctx, q interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterLogs", reflect.TypeOf((*MockClientInterface)(nil).FilterLogs), ctx, q)
}
// GetBaseFeeFromBlock mocks base method.
func (m *MockClientInterface) GetBaseFeeFromBlock(ctx context.Context, blockNumber *big.Int) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBaseFeeFromBlock", ctx, blockNumber)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBaseFeeFromBlock indicates an expected call of GetBaseFeeFromBlock.
func (mr *MockClientInterfaceMockRecorder) GetBaseFeeFromBlock(ctx, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaseFeeFromBlock", reflect.TypeOf((*MockClientInterface)(nil).GetBaseFeeFromBlock), ctx, blockNumber)
}
// GetLimiter mocks base method.
func (m *MockClientInterface) GetLimiter() chain.RequestLimiter {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetLimiter")
ret0, _ := ret[0].(chain.RequestLimiter)
return ret0
}
// GetLimiter indicates an expected call of GetLimiter.
func (mr *MockClientInterfaceMockRecorder) GetLimiter() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLimiter", reflect.TypeOf((*MockClientInterface)(nil).GetLimiter))
}
// GetWalletNotifier mocks base method.
func (m *MockClientInterface) GetWalletNotifier() func(uint64, string) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetWalletNotifier")
ret0, _ := ret[0].(func(uint64, string))
return ret0
}
// GetWalletNotifier indicates an expected call of GetWalletNotifier.
func (mr *MockClientInterfaceMockRecorder) GetWalletNotifier() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWalletNotifier", reflect.TypeOf((*MockClientInterface)(nil).GetWalletNotifier))
}
// HeaderByHash mocks base method.
func (m *MockClientInterface) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HeaderByHash", ctx, hash)
ret0, _ := ret[0].(*types.Header)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// HeaderByHash indicates an expected call of HeaderByHash.
func (mr *MockClientInterfaceMockRecorder) HeaderByHash(ctx, hash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockClientInterface)(nil).HeaderByHash), ctx, hash)
}
// HeaderByNumber mocks base method.
func (m *MockClientInterface) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HeaderByNumber", ctx, number)
ret0, _ := ret[0].(*types.Header)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// HeaderByNumber indicates an expected call of HeaderByNumber.
func (mr *MockClientInterfaceMockRecorder) HeaderByNumber(ctx, number interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockClientInterface)(nil).HeaderByNumber), ctx, number)
}
// IsConnected mocks base method.
func (m *MockClientInterface) IsConnected() bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsConnected")
ret0, _ := ret[0].(bool)
return ret0
}
// IsConnected indicates an expected call of IsConnected.
func (mr *MockClientInterfaceMockRecorder) IsConnected() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsConnected", reflect.TypeOf((*MockClientInterface)(nil).IsConnected))
}
// NetworkID mocks base method.
func (m *MockClientInterface) NetworkID() uint64 {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NetworkID")
ret0, _ := ret[0].(uint64)
return ret0
}
// NetworkID indicates an expected call of NetworkID.
func (mr *MockClientInterfaceMockRecorder) NetworkID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkID", reflect.TypeOf((*MockClientInterface)(nil).NetworkID))
}
// NonceAt mocks base method.
func (m *MockClientInterface) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NonceAt", ctx, account, blockNumber)
ret0, _ := ret[0].(uint64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// NonceAt indicates an expected call of NonceAt.
func (mr *MockClientInterfaceMockRecorder) NonceAt(ctx, account, blockNumber interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NonceAt", reflect.TypeOf((*MockClientInterface)(nil).NonceAt), ctx, account, blockNumber)
}
// PendingCodeAt mocks base method.
func (m *MockClientInterface) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PendingCodeAt", ctx, account)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PendingCodeAt indicates an expected call of PendingCodeAt.
func (mr *MockClientInterfaceMockRecorder) PendingCodeAt(ctx, account interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingCodeAt", reflect.TypeOf((*MockClientInterface)(nil).PendingCodeAt), ctx, account)
}
// PendingNonceAt mocks base method.
func (m *MockClientInterface) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PendingNonceAt", ctx, account)
ret0, _ := ret[0].(uint64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PendingNonceAt indicates an expected call of PendingNonceAt.
func (mr *MockClientInterfaceMockRecorder) PendingNonceAt(ctx, account interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingNonceAt", reflect.TypeOf((*MockClientInterface)(nil).PendingNonceAt), ctx, account)
}
// SendTransaction mocks base method.
func (m *MockClientInterface) SendTransaction(ctx context.Context, tx *types.Transaction) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendTransaction", ctx, tx)
ret0, _ := ret[0].(error)
return ret0
}
// SendTransaction indicates an expected call of SendTransaction.
func (mr *MockClientInterfaceMockRecorder) SendTransaction(ctx, tx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransaction", reflect.TypeOf((*MockClientInterface)(nil).SendTransaction), ctx, tx)
}
// SetIsConnected mocks base method.
func (m *MockClientInterface) SetIsConnected(arg0 bool) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetIsConnected", arg0)
}
// SetIsConnected indicates an expected call of SetIsConnected.
func (mr *MockClientInterfaceMockRecorder) SetIsConnected(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIsConnected", reflect.TypeOf((*MockClientInterface)(nil).SetIsConnected), arg0)
}
// SetLimiter mocks base method.
func (m *MockClientInterface) SetLimiter(arg0 chain.RequestLimiter) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetLimiter", arg0)
}
// SetLimiter indicates an expected call of SetLimiter.
func (mr *MockClientInterfaceMockRecorder) SetLimiter(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLimiter", reflect.TypeOf((*MockClientInterface)(nil).SetLimiter), arg0)
}
// SetWalletNotifier mocks base method.
func (m *MockClientInterface) SetWalletNotifier(notifier func(uint64, string)) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetWalletNotifier", notifier)
}
// SetWalletNotifier indicates an expected call of SetWalletNotifier.
func (mr *MockClientInterfaceMockRecorder) SetWalletNotifier(notifier interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetWalletNotifier", reflect.TypeOf((*MockClientInterface)(nil).SetWalletNotifier), notifier)
}
// SubscribeFilterLogs mocks base method.
func (m *MockClientInterface) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SubscribeFilterLogs", ctx, query, ch)
ret0, _ := ret[0].(ethereum.Subscription)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SubscribeFilterLogs indicates an expected call of SubscribeFilterLogs.
func (mr *MockClientInterfaceMockRecorder) SubscribeFilterLogs(ctx, query, ch interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeFilterLogs", reflect.TypeOf((*MockClientInterface)(nil).SubscribeFilterLogs), ctx, query, ch)
}
// SuggestGasPrice mocks base method.
func (m *MockClientInterface) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SuggestGasPrice", ctx)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SuggestGasPrice indicates an expected call of SuggestGasPrice.
func (mr *MockClientInterfaceMockRecorder) SuggestGasPrice(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasPrice", reflect.TypeOf((*MockClientInterface)(nil).SuggestGasPrice), ctx)
}
// SuggestGasTipCap mocks base method.
func (m *MockClientInterface) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SuggestGasTipCap", ctx)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SuggestGasTipCap indicates an expected call of SuggestGasTipCap.
func (mr *MockClientInterfaceMockRecorder) SuggestGasTipCap(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasTipCap", reflect.TypeOf((*MockClientInterface)(nil).SuggestGasTipCap), ctx)
}
// ToBigInt mocks base method.
func (m *MockClientInterface) ToBigInt() *big.Int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ToBigInt")
ret0, _ := ret[0].(*big.Int)
return ret0
}
// ToBigInt indicates an expected call of ToBigInt.
func (mr *MockClientInterfaceMockRecorder) ToBigInt() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToBigInt", reflect.TypeOf((*MockClientInterface)(nil).ToBigInt))
}
// TransactionByHash mocks base method.
func (m *MockClientInterface) TransactionByHash(ctx context.Context, hash common.Hash) (*types.Transaction, bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TransactionByHash", ctx, hash)
ret0, _ := ret[0].(*types.Transaction)
ret1, _ := ret[1].(bool)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// TransactionByHash indicates an expected call of TransactionByHash.
func (mr *MockClientInterfaceMockRecorder) TransactionByHash(ctx, hash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByHash", reflect.TypeOf((*MockClientInterface)(nil).TransactionByHash), ctx, hash)
}
// TransactionReceipt mocks base method.
func (m *MockClientInterface) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TransactionReceipt", ctx, txHash)
ret0, _ := ret[0].(*types.Receipt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// TransactionReceipt indicates an expected call of TransactionReceipt.
func (mr *MockClientInterfaceMockRecorder) TransactionReceipt(ctx, txHash interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionReceipt", reflect.TypeOf((*MockClientInterface)(nil).TransactionReceipt), ctx, txHash)
}
// MockTagger is a mock of Tagger interface.
type MockTagger struct {
ctrl *gomock.Controller
recorder *MockTaggerMockRecorder
}
// MockTaggerMockRecorder is the mock recorder for MockTagger.
type MockTaggerMockRecorder struct {
mock *MockTagger
}
// NewMockTagger creates a new mock instance.
func NewMockTagger(ctrl *gomock.Controller) *MockTagger {
mock := &MockTagger{ctrl: ctrl}
mock.recorder = &MockTaggerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockTagger) EXPECT() *MockTaggerMockRecorder {
return m.recorder
}
// DeepCopyTag mocks base method.
func (m *MockTagger) DeepCopyTag() chain.Tagger {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeepCopyTag")
ret0, _ := ret[0].(chain.Tagger)
return ret0
}
// DeepCopyTag indicates an expected call of DeepCopyTag.
func (mr *MockTaggerMockRecorder) DeepCopyTag() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeepCopyTag", reflect.TypeOf((*MockTagger)(nil).DeepCopyTag))
}
// GroupTag mocks base method.
func (m *MockTagger) GroupTag() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GroupTag")
ret0, _ := ret[0].(string)
return ret0
}
// GroupTag indicates an expected call of GroupTag.
func (mr *MockTaggerMockRecorder) GroupTag() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GroupTag", reflect.TypeOf((*MockTagger)(nil).GroupTag))
}
// SetGroupTag mocks base method.
func (m *MockTagger) SetGroupTag(tag string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetGroupTag", tag)
}
// SetGroupTag indicates an expected call of SetGroupTag.
func (mr *MockTaggerMockRecorder) SetGroupTag(tag interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetGroupTag", reflect.TypeOf((*MockTagger)(nil).SetGroupTag), tag)
}
// SetTag mocks base method.
func (m *MockTagger) SetTag(tag string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetTag", tag)
}
// SetTag indicates an expected call of SetTag.
func (mr *MockTaggerMockRecorder) SetTag(tag interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTag", reflect.TypeOf((*MockTagger)(nil).SetTag), tag)
}
// Tag mocks base method.
func (m *MockTagger) Tag() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Tag")
ret0, _ := ret[0].(string)
return ret0
}
// Tag indicates an expected call of Tag.
func (mr *MockTaggerMockRecorder) Tag() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Tag", reflect.TypeOf((*MockTagger)(nil).Tag))
}

View File

@ -324,3 +324,26 @@ func (nm *Manager) GetConfiguredNetworks() []params.Network {
func (nm *Manager) GetTestNetworksEnabled() (result bool, err error) {
return nm.accountsDB.GetTestNetworksEnabled()
}
// Returns all networks for active mode (test/prod) and in case of test mode,
// returns either Goerli or Sepolia networks based on the value of isGoerliEnabled
func (nm *Manager) GetActiveNetworks() ([]*params.Network, error) {
areTestNetworksEnabled, err := nm.GetTestNetworksEnabled()
if err != nil {
return nil, err
}
networks, err := nm.Get(false)
if err != nil {
return nil, err
}
availableNetworks := make([]*params.Network, 0)
for _, network := range networks {
if network.IsTest != areTestNetworksEnabled {
continue
}
availableNetworks = append(availableNetworks, network)
}
return availableNetworks, nil
}

View File

@ -8,10 +8,12 @@ import (
"time"
eth "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/event"
"github.com/status-im/status-go/appdatabase"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/wallet/bigint"
"github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty"
@ -70,6 +72,18 @@ func (m *mockTokenManager) LookupToken(chainID *uint64, tokenSymbol string) (tkn
return args.Get(0).(*token.Token), args.Bool(1)
}
func (m *mockTokenManager) GetBalancesByChain(parent context.Context, clients map[uint64]chain.ClientInterface, accounts, tokens []eth.Address) (map[uint64]map[eth.Address]map[eth.Address]*hexutil.Big, error) {
return nil, nil // Not used here
}
func (m *mockTokenManager) GetTokensByChainIDs(chainIDs []uint64) ([]*token.Token, error) {
return nil, nil // Not used here
}
func (m *mockTokenManager) GetTokenHistoricalBalance(account eth.Address, chainID uint64, symbol string, timestamp int64) (*big.Int, error) {
return nil, nil // Not used here
}
type testState struct {
service *Service
eventFeed *event.Feed

View File

@ -64,8 +64,25 @@ func (api *API) SetPairingsJSONFileContent(content []byte) error {
return api.s.keycardPairings.SetPairingsJSONFileContent(content)
}
func (api *API) GetWalletToken(ctx context.Context, addresses []common.Address) (map[common.Address][]Token, error) {
return api.reader.GetWalletToken(ctx, addresses)
// Used by mobile
func (api *API) GetWalletToken(ctx context.Context, addresses []common.Address) (map[common.Address][]token.StorageToken, error) {
currency, err := api.s.accountsDB.GetCurrency()
if err != nil {
return nil, err
}
activeNetworks, err := api.s.rpcClient.NetworkManager.GetActiveNetworks()
if err != nil {
return nil, err
}
chainIDs := wcommon.NetworksToChainIDs(activeNetworks)
clients, err := api.s.rpcClient.EthClients(chainIDs)
if err != nil {
return nil, err
}
return api.reader.GetWalletToken(ctx, clients, addresses, currency)
}
// GetBalancesByChain return a map with key as chain id and value as map of account address and map of token address and balance
@ -79,16 +96,19 @@ func (api *API) GetBalancesByChain(ctx context.Context, chainIDs []uint64, addre
return api.s.tokenManager.GetBalancesByChain(ctx, clients, addresses, tokens)
}
func (api *API) GetWalletTokenBalances(ctx context.Context, addresses []common.Address) (map[common.Address][]Token, error) {
return api.reader.GetWalletTokenBalances(ctx, addresses)
}
func (api *API) FetchOrGetCachedWalletBalances(ctx context.Context, addresses []common.Address) (map[common.Address][]token.StorageToken, error) {
activeNetworks, err := api.s.rpcClient.NetworkManager.GetActiveNetworks()
if err != nil {
return nil, err
}
func (api *API) FetchOrGetCachedWalletBalances(ctx context.Context, addresses []common.Address) (map[common.Address][]Token, error) {
return api.reader.FetchOrGetCachedWalletBalances(ctx, addresses)
}
chainIDs := wcommon.NetworksToChainIDs(activeNetworks)
clients, err := api.s.rpcClient.EthClients(chainIDs)
if err != nil {
return nil, err
}
func (api *API) GetCachedWalletTokensWithoutMarketData(ctx context.Context) (map[common.Address][]Token, error) {
return api.reader.GetCachedWalletTokensWithoutMarketData()
return api.reader.FetchOrGetCachedWalletBalances(ctx, clients, addresses)
}
type DerivedAddress struct {
@ -428,7 +448,7 @@ func (api *API) GetSuggestedRoutes(
) (*router.SuggestedRoutes, error) {
log.Debug("call to GetSuggestedRoutes")
testnetMode, err := api.s.accountsDB.GetTestNetworksEnabled()
testnetMode, err := api.s.rpcClient.NetworkManager.GetTestNetworksEnabled()
if err != nil {
return nil, err
}
@ -439,7 +459,7 @@ func (api *API) GetSuggestedRoutes(
func (api *API) GetSuggestedRoutesV2(ctx context.Context, input *router.RouteInputParams) (*router.SuggestedRoutesV2, error) {
log.Debug("call to GetSuggestedRoutesV2")
testnetMode, err := api.s.accountsDB.GetTestNetworksEnabled()
testnetMode, err := api.s.rpcClient.NetworkManager.GetTestNetworksEnabled()
if err != nil {
return nil, err
}

View File

@ -1,6 +1,10 @@
package common
import "context"
import (
"context"
"github.com/status-im/status-go/params"
)
// ShouldCancel returns true if the context has been cancelled and task should be aborted
func ShouldCancel(ctx context.Context) bool {
@ -11,3 +15,12 @@ func ShouldCancel(ctx context.Context) bool {
}
return false
}
func NetworksToChainIDs(networks []*params.Network) []uint64 {
chainIDs := make([]uint64, 0)
for _, network := range networks {
chainIDs = append(chainIDs, network.ChainID)
}
return chainIDs
}

View File

@ -7,15 +7,14 @@ import (
"sync"
"time"
"golang.org/x/exp/maps"
"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/multiaccounts/accounts"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/rpc/chain"
"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/market"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/token"
@ -47,13 +46,10 @@ func belongsToMandatoryTokens(symbol string) bool {
return false
}
func NewReader(rpcClient *rpc.Client, tokenManager *token.Manager, marketManager *market.Manager, communityManager *community.Manager, accountsDB *accounts.Database, persistence *Persistence, walletFeed *event.Feed) *Reader {
func NewReader(tokenManager token.ManagerInterface, marketManager *market.Manager, persistence token.TokenBalancesStorage, walletFeed *event.Feed) *Reader {
return &Reader{
rpcClient: rpcClient,
tokenManager: tokenManager,
marketManager: marketManager,
communityManager: communityManager,
accountsDB: accountsDB,
persistence: persistence,
walletFeed: walletFeed,
refreshBalanceCache: true,
@ -61,12 +57,9 @@ func NewReader(rpcClient *rpc.Client, tokenManager *token.Manager, marketManager
}
type Reader struct {
rpcClient *rpc.Client
tokenManager *token.Manager
tokenManager token.ManagerInterface
marketManager *market.Manager
communityManager *community.Manager
accountsDB *accounts.Database
persistence *Persistence
persistence token.TokenBalancesStorage
walletFeed *event.Feed
cancel context.CancelFunc
walletEventsWatcher *walletevent.Watcher
@ -76,42 +69,6 @@ type Reader struct {
rw sync.RWMutex
}
type TokenMarketValues struct {
MarketCap float64 `json:"marketCap"`
HighDay float64 `json:"highDay"`
LowDay float64 `json:"lowDay"`
ChangePctHour float64 `json:"changePctHour"`
ChangePctDay float64 `json:"changePctDay"`
ChangePct24hour float64 `json:"changePct24hour"`
Change24hour float64 `json:"change24hour"`
Price float64 `json:"price"`
HasError bool `json:"hasError"`
}
type ChainBalance struct {
RawBalance string `json:"rawBalance"`
Balance *big.Float `json:"balance"`
Balance1DayAgo string `json:"balance1DayAgo"`
Address common.Address `json:"address"`
ChainID uint64 `json:"chainId"`
HasError bool `json:"hasError"`
}
type Token struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint `json:"decimals"`
BalancesPerChain map[uint64]ChainBalance `json:"balancesPerChain"`
Description string `json:"description"`
AssetWebsiteURL string `json:"assetWebsiteUrl"`
BuiltOn string `json:"builtOn"`
MarketValuesPerCurrency map[string]TokenMarketValues `json:"marketValuesPerCurrency"`
PegSymbol string `json:"pegSymbol"`
Verified bool `json:"verified"`
Image string `json:"image,omitempty"`
CommunityData *community.Data `json:"community_data,omitempty"`
}
func splitVerifiedTokens(tokens []*token.Token) ([]*token.Token, []*token.Token) {
verified := make([]*token.Token, 0)
unverified := make([]*token.Token, 0)
@ -248,12 +205,12 @@ func (r *Reader) stopWalletEventsWatcher() {
}
func (r *Reader) tokensCachedForAddresses(addresses []common.Address) bool {
for _, address := range addresses {
cachedTokens, err := r.GetCachedWalletTokensWithoutMarketData()
if err != nil {
return false
}
cachedTokens, err := r.getCachedWalletTokensWithoutMarketData()
if err != nil {
return false
}
for _, address := range addresses {
_, ok := cachedTokens[address]
if !ok {
return false
@ -299,189 +256,152 @@ func (r *Reader) invalidateBalanceCache() {
r.refreshBalanceCache = true
}
func (r *Reader) FetchOrGetCachedWalletBalances(ctx context.Context, addresses []common.Address) (map[common.Address][]Token, error) {
if !r.isBalanceCacheValid(addresses) {
balances, err := r.GetWalletTokenBalances(ctx, addresses)
if err != nil {
return nil, err
}
r.balanceRefreshed()
return balances, nil
func (r *Reader) FetchOrGetCachedWalletBalances(ctx context.Context, clients map[uint64]chain.ClientInterface, addresses []common.Address) (map[common.Address][]token.StorageToken, error) {
needFetch := !r.isBalanceCacheValid(addresses) || r.isBalanceUpdateNeededAnyway(clients, addresses)
if needFetch {
return r.FetchBalances(ctx, clients, addresses)
}
tokens, err := r.getWalletTokenBalances(ctx, addresses, false)
return tokens, err
return r.GetCachedBalances(clients, addresses)
}
func (r *Reader) getWalletTokenBalances(ctx context.Context, addresses []common.Address, updateBalances bool) (map[common.Address][]Token, error) {
areTestNetworksEnabled, err := r.accountsDB.GetTestNetworksEnabled()
func (r *Reader) isBalanceUpdateNeededAnyway(clients map[uint64]chain.ClientInterface, addresses []common.Address) bool {
cachedTokens, err := r.getCachedWalletTokensWithoutMarketData()
if err != nil {
return nil, err
return true
}
networks, err := r.rpcClient.NetworkManager.Get(false)
if err != nil {
return nil, err
}
availableNetworks := make([]*params.Network, 0)
for _, network := range networks {
if network.IsTest != areTestNetworksEnabled {
continue
chainIDs := maps.Keys(clients)
updateAnyway := false
for _, address := range addresses {
if res, ok := cachedTokens[address]; !ok || len(res) == 0 {
updateAnyway = true
break
}
networkFound := map[uint64]bool{}
for _, token := range cachedTokens[address] {
for _, chain := range chainIDs {
if _, ok := token.BalancesPerChain[chain]; ok {
networkFound[chain] = true
}
}
}
for _, chain := range chainIDs {
if !networkFound[chain] {
updateAnyway = true
return updateAnyway
}
}
availableNetworks = append(availableNetworks, network)
}
cachedTokens, err := r.GetCachedWalletTokensWithoutMarketData()
return updateAnyway
}
func tokensToBalancesPerChain(cachedTokens map[common.Address][]token.StorageToken) map[uint64]map[common.Address]map[common.Address]*hexutil.Big {
cachedBalancesPerChain := map[uint64]map[common.Address]map[common.Address]*hexutil.Big{}
for address, tokens := range cachedTokens {
for _, token := range tokens {
for _, balance := range token.BalancesPerChain {
if _, ok := cachedBalancesPerChain[balance.ChainID]; !ok {
cachedBalancesPerChain[balance.ChainID] = map[common.Address]map[common.Address]*hexutil.Big{}
}
if _, ok := cachedBalancesPerChain[balance.ChainID][address]; !ok {
cachedBalancesPerChain[balance.ChainID][address] = map[common.Address]*hexutil.Big{}
}
bigBalance, _ := new(big.Int).SetString(balance.RawBalance, 10)
cachedBalancesPerChain[balance.ChainID][address][balance.Address] = (*hexutil.Big)(bigBalance)
}
}
}
return cachedBalancesPerChain
}
func (r *Reader) fetchBalances(ctx context.Context, clients map[uint64]chain.ClientInterface, addresses []common.Address, tokenAddresses []common.Address) (map[uint64]map[common.Address]map[common.Address]*hexutil.Big, error) {
latestBalances, err := r.tokenManager.GetBalancesByChain(ctx, clients, addresses, tokenAddresses)
if err != nil {
log.Error("tokenManager.GetBalancesByChain error", "err", err)
return nil, err
}
chainIDs := make([]uint64, 0)
for _, network := range availableNetworks {
chainIDs = append(chainIDs, network.ChainID)
return latestBalances, nil
}
func toChainBalance(
balances map[uint64]map[common.Address]map[common.Address]*hexutil.Big,
tok *token.Token,
address common.Address,
decimals uint,
cachedTokens map[common.Address][]token.StorageToken,
hasError bool,
isMandatoryToken bool,
) *token.ChainBalance {
hexBalance := &big.Int{}
if balances != nil {
hexBalance = balances[tok.ChainID][address][tok.Address].ToInt()
}
allTokens, err := r.tokenManager.GetTokensByChainIDs(chainIDs)
balance := big.NewFloat(0.0)
if hexBalance != nil {
balance = new(big.Float).Quo(
new(big.Float).SetInt(hexBalance),
big.NewFloat(math.Pow(10, float64(decimals))),
)
}
isVisible := balance.Cmp(big.NewFloat(0.0)) > 0 || isCachedToken(cachedTokens, address, tok.Symbol, tok.ChainID)
if !isVisible && !isMandatoryToken {
return nil
}
return &token.ChainBalance{
RawBalance: hexBalance.String(),
Balance: balance,
Balance1DayAgo: "0",
Address: tok.Address,
ChainID: tok.ChainID,
HasError: hasError,
}
}
func (r *Reader) getBalance1DayAgo(balance *token.ChainBalance, dayAgoTimestamp int64, symbol string, address common.Address) (*big.Int, error) {
balance1DayAgo, err := r.tokenManager.GetTokenHistoricalBalance(address, balance.ChainID, symbol, dayAgoTimestamp)
if err != nil {
log.Error("tokenManager.GetTokenHistoricalBalance error", "err", err)
return nil, err
}
for _, network := range availableNetworks {
allTokens = append(allTokens, r.tokenManager.ToToken(network))
}
tokenAddresses := getTokenAddresses(allTokens)
clients, err := r.rpcClient.EthClients(chainIDs)
if err != nil {
return nil, err
}
return balance1DayAgo, nil
}
func (r *Reader) balancesToTokensByAddress(connectedPerChain map[uint64]bool, addresses []common.Address, allTokens []*token.Token, balances map[uint64]map[common.Address]map[common.Address]*hexutil.Big, cachedTokens map[common.Address][]token.StorageToken) map[common.Address][]token.StorageToken {
verifiedTokens, unverifiedTokens := splitVerifiedTokens(allTokens)
cachedBalancesPerChain := map[common.Address]map[common.Address]map[uint64]string{}
updateAnyway := false
if !updateBalances {
cacheCheck:
for _, address := range addresses {
if res, ok := cachedTokens[address]; !ok || len(res) == 0 {
updateAnyway = true
break
}
networkFound := map[uint64]bool{}
for _, token := range cachedTokens[address] {
for _, chain := range chainIDs {
if _, ok := token.BalancesPerChain[chain]; ok {
networkFound[chain] = true
}
}
}
for _, chain := range chainIDs {
if !networkFound[chain] {
updateAnyway = true
break cacheCheck
}
}
}
}
if !updateBalances && !updateAnyway {
for address, tokens := range cachedTokens {
for _, token := range tokens {
for _, balance := range token.BalancesPerChain {
if _, ok := cachedBalancesPerChain[address]; !ok {
cachedBalancesPerChain[address] = map[common.Address]map[uint64]string{}
}
if _, ok := cachedBalancesPerChain[address][balance.Address]; !ok {
cachedBalancesPerChain[address][balance.Address] = map[uint64]string{}
}
cachedBalancesPerChain[address][balance.Address][balance.ChainID] = balance.RawBalance
}
}
}
}
var latestBalances map[uint64]map[common.Address]map[common.Address]*hexutil.Big
if updateBalances || updateAnyway {
latestBalances, err = r.tokenManager.GetBalancesByChain(ctx, clients, addresses, tokenAddresses)
if err != nil {
log.Info("tokenManager.GetBalancesByChain error", "err", err)
return nil, err
}
}
result := make(map[common.Address][]Token)
result := make(map[common.Address][]token.StorageToken)
dayAgoTimestamp := time.Now().Add(-24 * time.Hour).Unix()
for _, address := range addresses {
for _, tokenList := range [][]*token.Token{verifiedTokens, unverifiedTokens} {
for symbol, tokens := range getTokenBySymbols(tokenList) {
balancesPerChain := make(map[uint64]ChainBalance)
decimals := tokens[0].Decimals
isVisible := false
for _, token := range tokens {
var balance *big.Float
hexBalance := &big.Int{}
if latestBalances != nil {
hexBalance = latestBalances[token.ChainID][address][token.Address].ToInt()
} else {
if cachedRawBalance, ok := cachedBalancesPerChain[address][token.Address][token.ChainID]; ok {
hexBalance, _ = new(big.Int).SetString(cachedRawBalance, 10)
}
}
balance = big.NewFloat(0.0)
if hexBalance != nil {
balance = new(big.Float).Quo(
new(big.Float).SetInt(hexBalance),
big.NewFloat(math.Pow(10, float64(decimals))),
)
}
hasError := false
if client, ok := clients[token.ChainID]; ok {
hasError = err != nil || !client.IsConnected()
}
if !isVisible {
isVisible = balance.Cmp(big.NewFloat(0.0)) > 0 || r.isCachedToken(cachedTokens, address, token.Symbol, token.ChainID)
}
balancesPerChain[token.ChainID] = ChainBalance{
RawBalance: hexBalance.String(),
Balance: balance,
Balance1DayAgo: "0",
Address: token.Address,
ChainID: token.ChainID,
HasError: hasError,
}
}
if !isVisible && !belongsToMandatoryTokens(symbol) {
balancesPerChain := r.createBalancePerChainPerSymbol(address, balances, tokens, cachedTokens, connectedPerChain, dayAgoTimestamp)
if balancesPerChain == nil {
continue
}
for _, balance := range balancesPerChain {
balance1DayAgo, err := r.tokenManager.GetTokenHistoricalBalance(address, balance.ChainID, symbol, dayAgoTimestamp)
if err != nil {
return nil, err
}
if balance1DayAgo != nil {
balance.Balance1DayAgo = balance1DayAgo.String()
balancesPerChain[balance.ChainID] = balance
}
}
walletToken := Token{
Name: tokens[0].Name,
Symbol: symbol,
walletToken := token.StorageToken{
Token: token.Token{
Name: tokens[0].Name,
Symbol: symbol,
Decimals: tokens[0].Decimals,
PegSymbol: token.GetTokenPegSymbol(symbol),
Verified: tokens[0].Verified,
CommunityData: tokens[0].CommunityData,
Image: tokens[0].Image,
},
BalancesPerChain: balancesPerChain,
Decimals: decimals,
PegSymbol: token.GetTokenPegSymbol(symbol),
Verified: tokens[0].Verified,
CommunityData: tokens[0].CommunityData,
Image: tokens[0].Image,
}
result[address] = append(result[address], walletToken)
@ -489,66 +409,63 @@ func (r *Reader) getWalletTokenBalances(ctx context.Context, addresses []common.
}
}
r.updateTokenUpdateTimestamp(addresses)
return result, r.persistence.SaveTokens(result)
return result
}
func (r *Reader) GetWalletTokenBalances(ctx context.Context, addresses []common.Address) (map[common.Address][]Token, error) {
return r.getWalletTokenBalances(ctx, addresses, true)
}
func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address) (map[common.Address][]Token, error) {
areTestNetworksEnabled, err := r.accountsDB.GetTestNetworksEnabled()
if err != nil {
return nil, err
}
networks, err := r.rpcClient.NetworkManager.Get(false)
if err != nil {
return nil, err
}
availableNetworks := make([]*params.Network, 0)
for _, network := range networks {
if network.IsTest != areTestNetworksEnabled {
continue
// For tokens with single symbol, create a chain balance for each chain
func (r *Reader) createBalancePerChainPerSymbol(
address common.Address,
balances map[uint64]map[common.Address]map[common.Address]*hexutil.Big,
tokens []*token.Token,
cachedTokens map[common.Address][]token.StorageToken,
clientConnectionPerChain map[uint64]bool,
dayAgoTimestamp int64,
) map[uint64]token.ChainBalance {
var balancesPerChain map[uint64]token.ChainBalance
decimals := tokens[0].Decimals
isMandatoryToken := belongsToMandatoryTokens(tokens[0].Symbol) // we expect all tokens in the list to have the same symbol
for _, tok := range tokens {
hasError := false
if connected, ok := clientConnectionPerChain[tok.ChainID]; ok {
hasError = !connected
}
// TODO: Avoid passing the entire balances map to toChainBalance. Iterate over the balances map once and pass the balance per address per token to toChainBalance
balance := toChainBalance(balances, tok, address, decimals, cachedTokens, hasError, isMandatoryToken)
if balance != nil {
balance1DayAgo, _ := r.getBalance1DayAgo(balance, dayAgoTimestamp, tok.Symbol, address) // Ignore error
if balance1DayAgo != nil {
balance.Balance1DayAgo = balance1DayAgo.String()
}
if balancesPerChain == nil {
balancesPerChain = make(map[uint64]token.ChainBalance)
}
balancesPerChain[tok.ChainID] = *balance
}
availableNetworks = append(availableNetworks, network)
}
cachedTokens, err := r.GetCachedWalletTokensWithoutMarketData()
return balancesPerChain
}
func (r *Reader) GetWalletToken(ctx context.Context, clients map[uint64]chain.ClientInterface, addresses []common.Address, currency string) (map[common.Address][]token.StorageToken, error) {
cachedTokens, err := r.getCachedWalletTokensWithoutMarketData()
if err != nil {
return nil, err
}
chainIDs := make([]uint64, 0)
for _, network := range availableNetworks {
chainIDs = append(chainIDs, network.ChainID)
}
chainIDs := maps.Keys(clients)
currencies := make([]string, 0)
currency, err := r.accountsDB.GetCurrency()
if err != nil {
return nil, err
}
currencies = append(currencies, currency)
currencies = append(currencies, getFixedCurrencies()...)
allTokens, err := r.tokenManager.GetTokensByChainIDs(chainIDs)
if err != nil {
return nil, err
}
for _, network := range availableNetworks {
allTokens = append(allTokens, r.tokenManager.ToToken(network))
}
tokenAddresses := getTokenAddresses(allTokens)
clients, err := r.rpcClient.EthClients(chainIDs)
if err != nil {
return nil, err
}
balances, err := r.tokenManager.GetBalancesByChain(ctx, clients, addresses, tokenAddresses)
if err != nil {
log.Info("tokenManager.GetBalancesByChain error", "err", err)
@ -557,16 +474,16 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
verifiedTokens, unverifiedTokens := splitVerifiedTokens(allTokens)
tokenSymbols := make([]string, 0)
result := make(map[common.Address][]Token)
result := make(map[common.Address][]token.StorageToken)
for _, address := range addresses {
for _, tokenList := range [][]*token.Token{verifiedTokens, unverifiedTokens} {
for symbol, tokens := range getTokenBySymbols(tokenList) {
balancesPerChain := make(map[uint64]ChainBalance)
balancesPerChain := make(map[uint64]token.ChainBalance)
decimals := tokens[0].Decimals
isVisible := false
for _, token := range tokens {
hexBalance := balances[token.ChainID][address][token.Address]
for _, tok := range tokens {
hexBalance := balances[tok.ChainID][address][tok.Address]
balance := big.NewFloat(0.0)
if hexBalance != nil {
balance = new(big.Float).Quo(
@ -575,17 +492,17 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
)
}
hasError := false
if client, ok := clients[token.ChainID]; ok {
if client, ok := clients[tok.ChainID]; ok {
hasError = err != nil || !client.IsConnected()
}
if !isVisible {
isVisible = balance.Cmp(big.NewFloat(0.0)) > 0 || r.isCachedToken(cachedTokens, address, token.Symbol, token.ChainID)
isVisible = balance.Cmp(big.NewFloat(0.0)) > 0 || isCachedToken(cachedTokens, address, tok.Symbol, tok.ChainID)
}
balancesPerChain[token.ChainID] = ChainBalance{
balancesPerChain[tok.ChainID] = token.ChainBalance{
RawBalance: hexBalance.ToInt().String(),
Balance: balance,
Address: token.Address,
ChainID: token.ChainID,
Address: tok.Address,
ChainID: tok.ChainID,
HasError: hasError,
}
}
@ -594,15 +511,17 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
continue
}
walletToken := Token{
Name: tokens[0].Name,
Symbol: symbol,
walletToken := token.StorageToken{
Token: token.Token{
Name: tokens[0].Name,
Symbol: symbol,
Decimals: decimals,
PegSymbol: token.GetTokenPegSymbol(symbol),
Verified: tokens[0].Verified,
CommunityData: tokens[0].CommunityData,
Image: tokens[0].Image,
},
BalancesPerChain: balancesPerChain,
Decimals: decimals,
PegSymbol: token.GetTokenPegSymbol(symbol),
Verified: tokens[0].Verified,
CommunityData: tokens[0].CommunityData,
Image: tokens[0].Image,
}
tokenSymbols = append(tokenSymbols, symbol)
@ -653,32 +572,32 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
}
for address, tokens := range result {
for index, token := range tokens {
marketValuesPerCurrency := make(map[string]TokenMarketValues)
for index, tok := range tokens {
marketValuesPerCurrency := make(map[string]token.TokenMarketValues)
for _, currency := range currencies {
if _, ok := tokenMarketValues[token.Symbol]; !ok {
if _, ok := tokenMarketValues[tok.Symbol]; !ok {
continue
}
marketValuesPerCurrency[currency] = TokenMarketValues{
MarketCap: tokenMarketValues[token.Symbol].MKTCAP,
HighDay: tokenMarketValues[token.Symbol].HIGHDAY,
LowDay: tokenMarketValues[token.Symbol].LOWDAY,
ChangePctHour: tokenMarketValues[token.Symbol].CHANGEPCTHOUR,
ChangePctDay: tokenMarketValues[token.Symbol].CHANGEPCTDAY,
ChangePct24hour: tokenMarketValues[token.Symbol].CHANGEPCT24HOUR,
Change24hour: tokenMarketValues[token.Symbol].CHANGE24HOUR,
Price: prices[token.Symbol][currency],
marketValuesPerCurrency[currency] = token.TokenMarketValues{
MarketCap: tokenMarketValues[tok.Symbol].MKTCAP,
HighDay: tokenMarketValues[tok.Symbol].HIGHDAY,
LowDay: tokenMarketValues[tok.Symbol].LOWDAY,
ChangePctHour: tokenMarketValues[tok.Symbol].CHANGEPCTHOUR,
ChangePctDay: tokenMarketValues[tok.Symbol].CHANGEPCTDAY,
ChangePct24hour: tokenMarketValues[tok.Symbol].CHANGEPCT24HOUR,
Change24hour: tokenMarketValues[tok.Symbol].CHANGE24HOUR,
Price: prices[tok.Symbol][currency],
HasError: !r.marketManager.IsConnected,
}
}
if _, ok := tokenDetails[token.Symbol]; !ok {
if _, ok := tokenDetails[tok.Symbol]; !ok {
continue
}
result[address][index].Description = tokenDetails[token.Symbol].Description
result[address][index].AssetWebsiteURL = tokenDetails[token.Symbol].AssetWebsiteURL
result[address][index].BuiltOn = tokenDetails[token.Symbol].BuiltOn
result[address][index].Description = tokenDetails[tok.Symbol].Description
result[address][index].AssetWebsiteURL = tokenDetails[tok.Symbol].AssetWebsiteURL
result[address][index].BuiltOn = tokenDetails[tok.Symbol].BuiltOn
result[address][index].MarketValuesPerCurrency = marketValuesPerCurrency
}
}
@ -688,7 +607,7 @@ func (r *Reader) GetWalletToken(ctx context.Context, addresses []common.Address)
return result, r.persistence.SaveTokens(result)
}
func (r *Reader) isCachedToken(cachedTokens map[common.Address][]Token, address common.Address, symbol string, chainID uint64) bool {
func isCachedToken(cachedTokens map[common.Address][]token.StorageToken, address common.Address, symbol string, chainID uint64) bool {
if tokens, ok := cachedTokens[address]; ok {
for _, t := range tokens {
if t.Symbol != symbol {
@ -703,9 +622,9 @@ func (r *Reader) isCachedToken(cachedTokens map[common.Address][]Token, address
return false
}
// GetCachedWalletTokensWithoutMarketData returns the latest fetched balances, minus
// getCachedWalletTokensWithoutMarketData returns the latest fetched balances, minus
// price information
func (r *Reader) GetCachedWalletTokensWithoutMarketData() (map[common.Address][]Token, error) {
func (r *Reader) getCachedWalletTokensWithoutMarketData() (map[common.Address][]token.StorageToken, error) {
return r.persistence.GetTokens()
}
@ -714,3 +633,61 @@ func (r *Reader) updateTokenUpdateTimestamp(addresses []common.Address) {
r.lastWalletTokenUpdateTimestamp.Store(address, time.Now().Unix())
}
}
func (r *Reader) FetchBalances(ctx context.Context, clients map[uint64]chain.ClientInterface, addresses []common.Address) (map[common.Address][]token.StorageToken, error) {
cachedTokens, err := r.getCachedWalletTokensWithoutMarketData()
if err != nil {
return nil, err
}
chainIDs := maps.Keys(clients)
allTokens, err := r.tokenManager.GetTokensByChainIDs(chainIDs)
if err != nil {
return nil, err
}
connectedPerChain := map[uint64]bool{}
for chainID, client := range clients {
connectedPerChain[chainID] = client.IsConnected()
}
tokenAddresses := getTokenAddresses(allTokens)
balances, err := r.fetchBalances(ctx, clients, addresses, tokenAddresses)
if err != nil {
log.Error("failed to update balances", "err", err)
return nil, err
}
tokens := r.balancesToTokensByAddress(connectedPerChain, addresses, allTokens, balances, cachedTokens)
err = r.persistence.SaveTokens(tokens)
if err != nil {
log.Error("failed to save tokens", "err", err) // Do not return error, as it is not critical
}
r.updateTokenUpdateTimestamp(addresses)
r.balanceRefreshed()
return tokens, err
}
func (r *Reader) GetCachedBalances(clients map[uint64]chain.ClientInterface, addresses []common.Address) (map[common.Address][]token.StorageToken, error) {
cachedTokens, err := r.getCachedWalletTokensWithoutMarketData()
if err != nil {
return nil, err
}
chainIDs := maps.Keys(clients)
allTokens, err := r.tokenManager.GetTokensByChainIDs(chainIDs)
if err != nil {
return nil, err
}
connectedPerChain := map[uint64]bool{}
for chainID, client := range clients {
connectedPerChain[chainID] = client.IsConnected()
}
balances := tokensToBalancesPerChain(cachedTokens)
return r.balancesToTokensByAddress(connectedPerChain, addresses, allTokens, balances, cachedTokens), nil
}

File diff suppressed because it is too large Load Diff

View File

@ -103,7 +103,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, feed, accountFeed, accountsDB)
tokenManager := token.NewTokenManager(db, rpcClient, communityManager, rpcClient.NetworkManager, appDB, mediaServer, feed, accountFeed, accountsDB, token.NewPersistence(db))
tokenManager.Start()
savedAddressesManager := &SavedAddressesManager{db: db}
transactionManager := transfer.NewTransactionManager(transfer.NewMultiTransactionDB(db), gethManager, transactor, config, accountsDB, pendingTxManager, feed)
@ -114,7 +114,7 @@ func NewService(
cryptoCompare := cryptocompare.NewClient()
coingecko := coingecko.NewClient()
marketManager := market.NewManager(cryptoCompare, coingecko, feed)
reader := NewReader(rpcClient, tokenManager, marketManager, communityManager, accountsDB, NewPersistence(db), feed)
reader := NewReader(tokenManager, marketManager, token.NewPersistence(db), feed)
history := history.NewService(db, accountsDB, accountFeed, feed, rpcClient, tokenManager, marketManager, balanceCacher.Cache())
currency := currency.NewService(db, feed, tokenManager, marketManager)

View File

@ -1,6 +1,13 @@
package testutils
import "reflect"
import (
"reflect"
"sort"
"github.com/golang/mock/gomock"
"github.com/ethereum/go-ethereum/common"
)
const EthSymbol = "ETH"
const SntSymbol = "SNT"
@ -31,3 +38,85 @@ func Filter[T any](ss []T, test func(T) bool) (ret []T) {
}
return
}
// AddressSliceMatcher is a custom matcher for comparing common.Address slices regardless of order.
type AddressSliceMatcher struct {
expected []common.Address
}
func NewAddressSliceMatcher(expected []common.Address) gomock.Matcher {
return &AddressSliceMatcher{expected: expected}
}
func (m *AddressSliceMatcher) Matches(x interface{}) bool {
actual, ok := x.([]common.Address)
if !ok {
return false
}
if len(m.expected) != len(actual) {
return false
}
// Create copies of the slices to sort them
expectedCopy := make([]common.Address, len(m.expected))
actualCopy := make([]common.Address, len(actual))
copy(expectedCopy, m.expected)
copy(actualCopy, actual)
sort.Slice(expectedCopy, func(i, j int) bool { return expectedCopy[i].Hex() < expectedCopy[j].Hex() })
sort.Slice(actualCopy, func(i, j int) bool { return actualCopy[i].Hex() < actualCopy[j].Hex() })
for i := range expectedCopy {
if expectedCopy[i] != actualCopy[i] {
return false
}
}
return true
}
func (m *AddressSliceMatcher) String() string {
return "matches Address slice regardless of order"
}
// Uint64SliceMatcher is a custom matcher for comparing uint64 slices regardless of order.
type Uint64SliceMatcher struct {
expected []uint64
}
func NewUint64SliceMatcher(expected []uint64) gomock.Matcher {
return &Uint64SliceMatcher{expected: expected}
}
func (m *Uint64SliceMatcher) Matches(x interface{}) bool {
actual, ok := x.([]uint64)
if !ok {
return false
}
if len(m.expected) != len(actual) {
return false
}
// Create copies of the slices to sort them
expectedCopy := make([]uint64, len(m.expected))
actualCopy := make([]uint64, len(actual))
copy(expectedCopy, m.expected)
copy(actualCopy, actual)
sort.Slice(expectedCopy, func(i, j int) bool { return expectedCopy[i] < expectedCopy[j] })
sort.Slice(actualCopy, func(i, j int) bool { return actualCopy[i] < actualCopy[j] })
for i := range expectedCopy {
if expectedCopy[i] != actualCopy[i] {
return false
}
}
return true
}
func (m *Uint64SliceMatcher) String() string {
return "matches uint64 slice regardless of order"
}

View File

@ -1,4 +1,4 @@
package wallet
package token
import (
"context"
@ -8,6 +8,41 @@ import (
"github.com/ethereum/go-ethereum/common"
)
type TokenMarketValues struct {
MarketCap float64 `json:"marketCap"`
HighDay float64 `json:"highDay"`
LowDay float64 `json:"lowDay"`
ChangePctHour float64 `json:"changePctHour"`
ChangePctDay float64 `json:"changePctDay"`
ChangePct24hour float64 `json:"changePct24hour"`
Change24hour float64 `json:"change24hour"`
Price float64 `json:"price"`
HasError bool `json:"hasError"`
}
type StorageToken struct {
Token
BalancesPerChain map[uint64]ChainBalance `json:"balancesPerChain"`
Description string `json:"description"`
AssetWebsiteURL string `json:"assetWebsiteUrl"`
BuiltOn string `json:"builtOn"`
MarketValuesPerCurrency map[string]TokenMarketValues `json:"marketValuesPerCurrency"`
}
type ChainBalance struct {
RawBalance string `json:"rawBalance"`
Balance *big.Float `json:"balance"`
Balance1DayAgo string `json:"balance1DayAgo"`
Address common.Address `json:"address"`
ChainID uint64 `json:"chainId"`
HasError bool `json:"hasError"`
}
type TokenBalancesStorage interface {
SaveTokens(tokens map[common.Address][]StorageToken) error
GetTokens() (map[common.Address][]StorageToken, error)
}
type Persistence struct {
db *sql.DB
}
@ -16,7 +51,7 @@ func NewPersistence(db *sql.DB) *Persistence {
return &Persistence{db: db}
}
func (p *Persistence) SaveTokens(tokens map[common.Address][]Token) (err error) {
func (p *Persistence) SaveTokens(tokens map[common.Address][]StorageToken) (err error) {
tx, err := p.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return
@ -48,7 +83,7 @@ func (p *Persistence) SaveTokens(tokens map[common.Address][]Token) (err error)
return nil
}
func (p *Persistence) GetTokens() (map[common.Address][]Token, error) {
func (p *Persistence) GetTokens() (map[common.Address][]StorageToken, error) {
rows, err := p.db.Query(`SELECT user_address, token_name, token_symbol, token_address, token_decimals, token_description, token_url, balance, raw_balance, chain_id FROM token_balances `)
if err != nil {
return nil, err
@ -56,11 +91,11 @@ func (p *Persistence) GetTokens() (map[common.Address][]Token, error) {
defer rows.Close()
acc := make(map[common.Address]map[string]Token)
acc := make(map[common.Address]map[string]StorageToken)
for rows.Next() {
var addressStr, balance, rawBalance, tokenAddress string
token := Token{}
token := StorageToken{}
var chainID uint64
err := rows.Scan(&addressStr, &token.Name, &token.Symbol, &tokenAddress, &token.Decimals, &token.Description, &token.AssetWebsiteURL, &balance, &rawBalance, &chainID)
@ -68,10 +103,12 @@ func (p *Persistence) GetTokens() (map[common.Address][]Token, error) {
return nil, err
}
token.Address = common.HexToAddress(tokenAddress)
token.ChainID = chainID
address := common.HexToAddress(addressStr)
if acc[address] == nil {
acc[address] = make(map[string]Token)
acc[address] = make(map[string]StorageToken)
}
if acc[address][token.Name].Name == "" {
@ -95,7 +132,7 @@ func (p *Persistence) GetTokens() (map[common.Address][]Token, error) {
}
}
result := make(map[common.Address][]Token)
result := make(map[common.Address][]StorageToken)
for address, tks := range acc {
for _, t := range tks {

View File

@ -1,4 +1,4 @@
package wallet
package token
import (
"math/big"
@ -21,7 +21,7 @@ func TestSaveTokens(t *testing.T) {
persistence := NewPersistence(db)
require.NotNil(t, persistence)
tokens := make(map[common.Address][]Token)
tokens := make(map[common.Address][]StorageToken)
address1 := common.HexToAddress("0xdAC17F958D2ee523a2206206994597C13D831ec7")
address2 := common.HexToAddress("0x5e4e65926ba27467555eb562121fac00d24e9dd2")
@ -31,10 +31,12 @@ func TestSaveTokens(t *testing.T) {
var chain1 uint64 = 1
var chain2 uint64 = 2
token1 := Token{
Name: "token-1",
Symbol: "TT1",
Decimals: 10,
token1 := StorageToken{
Token: Token{
Name: "token-1",
Symbol: "TT1",
Decimals: 10,
},
BalancesPerChain: make(map[uint64]ChainBalance),
Description: "description-1",
AssetWebsiteURL: "url-1",
@ -54,10 +56,12 @@ func TestSaveTokens(t *testing.T) {
ChainID: chain2,
}
token2 := Token{
Name: "token-2",
Symbol: "TT2",
Decimals: 11,
token2 := StorageToken{
Token: Token{
Name: "token-2",
Symbol: "TT2",
Decimals: 11,
},
BalancesPerChain: make(map[uint64]ChainBalance),
Description: "description-2",
AssetWebsiteURL: "url-2",
@ -70,10 +74,12 @@ func TestSaveTokens(t *testing.T) {
ChainID: chain1,
}
token3 := Token{
Name: "token-3",
Symbol: "TT3",
Decimals: 11,
token3 := StorageToken{
Token: Token{
Name: "token-3",
Symbol: "TT3",
Decimals: 11,
},
BalancesPerChain: make(map[uint64]ChainBalance),
Description: "description-3",
AssetWebsiteURL: "url-3",
@ -86,9 +92,9 @@ func TestSaveTokens(t *testing.T) {
ChainID: chain1,
}
tokens[address1] = []Token{token1, token2}
tokens[address1] = []StorageToken{token1, token2}
tokens[address2] = []Token{token3}
tokens[address2] = []StorageToken{token3}
require.NoError(t, persistence.SaveTokens(tokens))
@ -98,7 +104,7 @@ func TestSaveTokens(t *testing.T) {
require.NotNil(t, actualTokens[address1])
require.Len(t, actualTokens[address1], 2)
var actualToken1, actualToken2, actualToken3 Token
var actualToken1, actualToken2, actualToken3 StorageToken
if actualTokens[address1][0].Name == "token-1" {
actualToken1 = actualTokens[address1][0]
actualToken2 = actualTokens[address1][1]

View File

@ -0,0 +1,66 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: services/wallet/token/balance_persistence.go
// Package mock_balance_persistence is a generated GoMock package.
package mock_balance_persistence
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
common "github.com/ethereum/go-ethereum/common"
token "github.com/status-im/status-go/services/wallet/token"
)
// MockTokenBalancesStorage is a mock of TokenBalancesStorage interface
type MockTokenBalancesStorage struct {
ctrl *gomock.Controller
recorder *MockTokenBalancesStorageMockRecorder
}
// MockTokenBalancesStorageMockRecorder is the mock recorder for MockTokenBalancesStorage
type MockTokenBalancesStorageMockRecorder struct {
mock *MockTokenBalancesStorage
}
// NewMockTokenBalancesStorage creates a new mock instance
func NewMockTokenBalancesStorage(ctrl *gomock.Controller) *MockTokenBalancesStorage {
mock := &MockTokenBalancesStorage{ctrl: ctrl}
mock.recorder = &MockTokenBalancesStorageMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockTokenBalancesStorage) EXPECT() *MockTokenBalancesStorageMockRecorder {
return m.recorder
}
// SaveTokens mocks base method
func (m *MockTokenBalancesStorage) SaveTokens(tokens map[common.Address][]token.StorageToken) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveTokens", tokens)
ret0, _ := ret[0].(error)
return ret0
}
// SaveTokens indicates an expected call of SaveTokens
func (mr *MockTokenBalancesStorageMockRecorder) SaveTokens(tokens interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveTokens", reflect.TypeOf((*MockTokenBalancesStorage)(nil).SaveTokens), tokens)
}
// GetTokens mocks base method
func (m *MockTokenBalancesStorage) GetTokens() (map[common.Address][]token.StorageToken, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTokens")
ret0, _ := ret[0].(map[common.Address][]token.StorageToken)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTokens indicates an expected call of GetTokens
func (mr *MockTokenBalancesStorageMockRecorder) GetTokens() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTokens", reflect.TypeOf((*MockTokenBalancesStorage)(nil).GetTokens))
}

View File

@ -0,0 +1,115 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: services/wallet/token/token.go
// Package mock_token is a generated GoMock package.
package mock_token
import (
context "context"
big "math/big"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
common "github.com/ethereum/go-ethereum/common"
hexutil "github.com/ethereum/go-ethereum/common/hexutil"
chain "github.com/status-im/status-go/rpc/chain"
token "github.com/status-im/status-go/services/wallet/token"
)
// MockManagerInterface is a mock of ManagerInterface interface
type MockManagerInterface struct {
ctrl *gomock.Controller
recorder *MockManagerInterfaceMockRecorder
}
// MockManagerInterfaceMockRecorder is the mock recorder for MockManagerInterface
type MockManagerInterfaceMockRecorder struct {
mock *MockManagerInterface
}
// NewMockManagerInterface creates a new mock instance
func NewMockManagerInterface(ctrl *gomock.Controller) *MockManagerInterface {
mock := &MockManagerInterface{ctrl: ctrl}
mock.recorder = &MockManagerInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockManagerInterface) EXPECT() *MockManagerInterfaceMockRecorder {
return m.recorder
}
// LookupTokenIdentity mocks base method
func (m *MockManagerInterface) LookupTokenIdentity(chainID uint64, address common.Address, native bool) *token.Token {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LookupTokenIdentity", chainID, address, native)
ret0, _ := ret[0].(*token.Token)
return ret0
}
// LookupTokenIdentity indicates an expected call of LookupTokenIdentity
func (mr *MockManagerInterfaceMockRecorder) LookupTokenIdentity(chainID, address, native interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupTokenIdentity", reflect.TypeOf((*MockManagerInterface)(nil).LookupTokenIdentity), chainID, address, native)
}
// LookupToken mocks base method
func (m *MockManagerInterface) LookupToken(chainID *uint64, tokenSymbol string) (*token.Token, bool) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LookupToken", chainID, tokenSymbol)
ret0, _ := ret[0].(*token.Token)
ret1, _ := ret[1].(bool)
return ret0, ret1
}
// LookupToken indicates an expected call of LookupToken
func (mr *MockManagerInterfaceMockRecorder) LookupToken(chainID, tokenSymbol interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupToken", reflect.TypeOf((*MockManagerInterface)(nil).LookupToken), chainID, tokenSymbol)
}
// GetTokensByChainIDs mocks base method
func (m *MockManagerInterface) GetTokensByChainIDs(chainIDs []uint64) ([]*token.Token, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTokensByChainIDs", chainIDs)
ret0, _ := ret[0].([]*token.Token)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTokensByChainIDs indicates an expected call of GetTokensByChainIDs
func (mr *MockManagerInterfaceMockRecorder) GetTokensByChainIDs(chainIDs interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTokensByChainIDs", reflect.TypeOf((*MockManagerInterface)(nil).GetTokensByChainIDs), chainIDs)
}
// GetBalancesByChain mocks base method
func (m *MockManagerInterface) GetBalancesByChain(parent context.Context, clients map[uint64]chain.ClientInterface, accounts, tokens []common.Address) (map[uint64]map[common.Address]map[common.Address]*hexutil.Big, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBalancesByChain", parent, clients, accounts, tokens)
ret0, _ := ret[0].(map[uint64]map[common.Address]map[common.Address]*hexutil.Big)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBalancesByChain indicates an expected call of GetBalancesByChain
func (mr *MockManagerInterfaceMockRecorder) GetBalancesByChain(parent, clients, accounts, tokens interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalancesByChain", reflect.TypeOf((*MockManagerInterface)(nil).GetBalancesByChain), parent, clients, accounts, tokens)
}
// GetTokenHistoricalBalance mocks base method
func (m *MockManagerInterface) GetTokenHistoricalBalance(account common.Address, chainID uint64, symbol string, timestamp int64) (*big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTokenHistoricalBalance", account, chainID, symbol, timestamp)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTokenHistoricalBalance indicates an expected call of GetTokenHistoricalBalance
func (mr *MockManagerInterfaceMockRecorder) GetTokenHistoricalBalance(account, chainID, symbol, timestamp interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTokenHistoricalBalance", reflect.TypeOf((*MockManagerInterface)(nil).GetTokenHistoricalBalance), account, chainID, symbol, timestamp)
}

View File

@ -94,22 +94,26 @@ type storeMap = map[uint64]addressTokenMap
type ManagerInterface interface {
LookupTokenIdentity(chainID uint64, address common.Address, native bool) *Token
LookupToken(chainID *uint64, tokenSymbol string) (token *Token, isNative bool)
GetTokensByChainIDs(chainIDs []uint64) ([]*Token, error)
GetBalancesByChain(parent context.Context, clients map[uint64]chain.ClientInterface, accounts, tokens []common.Address) (map[uint64]map[common.Address]map[common.Address]*hexutil.Big, error)
GetTokenHistoricalBalance(account common.Address, chainID uint64, symbol string, timestamp int64) (*big.Int, error)
}
// Manager is used for accessing token store. It changes the token store based on overridden tokens
type Manager struct {
db *sql.DB
RPCClient *rpc.Client
ContractMaker *contracts.ContractMaker
networkManager *network.Manager
stores []store // Set on init, not changed afterwards
communityTokensDB *communitytokensdatabase.Database
communityManager *community.Manager
mediaServer *server.MediaServer
walletFeed *event.Feed
accountFeed *event.Feed
accountWatcher *accountsevent.Watcher
accountsDB *accounts.Database
db *sql.DB
RPCClient *rpc.Client
ContractMaker *contracts.ContractMaker
networkManager *network.Manager
stores []store // Set on init, not changed afterwards
communityTokensDB *communitytokensdatabase.Database
communityManager *community.Manager
mediaServer *server.MediaServer
walletFeed *event.Feed
accountFeed *event.Feed
accountWatcher *accountsevent.Watcher
accountsDB *accounts.Database
tokenBalancesStorage TokenBalancesStorage
tokens []*Token
@ -167,24 +171,26 @@ func NewTokenManager(
walletFeed *event.Feed,
accountFeed *event.Feed,
accountsDB *accounts.Database,
tokenBalancesStorage TokenBalancesStorage,
) *Manager {
maker, _ := contracts.NewContractMaker(RPCClient)
stores := []store{newUniswapStore(), newDefaultStore()}
tokens := prepareTokens(networkManager, stores)
return &Manager{
db: db,
RPCClient: RPCClient,
ContractMaker: maker,
networkManager: networkManager,
communityManager: communityManager,
stores: stores,
communityTokensDB: communitytokensdatabase.NewCommunityTokensDatabase(appDB),
tokens: tokens,
mediaServer: mediaServer,
walletFeed: walletFeed,
accountFeed: accountFeed,
accountsDB: accountsDB,
db: db,
RPCClient: RPCClient,
ContractMaker: maker,
networkManager: networkManager,
communityManager: communityManager,
stores: stores,
communityTokensDB: communitytokensdatabase.NewCommunityTokensDatabase(appDB),
tokens: tokens,
mediaServer: mediaServer,
walletFeed: walletFeed,
accountFeed: accountFeed,
accountsDB: accountsDB,
tokenBalancesStorage: tokenBalancesStorage,
}
}
@ -360,13 +366,43 @@ func (tm *Manager) MarkAsPreviouslyOwnedToken(token *Token, owner common.Address
if (owner == common.Address{}) {
return false, errors.New("owner is nil")
}
count := 0
err := tm.db.QueryRow(`SELECT EXISTS(SELECT 1 FROM token_balances WHERE user_address = ? AND token_address = ? AND chain_id = ?)`, owner.Hex(), token.Address.Hex(), token.ChainID).Scan(&count)
if err != nil || count > 0 {
tokens, err := tm.tokenBalancesStorage.GetTokens()
if err != nil {
return false, err
}
_, err = tm.db.Exec(`INSERT INTO token_balances(user_address,token_name,token_symbol,token_address,token_decimals,chain_id,token_decimals,raw_balance,balance) VALUES (?,?,?,?,?,?,?,?,?)`, owner.Hex(), token.Name, token.Symbol, token.Address.Hex(), token.Decimals, token.ChainID, 0, "0", "0")
return true, err
if tokens[owner] == nil {
tokens[owner] = make([]StorageToken, 0)
} else {
for _, t := range tokens[owner] {
if t.Address == token.Address && t.ChainID == token.ChainID && t.Symbol == token.Symbol {
log.Info("Token already marked as previously owned", "token", token, "owner", owner)
return false, nil
}
}
}
// append token to the list of tokens
tokens[owner] = append(tokens[owner], StorageToken{
Token: *token,
BalancesPerChain: map[uint64]ChainBalance{
token.ChainID: {
RawBalance: "0",
Balance: &big.Float{},
Address: token.Address,
ChainID: token.ChainID,
},
},
})
// save the updated list of tokens
err = tm.tokenBalancesStorage.SaveTokens(tokens)
if err != nil {
return false, err
}
return true, nil
}
func (tm *Manager) discoverTokenCommunityID(ctx context.Context, token *Token, address common.Address) {
@ -917,37 +953,20 @@ func (tm *Manager) GetTokenHistoricalBalance(account common.Address, chainID uin
return &balance, nil
}
func (tm *Manager) GetPreviouslyOwnedTokens() (map[common.Address][]*Token, error) {
tokenMap := make(map[common.Address][]*Token)
rows, err := tm.db.Query("SELECT user_address, token_name, token_symbol, token_address, token_decimals, chain_id FROM token_balances")
func (tm *Manager) GetPreviouslyOwnedTokens() (map[common.Address][]Token, error) {
storageTokens, err := tm.tokenBalancesStorage.GetTokens()
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
token := &Token{}
var addressStr, tokenAddressStr string
err := rows.Scan(&addressStr, &token.Name, &token.Symbol, &tokenAddressStr, &token.Decimals, &token.ChainID)
if err != nil {
return nil, err
tokens := make(map[common.Address][]Token)
for account, storageToken := range storageTokens {
for _, token := range storageToken {
tokens[account] = append(tokens[account], token.Token)
}
address := common.HexToAddress(addressStr)
if (address == common.Address{}) {
continue
}
token.Address = common.HexToAddress(tokenAddressStr)
if (token.Address == common.Address{}) {
continue
}
if _, ok := tokenMap[address]; !ok {
tokenMap[address] = make([]*Token, 0)
}
tokenMap[address] = append(tokenMap[address], token)
}
return tokenMap, nil
return tokens, nil
}
func (tm *Manager) removeTokenBalances(account common.Address) error {

View File

@ -35,13 +35,14 @@ func setupTestTokenDB(t *testing.T) (*Manager, func()) {
require.NoError(t, err)
return &Manager{
db: db,
RPCClient: nil,
ContractMaker: nil,
networkManager: nil,
stores: nil,
communityTokensDB: nil,
communityManager: nil,
db: db,
RPCClient: nil,
ContractMaker: nil,
networkManager: nil,
stores: nil,
communityTokensDB: nil,
communityManager: nil,
tokenBalancesStorage: NewPersistence(db),
}, func() {
require.NoError(t, db.Close())
}
@ -335,7 +336,7 @@ func Test_removeTokenBalanceOnEventAccountRemoved(t *testing.T) {
mediaServer, err := mediaserver.NewMediaServer(appDB, nil, nil, walletDB)
require.NoError(t, err)
manager := NewTokenManager(walletDB, rpcClient, nil, nm, appDB, mediaServer, nil, &accountFeed, accountsDB)
manager := NewTokenManager(walletDB, rpcClient, nil, nm, appDB, mediaServer, nil, &accountFeed, accountsDB, NewPersistence(walletDB))
// Insert balances for address
marked, err := manager.MarkAsPreviouslyOwnedToken(&Token{
@ -397,7 +398,7 @@ func Test_tokensListsValidity(t *testing.T) {
nm := network.NewManager(appDB)
manager := NewTokenManager(walletDB, nil, nil, nm, appDB, nil, nil, nil, accountsDB)
manager := NewTokenManager(walletDB, nil, nil, nm, appDB, nil, nil, nil, accountsDB, NewPersistence(walletDB))
require.NotNil(t, manager)
tokensListWrapper := manager.GetList()

View File

@ -1075,7 +1075,7 @@ func setupFindBlocksCommand(t *testing.T, accountAddress common.Address, fromBlo
}
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, nil, nil, nil)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
tokenManager.SetTokens([]*token.Token{
{
Address: tokenTXXAddress,
@ -1337,7 +1337,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, nil, nil, nil)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
tokenManager.SetTokens([]*token.Token{
{
@ -1457,7 +1457,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, nil, nil, nil)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
tokenManager.SetTokens([]*token.Token{
{
@ -1537,7 +1537,7 @@ func TestFetchNewBlocksCommand_nonceDetection(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, nil, nil, nil)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
wdb := NewDB(db)
blockChannel := make(chan []*DBHeader, 10)
@ -1652,7 +1652,7 @@ 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, nil, nil, nil)
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
tokenManager.SetTokens([]*token.Token{
{