feat(@desktop/wallet-sync): accounts syncing part 1

This commit is contained in:
Sale Djenic 2023-04-25 14:02:45 +02:00 committed by saledjenic
parent 1a919f586f
commit 69bf8c0e53
9 changed files with 100 additions and 21 deletions

View File

@ -10,8 +10,8 @@ import ../../../../app_service/service/activity_center/dto/[notification]
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]
import ../../../../app_service/service/wallet_account/[key_pair_dto]
import ../../../../app_service/service/saved_address/dto as saved_address_dto
import ../../../../app_service/service/wallet_account/[dto, key_pair_dto]
type MessageSignal* = ref object of Signal
bookmarks*: seq[BookmarkDto]
@ -35,6 +35,7 @@ type MessageSignal* = ref object of Signal
savedAddresses*: seq[SavedAddressDto]
keycards*: seq[KeyPairDto]
keycardActions*: seq[KeycardActionDto]
walletAccounts*: seq[WalletAccountDto]
type MessageDeliveredSignal* = ref object of Signal
chatId*: string
@ -141,5 +142,9 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal =
for jsonKc in event["event"]["keycardActions"]:
signal.keycardActions.add(jsonKc.toKeycardActionDto())
if event["event"]{"accounts"} != nil:
for jsonAcc in event["event"]["accounts"]:
signal.walletAccounts.add(jsonAcc.toWalletAccountDto())
result = signal

View File

@ -49,6 +49,7 @@ type SignalType* {.pure.} = enum
WakuFetchingBackupProgress = "waku.fetching.backup.progress"
WakuBackedUpProfile = "waku.backedup.profile"
WakuBackedUpSettings = "waku.backedup.settings"
WakuBackedUpWalletAccount = "waku.backedup.wallet-account"
WakuBackedUpKeycards = "waku.backedup.keycards"
LocalPairing = "localPairing"
Unknown

View File

@ -0,0 +1,13 @@
import json
import base
import ../../../../app_service/service/wallet_account/[dto]
type WakuBackedUpWalletAccountsSignal* = ref object of Signal
account*: WalletAccountDto
proc fromEvent*(T: type WakuBackedUpWalletAccountsSignal, event: JsonNode): WakuBackedUpWalletAccountsSignal =
result = WakuBackedUpWalletAccountsSignal()
if event["event"]{"backedUpWalletAccount"} != nil:
result.account = event["event"]["backedUpWalletAccount"].toWalletAccountDto()

View File

@ -116,6 +116,7 @@ QtObject:
of SignalType.WakuFetchingBackupProgress: WakuFetchingBackupProgressSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpProfile: WakuBackedUpProfileSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpSettings: WakuBackedUpSettingsSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpWalletAccount: WakuBackedUpWalletAccountsSignal.fromEvent(jsonSignal)
of SignalType.WakuBackedUpKeycards: WakuBackedUpKeycardsSignal.fromEvent(jsonSignal)
# pairing
of SignalType.LocalPairing: LocalPairingSignal.fromEvent(jsonSignal)

View File

@ -2,8 +2,8 @@
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_keycards, waku_fetching_backup_progress, pairing]
waku_backed_up_settings, waku_backed_up_wallet_accounts, waku_backed_up_keycards, 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_keycards, waku_fetching_backup_progress, pairing
waku_backed_up_settings, waku_backed_up_wallet_accounts, waku_backed_up_keycards, waku_fetching_backup_progress, pairing

View File

@ -268,7 +268,8 @@ proc buildKeycardList(self: Module) =
## If all created keycards for certain keypair are locked, then we need to display that item as locked.
item.setLocked(self.areAllKnownKeycardsLockedForKeypair(item.getKeyUid()))
items.add(item)
self.view.setKeycardItems(items)
if items.len > 0:
self.view.setKeycardItems(items)
method onLoggedInUserImageChanged*(self: Module) =
self.view.keycardModel().setImage(singletonInstance.userProfile.getPubKey(), singletonInstance.userProfile.getIcon())

View File

@ -1,4 +1,4 @@
import tables, json, sequtils, sugar, strutils
import tables, json, strformat, sequtils, sugar, strutils
include ../../common/json_utils
@ -104,6 +104,7 @@ type
lastUsedDerivationIndex*: int
hasBalanceCache*: bool
hasMarketValuesCache*: bool
removed*: bool # needs for synchronization
proc newDto*(
name: string,
@ -149,10 +150,31 @@ proc toWalletAccountDto*(jsonObj: JsonNode): WalletAccountDto =
discard jsonObj.getProp("derived-from", result.derivedfrom)
discard jsonObj.getProp("keypair-name", result.keypairName)
discard jsonObj.getProp("last-used-derivation-index", result.lastUsedDerivationIndex)
discard jsonObj.getProp("removed", result.removed)
result.assetsLoading = true
result.hasBalanceCache = false
result.hasMarketValuesCache = false
proc `$`*(self: WalletAccountDto): string =
result = fmt"""WalletAccountDto[
name: {self.name},
address: {self.address},
mixedcaseAddress: {self.mixedcaseAddress},
keyUid: {self.keyUid},
path: {self.path},
color: {self.color},
publicKey: {self.publicKey},
walletType: {self.walletType},
isChat: {self.isChat},
emoji: {self.emoji},
derivedfrom: {self.derivedfrom},
keypairName: {self.keypairName},
lastUsedDerivationIndex: {self.lastUsedDerivationIndex},
hasBalanceCache: {self.hasBalanceCache},
hasMarketValuesCache: {self.hasMarketValuesCache},
removed: {self.removed}
]"""
proc getCurrencyBalance*(self: BalanceDto, currencyPrice: float64): float64 =
return self.balance * currencyPrice

View File

@ -128,6 +128,7 @@ QtObject:
proc buildAllTokens(self: Service, accounts: seq[string], store: bool)
proc checkRecentHistory*(self: Service)
proc startWallet(self: Service)
proc handleWalletAccount(self: Service, account: WalletAccountDto)
proc handleKeycardActions(self: Service, keycardActions: seq[KeycardActionDto])
proc handleKeycardsState(self: Service, keycardsState: seq[KeyPairDto])
proc getAllKnownKeycards*(self: Service): seq[KeyPairDto]
@ -177,6 +178,15 @@ QtObject:
except Exception as e:
error "error: ", procName="getAccountsByKeyUID", errName = e.name, errDesription = e.msg
proc verifyKeystoreFileForAccount*(self: Service, account, password: string): bool =
try:
let hashedPassword = utils.hashPassword(password)
let response = status_go_accounts.verifyKeystoreFileForAccount(account, hashedPassword)
return response.result.getBool
except Exception as e:
error "error: ", procName="verifyKeystoreFileForAccount", errName = e.name, errDesription = e.msg
return false
proc setEnsName(self: Service, account: WalletAccountDto) =
let chainId = self.networkService.getNetworkForEns().chainId
try:
@ -193,14 +203,17 @@ QtObject:
(cmpIgnoreCase(x.derivedFrom, account.derivedFrom) == 0))
proc setRelatedAccountsForAllAccounts(self: Service, derivedFrom: string) =
if derivedFrom.len == 0:
return
for wAcc in self.walletAccounts.mvalues:
if not wAcc.derivedFrom.isEmptyOrWhitespace and
cmpIgnoreCase(wAcc.derivedFrom, derivedFrom) == 0:
self.setRelatedAccountsToAccount(wAcc)
proc storeAccount(self: Service, account: WalletAccountDto) =
# updating related accounts for already added accounts
self.setRelatedAccountsForAllAccounts(account.derivedFrom)
proc storeAccount(self: Service, account: WalletAccountDto, updateRelatedAccounts = true) =
if updateRelatedAccounts:
# updating related accounts for already added accounts
self.setRelatedAccountsForAllAccounts(account.derivedFrom)
# add new account to store
self.walletAccounts[account.address] = account
@ -291,6 +304,9 @@ QtObject:
if settingsField.name == KEY_CURRENCY:
self.events.emit(SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED, CurrencyUpdated())
if receivedData.walletAccounts.len > 0:
for acc in receivedData.walletAccounts:
self.handleWalletAccount(acc)
self.handleKeycardsState(receivedData.keycards)
self.handleKeycardActions(receivedData.keycardActions)
@ -336,7 +352,7 @@ QtObject:
error "error: ", errDescription
return
proc addNewAccountToLocalStore(self: Service) =
proc addNewAccountToLocalStoreAndNotify(self: Service) =
let accounts = self.fetchAccounts()
var newAccount: WalletAccountDto
var found = false
@ -367,6 +383,16 @@ QtObject:
self.setRelatedAccountsForAllAccounts(removedAcc.derivedFrom)
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountDeleted(address: address))
proc updateAccountFromLocalStoreAndNotify(self: Service, address, name, color, emoji: string) =
if not self.walletAccountsContainsAddress(address):
return
var account = self.getAccountByAddress(address)
account.name = name
account.color = color
account.emoji = emoji
self.storeAccount(account, updateRelatedAccounts = false)
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))
## if password is not provided local keystore file won't be created
proc addWalletAccount*(self: Service, password: string, doPasswordHashing: bool, name, keyPairName, address, path: string,
lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey, keyUid, accountType, color, emoji: string): string =
@ -384,7 +410,7 @@ QtObject:
if not response.error.isNil:
error "status-go error", procName="addWalletAccount", errCode=response.error.code, errDesription=response.error.message
return response.error.message
self.addNewAccountToLocalStore()
self.addNewAccountToLocalStoreAndNotify()
return ""
except Exception as e:
error "error: ", procName="addWalletAccount", errName=e.name, errDesription=e.msg
@ -490,10 +516,7 @@ QtObject:
if not response.error.isNil:
error "status-go error", procName="updateWalletAccount", errCode=response.error.code, errDesription=response.error.message
return false
account.name = accountName
account.color = color
account.emoji = emoji
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))
self.updateAccountFromLocalStoreAndNotify(address, accountName, color, emoji)
return true
except Exception as e:
error "error: ", procName="updateWalletAccount", errName=e.name, errDesription=e.msg
@ -854,6 +877,15 @@ QtObject:
error "error: ", procName="deleteKeycard", errName = e.name, errDesription = e.msg
return false
proc handleWalletAccount(self: Service, account: WalletAccountDto) =
if account.removed:
self.removeAccountFromLocalStoreAndNotify(account.address)
else:
if self.walletAccountsContainsAddress(account.address):
self.updateAccountFromLocalStoreAndNotify(account.address, account.name, account.color, account.emoji)
else:
self.addNewAccountToLocalStoreAndNotify()
proc handleKeycardActions(self: Service, keycardActions: seq[KeycardActionDto]) =
if keycardActions.len == 0:
return

View File

@ -29,7 +29,7 @@ proc deleteAccount*(address: string, password: string): RpcResponse[JsonNode] {.
let payload = %* [address, password]
return core.callPrivateRPC("accounts_deleteAccount", payload)
## Adds a new account and creates a Keystore file if password is provided, otherwise it only creates a new account
## Adds a new account and creates a Keystore file if password is provided, otherwise it only creates a new account. Notifies paired devices.
proc addAccount*(password, name, keyPairName, address, path: string, lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji: string):
RpcResponse[JsonNode] {.raises: [Exception].} =
@ -49,7 +49,7 @@ proc addAccount*(password, name, keyPairName, address, path: string, lastUsedDer
"color": color,
#"hidden" present on the status-go side, but we don't use it
"derived-from": rootWalletMasterKey,
#"clock" we leave this empty, if needed should be set on the status-go side
#"clock" we leave this empty, set on the status-go side
#"removed" present on the status-go side, used for synchronization, no need to set it here
"keypair-name": keyPairName,
"last-used-derivation-index": lastUsedDerivationIndex
@ -57,14 +57,14 @@ proc addAccount*(password, name, keyPairName, address, path: string, lastUsedDer
]
return core.callPrivateRPC("accounts_addAccount", payload)
## Adds a new account without creating a Keystore file
## Adds a new account without creating a Keystore file and notifies paired devices
proc addAccountWithoutKeystoreFileCreation*(name, keyPairName, address, path: string, lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji: string):
RpcResponse[JsonNode] {.raises: [Exception].} =
return addAccount(password = "", name, keyPairName, address, path, lastUsedDerivationIndex, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji)
## Updates either regular or keycard account, without interaction to a Keystore file
## Updates either regular or keycard account, without interaction to a Keystore file and notifies paired devices
proc updateAccount*(name, keyPairName, address, path: string, lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji: string, walletDefaultAccount: bool, chatDefaultAccount: bool):
RpcResponse[JsonNode] {.raises: [Exception].} =
@ -83,7 +83,7 @@ proc updateAccount*(name, keyPairName, address, path: string, lastUsedDerivation
"color": color,
#"hidden" present on the status-go side, but we don't use it
"derived-from": rootWalletMasterKey,
#"clock" we leave this empty, if needed should be set on the status-go side
#"clock" we leave this empty, set on the status-go side
#"removed" present on the status-go side, used for synchronization, no need to set it here
"keypair-name": keyPairName,
"last-used-derivation-index": lastUsedDerivationIndex
@ -408,4 +408,8 @@ proc getAddressDetails*(address: string,): RpcResponse[JsonNode] {.raises: [Exce
proc verifyPassword*(password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [password]
return core.callPrivateRPC("accounts_verifyPassword", payload)
return core.callPrivateRPC("accounts_verifyPassword", payload)
proc verifyKeystoreFileForAccount*(address, password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [address, password]
return core.callPrivateRPC("accounts_verifyKeystoreFileForAccount", payload)