fix(@desktop/keycard): Keycard -> Factory reset: $NaN amount is shown in factory reset flow when account has no funds

Fixes: #9418
This commit is contained in:
Sale Djenic 2023-02-13 18:19:08 +01:00 committed by saledjenic
parent 31be818e0e
commit 86fb93ecb7
14 changed files with 151 additions and 52 deletions

View File

@ -80,6 +80,7 @@ type
urlsManager: UrlsManager urlsManager: UrlsManager
keycardService: keycard_service.Service keycardService: keycard_service.Service
settingsService: settings_service.Service settingsService: settings_service.Service
networkService: network_service.Service
privacyService: privacy_service.Service privacyService: privacy_service.Service
accountsService: accounts_service.Service accountsService: accounts_service.Service
walletAccountService: wallet_account_service.Service walletAccountService: wallet_account_service.Service
@ -163,6 +164,7 @@ proc newModule*[T](
result.urlsManager = urlsManager result.urlsManager = urlsManager
result.keycardService = keycardService result.keycardService = keycardService
result.settingsService = settingsService result.settingsService = settingsService
result.networkService = networkService
result.privacyService = privacyService result.privacyService = privacyService
result.accountsService = accountsService result.accountsService = accountsService
result.walletAccountService = walletAccountService result.walletAccountService = walletAccountService
@ -981,7 +983,7 @@ method getKeycardSharedModule*[T](self: Module[T]): QVariant =
proc createSharedKeycardModule[T](self: Module[T]) = proc createSharedKeycardModule[T](self: Module[T]) =
self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_IDENTIFIER, self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService, self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService) self.walletAccountService, self.keychainService)
method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool) = method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool) =
@ -1003,7 +1005,7 @@ method onSharedKeycarModuleKeycardSyncPurposeTerminated*[T](self: Module[T], las
method tryKeycardSync*[T](self: Module[T], keyUid: string, pin: string) = method tryKeycardSync*[T](self: Module[T], keyUid: string, pin: string) =
self.keycardSharedModuleKeycardSyncPurpose = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER, self.keycardSharedModuleKeycardSyncPurpose = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService, self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService) self.walletAccountService, self.keychainService)
if self.keycardSharedModuleKeycardSyncPurpose.isNil: if self.keycardSharedModuleKeycardSyncPurpose.isNil:
return return

View File

@ -8,6 +8,7 @@ import ../../../../core/eventemitter
import ../../../../../app_service/service/keycard/service as keycard_service import ../../../../../app_service/service/keycard/service as keycard_service
import ../../../../../app_service/service/settings/service as settings_service import ../../../../../app_service/service/settings/service as settings_service
import ../../../../../app_service/service/network/service as network_service
import ../../../../../app_service/service/privacy/service as privacy_service import ../../../../../app_service/service/privacy/service as privacy_service
import ../../../../../app_service/service/accounts/service as accounts_service import ../../../../../app_service/service/accounts/service as accounts_service
import ../../../../../app_service/service/wallet_account/service as wallet_account_service import ../../../../../app_service/service/wallet_account/service as wallet_account_service
@ -36,6 +37,7 @@ type
events: EventEmitter events: EventEmitter
keycardService: keycard_service.Service keycardService: keycard_service.Service
settingsService: settings_service.Service settingsService: settings_service.Service
networkService: network_service.Service
privacyService: privacy_service.Service privacyService: privacy_service.Service
accountsService: accounts_service.Service accountsService: accounts_service.Service
walletAccountService: wallet_account_service.Service walletAccountService: wallet_account_service.Service
@ -49,6 +51,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
events: EventEmitter, events: EventEmitter,
keycardService: keycard_service.Service, keycardService: keycard_service.Service,
settingsService: settings_service.Service, settingsService: settings_service.Service,
networkService: network_service.Service,
privacyService: privacy_service.Service, privacyService: privacy_service.Service,
accountsService: accounts_service.Service, accountsService: accounts_service.Service,
walletAccountService: wallet_account_service.Service, walletAccountService: wallet_account_service.Service,
@ -58,6 +61,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result.events = events result.events = events
result.keycardService = keycardService result.keycardService = keycardService
result.settingsService = settingsService result.settingsService = settingsService
result.networkService = networkService
result.privacyService = privacyService result.privacyService = privacyService
result.accountsService = accountsService result.accountsService = accountsService
result.walletAccountService = walletAccountService result.walletAccountService = walletAccountService
@ -102,7 +106,7 @@ proc createSharedKeycardModule(self: Module) =
self.view.emitSharedModuleBusy() self.view.emitSharedModuleBusy()
return return
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_SETTING_KEYCARD_MODULE_IDENTIFIER, self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_SETTING_KEYCARD_MODULE_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService, self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService) self.walletAccountService, self.keychainService)
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) = method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) =

View File

@ -106,8 +106,8 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result, events, settingsService, ensService, walletAccountService, networkService, tokenService result, events, settingsService, ensService, walletAccountService, networkService, tokenService
) )
result.communitiesModule = communities_module.newModule(result, communityService) result.communitiesModule = communities_module.newModule(result, communityService)
result.keycardModule = keycard_module.newModule(result, events, keycardService, settingsService, privacyService, result.keycardModule = keycard_module.newModule(result, events, keycardService, settingsService, networkService,
accountsService, walletAccountService, keychainService) privacyService, accountsService, walletAccountService, keychainService)
singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant) singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant)

View File

@ -237,7 +237,7 @@ method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid:
method createSharedKeycardModule*(self: Module) = method createSharedKeycardModule*(self: Module) =
if self.keycardSharedModule.isNil: if self.keycardSharedModule.isNil:
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER, self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER,
self.events, self.keycardService, settingsService = nil, privacyService = nil, self.accountsService, self.events, self.keycardService, settingsService = nil, networkService = nil, privacyService = nil, self.accountsService,
self.walletAccountService, keychainService = nil) self.walletAccountService, keychainService = nil)
method destroySharedKeycarModule*(self: Module) = method destroySharedKeycarModule*(self: Module) =

View File

@ -12,6 +12,7 @@ import ../../../../app_service/common/utils
import ../../../../app_service/common/account_constants import ../../../../app_service/common/account_constants
import ../../../../app_service/service/keycard/service as keycard_service import ../../../../app_service/service/keycard/service as keycard_service
import ../../../../app_service/service/settings/service as settings_service import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/network/service as network_service
import ../../../../app_service/service/privacy/service as privacy_service import ../../../../app_service/service/privacy/service as privacy_service
import ../../../../app_service/service/accounts/service as accounts_service import ../../../../app_service/service/accounts/service as accounts_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service import ../../../../app_service/service/wallet_account/service as wallet_account_service
@ -29,6 +30,7 @@ type
events: EventEmitter events: EventEmitter
keycardService: keycard_service.Service keycardService: keycard_service.Service
settingsService: settings_service.Service settingsService: settings_service.Service
networkService: network_service.Service
privacyService: privacy_service.Service privacyService: privacy_service.Service
accountsService: accounts_service.Service accountsService: accounts_service.Service
walletAccountService: wallet_account_service.Service walletAccountService: wallet_account_service.Service
@ -71,6 +73,7 @@ proc newController*(delegate: io_interface.AccessInterface,
events: EventEmitter, events: EventEmitter,
keycardService: keycard_service.Service, keycardService: keycard_service.Service,
settingsService: settings_service.Service, settingsService: settings_service.Service,
networkService: network_service.Service,
privacyService: privacy_service.Service, privacyService: privacy_service.Service,
accountsService: accounts_service.Service, accountsService: accounts_service.Service,
walletAccountService: wallet_account_service.Service, walletAccountService: wallet_account_service.Service,
@ -82,6 +85,7 @@ proc newController*(delegate: io_interface.AccessInterface,
result.events = events result.events = events
result.keycardService = keycardService result.keycardService = keycardService
result.settingsService = settingsService result.settingsService = settingsService
result.networkService = networkService
result.privacyService = privacyService result.privacyService = privacyService
result.accountsService = accountsService result.accountsService = accountsService
result.walletAccountService = walletAccountService result.walletAccountService = walletAccountService
@ -112,6 +116,8 @@ proc serviceApplicable[T](service: T): bool =
serviceName = "PrivacyService" serviceName = "PrivacyService"
when (service is settings_service.Service): when (service is settings_service.Service):
serviceName = "SettingsService" serviceName = "SettingsService"
when (service is network_service.Service):
serviceName = "NetworkService"
when (service is accounts_service.Service): when (service is accounts_service.Service):
serviceName = "AccountsService" serviceName = "AccountsService"
when (service is keychain_service.Service): when (service is keychain_service.Service):
@ -182,6 +188,11 @@ proc init*(self: Controller) =
self.delegate.onSecondaryActionClicked() self.delegate.onSecondaryActionClicked()
self.connectionIds.add(handlerId) self.connectionIds.add(handlerId)
handlerId = self.events.onWithUUID(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e:Args):
let arg = TokensPerAccountArgs(e)
self.delegate.onTokensRebuilt(arg.accountsTokens)
self.connectionIds.add(handlerId)
proc switchToWalletSection*(self: Controller) = proc switchToWalletSection*(self: Controller) =
let data = ActiveSectionChatArgs(sectionId: conf.WALLET_SECTION_ID) let data = ActiveSectionChatArgs(sectionId: conf.WALLET_SECTION_ID)
self.events.emit(SIGNAL_MAKE_SECTION_CHAT_ACTIVE, data) self.events.emit(SIGNAL_MAKE_SECTION_CHAT_ACTIVE, data)
@ -602,10 +613,11 @@ proc isKeyPairAlreadyAdded*(self: Controller, keyUid: string): bool =
let accountsForKeyUid = walletAccounts.filter(a => a.keyUid == keyUid) let accountsForKeyUid = walletAccounts.filter(a => a.keyUid == keyUid)
return accountsForKeyUid.len > 0 return accountsForKeyUid.len > 0
proc getCurrencyBalanceForAddress*(self: Controller, address: string): float64 = proc getOrFetchBalanceForAddressInPreferredCurrency*(self: Controller, address: string): tuple[balance: float64, fetched: bool] =
if not serviceApplicable(self.walletAccountService): if not serviceApplicable(self.walletAccountService):
return # Return 0, casuse JSON-RPC client is unavailable before user logs in.
return self.walletAccountService.getCurrencyBalanceForAddress(address) return (0.0, true)
return self.walletAccountService.getOrFetchBalanceForAddressInPreferredCurrency(address)
proc addMigratedKeyPair*(self: Controller, keyPair: KeyPairDto) = proc addMigratedKeyPair*(self: Controller, keyPair: KeyPairDto) =
if not serviceApplicable(self.walletAccountService): if not serviceApplicable(self.walletAccountService):
@ -682,6 +694,16 @@ proc getSigningPhrase*(self: Controller): string =
return return
return self.settingsService.getSigningPhrase() return self.settingsService.getSigningPhrase()
proc getCurrency*(self: Controller): string =
if not serviceApplicable(self.settingsService):
return
return self.settingsService.getCurrency()
proc getChainIdsOfAllKnownNetworks*(self: Controller): seq[int] =
if not serviceApplicable(self.networkService):
return
return self.networkService.getNetworks().map(n => n.chainId)
proc enterKeycardPin*(self: Controller, pin: string) = proc enterKeycardPin*(self: Controller, pin: string) =
if not serviceApplicable(self.keycardService): if not serviceApplicable(self.keycardService):
return return

View File

@ -1,6 +1,7 @@
import NimQml import NimQml, tables
import ../../../../app/core/eventemitter import ../../../../app/core/eventemitter
from ../../../../app_service/service/keycard/service import KeycardEvent, CardMetadata, KeyDetails from ../../../../app_service/service/keycard/service import KeycardEvent, CardMetadata, KeyDetails
from ../../../../app_service/service/wallet_account/service as wallet_account_service import WalletTokenDto
import models/key_pair_item import models/key_pair_item
const SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED_AND_WALLET_ADDRESS_GENERATED* = "sharedKeycarModuleUserAuthenticatedAndWalletAddressGenerated" const SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED_AND_WALLET_ADDRESS_GENERATED* = "sharedKeycarModuleUserAuthenticatedAndWalletAddressGenerated"
@ -202,5 +203,8 @@ method syncKeycardBasedOnAppState*(self: AccessInterface, keyUid: string, pin: s
method getPin*(self: AccessInterface): string {.base.} = method getPin*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onTokensRebuilt*(self: AccessInterface, accountsTokens: OrderedTable[string, seq[WalletTokenDto]]) {.base.} =
raise newException(ValueError, "No implementation available")
type type
DelegateInterface* = concept c DelegateInterface* = concept c

View File

@ -10,12 +10,13 @@ QtObject:
color: string color: string
icon: string icon: string
balance: float balance: float
balanceFetched: bool
proc delete*(self: KeyPairAccountItem) = proc delete*(self: KeyPairAccountItem) =
self.QObject.delete self.QObject.delete
proc newKeyPairAccountItem*(name = "", path = "", address = "", pubKey = "", emoji = "", color = "", icon = "", proc newKeyPairAccountItem*(name = "", path = "", address = "", pubKey = "", emoji = "", color = "", icon = "",
balance = 0.0): KeyPairAccountItem = balance = 0.0, balanceFetched = true): KeyPairAccountItem =
new(result, delete) new(result, delete)
result.QObject.setup result.QObject.setup
result.name = name result.name = name
@ -26,6 +27,7 @@ QtObject:
result.color = color result.color = color
result.icon = icon result.icon = icon
result.balance = balance result.balance = balance
result.balanceFetched = balanceFetched
proc `$`*(self: KeyPairAccountItem): string = proc `$`*(self: KeyPairAccountItem): string =
result = fmt"""KeyPairAccountItem[ result = fmt"""KeyPairAccountItem[
@ -37,7 +39,8 @@ QtObject:
color: {self.color}, color: {self.color},
icon: {self.icon}, icon: {self.icon},
icon: {$self.icon}, icon: {$self.icon},
balance: {self.balance} balance: {self.balance},
balanceFetched: {self.balanceFetched}
]""" ]"""
proc nameChanged*(self: KeyPairAccountItem) {.signal.} proc nameChanged*(self: KeyPairAccountItem) {.signal.}
@ -122,8 +125,15 @@ QtObject:
return self.balance return self.balance
proc setBalance*(self: KeyPairAccountItem, value: float) {.slot.} = proc setBalance*(self: KeyPairAccountItem, value: float) {.slot.} =
self.balance = value self.balance = value
self.balanceFetched = true
self.balanceChanged() self.balanceChanged()
QtProperty[float] balance: QtProperty[float] balance:
read = getBalance read = getBalance
write = setBalance write = setBalance
notify = balanceChanged
proc getBalanceFetched*(self: KeyPairAccountItem): bool {.slot.} =
return self.balanceFetched
QtProperty[bool] balanceFetched:
read = getBalanceFetched
notify = balanceChanged notify = balanceChanged

View File

@ -119,4 +119,9 @@ QtObject:
if emoji.len > 0: if emoji.len > 0:
self.items[i].setEmoji(emoji) self.items[i].setEmoji(emoji)
return return
proc setBalanceForAddress*(self: KeyPairAccountModel, address: string, balance: float) =
for i in 0 ..< self.items.len:
if cmpIgnoreCase(self.items[i].getAddress(), address) == 0:
self.items[i].setBalance(balance)

View File

@ -196,6 +196,8 @@ QtObject:
return self.accounts.containsPathOutOfTheDefaultStatusDerivationTree() return self.accounts.containsPathOutOfTheDefaultStatusDerivationTree()
proc updateDetailsForAccountWithAddressIfTheyAreSet*(self: KeyPairItem, address, name, color, emoji: string) = proc updateDetailsForAccountWithAddressIfTheyAreSet*(self: KeyPairItem, address, name, color, emoji: string) =
self.accounts.updateDetailsForAddressIfTheyAreSet(address, name, color, emoji) self.accounts.updateDetailsForAddressIfTheyAreSet(address, name, color, emoji)
proc setBalanceForAddress*(self: KeyPairItem, address: string, balance: float) =
self.accounts.setBalanceForAddress(address, balance)
proc setItem*(self: KeyPairItem, item: KeyPairItem) = proc setItem*(self: KeyPairItem, item: KeyPairItem) =
self.setKeyUid(item.getKeyUid()) self.setKeyUid(item.getKeyUid())

View File

@ -1,4 +1,4 @@
import NimQml, random, strutils, marshal, sequtils, sugar, chronicles import NimQml, tables, random, strutils, marshal, sequtils, sugar, chronicles
import io_interface import io_interface
import view, controller import view, controller
@ -11,6 +11,7 @@ import ../../../../app_service/common/utils
import ../../../../app_service/service/keycard/constants import ../../../../app_service/service/keycard/constants
import ../../../../app_service/service/keycard/service as keycard_service import ../../../../app_service/service/keycard/service as keycard_service
import ../../../../app_service/service/settings/service as settings_service import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/network/service as network_service
import ../../../../app_service/service/privacy/service as privacy_service import ../../../../app_service/service/privacy/service as privacy_service
import ../../../../app_service/service/accounts/service as accounts_service import ../../../../app_service/service/accounts/service as accounts_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service import ../../../../app_service/service/wallet_account/service as wallet_account_service
@ -43,6 +44,7 @@ proc newModule*[T](delegate: T,
events: EventEmitter, events: EventEmitter,
keycardService: keycard_service.Service, keycardService: keycard_service.Service,
settingsService: settings_service.Service, settingsService: settings_service.Service,
networkService: network_service.Service,
privacyService: privacy_service.Service, privacyService: privacy_service.Service,
accountsService: accounts_service.Service, accountsService: accounts_service.Service,
walletAccountService: wallet_account_service.Service, walletAccountService: wallet_account_service.Service,
@ -53,7 +55,7 @@ proc newModule*[T](delegate: T,
result.view = view.newView(result) result.view = view.newView(result)
result.viewVariant = newQVariant(result.view) result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, uniqueIdentifier, events, keycardService, settingsService, result.controller = controller.newController(result, uniqueIdentifier, events, keycardService, settingsService,
privacyService, accountsService, walletAccountService, keychainService) networkService, privacyService, accountsService, walletAccountService, keychainService)
result.initialized = false result.initialized = false
result.authenticationPopupIsAlreadyRunning = false result.authenticationPopupIsAlreadyRunning = false
result.derivingAccountDetails.deriveAddressAfterAuthentication = false result.derivingAccountDetails.deriveAddressAfterAuthentication = false
@ -624,10 +626,17 @@ proc updateKeyPairItemIfDataAreKnown[T](self: Module[T], address: string, item:
if a.walletType == WalletTypeDefaultStatusAccount: if a.walletType == WalletTypeDefaultStatusAccount:
icon = "wallet" icon = "wallet"
item.setKeyUid(a.keyUid) item.setKeyUid(a.keyUid)
item.addAccount(newKeyPairAccountItem(a.name, a.path, a.address, a.publicKey, a.emoji, a.color, icon, balance = 0.0)) item.addAccount(newKeyPairAccountItem(a.name, a.path, a.address, a.publicKey, a.emoji, a.color, icon, balance = 0.0, balanceFetched = true))
return true return true
return false return false
method onTokensRebuilt*[T](self: Module[T], accountsTokens: OrderedTable[string, seq[WalletTokenDto]]) =
let chainIds = self.controller.getChainIdsOfAllKnownNetworks()
let currency = self.controller.getCurrency()
for address, tokens in accountsTokens.pairs:
let balance = tokens.map(t => t.getCurrencyBalance(chainIds, currency)).foldl(a + b, 0.0)
self.getKeyPairForProcessing().setBalanceForAddress(address, balance)
proc buildKeyPairItemBasedOnCardMetadata[T](self: Module[T], cardMetadata: CardMetadata): proc buildKeyPairItemBasedOnCardMetadata[T](self: Module[T], cardMetadata: CardMetadata):
tuple[item: KeyPairItem, knownKeyPair: bool] = tuple[item: KeyPairItem, knownKeyPair: bool] =
result.item = newKeyPairItem(keyUid = "", result.item = newKeyPairItem(keyUid = "",
@ -646,9 +655,10 @@ proc buildKeyPairItemBasedOnCardMetadata[T](self: Module[T], cardMetadata: CardM
for wa in cardMetadata.walletAccounts: for wa in cardMetadata.walletAccounts:
if self.updateKeyPairItemIfDataAreKnown(wa.address, result.item): if self.updateKeyPairItemIfDataAreKnown(wa.address, result.item):
continue continue
let balance = self.controller.getCurrencyBalanceForAddress(wa.address) let (balance, balanceFetched) = self.controller.getOrFetchBalanceForAddressInPreferredCurrency(wa.address)
result.knownKeyPair = false result.knownKeyPair = false
result.item.addAccount(newKeyPairAccountItem(name = "", wa.path, wa.address, pubKey = wa.publicKey, emoji = "", color = self.generateRandomColor(), icon = "wallet", balance)) result.item.addAccount(newKeyPairAccountItem(name = "", wa.path, wa.address, pubKey = wa.publicKey, emoji = "",
color = self.generateRandomColor(), icon = "wallet", balance, balanceFetched))
method updateKeyPairForProcessing*[T](self: Module[T], cardMetadata: CardMetadata) = method updateKeyPairForProcessing*[T](self: Module[T], cardMetadata: CardMetadata) =
let(item, knownKeyPair) = self.buildKeyPairItemBasedOnCardMetadata(cardMetadata) let(item, knownKeyPair) = self.buildKeyPairItemBasedOnCardMetadata(cardMetadata)

View File

@ -129,7 +129,7 @@ method getKeycardSharedModule*[T](self: Module[T]): QVariant =
proc createSharedKeycardModule[T](self: Module[T]) = proc createSharedKeycardModule[T](self: Module[T]) =
self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_STARTUP_MODULE_IDENTIFIER, self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_STARTUP_MODULE_IDENTIFIER,
self.events, self.keycardService, settingsService = nil, privacyService = nil, self.accountsService, self.events, self.keycardService, settingsService = nil, networkService = nil, privacyService = nil, self.accountsService,
walletAccountService = nil, self.keychainService) walletAccountService = nil, self.keychainService)
method moveToLoadingAppState*[T](self: Module[T]) = method moveToLoadingAppState*[T](self: Module[T]) =

View File

@ -112,11 +112,21 @@ const fetchDerivedAddressDetailsTask*: Task = proc(argEncoded: string) {.gcsafe,
type type
BuildTokensTaskArg = ref object of QObjectTaskArg BuildTokensTaskArg = ref object of QObjectTaskArg
accounts: seq[string] accounts: seq[string]
storeResult: bool
const prepareTokensTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = const prepareTokensTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[BuildTokensTaskArg](argEncoded) let arg = decode[BuildTokensTaskArg](argEncoded)
let response = backend.getWalletToken(arg.accounts) var output = %*{
arg.finish(response.result) "result": "",
"storeResult": false
}
try:
let response = backend.getWalletToken(arg.accounts)
output["result"] = response.result
output["storeResult"] = %* arg.storeResult
except Exception as e:
let err = fmt"Error getting wallet tokens"
arg.finish(output)
################################################# #################################################
# Async add migrated keypair # Async add migrated keypair

View File

@ -120,7 +120,7 @@ QtObject:
walletAccounts {.guard: walletAccountsLock.}: OrderedTable[string, WalletAccountDto] walletAccounts {.guard: walletAccountsLock.}: OrderedTable[string, WalletAccountDto]
# Forward declaration # Forward declaration
proc buildAllTokens(self: Service, accounts: seq[string]) proc buildAllTokens(self: Service, accounts: seq[string], store: bool)
proc checkRecentHistory*(self: Service) proc checkRecentHistory*(self: Service)
proc checkConnected(self: Service) proc checkConnected(self: Service)
proc startWallet(self: Service) proc startWallet(self: Service)
@ -212,7 +212,7 @@ QtObject:
account.relatedAccounts = accounts.filter(x => not account.derivedFrom.isEmptyOrWhitespace and (cmpIgnoreCase(x.derivedFrom, account.derivedFrom) == 0)) account.relatedAccounts = accounts.filter(x => not account.derivedFrom.isEmptyOrWhitespace and (cmpIgnoreCase(x.derivedFrom, account.derivedFrom) == 0))
self.storeAccount(account) self.storeAccount(account)
self.buildAllTokens(self.getAddresses()) self.buildAllTokens(self.getAddresses(), store = true)
self.checkRecentHistory() self.checkRecentHistory()
self.startWallet() self.startWallet()
except Exception as e: except Exception as e:
@ -231,7 +231,7 @@ QtObject:
var data = WalletSignal(e) var data = WalletSignal(e)
case data.eventType: case data.eventType:
of "wallet-tick-reload": of "wallet-tick-reload":
self.buildAllTokens(self.getAddresses()) self.buildAllTokens(self.getAddresses(), store = true)
self.checkRecentHistory() self.checkRecentHistory()
of "wallet-tick-check-connected": of "wallet-tick-check-connected":
self.checkConnected() self.checkConnected()
@ -290,7 +290,7 @@ QtObject:
newAccount.relatedAccounts = accounts.filter(x => cmpIgnoreCase(x.derivedFrom, account.derivedFrom) == 0) newAccount.relatedAccounts = accounts.filter(x => cmpIgnoreCase(x.derivedFrom, account.derivedFrom) == 0)
break break
self.storeAccount(newAccount) self.storeAccount(newAccount)
self.buildAllTokens(@[newAccount.address]) self.buildAllTokens(@[newAccount.address], store = true)
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount)) self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
proc addOrReplaceWalletAccount(self: Service, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType, proc addOrReplaceWalletAccount(self: Service, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType,
@ -405,7 +405,7 @@ QtObject:
proc updateCurrency*(self: Service, newCurrency: string) = proc updateCurrency*(self: Service, newCurrency: string) =
discard self.settingsService.saveCurrency(newCurrency) discard self.settingsService.saveCurrency(newCurrency)
self.buildAllTokens(self.getAddresses()) self.buildAllTokens(self.getAddresses(), store = true)
self.events.emit(SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED, CurrencyUpdated()) self.events.emit(SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED, CurrencyUpdated())
proc toggleNetworkEnabled*(self: Service, chainId: int) = proc toggleNetworkEnabled*(self: Service, chainId: int) =
@ -525,27 +525,33 @@ QtObject:
let chainIds = self.networkService.getNetworks().map(n => n.chainId) let chainIds = self.networkService.getNetworks().map(n => n.chainId)
let responseObj = response.parseJson let responseObj = response.parseJson
var storeResult: bool
var resultObj: JsonNode
discard responseObj.getProp("storeResult", storeResult)
discard responseObj.getProp("result", resultObj)
var data = TokensPerAccountArgs() var data = TokensPerAccountArgs()
if responseObj.kind == JObject: if resultObj.kind == JObject:
for wAddress, tokensDetailsObj in responseObj: for wAddress, tokensDetailsObj in resultObj:
if tokensDetailsObj.kind == JArray: if tokensDetailsObj.kind == JArray:
var tokens: seq[WalletTokenDto] var tokens: seq[WalletTokenDto]
tokens = map(tokensDetailsObj.getElems(), proc(x: JsonNode): WalletTokenDto = x.toWalletTokenDto()) tokens = map(tokensDetailsObj.getElems(), proc(x: JsonNode): WalletTokenDto = x.toWalletTokenDto())
tokens.sort(priorityTokenCmp) tokens.sort(priorityTokenCmp)
data.accountsTokens[wAddress] = tokens data.accountsTokens[wAddress] = tokens
self.storeTokensForAccount(wAddress, tokens) if storeResult:
self.tokenService.updateTokenPrices(tokens) # For efficiency. Will be removed when token info fetching gets moved to the tokenService self.storeTokensForAccount(wAddress, tokens)
# Gather symbol for visible tokens self.tokenService.updateTokenPrices(tokens) # For efficiency. Will be removed when token info fetching gets moved to the tokenService
for token in tokens: # Gather symbol for visible tokens
if token.getVisibleForNetworkWithPositiveBalance(chainIds) and find(visibleSymbols, token.symbol) == -1: for token in tokens:
visibleSymbols.add(token.symbol) if token.getVisibleForNetworkWithPositiveBalance(chainIds) and find(visibleSymbols, token.symbol) == -1:
visibleSymbols.add(token.symbol)
self.events.emit(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT, data) self.events.emit(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT, data)
if visibleSymbols.len > 0:
discard backend.updateVisibleTokens(visibleSymbols) discard backend.updateVisibleTokens(visibleSymbols)
except Exception as e: except Exception as e:
error "error: ", procName="onAllTokensBuilt", errName = e.name, errDesription = e.msg error "error: ", procName="onAllTokensBuilt", errName = e.name, errDesription = e.msg
proc buildAllTokens(self: Service, accounts: seq[string]) = proc buildAllTokens(self: Service, accounts: seq[string], store: bool) =
if not singletonInstance.localAccountSensitiveSettings.getIsWalletEnabled() or if not singletonInstance.localAccountSensitiveSettings.getIsWalletEnabled() or
accounts.len == 0: accounts.len == 0:
return return
@ -554,16 +560,17 @@ QtObject:
tptr: cast[ByteAddress](prepareTokensTask), tptr: cast[ByteAddress](prepareTokensTask),
vptr: cast[ByteAddress](self.vptr), vptr: cast[ByteAddress](self.vptr),
slot: "onAllTokensBuilt", slot: "onAllTokensBuilt",
accounts: accounts accounts: accounts,
storeResult: store
) )
self.threadpool.start(arg) self.threadpool.start(arg)
proc onIsWalletEnabledChanged*(self: Service) {.slot.} = proc onIsWalletEnabledChanged*(self: Service) {.slot.} =
self.buildAllTokens(self.getAddresses()) self.buildAllTokens(self.getAddresses(), store = true)
self.checkRecentHistory() self.checkRecentHistory()
self.startWallet() self.startWallet()
proc getCurrentCurrencyIfEmpty(self: Service, currency: string): string = proc getCurrentCurrencyIfEmpty(self: Service, currency = ""): string =
if currency != "": if currency != "":
return currency return currency
else: else:
@ -577,9 +584,15 @@ QtObject:
proc findTokenSymbolByAddress*(self: Service, address: string): string = proc findTokenSymbolByAddress*(self: Service, address: string): string =
return self.tokenService.findTokenSymbolByAddress(address) return self.tokenService.findTokenSymbolByAddress(address)
proc getCurrencyBalanceForAddress*(self: Service, address: string, currency: string = ""): float64 = proc getOrFetchBalanceForAddressInPreferredCurrency*(self: Service, address: string): tuple[balance: float64, fetched: bool] =
let chainIds = self.networkService.getNetworks().map(n => n.chainId) if self.walletAccountsContainsAddress(address):
return self.getAccountByAddress(address).getCurrencyBalance(chainIds, self.getCurrentCurrencyIfEmpty(currency)) let chainIds = self.networkService.getNetworks().map(n => n.chainId)
result.balance = self.getAccountByAddress(address).getCurrencyBalance(chainIds, self.getCurrentCurrencyIfEmpty())
result.fetched = true
else:
self.buildAllTokens(@[address], store = false)
result.balance = 0.0
result.fetched = false
proc getTotalCurrencyBalance*(self: Service, currency: string = ""): float64 = proc getTotalCurrencyBalance*(self: Service, currency: string = ""): float64 =
let chainIds = self.networkService.getNetworks().filter(a => a.enabled).map(a => a.chainId) let chainIds = self.networkService.getNetworks().filter(a => a.enabled).map(a => a.chainId)

View File

@ -126,17 +126,34 @@ Rectangle {
Layout.preferredHeight: parent.height Layout.preferredHeight: parent.height
} }
StatusBaseText { Component {
Layout.alignment: Qt.AlignVCenter id: balance
text: { StatusBaseText {
return LocaleUtils.currencyAmountToLocaleString({
amount: parseFloat(model.account.balance.amount), text: {
symbol: SharedStore.RootStore.currencyStore.currentCurrencySymbol, return LocaleUtils.currencyAmountToLocaleString({
displayDecimals: 2}) amount: parseFloat(model.account.balance),
symbol: SharedStore.RootStore.currencyStore.currentCurrencySymbol,
displayDecimals: 2})
}
wrapMode: Text.WordWrap
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.baseColor1
} }
wrapMode: Text.WordWrap }
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.baseColor1 Component {
id: fetchingBalance
StatusLoadingIndicator {
width: 12
height: 12
}
}
Loader {
id: fetchLoaderIndicator
Layout.alignment: Qt.AlignVCenter
sourceComponent: model.account.balanceFetched? balance : fetchingBalance
} }
} }
} }