chore(@desktop/syncing): wallet keypairs/accounts syncing improvements part 1/2

Handling syncing improvements done on the status-go side.

Closes: #11267
This commit is contained in:
Sale Djenic 2023-06-30 12:19:39 +02:00 committed by saledjenic
parent c10809863a
commit a10e83bcba
18 changed files with 326 additions and 227 deletions

View File

@ -12,7 +12,7 @@ import ../../../../app_service/service/contacts/dto/[contacts, status_update]
import ../../../../app_service/service/devices/dto/[installation]
import ../../../../app_service/service/settings/dto/[settings]
import ../../../../app_service/service/saved_address/dto as saved_address_dto
import ../../../../app_service/service/wallet_account/[keypair_dto, keycard_dto]
import ../../../../app_service/service/wallet_account/[keypair_dto]
type MessageSignal* = ref object of Signal
bookmarks*: seq[BookmarkDto]
@ -36,9 +36,8 @@ type MessageSignal* = ref object of Signal
verificationRequests*: seq[VerificationRequest]
savedAddresses*: seq[SavedAddressDto]
keypairs*: seq[KeypairDto]
keycards*: seq[KeycardDto]
keycardActions*: seq[KeycardActionDto]
walletAccounts*: seq[WalletAccountDto]
# keycardActions*: seq[KeycardActionDto] //TODO: will be removed in the second part of synchronization improvements
watchOnlyAccounts*: seq[WalletAccountDto]
type MessageDeliveredSignal* = ref object of Signal
chatId*: string
@ -149,17 +148,14 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal =
for jsonKc in e["keypairs"]:
signal.keypairs.add(jsonKc.toKeypairDto())
if e.contains("keycards"):
for jsonKc in e["keycards"]:
signal.keycards.add(jsonKc.toKeycardDto())
## TODO: will be removed in the second part of synchronization improvements
# if e.contains("keycardActions"):
# for jsonKc in e["keycardActions"]:
# signal.keycardActions.add(jsonKc.toKeycardActionDto())
if e.contains("keycardActions"):
for jsonKc in e["keycardActions"]:
signal.keycardActions.add(jsonKc.toKeycardActionDto())
if e.contains("accounts"):
for jsonAcc in e["accounts"]:
signal.walletAccounts.add(jsonAcc.toWalletAccountDto())
if e.contains("watchOnlyAccounts"):
for jsonAcc in e["watchOnlyAccounts"]:
signal.watchOnlyAccounts.add(jsonAcc.toWalletAccountDto())
result = signal

View File

@ -50,7 +50,6 @@ type SignalType* {.pure.} = enum
WakuBackedUpProfile = "waku.backedup.profile"
WakuBackedUpSettings = "waku.backedup.settings"
WakuBackedUpKeypair = "waku.backedup.keypair"
WakuBackedUpKeycards = "waku.backedup.keycards"
WakuBackedUpWatchOnlyAccount = "waku.backedup.watch-only-account"
LocalPairing = "localPairing"
DBReEncryptionStarted = "db.reEncryption.started"

View File

@ -1,15 +0,0 @@
import json
import base
import ../../../../app_service/service/wallet_account/[keycard_dto]
type WakuBackedUpKeycardsSignal* = ref object of Signal
keycards*: seq[KeycardDto]
proc fromEvent*(T: type WakuBackedUpKeycardsSignal, event: JsonNode): WakuBackedUpKeycardsSignal =
result = WakuBackedUpKeycardsSignal()
let e = event["event"]
if e.contains("backedUpKeycards"):
for jsonKc in e["backedUpKeycards"]:
result.keycards.add(jsonKc.toKeycardDto())

View File

@ -55,12 +55,11 @@ QtObject:
if(signal.signalType == SignalType.NodeCrashed):
error "node.crashed", error=statusSignal
if self.ignoreBackedUpData and
if self.ignoreBackedUpData and
(signal.signalType == SignalType.WakuFetchingBackupProgress or
signal.signalType == SignalType.WakuBackedUpProfile or
signal.signalType == SignalType.WakuBackedUpSettings or
signal.signalType == SignalType.WakuBackedUpKeypair or
signal.signalType == SignalType.WakuBackedUpKeycards or
signal.signalType == SignalType.WakuBackedUpWatchOnlyAccount):
return
@ -119,7 +118,6 @@ QtObject:
of SignalType.WakuBackedUpProfile: WakuBackedUpProfileSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpSettings: WakuBackedUpSettingsSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpKeypair: WakuBackedUpKeypairSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpKeycards: WakuBackedUpKeycardsSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpWatchOnlyAccount: WakuBackedUpWatchOnlyAccountSignal.fromEvent(jsonSignal)
# pairing
of SignalType.LocalPairing: LocalPairingSignal.fromEvent(jsonSignal)

View File

@ -2,10 +2,10 @@
import ./remote_signals/[base, chronicles_logs, community, discovery_summary, envelope, expired, mailserver, messages,
peerstats, signal_type, stats, wallet, whisper_filter, update_available, status_updates, waku_backed_up_profile,
waku_backed_up_settings, waku_backed_up_keypair, waku_backed_up_keycards, waku_backed_up_watch_only_account,
waku_backed_up_settings, waku_backed_up_keypair, waku_backed_up_watch_only_account,
waku_fetching_backup_progress, pairing]
export base, chronicles_logs, community, discovery_summary, envelope, expired, mailserver, messages, peerstats,
signal_type, stats, wallet, whisper_filter, update_available, status_updates, waku_backed_up_profile,
waku_backed_up_settings, waku_backed_up_keypair, waku_backed_up_keycards, waku_backed_up_watch_only_account,
waku_backed_up_settings, waku_backed_up_keypair, waku_backed_up_watch_only_account,
waku_fetching_backup_progress, pairing

View File

@ -84,7 +84,7 @@ method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("browserSectionCurrentAccount", newQVariant(self.view))
self.events.on(SIGNAL_WALLET_ACCOUNT_DELETED) do(e:Args):
if(self.view.isAddressCurrentAccount(AccountDeleted(e).address)):
if(self.view.isAddressCurrentAccount(AccountArgs(e).account.address)):
self.switchAccount(0)
self.view.connectedAccountDeleted()

View File

@ -27,7 +27,7 @@ proc newController*(delegate: io_interface.AccessInterface,
result.delegate = delegate
result.events = events
result.walletAccountService = walletAccountService
proc delete*(self: Controller) =
discard
@ -53,11 +53,9 @@ proc init*(self: Controller) =
return
self.delegate.onNewKeycardSet(args.keycard)
self.events.on(SIGNAL_KEYCARDS_SYNCHRONIZED) do(e: Args):
let args = KeycardActivityArgs(e)
if not args.success:
return
self.delegate.rebuildKeycardsList()
self.events.on(SIGNAL_KEYPAIR_CHANGED) do(e: Args):
let args = KeypairArgs(e)
self.delegate.resolveRelatedKeycardsForKeypair(args.keypair)
self.events.on(SIGNAL_KEYCARD_LOCKED) do(e: Args):
let args = KeycardActivityArgs(e)
@ -82,14 +80,16 @@ proc init*(self: Controller) =
self.delegate.onKeycardAccountsRemoved(args.keycard.keyUid, args.keycard.keycardUid, args.keycard.accountsAddresses)
self.events.on(SIGNAL_WALLET_ACCOUNT_UPDATED) do(e: Args):
let args = WalletAccountUpdated(e)
let args = AccountArgs(e)
self.delegate.onWalletAccountUpdated(args.account)
self.events.on(SIGNAL_WALLET_ACCOUNT_SAVED) do(e: Args):
self.delegate.rebuildKeycardsList()
## TODO: will be removed in the second part of synchronization improvements
# self.events.on(SIGNAL_WALLET_ACCOUNT_SAVED) do(e: Args):
# self.delegate.rebuildKeycardsList()
self.events.on(SIGNAL_WALLET_ACCOUNT_DELETED) do(e: Args):
self.delegate.rebuildKeycardsList()
## TODO: will be removed in the second part of synchronization improvements
# self.events.on(SIGNAL_WALLET_ACCOUNT_DELETED) do(e: Args):
# self.delegate.rebuildKeycardsList()
proc getAllKnownKeycardsGroupedByKeyUid*(self: Controller): seq[KeycardDto] =
return self.walletAccountService.getAllKnownKeycardsGroupedByKeyUid()
@ -97,5 +97,9 @@ proc getAllKnownKeycardsGroupedByKeyUid*(self: Controller): seq[KeycardDto] =
proc getAllKnownKeycards*(self: Controller): seq[KeycardDto] =
return self.walletAccountService.getAllKnownKeycards()
proc getKeypairs*(self: Controller): seq[wallet_account_service.KeypairDto] =
return self.walletAccountService.getKeypairs()
## TODO: will be removed in the second part of synchronization improvements
# proc getKeypairs*(self: Controller): seq[wallet_account_service.KeypairDto] =
# return self.walletAccountService.getKeypairs()
proc getKeypairByKeyUid*(self: Controller, keyUid: string): wallet_account_service.KeypairDto =
return self.walletAccountService.getKeypairByKeyUid(keyUid)

View File

@ -1,6 +1,5 @@
import NimQml
from ../../../../../app_service/service/wallet_account/service import KeycardDto
from ../../../../../app_service/service/wallet_account/service import WalletAccountDto
import app_service/service/wallet_account/keypair_dto
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -23,7 +22,7 @@ method getKeycardSharedModule*(self: AccessInterface): QVariant {.base.} =
method onDisplayKeycardSharedModuleFlow*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
raise newException(ValueError, "No implementation available")
@ -66,7 +65,7 @@ method runCreateNewPairingCodePopup*(self: AccessInterface, keyUid: string) {.ba
method onLoggedInUserImageChanged*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method rebuildKeycardsList*(self: AccessInterface) {.base.} =
method resolveRelatedKeycardsForKeypair*(self: AccessInterface, keypair: KeypairDto) {.base.} =
raise newException(ValueError, "No implementation available")
method onNewKeycardSet*(self: AccessInterface, keyPair: KeycardDto) {.base.} =

View File

@ -106,8 +106,8 @@ proc createSharedKeycardModule(self: Module) =
info "keycard shared module is still running"
self.view.emitSharedModuleBusy()
return
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_SETTING_KEYCARD_MODULE_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_SETTING_KEYCARD_MODULE_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService)
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) =
@ -136,7 +136,7 @@ method runImportOrRestoreViaSeedPhrasePopup*(self: Module) =
if self.keycardSharedModule.isNil:
return
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.SetupNewKeycardOldSeedPhrase)
method runImportFromKeycardToAppPopup*(self: Module) =
self.createSharedKeycardModule()
if self.keycardSharedModule.isNil:
@ -191,14 +191,13 @@ method runCreateNewPairingCodePopup*(self: Module, keyUid: string) =
return
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.ChangePairingCode, keyUid)
proc findAccountByAccountAddress(keypairs: seq[KeypairDto], address: string): WalletAccountDto =
for kp in keypairs:
for acc in kp.accounts:
if cmpIgnoreCase(acc.address, address) == 0:
return acc
proc findAccountByAccountAddress(accounts: seq[WalletAccountDto], address: string): WalletAccountDto =
for acc in accounts:
if cmpIgnoreCase(acc.address, address) == 0:
return acc
return nil
proc buildKeycardItem(self: Module, keypairs: seq[KeypairDto], keycard: KeycardDto, reason: BuildItemReason):
proc buildKeycardItem(self: Module, keypair: KeypairDto, keycard: KeycardDto, reason: BuildItemReason):
KeycardItem =
let isAccountInKnownAccounts = proc(knownAccounts: seq[WalletAccountDto], address: string): bool =
for i in 0 ..< knownAccounts.len:
@ -206,20 +205,23 @@ proc buildKeycardItem(self: Module, keypairs: seq[KeypairDto], keycard: KeycardD
return true
return false
if keypair.isNil:
return
var knownAccounts: seq[WalletAccountDto]
var unknownAccountsAddresses: seq[string]
for accAddr in keycard.accountsAddresses:
let account = findAccountByAccountAddress(keypairs, accAddr)
let account = findAccountByAccountAddress(keypair.accounts, accAddr)
if account.isNil:
## We are here if the keycard is not sync yet with the app's state. That may happen if there are more copies of the
## We are here if the keycard is not sync yet with the app's state. That may happen if there are more copies of the
## same keycard, then deleting an account for a keypair syncs the inserted keycard, but other copies of the card
## remain with that account till the moment they are synced.
unknownAccountsAddresses.add(accAddr)
continue
if reason == BuildItemReason.MainView and
(isAccountInKnownAccounts(knownAccounts, accAddr) or
not self.view.keycardModel().getItemForKeyUid(account.keyUid).isNil):
if reason == BuildItemReason.MainView and
isAccountInKnownAccounts(knownAccounts, accAddr):
# if there are more then one keycard for a single keypair we don't want to add the same keypair more than once
# that's why caller of this proc should set `upgradeItem` to true, if item with the same `keyUid` was already added
# to a model for the `MainView`
continue
knownAccounts.add(account)
var item = initKeycardItem(keycardUid = keycard.keycardUid,
@ -233,10 +235,7 @@ proc buildKeycardItem(self: Module, keypairs: seq[KeypairDto], keycard: KeycardD
item.setPairType(KeyPairType.SeedImport.int)
item.setIcon("keycard")
else:
for kp in keypairs:
if kp.keyUid == keycard.keyUid:
item.setDerivedFrom(kp.derivedFrom)
break
item.setDerivedFrom(keypair.derivedFrom)
for ka in knownAccounts:
var icon = ""
@ -268,11 +267,11 @@ proc areAllKnownKeycardsLockedForKeypair(self: Module, keyUid: string): bool =
return keyUidRelatedKeycards.all(kp => kp.keycardLocked)
proc buildKeycardList(self: Module) =
let keypairs = self.controller.getKeypairs()
var items: seq[KeycardItem]
let migratedKeyPairs = self.controller.getAllKnownKeycardsGroupedByKeyUid()
for kp in migratedKeyPairs:
let item = self.buildKeycardItem(keypairs, kp, BuildItemReason.MainView)
let keypair = self.controller.getKeypairByKeyUid(kp.keyUid)
let item = self.buildKeycardItem(keypair, kp, BuildItemReason.MainView)
if item.isNil:
continue
## If all created keycards for certain keypair are locked, then we need to display that item as locked.
@ -287,90 +286,157 @@ method onLoggedInUserImageChanged*(self: Module) =
return
self.view.keycardDetailsModel().setImage(singletonInstance.userProfile.getPubKey(), singletonInstance.userProfile.getIcon())
method rebuildKeycardsList*(self: Module) =
self.view.setKeycardItems(@[])
self.buildKeycardList()
method resolveRelatedKeycardsForKeypair*(self: Module, keypair: KeypairDto) =
if keypair.keyUid.len == 0:
error "cannot rebuild keycards for a keypair with empty keyUid"
return
var
mainViewItem: KeycardItem
detailsViewItems: seq[KeycardItem]
let
appHasDisplayedKeycards = not self.view.keycardModel().getItemForKeyUid(keypair.keyUid).isNil
detailsViewCurrentlyDisplayed = not self.view.keycardDetailsModel().isNil
# prepare main view item and if needed details view item
for kc in keypair.keycards:
# create main view item
if mainViewItem.isNil:
mainViewItem = self.buildKeycardItem(keypair, kc, BuildItemReason.MainView)
else:
for accAddr in kc.accountsAddresses:
if mainViewItem.containsAccountAddress(accAddr):
continue
let account = findAccountByAccountAddress(keypair.accounts, accAddr)
if account.isNil:
## we should never be here cause all accounts are firstly added to wallet
continue
mainViewItem.addAccount(newKeyPairAccountItem(account.name, account.path, account.address, account.publicKey,
account.emoji, account.colorId, icon = "", balance = 0.0))
# create details view item if model is not nil (means the details view is currently active)
if detailsViewCurrentlyDisplayed:
let item = self.buildKeycardItem(keypair, kc, BuildItemReason.DetailsView)
if not item.isNil:
detailsViewItems.add(item)
if appHasDisplayedKeycards:
if keypair.keycards.len == 0:
# remove all related keycards from the app
self.view.keycardModel().removeItemWithKeyUid(keypair.keyUid)
if not detailsViewCurrentlyDisplayed:
return
self.view.keycardDetailsModel().removeItemWithKeyUid(keypair.keyUid)
return
if keypair.keycards.len > 0:
# replace displayed keycards
if not mainViewItem.isNil:
self.view.keycardModel().replaceItemWithKeyUid(mainViewItem)
if not detailsViewCurrentlyDisplayed:
return
self.view.keycardDetailsModel().setItems(detailsViewItems)
return
return
# display new keycards
if not mainViewItem.isNil:
self.view.keycardModel().addItem(mainViewItem)
if not detailsViewCurrentlyDisplayed:
return
self.view.keycardDetailsModel().setItems(detailsViewItems)
method onNewKeycardSet*(self: Module, keyPair: KeycardDto) =
let keypairs = self.controller.getKeypairs()
var mainViewItem = self.view.keycardModel().getItemForKeyUid(keyPair.keyUid)
if mainViewItem.isNil:
mainViewItem = self.buildKeycardItem(keypairs, keyPair, BuildItemReason.MainView)
if not mainViewItem.isNil:
self.view.keycardModel().addItem(mainViewItem)
else:
for accAddr in keyPair.accountsAddresses:
if mainViewItem.containsAccountAddress(accAddr):
continue
let account = findAccountByAccountAddress(keypairs, accAddr)
if account.isNil:
## we should never be here cause all keypairs are firstly added to wallet
continue
mainViewItem.addAccount(newKeyPairAccountItem(account.name, account.path, account.address, account.publicKey,
account.emoji, account.colorId, icon = "", balance = 0.0))
if self.view.keycardDetailsModel().isNil:
return
var detailsViewItem = self.view.keycardDetailsModel().getItemForKeycardUid(keyPair.keycardUid)
if detailsViewItem.isNil:
detailsViewItem = self.buildKeycardItem(keypairs, keyPair, BuildItemReason.DetailsView)
if not detailsViewItem.isNil:
self.view.keycardDetailsModel().addItem(detailsViewItem)
else:
for accAddr in keyPair.accountsAddresses:
if detailsViewItem.containsAccountAddress(accAddr):
continue
let account = findAccountByAccountAddress(keypairs, accAddr)
if account.isNil:
## we should never be here cause all keypairs are firstly added to wallet
continue
detailsViewItem.addAccount(newKeyPairAccountItem(account.name, account.path, account.address, account.publicKey,
account.emoji, account.colorId, icon = "", balance = 0.0))
## TODO: will be removed in the second part of synchronization improvements
discard
# let keypairs = self.controller.getKeypairs()
# var mainViewItem = self.view.keycardModel().getItemForKeyUid(keyPair.keyUid)
# if mainViewItem.isNil:
# mainViewItem = self.buildKeycardItem(keypairs, keyPair, BuildItemReason.MainView)
# if not mainViewItem.isNil:
# self.view.keycardModel().addItem(mainViewItem)
# else:
# for accAddr in keyPair.accountsAddresses:
# if mainViewItem.containsAccountAddress(accAddr):
# continue
# let account = findAccountByAccountAddress(keypairs, accAddr)
# if account.isNil:
# ## we should never be here cause all keypairs are firstly added to wallet
# continue
# mainViewItem.addAccount(newKeyPairAccountItem(account.name, account.path, account.address, account.publicKey,
# account.emoji, account.colorId, icon = "", balance = 0.0))
# if self.view.keycardDetailsModel().isNil:
# return
# var detailsViewItem = self.view.keycardDetailsModel().getItemForKeycardUid(keyPair.keycardUid)
# if detailsViewItem.isNil:
# detailsViewItem = self.buildKeycardItem(keypairs, keyPair, BuildItemReason.DetailsView)
# if not detailsViewItem.isNil:
# self.view.keycardDetailsModel().addItem(detailsViewItem)
# else:
# for accAddr in keyPair.accountsAddresses:
# if detailsViewItem.containsAccountAddress(accAddr):
# continue
# let account = findAccountByAccountAddress(keypairs, accAddr)
# if account.isNil:
# ## we should never be here cause all keypairs are firstly added to wallet
# continue
# detailsViewItem.addAccount(newKeyPairAccountItem(account.name, account.path, account.address, account.publicKey,
# account.emoji, account.colorId, icon = "", balance = 0.0))
method onKeycardLocked*(self: Module, keyUid: string, keycardUid: string) =
self.view.keycardModel().setLockedForKeycardsWithKeyUid(keyUid, true)
if self.view.keycardDetailsModel().isNil:
return
self.view.keycardDetailsModel().setLockedForKeycardWithKeycardUid(keycardUid, true)
## TODO: will be removed in the second part of synchronization improvements
discard
# self.view.keycardModel().setLockedForKeycardsWithKeyUid(keyUid, true)
# if self.view.keycardDetailsModel().isNil:
# return
# self.view.keycardDetailsModel().setLockedForKeycardWithKeycardUid(keycardUid, true)
method onKeycardUnlocked*(self: Module, keyUid: string, keycardUid: string) =
self.view.keycardModel().setLockedForKeycardsWithKeyUid(keyUid, false)
if self.view.keycardDetailsModel().isNil:
return
self.view.keycardDetailsModel().setLockedForKeycardWithKeycardUid(keycardUid, false)
## TODO: will be removed in the second part of synchronization improvements
discard
# self.view.keycardModel().setLockedForKeycardsWithKeyUid(keyUid, false)
# if self.view.keycardDetailsModel().isNil:
# return
# self.view.keycardDetailsModel().setLockedForKeycardWithKeycardUid(keycardUid, false)
method onKeycardNameChanged*(self: Module, keycardUid: string, keycardNewName: string) =
self.view.keycardModel().setNameForKeycardWithKeycardUid(keycardUid, keycardNewName)
if self.view.keycardDetailsModel().isNil:
return
self.view.keycardDetailsModel().setNameForKeycardWithKeycardUid(keycardUid, keycardNewName)
## TODO: will be removed in the second part of synchronization improvements
discard
# self.view.keycardModel().setNameForKeycardWithKeycardUid(keycardUid, keycardNewName)
# if self.view.keycardDetailsModel().isNil:
# return
# self.view.keycardDetailsModel().setNameForKeycardWithKeycardUid(keycardUid, keycardNewName)
method onKeycardUidUpdated*(self: Module, keycardUid: string, keycardNewUid: string) =
if self.view.keycardDetailsModel().isNil:
return
self.view.keycardDetailsModel().setKeycardUid(keycardUid, keycardNewUid)
method onKeycardUidUpdated*(self: Module, keycardUid: string, keycardNewUid: string) =
## TODO: will be removed in the second part of synchronization improvements
discard
# if self.view.keycardDetailsModel().isNil:
# return
# self.view.keycardDetailsModel().setKeycardUid(keycardUid, keycardNewUid)
method onKeycardAccountsRemoved*(self: Module, keyUid: string, keycardUid: string, accountsToRemove: seq[string]) =
self.view.keycardModel().removeAccountsFromKeycardsWithKeyUid(keyUid, accountsToRemove, removeKeycardItemIfHasNoAccounts = true)
if self.view.keycardDetailsModel().isNil:
return
self.view.keycardDetailsModel().removeAccountsFromKeycardWithKeycardUid(keycardUid, accountsToRemove, removeKeycardItemIfHasNoAccounts = true)
method onKeycardAccountsRemoved*(self: Module, keyUid: string, keycardUid: string, accountsToRemove: seq[string]) =
## TODO: will be removed in the second part of synchronization improvements
discard
# self.view.keycardModel().removeAccountsFromKeycardsWithKeyUid(keyUid, accountsToRemove, removeKeycardItemIfHasNoAccounts = true)
# if self.view.keycardDetailsModel().isNil:
# return
# self.view.keycardDetailsModel().removeAccountsFromKeycardWithKeycardUid(keycardUid, accountsToRemove, removeKeycardItemIfHasNoAccounts = true)
method onWalletAccountUpdated*(self: Module, account: WalletAccountDto) =
self.view.keycardModel().updateDetailsForAddressForKeyPairsWithKeyUid(account.keyUid, account.address, account.name,
account.colorId, account.emoji)
if self.view.keycardDetailsModel().isNil:
return
self.view.keycardDetailsModel().updateDetailsForAddressForKeyPairsWithKeyUid(account.keyUid, account.address, account.name,
account.colorId, account.emoji)
method onWalletAccountUpdated*(self: Module, account: WalletAccountDto) =
## TODO: will be removed in the second part of synchronization improvements
discard
# self.view.keycardModel().updateDetailsForAddressForKeyPairsWithKeyUid(account.keyUid, account.address, account.name,
# account.colorId, account.emoji)
# if self.view.keycardDetailsModel().isNil:
# return
# self.view.keycardDetailsModel().updateDetailsForAddressForKeyPairsWithKeyUid(account.keyUid, account.address, account.name,
# account.colorId, account.emoji)
method prepareKeycardDetailsModel*(self: Module, keyUid: string) =
let keypairs = self.controller.getKeypairs()
let keypair = self.controller.getKeypairByKeyUid(keyUid)
var items: seq[KeycardItem]
let allKnownKeycards = self.controller.getAllKnownKeycards()
for kp in allKnownKeycards:
if kp.keyUid != keyUid:
continue
let item = self.buildKeycardItem(keypairs, kp, BuildItemReason.DetailsView)
let item = self.buildKeycardItem(keypair, kp, BuildItemReason.DetailsView)
if item.isNil:
continue
items.add(item)

View File

@ -89,7 +89,7 @@ method load*(self: Module) =
self.refreshWalletAccounts()
self.events.on(SIGNAL_WALLET_ACCOUNT_UPDATED) do(e:Args):
let args = WalletAccountUpdated(e)
let args = AccountArgs(e)
let keycardAccount = self.controller.isKeycardAccount(args.account)
self.view.onUpdatedAccount(walletAccountToWalletSettingsAccountsItem(args.account, keycardAccount))
@ -99,12 +99,6 @@ method load*(self: Module) =
return
self.refreshWalletAccounts()
self.events.on(SIGNAL_KEYCARDS_SYNCHRONIZED) do(e: Args):
let args = KeycardActivityArgs(e)
if not args.success:
return
self.refreshWalletAccounts()
self.events.on(SIGNAL_WALLET_ACCOUNT_POSITION_UPDATED) do(e:Args):
self.refreshWalletAccounts()

View File

@ -170,15 +170,15 @@ method load*(self: Module) =
self.events.on(SIGNAL_WALLET_ACCOUNT_UPDATED) do(e:Args):
self.notifyFilterChanged()
self.events.on(SIGNAL_WALLET_ACCOUNT_SAVED) do(e:Args):
let args = AccountSaved(e)
let args = AccountArgs(e)
self.setTotalCurrencyBalance()
self.filter.setAddress(args.account.address)
self.view.showToastAccountAdded(args.account.name)
self.notifyFilterChanged()
self.events.on(SIGNAL_WALLET_ACCOUNT_DELETED) do(e:Args):
let args = AccountDeleted(e)
let args = AccountArgs(e)
self.setTotalCurrencyBalance()
self.filter.removeAddress(args.address)
self.filter.removeAddress(args.account.address)
self.notifyFilterChanged()
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args):
self.filter.updateNetworks()
@ -195,11 +195,6 @@ method load*(self: Module) =
if not args.success:
return
self.notifyFilterChanged()
self.events.on(SIGNAL_KEYCARDS_SYNCHRONIZED) do(e: Args):
let args = KeycardActivityArgs(e)
if not args.success:
return
self.notifyFilterChanged()
self.events.on(SIGNAL_WALLET_ACCOUNT_POSITION_UPDATED) do(e:Args):
self.notifyFilterChanged()
self.events.on(SIGNAL_INCLUDE_WATCH_ONLY_ACCOUNTS_UPDATED) do(e: Args):

View File

@ -109,12 +109,6 @@ method load*(self: Module) =
return
self.refreshWalletAccounts()
self.events.on(SIGNAL_KEYCARDS_SYNCHRONIZED) do(e: Args):
let args = KeycardActivityArgs(e)
if not args.success:
return
self.refreshWalletAccounts()
self.controller.init()
self.view.load()

View File

@ -51,4 +51,8 @@ QtObject:
QtProperty[string] keycardUid:
read = getKeycardUid
write = setKeycardUid
notify = keycardUidChanged
notify = keycardUidChanged
proc setItem*(self: KeycardItem, item: KeycardItem) =
self.setKeycardUid(item.getKeycardUid())
self.KeyPairItem.setItem(KeyPairItem(item))

View File

@ -6,7 +6,7 @@ export keycard_item
type
ModelRole {.pure.} = enum
Keycard = UserRole + 1
QtObject:
type
KeycardModel* = ref object of QAbstractListModel
@ -53,6 +53,11 @@ QtObject:
self.countChanged()
self.lockedItemsCountChanged()
proc replaceItemWithKeyUid*(self: KeycardModel, item: KeycardItem) =
for i in 0 ..< self.items.len:
if self.items[i].getKeyUid() == item.getKeyUid():
self.items[i].setItem(item)
proc removeItem*(self: KeycardModel, index: int) =
if (index < 0 or index >= self.items.len):
return
@ -63,6 +68,11 @@ QtObject:
self.endRemoveRows()
self.countChanged()
proc removeItemWithKeyUid*(self: KeycardModel, keyUid: string) =
for i in 0 ..< self.items.len:
if self.items[i].getKeyUid() == keyUid:
self.removeItem(i)
proc `$`*(self: KeycardModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""KeycardModel:
@ -134,7 +144,7 @@ QtObject:
if(self.items[i].getKeycardUid() == keycardUid):
self.items[i].setKeycardUid(keycardNewUid)
proc removeAccountsFromKeycardWithKeycardUid*(self: KeycardModel, keycardUid: string, accountsToRemove: seq[string],
proc removeAccountsFromKeycardWithKeycardUid*(self: KeycardModel, keycardUid: string, accountsToRemove: seq[string],
removeKeycardItemIfHasNoAccounts: bool) =
for i in 0 ..< self.items.len:
if(self.items[i].getKeycardUid() == keycardUid):
@ -142,7 +152,7 @@ QtObject:
self.items[i].removeAccountByAddress(acc)
if removeKeycardItemIfHasNoAccounts and self.items[i].getAccountsModel().getCount() == 0:
self.removeItem(i)
proc removeAccountsFromKeycardsWithKeyUid*(self: KeycardModel, keyUid: string, accountsToRemove: seq[string],
removeKeycardItemIfHasNoAccounts: bool) =
for i in 0 ..< self.items.len:

View File

@ -47,7 +47,7 @@ type
proc `$`*(self: OwnedCollectible): string =
return fmt"""OwnedCollectible(
id:{self.id},
id:{self.id},
isFromWatchedContract:{self.isFromWatchedContract}
)"""
@ -71,7 +71,7 @@ type
lastRefetchTimestamp*: DateTime
collectibles*: seq[OwnedCollectible]
collectiblesFromWatchedContracts: seq[OwnedCollectible]
proc newCollectiblesData(): CollectiblesData =
new(result)
result.state = State.Init
@ -108,13 +108,13 @@ proc allLoaded*(self: CollectiblesData): bool =
proc `$`*(self: CollectiblesData): string =
return fmt"""CollectiblesData(
state:{self.state},
lastLoadCount:{self.lastLoadCount},
previousCursor:{self.previousCursor},
nextCursor:{self.nextCursor},
isRefetching:{self.isRefetching},
lastRefetchTimestamp:{self.lastRefetchTimestamp},
collectibles:{self.collectibles},
state:{self.state},
lastLoadCount:{self.lastLoadCount},
previousCursor:{self.previousCursor},
nextCursor:{self.nextCursor},
isRefetching:{self.isRefetching},
lastRefetchTimestamp:{self.lastRefetchTimestamp},
collectibles:{self.collectibles},
collectiblesFromWatchedContracts:{self.collectiblesFromWatchedContracts}
)"""
@ -190,7 +190,7 @@ QtObject:
self.refetchAllOwnedCollectibles()
self.events.on(SIGNAL_WALLET_ACCOUNT_DELETED) do(e:Args):
self.removeAddress(AccountDeleted(e).address)
self.removeAddress(AccountArgs(e).account.address)
# needs to be re-written once cache for colletibles works
proc areCollectionsLoaded*(self: Service, address: string): bool =
@ -280,10 +280,10 @@ QtObject:
proc updateCollectiblesCache*(self: Service, chainId: int, collectibles: seq[CollectibleDto], collections: seq[CollectionDto]) =
if not self.collectibles.hasKey(chainId):
self.collectibles[chainId] = newTable[UniqueID, CollectibleDto]()
if not self.collections.hasKey(chainId):
self.collections[chainId] = newTable[string, CollectionDto]()
var data = CollectiblesUpdateArgs()
data.chainId = chainId
@ -298,7 +298,7 @@ QtObject:
)
self.collectibles[chainId][id] = collectible
data.ids.add(id)
self.events.emit(SIGNAL_COLLECTIBLES_UPDATED, data)
proc setWatchedContracts*(self: Service, chainId: int, address: string, contractAddresses: seq[string]) =
@ -391,7 +391,7 @@ QtObject:
return
let collectiblesData = self.accountsOwnershipData[chainId][address].data
let errorStr = responseObj["error"].getStr()
if errorStr != "":
self.processOwnedCollectiblesError(chainId, address)

View File

@ -1,10 +1,10 @@
import tables, json, strformat, strutils, chronicles
import dto
import dto, keycard_dto
include ../../common/json_utils
export dto
export dto, keycard_dto
const KeypairTypeProfile* = "profile"
const KeypairTypeSeed* = "seed"
@ -19,6 +19,8 @@ type
lastUsedDerivationIndex*: int
syncedFrom*: string
accounts*: seq[WalletAccountDto]
keycards*: seq[KeycardDto]
removed*: bool
proc toKeypairDto*(jsonObj: JsonNode): KeypairDto =
result = KeypairDto()
@ -28,17 +30,24 @@ proc toKeypairDto*(jsonObj: JsonNode): KeypairDto =
discard jsonObj.getProp("derived-from", result.derivedFrom)
discard jsonObj.getProp("last-used-derivation-index", result.lastUsedDerivationIndex)
discard jsonObj.getProp("synced-from", result.syncedFrom)
discard jsonObj.getProp("removed", result.removed)
if result.keypairType != KeypairTypeProfile and
result.keypairType != KeypairTypeSeed and
result.keypairType != KeypairTypeKey:
error "unknown keypair type", kpType=result.keypairType
if not result.removed:
if result.keypairType != KeypairTypeProfile and
result.keypairType != KeypairTypeSeed and
result.keypairType != KeypairTypeKey:
error "unknown keypair type", kpType=result.keypairType
var accountsObj: JsonNode
if(jsonObj.getProp("accounts", accountsObj)):
if jsonObj.getProp("accounts", accountsObj) and accountsObj.kind != JNull:
for accObj in accountsObj:
result.accounts.add(toWalletAccountDto(accObj))
var keycardsObj: JsonNode
if jsonObj.getProp("keycards", keycardsObj) and keycardsObj.kind != JNull:
for kcObj in keycardsObj:
result.keycards.add(toKeycardDto(kcObj))
proc `$`*(self: KeypairDto): string =
result = fmt"""KeypairDto[
keyUid: {self.keyUid},
@ -47,10 +56,17 @@ proc `$`*(self: KeypairDto): string =
derivedFrom: {self.derivedFrom},
lastUsedDerivationIndex: {self.lastUsedDerivationIndex},
syncedFrom: {self.syncedFrom},
accounts:
accounts:
"""
for i in 0 ..< self.accounts.len:
result &= fmt"""
[{i}]:({$self.accounts[i]})
"""
result &= "]"
result &= fmt"""
keycards:
"""
for i in 0 ..< self.keycards.len:
result &= fmt"""
[{i}]:({$self.accounts[i]})
"""
result &= "]"

View File

@ -34,8 +34,11 @@ const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESSES_FETCHED* = "walletAccount/derivedA
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESSES_FROM_MNEMONIC_FETCHED* = "walletAccount/derivedAddressesFromMnemonicFetched"
const SIGNAL_WALLET_ACCOUNT_ADDRESS_DETAILS_FETCHED* = "walletAccount/addressDetailsFetched"
const SIGNAL_WALLET_ACCOUNT_POSITION_UPDATED* = "walletAccount/positionUpdated"
const SIGNAL_WALLET_ACCOUNT_OPERABILITY_UPDATED* = "walletAccount/operabilityUpdated"
const SIGNAL_KEYCARDS_SYNCHRONIZED* = "keycardsSynchronized"
const SIGNAL_KEYPAIR_CHANGED* = "keypairChanged"
const SIGNAL_KEYPAIR_NAME_CHANGED* = "keypairNameChanged"
const SIGNAL_KEYPAIR_DELETED* = "keypairDeleted"
const SIGNAL_NEW_KEYCARD_SET* = "newKeycardSet"
const SIGNAL_KEYCARD_DELETED* = "keycardDeleted"
const SIGNAL_KEYCARD_ACCOUNTS_REMOVED* = "keycardAccountsRemoved"
@ -70,18 +73,11 @@ proc hex2Balance*(input: string, decimals: int): string =
result = $i
if(r > 0): result = fmt"{result}.{d}"
type AccountSaved* = ref object of Args
type AccountArgs* = ref object of Args
account*: WalletAccountDto
type AccountDeleted* = ref object of Args
address*: string
type CurrencyUpdated = ref object of Args
type NetwordkEnabledToggled = ref object of Args
type WalletAccountUpdated* = ref object of Args
account*: WalletAccountDto
type KeypairArgs* = ref object of Args
keypair*: KeypairDto
type DerivedAddressesArgs* = ref object of Args
uniqueId*: string
@ -129,7 +125,7 @@ QtObject:
proc startWallet(self: Service)
proc handleWalletAccount(self: Service, account: WalletAccountDto)
proc handleKeycardActions(self: Service, keycardActions: seq[KeycardActionDto])
proc handleKeycardsState(self: Service, keycardsState: seq[KeycardDto])
proc handleKeypair(self: Service, keypair: KeypairDto)
proc getAllKnownKeycards*(self: Service): seq[KeycardDto]
proc removeMigratedAccountsForKeycard*(self: Service, keyUid: string, keycardUid: string, accountsToRemove: seq[string])
@ -311,6 +307,9 @@ QtObject:
proc getWalletAccounts*(self: Service): seq[WalletAccountDto] =
result = toSeq(self.walletAccounts.values)
proc getWalletAccountsForKeypair*(self: Service, keyUid: string): seq[WalletAccountDto] =
return self.getWalletAccounts().filter(kp => kp.keyUid == keyUid)
proc getAddresses*(self: Service): seq[string] =
result = toSeq(self.walletAccounts.keys())
@ -333,11 +332,14 @@ QtObject:
self.events.on(SignalType.Message.event) do(e: Args):
var receivedData = MessageSignal(e)
if receivedData.walletAccounts.len > 0:
for acc in receivedData.walletAccounts:
if receivedData.watchOnlyAccounts.len > 0:
for acc in receivedData.watchOnlyAccounts:
self.handleWalletAccount(acc)
self.handleKeycardsState(receivedData.keycards)
self.handleKeycardActions(receivedData.keycardActions)
if receivedData.keypairs.len > 0:
for kp in receivedData.keypairs:
self.handleKeypair(kp)
## TODO: will be removed in the second part of synchronization improvements
# self.handleKeycardActions(receivedData.keycardActions)
self.events.on(SignalType.Wallet.event) do(e:Args):
var data = WalletSignal(e)
@ -404,7 +406,7 @@ QtObject:
self.storeAccount(newAccount)
self.buildAllTokens(@[newAccount.address], store = true)
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountArgs(account: newAccount))
proc removeAccountFromLocalStoreAndNotify(self: Service, address: string) =
if not self.walletAccountsContainsAddress(address):
@ -413,17 +415,29 @@ QtObject:
self.walletAccounts.del(address)
# updating related accounts for other accounts
self.setRelatedAccountsForAllAccounts(removedAcc.keyUid)
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountDeleted(address: address))
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountArgs(account: removedAcc))
proc updateAccountFromLocalStoreAndNotify(self: Service, address, name, colorId, emoji: string) =
proc updateAccountInLocalStoreAndNotify(self: Service, address, name, colorId, emoji: string, position: int = -1, accOperability: string = "") =
if not self.walletAccountsContainsAddress(address):
return
var account = self.getAccountByAddress(address)
account.name = name
account.colorId = colorId
account.emoji = emoji
self.storeAccount(account, updateRelatedAccounts = false)
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))
if name.len > 0 or colorId.len > 0 or emoji.len > 0:
if name.len > 0 and name != account.name:
account.name = name
if colorId.len > 0 and colorId != account.colorId:
account.colorId = colorId
if emoji.len > 0 and emoji != account.emoji:
account.emoji = emoji
self.storeAccount(account, updateRelatedAccounts = false)
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, AccountArgs(account: account))
if position > -1 and position != account.position:
account.position = position
self.storeAccount(account, updateRelatedAccounts = false)
self.events.emit(SIGNAL_WALLET_ACCOUNT_POSITION_UPDATED, AccountArgs(account: account))
if accOperability.len > 0 and account.operable != accOperability:
account.operable = accOperability
self.storeAccount(account, updateRelatedAccounts = false)
self.events.emit(SIGNAL_WALLET_ACCOUNT_OPERABILITY_UPDATED, AccountArgs(account: account))
## if password is not provided local keystore file won't be created
proc addWalletAccount*(self: Service, password: string, doPasswordHashing: bool, name, address, path, publicKey,
@ -524,14 +538,14 @@ QtObject:
proc setNetworksState*(self: Service, chainIds: seq[int], enabled: bool) =
self.networkService.setNetworksState(chainIds, enabled)
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, Args())
proc toggleTestNetworksEnabled*(self: Service) =
discard self.settingsService.toggleTestNetworksEnabled()
self.buildAllTokens(self.getAddresses(), store = true)
self.tokenService.loadData()
self.checkRecentHistory()
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, Args())
proc updateWalletAccount*(self: Service, address: string, accountName: string, colorId: string, emoji: string): bool =
if not self.walletAccountsContainsAddress(address):
@ -544,19 +558,25 @@ QtObject:
if not response.error.isNil:
error "status-go error", procName="updateWalletAccount", errCode=response.error.code, errDesription=response.error.message
return false
self.updateAccountFromLocalStoreAndNotify(address, accountName, colorId, emoji)
self.updateAccountInLocalStoreAndNotify(address, accountName, colorId, emoji)
return true
except Exception as e:
error "error: ", procName="updateWalletAccount", errName=e.name, errDesription=e.msg
return false
proc updateWalletAccountPosition*(self: Service, address: string, position: int) =
discard backend.updateAccountPosition(address, position)
for account in self.getAccounts():
self.walletAccounts[account.address].position = account.position
self.events.emit(SIGNAL_WALLET_ACCOUNT_POSITION_UPDATED, Args())
if not self.walletAccountsContainsAddress(address):
error "account's address is not among known addresses: ", address=address
return
try:
let response = backend.updateAccountPosition(address, position)
if not response.error.isNil:
error "status-go error", procName="updateAccountPosition", errCode=response.error.code, errDesription=response.error.message
return
self.updateAccountInLocalStoreAndNotify(address, name = "", colorId = "", emoji = "", position)
except Exception as e:
error "error: ", procName="updateAccountPosition", errName=e.name, errDesription=e.msg
proc fetchDerivedAddresses*(self: Service, password: string, derivedFrom: string, paths: seq[string], hashPassword: bool) =
let arg = FetchDerivedAddressesTaskArg(
password: if hashPassword: utils.hashPassword(password) else: password,
@ -921,7 +941,7 @@ QtObject:
self.removeAccountFromLocalStoreAndNotify(account.address)
else:
if self.walletAccountsContainsAddress(account.address):
self.updateAccountFromLocalStoreAndNotify(account.address, account.name, account.colorId, account.emoji)
self.updateAccountInLocalStoreAndNotify(account.address, account.name, account.colorId, account.emoji, account.position)
else:
self.addNewAccountToLocalStoreAndNotify()
@ -950,11 +970,30 @@ QtObject:
else:
error "unsupported action received", action=kcAction.action
proc handleKeycardsState(self: Service, keycardsState: seq[KeycardDto]) =
if keycardsState.len == 0:
return
let data = KeycardActivityArgs(success: true)
self.events.emit(SIGNAL_KEYCARDS_SYNCHRONIZED, data)
proc handleKeypair(self: Service, keypair: KeypairDto) =
## In some point in future instead `self.walletAccounts` table we should switch to maintaining local state in the
## form of keypairs + another list just for watch only accounts. We will benefint from that in terms of maintaining.
## Keycards detaiils will be in that case tracked easier and stored locally as well. Also at that point we can check
## if the local keypair name is different than one received here and emit signal only in that case, till then,
## we emit it always.
self.events.emit(SIGNAL_KEYPAIR_NAME_CHANGED, KeypairArgs(keypair: KeypairDto(name: keypair.name)))
# handle keypair related accounts
# - first remove removed accounts from the UI
let localKeypairRelatedAccounts = self.getWalletAccountsForKeypair(keypair.keyUid)
for localAcc in localKeypairRelatedAccounts:
let accAddress = localAcc.address
if keypair.accounts.filter(a => cmpIgnoreCase(a.address, accAddress) == 0).len == 0:
self.handleWalletAccount(WalletAccountDto(address: accAddress, removed: true))
# - second add/update new/existing accounts
for acc in keypair.accounts:
self.handleWalletAccount(acc)
if keypair.removed:
self.events.emit(SIGNAL_KEYPAIR_DELETED, KeypairArgs(keypair: keypair))
else:
# notify all interested parts about the keypair change
self.events.emit(SIGNAL_KEYPAIR_CHANGED, KeypairArgs(keypair: keypair))
proc allAccountsTokenBalance*(self: Service, symbol: string): float64 =
var totalTokenBalance = 0.0

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit ac666da495e8a007ae9deb120918baa920870749
Subproject commit 61527f8c7870331bc3c6b61f3adb1c68111e9188