github.com/status-im/status-go@v1.1.0/services/wallet/api.go (about)

     1  package wallet
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"math/big"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethereum/go-ethereum/common/hexutil"
    15  	"github.com/ethereum/go-ethereum/ethclient"
    16  	"github.com/ethereum/go-ethereum/log"
    17  	gethrpc "github.com/ethereum/go-ethereum/rpc"
    18  	signercore "github.com/ethereum/go-ethereum/signer/core/apitypes"
    19  	abi_spec "github.com/status-im/status-go/abi-spec"
    20  	"github.com/status-im/status-go/account"
    21  	"github.com/status-im/status-go/eth-node/crypto"
    22  	"github.com/status-im/status-go/eth-node/types"
    23  	"github.com/status-im/status-go/params"
    24  	"github.com/status-im/status-go/rpc/network"
    25  	"github.com/status-im/status-go/services/typeddata"
    26  	"github.com/status-im/status-go/services/wallet/activity"
    27  	"github.com/status-im/status-go/services/wallet/collectibles"
    28  	wcommon "github.com/status-im/status-go/services/wallet/common"
    29  	"github.com/status-im/status-go/services/wallet/currency"
    30  	"github.com/status-im/status-go/services/wallet/history"
    31  	"github.com/status-im/status-go/services/wallet/onramp"
    32  	"github.com/status-im/status-go/services/wallet/requests"
    33  	"github.com/status-im/status-go/services/wallet/router"
    34  	"github.com/status-im/status-go/services/wallet/router/fees"
    35  	"github.com/status-im/status-go/services/wallet/router/pathprocessor"
    36  	"github.com/status-im/status-go/services/wallet/thirdparty"
    37  	"github.com/status-im/status-go/services/wallet/token"
    38  	"github.com/status-im/status-go/services/wallet/transfer"
    39  	"github.com/status-im/status-go/services/wallet/walletconnect"
    40  	"github.com/status-im/status-go/transactions"
    41  )
    42  
    43  func NewAPI(s *Service) *API {
    44  	rpcClient := s.GetRPCClient()
    45  	transactor := s.GetTransactor()
    46  	tokenManager := s.GetTokenManager()
    47  	ensService := s.GetEnsService()
    48  	stickersService := s.GetStickersService()
    49  	featureFlags := s.FeatureFlags()
    50  
    51  	router := router.NewRouter(rpcClient, transactor, tokenManager, s.GetMarketManager(), s.GetCollectiblesService(),
    52  		s.GetCollectiblesManager(), ensService, stickersService)
    53  
    54  	transfer := pathprocessor.NewTransferProcessor(rpcClient, transactor)
    55  	router.AddPathProcessor(transfer)
    56  
    57  	erc721Transfer := pathprocessor.NewERC721Processor(rpcClient, transactor)
    58  	router.AddPathProcessor(erc721Transfer)
    59  
    60  	erc1155Transfer := pathprocessor.NewERC1155Processor(rpcClient, transactor)
    61  	router.AddPathProcessor(erc1155Transfer)
    62  
    63  	hop := pathprocessor.NewHopBridgeProcessor(rpcClient, transactor, tokenManager, rpcClient.NetworkManager)
    64  	router.AddPathProcessor(hop)
    65  
    66  	if featureFlags.EnableCelerBridge {
    67  		// TODO: Celar Bridge is out of scope for 2.30, check it thoroughly once we decide to include it again
    68  		cbridge := pathprocessor.NewCelerBridgeProcessor(rpcClient, transactor, tokenManager)
    69  		router.AddPathProcessor(cbridge)
    70  	}
    71  
    72  	paraswap := pathprocessor.NewSwapParaswapProcessor(rpcClient, transactor, tokenManager)
    73  	router.AddPathProcessor(paraswap)
    74  
    75  	ensRegister := pathprocessor.NewENSRegisterProcessor(rpcClient, transactor, ensService)
    76  	router.AddPathProcessor(ensRegister)
    77  
    78  	ensRelease := pathprocessor.NewENSReleaseProcessor(rpcClient, transactor, ensService)
    79  	router.AddPathProcessor(ensRelease)
    80  
    81  	ensPublicKey := pathprocessor.NewENSPublicKeyProcessor(rpcClient, transactor, ensService)
    82  	router.AddPathProcessor(ensPublicKey)
    83  
    84  	buyStickers := pathprocessor.NewStickersBuyProcessor(rpcClient, transactor, stickersService)
    85  	router.AddPathProcessor(buyStickers)
    86  
    87  	return &API{s, s.reader, router}
    88  }
    89  
    90  // API is class with methods available over RPC.
    91  type API struct {
    92  	s      *Service
    93  	reader *Reader
    94  	router *router.Router
    95  }
    96  
    97  func (api *API) StartWallet(ctx context.Context) error {
    98  	return api.reader.Start()
    99  }
   100  
   101  func (api *API) StopWallet(ctx context.Context) error {
   102  	api.router.Stop()
   103  	return api.s.Stop()
   104  }
   105  
   106  func (api *API) GetPairingsJSONFileContent() ([]byte, error) {
   107  	return api.s.keycardPairings.GetPairingsJSONFileContent()
   108  }
   109  
   110  func (api *API) SetPairingsJSONFileContent(content []byte) error {
   111  	return api.s.keycardPairings.SetPairingsJSONFileContent(content)
   112  }
   113  
   114  // Used by mobile
   115  func (api *API) GetWalletToken(ctx context.Context, addresses []common.Address) (map[common.Address][]token.StorageToken, error) {
   116  	currency, err := api.s.accountsDB.GetCurrency()
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	activeNetworks, err := api.s.rpcClient.NetworkManager.GetActiveNetworks()
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	chainIDs := wcommon.NetworksToChainIDs(activeNetworks)
   127  	clients, err := api.s.rpcClient.EthClients(chainIDs)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	return api.reader.GetWalletToken(ctx, clients, addresses, currency)
   133  }
   134  
   135  // GetBalancesByChain return a map with key as chain id and value as map of account address and map of token address and balance
   136  // [chainID][account][token]balance
   137  func (api *API) GetBalancesByChain(ctx context.Context, chainIDs []uint64, addresses, tokens []common.Address) (map[uint64]map[common.Address]map[common.Address]*hexutil.Big, error) {
   138  	clients, err := api.s.rpcClient.EthClients(chainIDs)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	return api.s.tokenManager.GetBalancesByChain(ctx, clients, addresses, tokens)
   144  }
   145  
   146  func (api *API) FetchOrGetCachedWalletBalances(ctx context.Context, addresses []common.Address) (map[common.Address][]token.StorageToken, error) {
   147  	activeNetworks, err := api.s.rpcClient.NetworkManager.GetActiveNetworks()
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	chainIDs := wcommon.NetworksToChainIDs(activeNetworks)
   153  	clients, err := api.s.rpcClient.EthClients(chainIDs)
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  
   158  	return api.reader.FetchOrGetCachedWalletBalances(ctx, clients, addresses, false)
   159  }
   160  
   161  type DerivedAddress struct {
   162  	Address        common.Address `json:"address"`
   163  	PublicKey      types.HexBytes `json:"public-key,omitempty"`
   164  	Path           string         `json:"path"`
   165  	HasActivity    bool           `json:"hasActivity"`
   166  	AlreadyCreated bool           `json:"alreadyCreated"`
   167  }
   168  
   169  // @deprecated
   170  func (api *API) CheckRecentHistory(ctx context.Context, addresses []common.Address) error {
   171  	return api.s.transferController.CheckRecentHistory([]uint64{api.s.rpcClient.UpstreamChainID}, addresses)
   172  }
   173  
   174  // @deprecated
   175  func (api *API) CheckRecentHistoryForChainIDs(ctx context.Context, chainIDs []uint64, addresses []common.Address) error {
   176  	return api.s.transferController.CheckRecentHistory(chainIDs, addresses)
   177  }
   178  
   179  func hexBigToBN(hexBig *hexutil.Big) *big.Int {
   180  	var bN *big.Int
   181  	if hexBig != nil {
   182  		bN = hexBig.ToInt()
   183  	}
   184  	return bN
   185  }
   186  
   187  // @deprecated
   188  // GetTransfersByAddress returns transfers for a single address
   189  func (api *API) GetTransfersByAddress(ctx context.Context, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) {
   190  	log.Debug("[WalletAPI:: GetTransfersByAddress] get transfers for an address", "address", address)
   191  	var intLimit = int64(1)
   192  	if limit != nil {
   193  		intLimit = limit.ToInt().Int64()
   194  	}
   195  	return api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, address, hexBigToBN(toBlock), intLimit, fetchMore)
   196  }
   197  
   198  // @deprecated
   199  // LoadTransferByHash loads transfer to the database
   200  // Only used by status-mobile
   201  func (api *API) LoadTransferByHash(ctx context.Context, address common.Address, hash common.Hash) error {
   202  	log.Debug("[WalletAPI:: LoadTransferByHash] get transfer by hash", "address", address, "hash", hash)
   203  	return api.s.transferController.LoadTransferByHash(ctx, api.s.rpcClient, address, hash)
   204  }
   205  
   206  // @deprecated
   207  func (api *API) GetTransfersByAddressAndChainID(ctx context.Context, chainID uint64, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) {
   208  	log.Debug("[WalletAPI:: GetTransfersByAddressAndChainIDs] get transfers for an address", "address", address)
   209  	return api.s.transferController.GetTransfersByAddress(ctx, chainID, address, hexBigToBN(toBlock), limit.ToInt().Int64(), fetchMore)
   210  }
   211  
   212  // @deprecated
   213  func (api *API) GetTransfersForIdentities(ctx context.Context, identities []transfer.TransactionIdentity) ([]transfer.View, error) {
   214  	log.Debug("wallet.api.GetTransfersForIdentities", "identities.len", len(identities))
   215  
   216  	return api.s.transferController.GetTransfersForIdentities(ctx, identities)
   217  }
   218  
   219  func (api *API) FetchDecodedTxData(ctx context.Context, data string) (*thirdparty.DataParsed, error) {
   220  	log.Debug("[Wallet: FetchDecodedTxData]")
   221  
   222  	return api.s.decoder.Decode(data)
   223  }
   224  
   225  // GetBalanceHistory retrieves token balance history for token identity on multiple chains
   226  func (api *API) GetBalanceHistory(ctx context.Context, chainIDs []uint64, addresses []common.Address, tokenSymbol string, currencySymbol string, timeInterval history.TimeInterval) ([]*history.ValuePoint, error) {
   227  	log.Debug("wallet.api.GetBalanceHistory", "chainIDs", chainIDs, "address", addresses, "tokenSymbol", tokenSymbol, "currencySymbol", currencySymbol, "timeInterval", timeInterval)
   228  
   229  	var fromTimestamp uint64
   230  	now := uint64(time.Now().UTC().Unix())
   231  	switch timeInterval {
   232  	case history.BalanceHistoryAllTime:
   233  		fromTimestamp = 0
   234  	case history.BalanceHistory1Year:
   235  		fallthrough
   236  	case history.BalanceHistory6Months:
   237  		fallthrough
   238  	case history.BalanceHistory1Month:
   239  		fallthrough
   240  	case history.BalanceHistory7Days:
   241  		fromTimestamp = now - history.TimeIntervalDurationSecs(timeInterval)
   242  	default:
   243  		return nil, fmt.Errorf("unknown time interval: %v", timeInterval)
   244  	}
   245  
   246  	return api.GetBalanceHistoryRange(ctx, chainIDs, addresses, tokenSymbol, currencySymbol, fromTimestamp, now)
   247  }
   248  
   249  // GetBalanceHistoryRange retrieves token balance history for token identity on multiple chains for a time range
   250  // 'toTimestamp' is ignored for now, but will be used in the future to limit the range of the history
   251  func (api *API) GetBalanceHistoryRange(ctx context.Context, chainIDs []uint64, addresses []common.Address, tokenSymbol string, currencySymbol string, fromTimestamp uint64, _ uint64) ([]*history.ValuePoint, error) {
   252  	log.Debug("wallet.api.GetBalanceHistoryRange", "chainIDs", chainIDs, "address", addresses, "tokenSymbol", tokenSymbol, "currencySymbol", currencySymbol, "fromTimestamp", fromTimestamp)
   253  	return api.s.history.GetBalanceHistory(ctx, chainIDs, addresses, tokenSymbol, currencySymbol, fromTimestamp)
   254  }
   255  
   256  func (api *API) GetTokenList(ctx context.Context) (*token.ListWrapper, error) {
   257  	log.Debug("call to get token list")
   258  	rst := api.s.tokenManager.GetList()
   259  	log.Debug("result from token list", "len", len(rst.Data))
   260  	return rst, nil
   261  }
   262  
   263  // @deprecated
   264  func (api *API) GetTokens(ctx context.Context, chainID uint64) ([]*token.Token, error) {
   265  	log.Debug("call to get tokens")
   266  	rst, err := api.s.tokenManager.GetTokens(chainID)
   267  	log.Debug("result from token store", "len", len(rst))
   268  	return rst, err
   269  }
   270  
   271  // @deprecated
   272  func (api *API) GetCustomTokens(ctx context.Context) ([]*token.Token, error) {
   273  	log.Debug("call to get custom tokens")
   274  	rst, err := api.s.tokenManager.GetCustoms(true)
   275  	log.Debug("result from database for custom tokens", "len", len(rst))
   276  	return rst, err
   277  }
   278  
   279  func (api *API) DiscoverToken(ctx context.Context, chainID uint64, address common.Address) (*token.Token, error) {
   280  	log.Debug("call to get discover token")
   281  	token, err := api.s.tokenManager.DiscoverToken(ctx, chainID, address)
   282  	return token, err
   283  }
   284  
   285  func (api *API) AddCustomToken(ctx context.Context, token token.Token) error {
   286  	log.Debug("call to create or edit custom token")
   287  	if token.ChainID == 0 {
   288  		token.ChainID = api.s.rpcClient.UpstreamChainID
   289  	}
   290  	err := api.s.tokenManager.UpsertCustom(token)
   291  	log.Debug("result from database for create or edit custom token", "err", err)
   292  	return err
   293  }
   294  
   295  // @deprecated
   296  func (api *API) DeleteCustomToken(ctx context.Context, address common.Address) error {
   297  	log.Debug("call to remove custom token")
   298  	err := api.s.tokenManager.DeleteCustom(api.s.rpcClient.UpstreamChainID, address)
   299  	log.Debug("result from database for remove custom token", "err", err)
   300  	return err
   301  }
   302  
   303  func (api *API) DeleteCustomTokenByChainID(ctx context.Context, chainID uint64, address common.Address) error {
   304  	log.Debug("call to remove custom token")
   305  	err := api.s.tokenManager.DeleteCustom(chainID, address)
   306  	log.Debug("result from database for remove custom token", "err", err)
   307  	return err
   308  }
   309  
   310  // @deprecated
   311  // Not used by status-desktop anymore
   312  func (api *API) GetPendingTransactions(ctx context.Context) ([]*transactions.PendingTransaction, error) {
   313  	log.Debug("wallet.api.GetPendingTransactions")
   314  	rst, err := api.s.pendingTxManager.GetAllPending()
   315  	log.Debug("wallet.api.GetPendingTransactions RESULT", "len", len(rst))
   316  	return rst, err
   317  }
   318  
   319  // @deprecated
   320  // Not used by status-desktop anymore
   321  func (api *API) GetPendingTransactionsForIdentities(ctx context.Context, identities []transfer.TransactionIdentity) (
   322  	result []*transactions.PendingTransaction, err error) {
   323  
   324  	log.Debug("wallet.api.GetPendingTransactionsForIdentities")
   325  
   326  	result = make([]*transactions.PendingTransaction, 0, len(identities))
   327  	var pt *transactions.PendingTransaction
   328  	for _, identity := range identities {
   329  		pt, err = api.s.pendingTxManager.GetPendingEntry(identity.ChainID, identity.Hash)
   330  		result = append(result, pt)
   331  	}
   332  
   333  	log.Debug("wallet.api.GetPendingTransactionsForIdentities RES", "len", len(result))
   334  	return
   335  }
   336  
   337  // @deprecated
   338  // TODO - #11861: Remove this and replace with EventPendingTransactionStatusChanged event and Delete to confirm the transaction where it is needed
   339  func (api *API) WatchTransactionByChainID(ctx context.Context, chainID uint64, transactionHash common.Hash) (err error) {
   340  	log.Debug("wallet.api.WatchTransactionByChainID", "chainID", chainID, "transactionHash", transactionHash)
   341  	defer func() {
   342  		log.Debug("wallet.api.WatchTransactionByChainID return", "err", err, "chainID", chainID, "transactionHash", transactionHash)
   343  	}()
   344  
   345  	return api.s.transactionManager.WatchTransaction(ctx, chainID, transactionHash)
   346  }
   347  
   348  func (api *API) GetCryptoOnRamps(ctx context.Context) ([]onramp.CryptoOnRamp, error) {
   349  	log.Debug("call to GetCryptoOnRamps")
   350  	return api.s.cryptoOnRampManager.GetProviders(ctx)
   351  }
   352  
   353  func (api *API) GetCryptoOnRampURL(ctx context.Context, providerID string, parameters onramp.Parameters) (string, error) {
   354  	log.Debug("call to GetCryptoOnRampURL")
   355  	return api.s.cryptoOnRampManager.GetURL(ctx, providerID, parameters)
   356  }
   357  
   358  /*
   359     Collectibles API Start
   360  */
   361  
   362  func (api *API) FetchCachedBalancesByOwnerAndContractAddress(ctx context.Context, chainID wcommon.ChainID, ownerAddress common.Address, contractAddresses []common.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
   363  	log.Debug("call to FetchCachedBalancesByOwnerAndContractAddress")
   364  
   365  	return api.s.collectiblesManager.FetchCachedBalancesByOwnerAndContractAddress(ctx, chainID, ownerAddress, contractAddresses)
   366  }
   367  
   368  func (api *API) FetchBalancesByOwnerAndContractAddress(ctx context.Context, chainID wcommon.ChainID, ownerAddress common.Address, contractAddresses []common.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
   369  	log.Debug("call to FetchBalancesByOwnerAndContractAddress")
   370  
   371  	return api.s.collectiblesManager.FetchBalancesByOwnerAndContractAddress(ctx, chainID, ownerAddress, contractAddresses)
   372  }
   373  
   374  func (api *API) GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error) {
   375  	return api.s.collectiblesManager.GetCollectibleOwnership(id)
   376  }
   377  
   378  func (api *API) RefetchOwnedCollectibles() error {
   379  	log.Debug("wallet.api.RefetchOwnedCollectibles")
   380  
   381  	api.s.collectibles.RefetchOwnedCollectibles()
   382  	return nil
   383  }
   384  
   385  func (api *API) GetOwnedCollectiblesAsync(requestID int32, chainIDs []wcommon.ChainID, addresses []common.Address, filter collectibles.Filter, offset int, limit int, dataType collectibles.CollectibleDataType, fetchCriteria collectibles.FetchCriteria) error {
   386  	log.Debug("wallet.api.GetOwnedCollectiblesAsync", "requestID", requestID, "chainIDs.count", len(chainIDs), "addr.count", len(addresses), "offset", offset, "limit", limit, "dataType", dataType, "fetchCriteria", fetchCriteria)
   387  
   388  	api.s.collectibles.GetOwnedCollectiblesAsync(requestID, chainIDs, addresses, filter, offset, limit, dataType, fetchCriteria)
   389  	return nil
   390  }
   391  
   392  func (api *API) GetCollectiblesByUniqueIDAsync(requestID int32, uniqueIDs []thirdparty.CollectibleUniqueID, dataType collectibles.CollectibleDataType) error {
   393  	log.Debug("wallet.api.GetCollectiblesByUniqueIDAsync", "requestID", requestID, "uniqueIDs.count", len(uniqueIDs), "dataType", dataType)
   394  
   395  	api.s.collectibles.GetCollectiblesByUniqueIDAsync(requestID, uniqueIDs, dataType)
   396  	return nil
   397  }
   398  
   399  func (api *API) FetchCollectionSocialsAsync(contractID thirdparty.ContractID) error {
   400  	log.Debug("wallet.api.FetchCollectionSocialsAsync", "contractID", contractID)
   401  
   402  	return api.s.collectiblesManager.FetchCollectionSocialsAsync(contractID)
   403  }
   404  
   405  func (api *API) GetCollectibleOwnersByContractAddress(ctx context.Context, chainID wcommon.ChainID, contractAddress common.Address) (*thirdparty.CollectibleContractOwnership, error) {
   406  	log.Debug("call to GetCollectibleOwnersByContractAddress")
   407  	return api.s.collectiblesManager.FetchCollectibleOwnersByContractAddress(ctx, chainID, contractAddress)
   408  }
   409  
   410  func (api *API) FetchCollectibleOwnersByContractAddress(ctx context.Context, chainID wcommon.ChainID, contractAddress common.Address) (*thirdparty.CollectibleContractOwnership, error) {
   411  	log.Debug("call to FetchCollectibleOwnersByContractAddress")
   412  	return api.s.collectiblesManager.FetchCollectibleOwnersByContractAddress(ctx, chainID, contractAddress)
   413  }
   414  
   415  func (api *API) SearchCollectibles(ctx context.Context, chainID wcommon.ChainID, text string, cursor string, limit int, providerID string) (*thirdparty.FullCollectibleDataContainer, error) {
   416  	log.Debug("call to SearchCollectibles")
   417  	return api.s.collectiblesManager.SearchCollectibles(ctx, chainID, text, cursor, limit, providerID)
   418  }
   419  
   420  func (api *API) SearchCollections(ctx context.Context, chainID wcommon.ChainID, text string, cursor string, limit int, providerID string) (*thirdparty.CollectionDataContainer, error) {
   421  	log.Debug("call to SearchCollections")
   422  	return api.s.collectiblesManager.SearchCollections(ctx, chainID, text, cursor, limit, providerID)
   423  }
   424  
   425  /*
   426     Collectibles API End
   427  */
   428  
   429  func (api *API) AddEthereumChain(ctx context.Context, network params.Network) error {
   430  	log.Debug("call to AddEthereumChain")
   431  	return api.s.rpcClient.NetworkManager.Upsert(&network)
   432  }
   433  
   434  func (api *API) DeleteEthereumChain(ctx context.Context, chainID uint64) error {
   435  	log.Debug("call to DeleteEthereumChain")
   436  	return api.s.rpcClient.NetworkManager.Delete(chainID)
   437  }
   438  
   439  func (api *API) GetEthereumChains(ctx context.Context) ([]*network.CombinedNetwork, error) {
   440  	log.Debug("call to GetEthereumChains")
   441  	return api.s.rpcClient.NetworkManager.GetCombinedNetworks()
   442  }
   443  
   444  // @deprecated
   445  func (api *API) FetchPrices(ctx context.Context, symbols []string, currencies []string) (map[string]map[string]float64, error) {
   446  	log.Debug("call to FetchPrices")
   447  	return api.s.marketManager.FetchPrices(symbols, currencies)
   448  }
   449  
   450  // @deprecated
   451  func (api *API) FetchMarketValues(ctx context.Context, symbols []string, currency string) (map[string]thirdparty.TokenMarketValues, error) {
   452  	log.Debug("call to FetchMarketValues")
   453  	return api.s.marketManager.FetchTokenMarketValues(symbols, currency)
   454  }
   455  
   456  func (api *API) GetHourlyMarketValues(ctx context.Context, symbol string, currency string, limit int, aggregate int) ([]thirdparty.HistoricalPrice, error) {
   457  	log.Debug("call to GetHourlyMarketValues")
   458  	return api.s.marketManager.FetchHistoricalHourlyPrices(symbol, currency, limit, aggregate)
   459  }
   460  
   461  func (api *API) GetDailyMarketValues(ctx context.Context, symbol string, currency string, limit int, allData bool, aggregate int) ([]thirdparty.HistoricalPrice, error) {
   462  	log.Debug("call to GetDailyMarketValues")
   463  	return api.s.marketManager.FetchHistoricalDailyPrices(symbol, currency, limit, allData, aggregate)
   464  }
   465  
   466  // @deprecated
   467  func (api *API) FetchTokenDetails(ctx context.Context, symbols []string) (map[string]thirdparty.TokenDetails, error) {
   468  	log.Debug("call to FetchTokenDetails")
   469  	return api.s.marketManager.FetchTokenDetails(symbols)
   470  }
   471  
   472  func (api *API) GetSuggestedFees(ctx context.Context, chainID uint64) (*fees.SuggestedFeesGwei, error) {
   473  	log.Debug("call to GetSuggestedFees")
   474  	return api.router.GetFeesManager().SuggestedFeesGwei(ctx, chainID)
   475  }
   476  
   477  func (api *API) GetEstimatedLatestBlockNumber(ctx context.Context, chainID uint64) (uint64, error) {
   478  	log.Debug("call to GetEstimatedLatestBlockNumber, chainID:", chainID)
   479  	return api.s.blockChainState.GetEstimatedLatestBlockNumber(ctx, chainID)
   480  }
   481  
   482  func (api *API) GetTransactionEstimatedTime(ctx context.Context, chainID uint64, maxFeePerGas *big.Float) (fees.TransactionEstimation, error) {
   483  	log.Debug("call to getTransactionEstimatedTime")
   484  	return api.router.GetFeesManager().TransactionEstimatedTime(ctx, chainID, gweiToWei(maxFeePerGas)), nil
   485  }
   486  
   487  func gweiToWei(val *big.Float) *big.Int {
   488  	res, _ := new(big.Float).Mul(val, big.NewFloat(1000000000)).Int(nil)
   489  	return res
   490  }
   491  
   492  func (api *API) GetSuggestedRoutes(ctx context.Context, input *requests.RouteInputParams) (*router.SuggestedRoutes, error) {
   493  	log.Debug("call to GetSuggestedRoutes")
   494  
   495  	return api.router.SuggestedRoutes(ctx, input)
   496  }
   497  
   498  func (api *API) GetSuggestedRoutesAsync(ctx context.Context, input *requests.RouteInputParams) {
   499  	log.Debug("call to GetSuggestedRoutesAsync")
   500  
   501  	api.router.SuggestedRoutesAsync(input)
   502  }
   503  
   504  func (api *API) StopSuggestedRoutesAsyncCalculation(ctx context.Context) {
   505  	log.Debug("call to StopSuggestedRoutesAsyncCalculation")
   506  
   507  	api.router.StopSuggestedRoutesAsyncCalculation()
   508  }
   509  
   510  func (api *API) StopSuggestedRoutesCalculation(ctx context.Context) {
   511  	log.Debug("call to StopSuggestedRoutesCalculation")
   512  
   513  	api.router.StopSuggestedRoutesCalculation()
   514  }
   515  
   516  // Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
   517  func (api *API) GetDerivedAddresses(ctx context.Context, password string, derivedFrom string, paths []string) ([]*DerivedAddress, error) {
   518  	info, err := api.s.gethManager.AccountsGenerator().LoadAccount(derivedFrom, password)
   519  	if err != nil {
   520  		return nil, err
   521  	}
   522  
   523  	return api.getDerivedAddresses(info.ID, paths)
   524  }
   525  
   526  // Generates addresses for the provided paths derived from the provided mnemonic, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
   527  func (api *API) GetDerivedAddressesForMnemonic(ctx context.Context, mnemonic string, paths []string) ([]*DerivedAddress, error) {
   528  	mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
   529  
   530  	info, err := api.s.gethManager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
   531  	if err != nil {
   532  		return nil, err
   533  	}
   534  
   535  	return api.getDerivedAddresses(info.ID, paths)
   536  }
   537  
   538  // Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
   539  func (api *API) getDerivedAddresses(id string, paths []string) ([]*DerivedAddress, error) {
   540  	addedAccounts, err := api.s.accountsDB.GetActiveAccounts()
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  
   545  	info, err := api.s.gethManager.AccountsGenerator().DeriveAddresses(id, paths)
   546  	if err != nil {
   547  		return nil, err
   548  	}
   549  
   550  	derivedAddresses := make([]*DerivedAddress, 0)
   551  	for accPath, acc := range info {
   552  
   553  		derivedAddress := &DerivedAddress{
   554  			Address:   common.HexToAddress(acc.Address),
   555  			PublicKey: types.Hex2Bytes(acc.PublicKey),
   556  			Path:      accPath,
   557  		}
   558  
   559  		for _, account := range addedAccounts {
   560  			if types.Address(derivedAddress.Address) == account.Address {
   561  				derivedAddress.AlreadyCreated = true
   562  				break
   563  			}
   564  		}
   565  
   566  		derivedAddresses = append(derivedAddresses, derivedAddress)
   567  	}
   568  
   569  	return derivedAddresses, nil
   570  }
   571  
   572  func (api *API) AddressExists(ctx context.Context, address types.Address) (bool, error) {
   573  	return api.s.accountsDB.AddressExists(address)
   574  }
   575  
   576  // AddressDetails returns details for passed params (passed address, chains to check, timeout for the call to complete)
   577  // if chainIDs is empty, it will use all active chains
   578  // if timeout is zero, it will wait until the call completes
   579  // response doesn't include derivation path
   580  func (api *API) AddressDetails(ctx context.Context, params *requests.AddressDetails) (*DerivedAddress, error) {
   581  	if err := params.Validate(); err != nil {
   582  		return nil, err
   583  	}
   584  
   585  	result := &DerivedAddress{
   586  		Address: common.HexToAddress(params.Address),
   587  	}
   588  	addressExists, err := api.s.accountsDB.AddressExists(types.Address(result.Address))
   589  	if err != nil {
   590  		return result, err
   591  	}
   592  
   593  	result.AlreadyCreated = addressExists
   594  
   595  	chainIDs := params.ChainIDs
   596  	if len(chainIDs) == 0 {
   597  		activeNetworks, err := api.s.rpcClient.NetworkManager.GetActiveNetworks()
   598  		if err != nil {
   599  			return nil, err
   600  		}
   601  
   602  		chainIDs = wcommon.NetworksToChainIDs(activeNetworks)
   603  	}
   604  
   605  	clients, err := api.s.rpcClient.EthClients(chainIDs)
   606  	if err != nil {
   607  		return nil, err
   608  	}
   609  
   610  	if params.TimeoutInMilliseconds > 0 {
   611  		var cancel context.CancelFunc
   612  		ctx, cancel = context.WithTimeout(ctx, time.Duration(params.TimeoutInMilliseconds)*time.Millisecond)
   613  		defer cancel()
   614  	}
   615  
   616  	for _, client := range clients {
   617  		balance, err := api.s.tokenManager.GetChainBalance(ctx, client, result.Address)
   618  		if err != nil {
   619  			if err != nil && errors.Is(err, context.DeadlineExceeded) {
   620  				return result, nil
   621  			}
   622  			return result, err
   623  		}
   624  
   625  		result.HasActivity = balance.Cmp(big.NewInt(0)) != 0
   626  		if result.HasActivity {
   627  			break
   628  		}
   629  	}
   630  
   631  	return result, nil
   632  }
   633  
   634  // @deprecated replaced by AddressDetails
   635  // GetAddressDetails returns details for the passed address (response doesn't include derivation path)
   636  func (api *API) GetAddressDetails(ctx context.Context, chainID uint64, address string) (*DerivedAddress, error) {
   637  	result := &DerivedAddress{
   638  		Address: common.HexToAddress(address),
   639  	}
   640  	addressExists, err := api.s.accountsDB.AddressExists(types.Address(result.Address))
   641  	if err != nil {
   642  		return result, err
   643  	}
   644  
   645  	result.AlreadyCreated = addressExists
   646  
   647  	chainClient, err := api.s.rpcClient.EthClient(chainID)
   648  	if err != nil {
   649  		return result, err
   650  	}
   651  
   652  	balance, err := api.s.tokenManager.GetChainBalance(ctx, chainClient, result.Address)
   653  	if err != nil {
   654  		return result, err
   655  	}
   656  
   657  	result.HasActivity = balance.Cmp(big.NewInt(0)) != 0
   658  	return result, nil
   659  }
   660  
   661  func (api *API) SignMessage(ctx context.Context, message types.HexBytes, address common.Address, password string) (string, error) {
   662  	log.Debug("[WalletAPI::SignMessage]", "message", message, "address", address)
   663  
   664  	selectedAccount, err := api.s.gethManager.VerifyAccountPassword(api.s.Config().KeyStoreDir, address.Hex(), password)
   665  	if err != nil {
   666  		return "", err
   667  	}
   668  
   669  	return api.s.transactionManager.SignMessage(message, selectedAccount)
   670  }
   671  
   672  func (api *API) BuildTransaction(ctx context.Context, chainID uint64, sendTxArgsJSON string) (response *transfer.TxResponse, err error) {
   673  	log.Debug("[WalletAPI::BuildTransaction]", "chainID", chainID, "sendTxArgsJSON", sendTxArgsJSON)
   674  	var params transactions.SendTxArgs
   675  	err = json.Unmarshal([]byte(sendTxArgsJSON), &params)
   676  	if err != nil {
   677  		return nil, err
   678  	}
   679  	return api.s.transactionManager.BuildTransaction(chainID, params)
   680  }
   681  
   682  func (api *API) BuildRawTransaction(ctx context.Context, chainID uint64, sendTxArgsJSON string, signature string) (response *transfer.TxResponse, err error) {
   683  	log.Debug("[WalletAPI::BuildRawTransaction]", "chainID", chainID, "sendTxArgsJSON", sendTxArgsJSON, "signature", signature)
   684  
   685  	sig, err := hex.DecodeString(signature)
   686  	if err != nil {
   687  		return nil, err
   688  	}
   689  
   690  	var params transactions.SendTxArgs
   691  	err = json.Unmarshal([]byte(sendTxArgsJSON), &params)
   692  	if err != nil {
   693  		return nil, err
   694  	}
   695  
   696  	return api.s.transactionManager.BuildRawTransaction(chainID, params, sig)
   697  }
   698  
   699  func (api *API) SendTransactionWithSignature(ctx context.Context, chainID uint64, txType transactions.PendingTrxType,
   700  	sendTxArgsJSON string, signature string) (hash types.Hash, err error) {
   701  	log.Debug("[WalletAPI::SendTransactionWithSignature]", "chainID", chainID, "txType", txType, "sendTxArgsJSON", sendTxArgsJSON, "signature", signature)
   702  	sig, err := hex.DecodeString(signature)
   703  	if err != nil {
   704  		return hash, err
   705  	}
   706  
   707  	var params transactions.SendTxArgs
   708  	err = json.Unmarshal([]byte(sendTxArgsJSON), &params)
   709  	if err != nil {
   710  		return hash, err
   711  	}
   712  	return api.s.transactionManager.SendTransactionWithSignature(chainID, params, sig)
   713  }
   714  
   715  func (api *API) CreateMultiTransaction(ctx context.Context, multiTransactionCommand *transfer.MultiTransactionCommand, data []*pathprocessor.MultipathProcessorTxArgs, password string) (*transfer.MultiTransactionCommandResult, error) {
   716  	log.Debug("[WalletAPI:: CreateMultiTransaction] create multi transaction")
   717  
   718  	cmd, err := api.s.transactionManager.CreateMultiTransactionFromCommand(multiTransactionCommand, data)
   719  	if err != nil {
   720  		return nil, err
   721  	}
   722  
   723  	if password != "" {
   724  		selectedAccount, err := api.getVerifiedWalletAccount(multiTransactionCommand.FromAddress.Hex(), password)
   725  		if err != nil {
   726  			return nil, err
   727  		}
   728  
   729  		cmdRes, err := api.s.transactionManager.SendTransactions(ctx, cmd, data, api.router.GetPathProcessors(), selectedAccount)
   730  		if err != nil {
   731  			return nil, err
   732  		}
   733  
   734  		_, err = api.s.transactionManager.InsertMultiTransaction(cmd)
   735  		if err != nil {
   736  			log.Error("Failed to save multi transaction", "error", err) // not critical
   737  		}
   738  
   739  		return cmdRes, nil
   740  	}
   741  
   742  	return nil, api.s.transactionManager.SendTransactionForSigningToKeycard(ctx, cmd, data, api.router.GetPathProcessors())
   743  }
   744  
   745  func (api *API) ProceedWithTransactionsSignatures(ctx context.Context, signatures map[string]transfer.SignatureDetails) (*transfer.MultiTransactionCommandResult, error) {
   746  	log.Debug("[WalletAPI:: ProceedWithTransactionsSignatures] sign with signatures and send multi transaction")
   747  	return api.s.transactionManager.ProceedWithTransactionsSignatures(ctx, signatures)
   748  }
   749  
   750  func (api *API) GetMultiTransactions(ctx context.Context, transactionIDs []wcommon.MultiTransactionIDType) ([]*transfer.MultiTransaction, error) {
   751  	log.Debug("wallet.api.GetMultiTransactions", "IDs.len", len(transactionIDs))
   752  	return api.s.transactionManager.GetMultiTransactions(ctx, transactionIDs)
   753  }
   754  
   755  func (api *API) GetCachedCurrencyFormats() (currency.FormatPerSymbol, error) {
   756  	log.Debug("call to GetCachedCurrencyFormats")
   757  	return api.s.currency.GetCachedCurrencyFormats()
   758  }
   759  
   760  func (api *API) FetchAllCurrencyFormats() (currency.FormatPerSymbol, error) {
   761  	log.Debug("call to FetchAllCurrencyFormats")
   762  	return api.s.currency.FetchAllCurrencyFormats()
   763  }
   764  
   765  // @deprecated replaced by session APIs; see #12120
   766  func (api *API) FilterActivityAsync(requestID int32, addresses []common.Address, chainIDs []wcommon.ChainID, filter activity.Filter, offset int, limit int) error {
   767  	log.Debug("wallet.api.FilterActivityAsync", "requestID", requestID, "addr.count", len(addresses), "chainIDs.count", len(chainIDs), "offset", offset, "limit", limit)
   768  
   769  	api.s.activity.FilterActivityAsync(requestID, addresses, chainIDs, filter, offset, limit)
   770  	return nil
   771  }
   772  
   773  // @deprecated replaced by session APIs; see #12120
   774  func (api *API) CancelActivityFilterTask(requestID int32) error {
   775  	log.Debug("wallet.api.CancelActivityFilterTask", "requestID", requestID)
   776  
   777  	api.s.activity.CancelFilterTask(requestID)
   778  	return nil
   779  }
   780  
   781  func (api *API) StartActivityFilterSession(addresses []common.Address, chainIDs []wcommon.ChainID, filter activity.Filter, firstPageCount int) (activity.SessionID, error) {
   782  	log.Debug("wallet.api.StartActivityFilterSession", "addr.count", len(addresses), "chainIDs.count", len(chainIDs), "firstPageCount", firstPageCount)
   783  
   784  	return api.s.activity.StartFilterSession(addresses, chainIDs, filter, firstPageCount), nil
   785  }
   786  
   787  func (api *API) UpdateActivityFilterForSession(sessionID activity.SessionID, filter activity.Filter, firstPageCount int) error {
   788  	log.Debug("wallet.api.UpdateActivityFilterForSession", "sessionID", sessionID, "firstPageCount", firstPageCount)
   789  
   790  	return api.s.activity.UpdateFilterForSession(sessionID, filter, firstPageCount)
   791  }
   792  
   793  func (api *API) ResetActivityFilterSession(id activity.SessionID, firstPageCount int) error {
   794  	log.Debug("wallet.api.ResetActivityFilterSession", "id", id, "firstPageCount", firstPageCount)
   795  
   796  	return api.s.activity.ResetFilterSession(id, firstPageCount)
   797  }
   798  
   799  func (api *API) GetMoreForActivityFilterSession(id activity.SessionID, pageCount int) error {
   800  	log.Debug("wallet.api.GetMoreForActivityFilterSession", "id", id, "pageCount", pageCount)
   801  
   802  	return api.s.activity.GetMoreForFilterSession(id, pageCount)
   803  }
   804  
   805  func (api *API) StopActivityFilterSession(id activity.SessionID) {
   806  	log.Debug("wallet.api.StopActivityFilterSession", "id", id)
   807  
   808  	api.s.activity.StopFilterSession(id)
   809  }
   810  
   811  func (api *API) GetMultiTxDetails(ctx context.Context, multiTxID int) (*activity.EntryDetails, error) {
   812  	log.Debug("wallet.api.GetMultiTxDetails", "multiTxID", multiTxID)
   813  
   814  	return api.s.activity.GetMultiTxDetails(ctx, multiTxID)
   815  }
   816  
   817  func (api *API) GetTxDetails(ctx context.Context, id string) (*activity.EntryDetails, error) {
   818  	log.Debug("wallet.api.GetTxDetails", "id", id)
   819  
   820  	return api.s.activity.GetTxDetails(ctx, id)
   821  }
   822  
   823  func (api *API) GetRecipientsAsync(requestID int32, chainIDs []wcommon.ChainID, addresses []common.Address, offset int, limit int) (ignored bool, err error) {
   824  	log.Debug("wallet.api.GetRecipientsAsync", "addresses.len", len(addresses), "chainIDs.len", len(chainIDs), "offset", offset, "limit", limit)
   825  
   826  	ignored = api.s.activity.GetRecipientsAsync(requestID, chainIDs, addresses, offset, limit)
   827  	return ignored, err
   828  }
   829  
   830  func (api *API) GetOldestActivityTimestampAsync(requestID int32, addresses []common.Address) error {
   831  	log.Debug("wallet.api.GetOldestActivityTimestamp", "addresses.len", len(addresses))
   832  
   833  	api.s.activity.GetOldestTimestampAsync(requestID, addresses)
   834  	return nil
   835  }
   836  
   837  func (api *API) GetActivityCollectiblesAsync(requestID int32, chainIDs []wcommon.ChainID, addresses []common.Address, offset int, limit int) error {
   838  	log.Debug("wallet.api.GetActivityCollectiblesAsync", "addresses.len", len(addresses), "chainIDs.len", len(chainIDs), "offset", offset, "limit", limit)
   839  
   840  	api.s.activity.GetActivityCollectiblesAsync(requestID, chainIDs, addresses, offset, limit)
   841  
   842  	return nil
   843  }
   844  
   845  func (api *API) FetchChainIDForURL(ctx context.Context, rpcURL string) (*big.Int, error) {
   846  	log.Debug("wallet.api.VerifyURL", "rpcURL", rpcURL)
   847  
   848  	rpcClient, err := gethrpc.Dial(rpcURL)
   849  	if err != nil {
   850  		return nil, fmt.Errorf("dial upstream server: %s", err)
   851  	}
   852  	client := ethclient.NewClient(rpcClient)
   853  	return client.ChainID(ctx)
   854  }
   855  
   856  func (api *API) getVerifiedWalletAccount(address, password string) (*account.SelectedExtKey, error) {
   857  	exists, err := api.s.accountsDB.AddressExists(types.HexToAddress(address))
   858  	if err != nil {
   859  		log.Error("failed to query db for a given address", "address", address, "error", err)
   860  		return nil, err
   861  	}
   862  
   863  	if !exists {
   864  		log.Error("failed to get a selected account", "err", transactions.ErrInvalidTxSender)
   865  		return nil, transactions.ErrAccountDoesntExist
   866  	}
   867  
   868  	keyStoreDir := api.s.Config().KeyStoreDir
   869  	key, err := api.s.gethManager.VerifyAccountPassword(keyStoreDir, address, password)
   870  	if err != nil {
   871  		log.Error("failed to verify account", "account", address, "error", err)
   872  		return nil, err
   873  	}
   874  
   875  	return &account.SelectedExtKey{
   876  		Address:    key.Address,
   877  		AccountKey: key,
   878  	}, nil
   879  }
   880  
   881  // AddWalletConnectSession adds or updates a session wallet connect session
   882  func (api *API) AddWalletConnectSession(ctx context.Context, session_json string) error {
   883  	log.Debug("wallet.api.AddWalletConnectSession", "rpcURL", len(session_json))
   884  	return walletconnect.AddSession(api.s.db, api.s.config.Networks, session_json)
   885  }
   886  
   887  // DisconnectWalletConnectSession removes a wallet connect session
   888  func (api *API) DisconnectWalletConnectSession(ctx context.Context, topic walletconnect.Topic) error {
   889  	log.Debug("wallet.api.DisconnectWalletConnectSession", "topic", topic)
   890  	return walletconnect.DisconnectSession(api.s.db, topic)
   891  }
   892  
   893  // GetWalletConnectActiveSessions returns all active wallet connect sessions
   894  func (api *API) GetWalletConnectActiveSessions(ctx context.Context, validAtTimestamp int64) ([]walletconnect.DBSession, error) {
   895  	log.Debug("wallet.api.GetWalletConnectActiveSessions")
   896  	return walletconnect.GetActiveSessions(api.s.db, validAtTimestamp)
   897  }
   898  
   899  // GetWalletConnectDapps returns all active wallet connect dapps
   900  // Active dApp are those having active sessions (not expired and not disconnected)
   901  func (api *API) GetWalletConnectDapps(ctx context.Context, validAtTimestamp int64, testChains bool) ([]walletconnect.DBDApp, error) {
   902  	log.Debug("wallet.api.GetWalletConnectDapps", "validAtTimestamp", validAtTimestamp, "testChains", testChains)
   903  	return walletconnect.GetActiveDapps(api.s.db, validAtTimestamp, testChains)
   904  }
   905  
   906  // HashMessageEIP191 is used for hashing dApps requests for "personal_sign" and "eth_sign"
   907  // in a safe manner following the EIP-191 version 0x45 for signing on the client side.
   908  func (api *API) HashMessageEIP191(ctx context.Context, message types.HexBytes) types.Hash {
   909  	log.Debug("wallet.api.HashMessageEIP191", "len(data)", len(message))
   910  	safeMsg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(message), string(message))
   911  	return crypto.Keccak256Hash([]byte(safeMsg))
   912  }
   913  
   914  // SignTypedDataV4 dApps use it to execute "eth_signTypedData_v4" requests
   915  // the formatted typed data will be prefixed with \x19\x01 based on the EIP-712
   916  // @deprecated
   917  func (api *API) SignTypedDataV4(typedJson string, address string, password string) (types.HexBytes, error) {
   918  	log.Debug("wallet.api.SignTypedDataV4", "len(typedJson)", len(typedJson), "address", address, "len(password)", len(password))
   919  
   920  	account, err := api.getVerifiedWalletAccount(address, password)
   921  	if err != nil {
   922  		return types.HexBytes{}, err
   923  	}
   924  	var typed signercore.TypedData
   925  	err = json.Unmarshal([]byte(typedJson), &typed)
   926  	if err != nil {
   927  		return types.HexBytes{}, err
   928  	}
   929  
   930  	// This is not used down the line but required by the typeddata.SignTypedDataV4 function call
   931  	chain := new(big.Int).SetUint64(api.s.config.NetworkID)
   932  	sig, err := typeddata.SignTypedDataV4(typed, account.AccountKey.PrivateKey, chain)
   933  	if err != nil {
   934  		return types.HexBytes{}, err
   935  	}
   936  	return types.HexBytes(sig), err
   937  }
   938  
   939  // SafeSignTypedDataForDApps is used to execute requests for "eth_signTypedData"
   940  // if legacy is true else "eth_signTypedData_v4"
   941  // the formatted typed data won't be prefixed in case of legacy calls, as the
   942  // old dApps implementation expects
   943  // the chain is validate for both cases
   944  func (api *API) SafeSignTypedDataForDApps(typedJson string, address string, password string, chainID uint64, legacy bool) (types.HexBytes, error) {
   945  	log.Debug("wallet.api.SafeSignTypedDataForDApps", "len(typedJson)", len(typedJson), "address", address, "len(password)", len(password), "chainID", chainID, "legacy", legacy)
   946  
   947  	account, err := api.getVerifiedWalletAccount(address, password)
   948  	if err != nil {
   949  		return types.HexBytes{}, err
   950  	}
   951  
   952  	return walletconnect.SafeSignTypedDataForDApps(typedJson, account.AccountKey.PrivateKey, chainID, legacy)
   953  }
   954  
   955  func (api *API) RestartWalletReloadTimer(ctx context.Context) error {
   956  	return api.s.reader.Restart()
   957  }
   958  
   959  func (api *API) IsChecksumValidForAddress(address string) (bool, error) {
   960  	log.Debug("wallet.api.isChecksumValidForAddress", "address", address)
   961  	return abi_spec.CheckAddressChecksum(address)
   962  }