refactor(@desktop/wallet): tokens removed from `WalletAccountDto` and cached separately in wallet accounts service

This commit is contained in:
Sale Djenic 2023-08-02 15:50:03 +02:00 committed by saledjenic
parent 838aa215e0
commit 23426f184b
13 changed files with 126 additions and 87 deletions

View File

@ -59,3 +59,9 @@ proc getCurrencyFormat*(self: Controller, symbol: string): CurrencyFormatDto =
proc areTestNetworksEnabled*(self: Controller): bool =
return self.walletAccountService.areTestNetworksEnabled()
proc getTokensByAddress*(self: Controller, address: string): seq[WalletTokenDto] =
return self.walletAccountService.getTokensByAddress(address)
proc getCurrencyBalance*(self: Controller, address: string, chainIds: seq[int], currency: string): float64 =
return self.walletAccountService.getCurrencyBalance(address, chainIds, currency)

View File

@ -68,18 +68,19 @@ proc switchAccount*(self: Module, accountIndex: int) =
let enabledChainIds = self.controller.getEnabledChainIds()
let areTestNetworksEnabled = self.controller.areTestNetworksEnabled()
let currencyFormat = self.controller.getCurrencyFormat(currency)
let currencyBalance = self.controller.getCurrencyBalance(walletAccount.address, enabledChainIds, currency)
let tokens = self.controller.getTokensByAddress(walletAccount.address)
let accountItem = walletAccountToWalletAccountsItem(
walletAccount,
keycardAccount,
enabledChainIds,
currency,
currencyBalance,
currencyFormat,
areTestNetworksEnabled
)
self.view.setData(accountItem)
self.setAssets(walletAccount.tokens)
self.setAssets(tokens)
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("browserSectionCurrentAccount", newQVariant(self.view))
@ -131,7 +132,10 @@ proc onTokensRebuilt(self: Module, accountsTokens: OrderedTable[string, seq[Wall
proc onCurrencyFormatsUpdated(self: Module) =
# Update assets
let walletAccount = self.controller.getWalletAccount(self.currentAccountIndex)
self.setAssets(walletAccount.tokens)
if walletAccount.isNil:
return
let tokens = self.controller.getTokensByAddress(walletAccount.address)
self.setAssets(tokens)
method findTokenSymbolByAddress*(self: Module, address: string): string =
return self.controller.findTokenSymbolByAddress(address)

View File

@ -67,3 +67,6 @@ proc updateWalletAccountTestPreferredChains*(self: Controller, address, preferre
proc areTestNetworksEnabled*(self: Controller): bool =
return self.walletAccountService.areTestNetworksEnabled()
proc getCurrencyBalance*(self: Controller, address: string, chainIds: seq[int], currency: string): float64 =
return self.walletAccountService.getCurrencyBalance(address, chainIds, currency)

View File

@ -49,11 +49,11 @@ method filterChanged*(self: Module, addresses: seq[string], chainIds: seq[int])
let areTestNetworksEnabled = self.controller.areTestNetworksEnabled()
let items = walletAccounts.map(w => (block:
let keycardAccount = self.controller.isKeycardAccount(w)
let currencyBalance = self.controller.getCurrencyBalance(w.address, chainIds, currency)
walletAccountToWalletAccountsItem(
w,
keycardAccount,
chainIds,
currency,
currencyBalance,
currencyFormat,
areTestNetworksEnabled
)

View File

@ -95,7 +95,7 @@ method filterChanged*(self: Module, addresses: seq[string], chainIds: seq[int])
let accountItem = walletAccountToWalletAssetsItem(walletAccounts[0])
self.view.setData(accountItem)
if walletAccounts[0].tokens.len == 0 and walletAccounts[0].assetsLoading:
if walletAccounts[0].assetsLoading:
self.setLoadingAssets()
else:
let walletTokens = self.controller.getWalletTokensByAddresses(addresses)

View File

@ -104,3 +104,9 @@ proc suggestedFees*(self: Controller, chainId: int): string =
proc areTestNetworksEnabled*(self: Controller): bool =
return self.walletAccountService.areTestNetworksEnabled()
proc getTokensByAddress*(self: Controller, address: string): seq[WalletTokenDto] =
return self.walletAccountService.getTokensByAddress(address)
proc getCurrencyBalance*(self: Controller, address: string, chainIds: seq[int], currency: string): float64 =
return self.walletAccountService.getCurrencyBalance(address, chainIds, currency)

View File

@ -65,14 +65,18 @@ method refreshWalletAccounts*(self: Module) =
let areTestNetworksEnabled = self.controller.areTestNetworksEnabled()
let items = walletAccounts.map(w => (block:
let tokens = self.controller.getTokensByAddress(w.address)
let tokenFormats = collect(initTable()):
for t in w.tokens: {t.symbol: self.controller.getCurrencyFormat(t.symbol)}
for t in tokens: {t.symbol: self.controller.getCurrencyFormat(t.symbol)}
let currencyBalance = self.controller.getCurrencyBalance(w.address, enabledChainIds, currency)
walletAccountToWalletSendAccountItem(
w,
tokens,
chainIds,
enabledChainIds,
currency,
currencyBalance,
currencyFormat,
tokenFormats,
areTestNetworksEnabled,

View File

@ -44,15 +44,15 @@ proc walletAccountToWalletAccountItem*(w: WalletAccountDto, keycardAccount: bool
w.testPreferredChainIds
)
proc walletAccountToWalletAccountsItem*(w: WalletAccountDto, keycardAccount: bool, enabledChainIds: seq[int], currency: string,
currencyFormat: CurrencyFormatDto, areTestNetworksEnabled: bool): wallet_accounts_item.Item =
proc walletAccountToWalletAccountsItem*(w: WalletAccountDto, keycardAccount: bool,
currencyBalance: float64, currencyFormat: CurrencyFormatDto, areTestNetworksEnabled: bool): wallet_accounts_item.Item =
return wallet_accounts_item.initItem(
w.name,
w.address,
w.path,
w.colorId,
w.walletType,
currencyAmountToItem(w.getCurrencyBalance(enabledChainIds, currency), currencyFormat),
currencyAmountToItem(currencyBalance, currencyFormat),
w.emoji,
w.keyUid,
w.createdAt,
@ -101,11 +101,11 @@ proc walletTokenToItem*(
loading = false
)
proc walletAccountToWalletSendAccountItem*(w: WalletAccountDto, chainIds: seq[int], enabledChainIds: seq[int], currency: string,
currencyFormat: CurrencyFormatDto, tokenFormats: Table[string, CurrencyFormatDto], areTestNetworksEnabled: bool): wallet_send_account_item.AccountItem =
proc walletAccountToWalletSendAccountItem*(w: WalletAccountDto, tokens: seq[WalletTokenDto], chainIds: seq[int], enabledChainIds: seq[int], currency: string,
currencyBalance: float64, currencyFormat: CurrencyFormatDto, tokenFormats: Table[string, CurrencyFormatDto], areTestNetworksEnabled: bool): wallet_send_account_item.AccountItem =
let assets = token_model.newModel()
assets.setItems(
w.tokens.map(t => walletTokenToItem(t, chainIds, enabledChainIds, currency, currencyFormat, tokenFormats[t.symbol]))
tokens.map(t => walletTokenToItem(t, chainIds, enabledChainIds, currency, currencyFormat, tokenFormats[t.symbol]))
)
return wallet_send_account_item.newAccountItem(
w.name,
@ -114,7 +114,7 @@ proc walletAccountToWalletSendAccountItem*(w: WalletAccountDto, chainIds: seq[in
w.emoji,
w.walletType,
assets,
currencyAmountToItem(w.getCurrencyBalance(enabledChainIds, currency), currencyFormat),
currencyAmountToItem(currencyBalance, currencyFormat),
areTestNetworksEnabled,
w.prodPreferredChainIds,
w.testPreferredChainIds

View File

@ -631,7 +631,7 @@ proc authenticateUser*(self: Controller, keyUid = "") =
proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
if not serviceApplicable(self.walletAccountService):
return
return self.walletAccountService.getAccounts()
return self.walletAccountService.getWalletAccounts()
proc getKeypairs*(self: Controller): seq[wallet_account_service.KeypairDto] =
if not serviceApplicable(self.walletAccountService):

View File

@ -696,14 +696,10 @@ QtObject:
error "Error computing eth value", msg = e.msg
proc getWalletBalanceForChain(self:Service, walletAddress: string, chainId: int): float =
let wallet = self.walletAccountService.getAccountByAddress(walletAddress.toLower())
var balance = 0.0
let tokens = wallet.tokens
let tokens = self.walletAccountService.getTokensByAddress(walletAddress.toLower())
for token in tokens:
if token.symbol == ethSymbol:
balance = token.balancesPerChain[chainId].balance
break
return balance
return token.balancesPerChain[chainId].balance
proc createComputeFeeArgsFromEthAndBalance(self: Service, ethValue: float, balance: float): ComputeFeeArgs =
let fiatValue = self.getFiatValue(ethValue, ethSymbol)

View File

@ -1,4 +1,4 @@
import tables, json, strformat, sequtils, sugar, strutils
import tables, json, strformat, strutils
import token_dto
@ -27,7 +27,6 @@ type
walletType*: string
isWallet*: bool
isChat*: bool
tokens*: seq[WalletTokenDto]
emoji*: string
ens*: string
assetsLoading*: bool
@ -76,13 +75,11 @@ proc `$`*(self: WalletAccountDto): string =
walletType: {self.walletType},
isChat: {self.isChat},
emoji: {self.emoji},
assetsLoading: {self.assetsLoading},
hasBalanceCache: {self.hasBalanceCache},
hasMarketValuesCache: {self.hasMarketValuesCache},
removed: {self.removed}
operable: {self.operable}
prodPreferredChainIds: {self.prodPreferredChainIds}
removed: {self.removed},
operable: {self.operable},
prodPreferredChainIds: {self.prodPreferredChainIds},
testPreferredChainIds: {self.testPreferredChainIds}
]"""
proc getCurrencyBalance*(self: WalletAccountDto, chainIds: seq[int], currency: string): float64 =
return self.tokens.map(t => t.getCurrencyBalance(chainIds, currency)).foldl(a + b, 0.0)

View File

@ -141,6 +141,7 @@ QtObject:
networkService: network_service.Service
currencyService: currency_service.Service
walletAccounts: OrderedTable[string, WalletAccountDto]
accountsTokens*: Table[string, seq[WalletTokenDto]] ## [address, seq[WalletTokenDto]]
# Forward declaration
proc buildAllTokens(self: Service, accounts: seq[string], store: bool)
@ -236,9 +237,9 @@ QtObject:
proc storeTokensForAccount*(self: Service, address: string, tokens: seq[WalletTokenDto], areBalancesCached: bool, areMarketValuesCached: bool) =
if self.walletAccounts.hasKey(address):
deepCopy(self.walletAccounts[address].tokens, tokens)
self.walletAccounts[address].hasBalanceCache = areBalancesCached
self.walletAccounts[address].hasMarketValuesCache = areMarketValuesCached
self.accountsTokens[address] = tokens
proc allBalancesForAllTokensHaveError(tokens: seq[WalletTokenDto]): bool =
for token in tokens:
@ -266,40 +267,47 @@ QtObject:
return true
return false
proc updateReceivedTokens*(self: Service, address: string, tokens: var seq[WalletTokenDto]) =
if not self.walletAccounts.hasKey(address) or
self.walletAccounts[address].tokens.len == 0:
return
let allBalancesForAllTokensHaveError = allBalancesForAllTokensHaveError(tokens)
let allMarketValuesForAllTokensHaveError = allMarketValuesForAllTokensHaveError(tokens)
for waToken in self.walletAccounts[address].tokens:
for token in tokens.mitems:
if waToken.name == token.name:
if allBalancesForAllTokensHaveError:
token.balancesPerChain = waToken.balancesPerChain
if allMarketValuesForAllTokensHaveError:
token.marketValuesPerCurrency = waToken.marketValuesPerCurrency
proc walletAccountsContainsAddress*(self: Service, address: string): bool =
proc walletAccountsContainsAddress(self: Service, address: string): bool =
return self.walletAccounts.hasKey(address)
proc getAccountByAddress*(self: Service, address: string): WalletAccountDto =
result = WalletAccountDto()
if not self.walletAccountsContainsAddress(address):
return
result = self.walletAccounts[address]
return self.walletAccounts[address]
proc updateReceivedTokens*(self: Service, address: string, tokens: var seq[WalletTokenDto]) =
let acc = self.getAccountByAddress(address)
if acc.isNil or not self.accountsTokens.hasKey(address):
return
let allBalancesForAllTokensHaveError = allBalancesForAllTokensHaveError(tokens)
let allMarketValuesForAllTokensHaveError = allMarketValuesForAllTokensHaveError(tokens)
for storedToken in self.accountsTokens[address]:
for token in tokens.mitems:
if storedToken.name == token.name:
if allBalancesForAllTokensHaveError:
token.balancesPerChain = storedToken.balancesPerChain
if allMarketValuesForAllTokensHaveError:
token.marketValuesPerCurrency = storedToken.marketValuesPerCurrency
proc getAccountsByAddresses*(self: Service, addresses: seq[string]): seq[WalletAccountDto] =
for address in addresses:
result.add(self.getAccountByAddress(address))
let acc = self.getAccountByAddress(address)
if acc.isNil:
continue
result.add(acc)
proc getTokensByAddress*(self: Service, address: string): seq[WalletTokenDto] =
if not self.accountsTokens.hasKey(address):
return
return self.accountsTokens[address]
proc getTokensByAddresses*(self: Service, addresses: seq[string]): seq[WalletTokenDto] =
var tokens = initTable[string, WalletTokenDto]()
for address in addresses:
let walletAccount = self.getAccountByAddress(address)
for token in walletAccount.tokens:
if not self.accountsTokens.hasKey(address):
continue
for token in self.accountsTokens[address]:
if not tokens.hasKey(token.symbol):
let newToken = token.copyToken()
tokens[token.symbol] = newToken
@ -327,6 +335,7 @@ QtObject:
proc init*(self: Service) =
try:
let chainId = self.networkService.getNetworkForEns().chainId
let accounts = self.getAccounts()
for account in accounts:
let account = account # TODO https://github.com/nim-lang/Nim/issues/16740
@ -399,6 +408,7 @@ QtObject:
return
proc addNewAccountToLocalStoreAndNotify(self: Service, notify: bool = true) =
let chainId = self.networkService.getNetworkForEns().chainId
let accounts = self.getAccounts()
var newAccount: WalletAccountDto
var found = false
@ -587,8 +597,7 @@ QtObject:
except Exception as e:
error "error: ", procName="deleteKeypair", errName = e.name, errDesription = e.msg
proc getCurrency*(self: Service): string =
return self.settingsService.getCurrency()
proc updateCurrency*(self: Service, newCurrency: string) =
discard self.settingsService.saveCurrency(newCurrency)
@ -610,6 +619,9 @@ QtObject:
return false
try:
var account = self.getAccountByAddress(address)
if account.isNil:
error "on account for given address", procName="updateWalletAccount"
return false
let response = status_go_accounts.updateAccount(accountName, account.address, account.path, account.publicKey,
account.keyUid, account.walletType, colorId, emoji, account.isWallet, account.isChat, account.prodPreferredChainIds, account.testPreferredChainIds)
if not response.error.isNil:
@ -627,6 +639,9 @@ QtObject:
return false
try:
var account = self.getAccountByAddress(address)
if account.isNil:
error "on account for given address", procName="updateWalletAccount"
return false
let response = status_go_accounts.updateAccount(account.name, account.address, account.path, account.publicKey,
account.keyUid, account.walletType, account.colorId, account.emoji, account.isWallet, account.isChat, preferredChainIds, account.testPreferredChainIds)
if not response.error.isNil:
@ -644,6 +659,9 @@ QtObject:
return false
try:
var account = self.getAccountByAddress(address)
if account.isNil:
error "on account for given address", procName="updateWalletAccount"
return false
let response = status_go_accounts.updateAccount(account.name, account.address, account.path, account.publicKey,
account.keyUid, account.walletType, account.colorId, account.emoji, account.isWallet, account.isChat, account.prodPreferredChainIds, preferredChainIds)
if not response.error.isNil:
@ -822,41 +840,45 @@ QtObject:
)
self.threadpool.start(arg)
proc getCurrency*(self: Service): string =
return self.settingsService.getCurrency()
proc getCurrentCurrencyIfEmpty(self: Service, currency = ""): string =
if currency != "":
return currency
else:
return self.getCurrency()
proc getNetworkCurrencyBalance*(self: Service, network: NetworkDto, currency: string = ""): float64 =
let accounts = self.getWalletAccounts()
for walletAccount in accounts:
result += walletAccount.getCurrencyBalance(@[network.chainId], self.getCurrentCurrencyIfEmpty(currency))
proc getCurrencyBalance*(self: Service, address: string, chainIds: seq[int], currency: string): float64 =
if not self.accountsTokens.hasKey(address):
return
return self.accountsTokens[address].map(t => t.getCurrencyBalance(chainIds, currency)).foldl(a + b, 0.0)
proc getTotalCurrencyBalance*(self: Service, addresses: seq[string], currency: string = ""): float64 =
let chainIds = self.networkService.getNetworks().filter(a => a.enabled).map(a => a.chainId)
let accounts = self.getWalletAccounts().filter(w => addresses.contains(w.address))
return accounts.map(a => self.getCurrencyBalance(a.address, chainIds, self.getCurrentCurrencyIfEmpty(currency))).foldl(a + b, 0.0)
proc findTokenSymbolByAddress*(self: Service, address: string): string =
return self.tokenService.findTokenSymbolByAddress(address)
proc getOrFetchBalanceForAddressInPreferredCurrency*(self: Service, address: string): tuple[balance: float64, fetched: bool] =
if self.walletAccountsContainsAddress(address):
let chainIds = self.networkService.getNetworks().map(n => n.chainId)
result.balance = self.getAccountByAddress(address).getCurrencyBalance(chainIds, self.getCurrentCurrencyIfEmpty())
result.fetched = true
else:
let acc = self.getAccountByAddress(address)
if acc.isNil:
self.buildAllTokens(@[address], store = false)
result.balance = 0.0
result.fetched = false
proc getTotalCurrencyBalance*(self: Service, addresses: seq[string], currency: string = ""): float64 =
let chainIds = self.networkService.getNetworks().filter(a => a.enabled).map(a => a.chainId)
let accounts = self.getWalletAccounts().filter(w => addresses.contains(w.address))
return accounts.map(a => a.getCurrencyBalance(chainIds, self.getCurrentCurrencyIfEmpty(currency))).foldl(a + b, 0.0)
return
let chainIds = self.networkService.getNetworks().map(n => n.chainId)
result.balance = self.getCurrencyBalance(acc.address, chainIds, self.getCurrentCurrencyIfEmpty())
result.fetched = true
proc getTokenBalanceOnChain*(self: Service, address: string, chainId: int, symbol: string): float64 =
let account = self.getAccountByAddress(address)
for token in account.tokens:
if not self.accountsTokens.hasKey(address):
return 0.0
for token in self.accountsTokens[address]:
if token.symbol == symbol and token.balancesPerChain.hasKey(chainId):
return token.balancesPerChain[chainId].balance
return 0.0
proc addKeycardOrAccountsAsync*(self: Service, keycard: KeycardDto, accountsComingFromKeycard: bool = false) =
@ -1076,12 +1098,13 @@ QtObject:
proc allAccountsTokenBalance*(self: Service, symbol: string): float64 =
var totalTokenBalance = 0.0
for walletAccount in self.getWalletAccounts:
if walletAccount.walletType != WalletTypeWatch:
for token in walletAccount.tokens:
for walletAccount in self.getWalletAccounts():
if walletAccount.walletType == WalletTypeWatch or
not self.accountsTokens.hasKey(walletAccount.address):
continue
for token in self.accountsTokens[walletAccount.address]:
if token.symbol == symbol:
totalTokenBalance += token.getTotalBalanceOfSupportedChains()
return totalTokenBalance
proc isIncludeWatchOnlyAccount*(self: Service): bool =