chore(@desktop/wallet): `Accounts` and `WalletAccount` services updated

- new procs to a new `status-go` endpoints added:
  - `AddAccount`
  - `ImportPrivateKey`
  - `ImportMnemonic`
  - `GetRandomMnemonic`
  - `GetDerivedAddresses`
  - `GetDerivedAddressesForMnemonic`
  - `GetAddressDetails`

- unused procs to the old `status-go` endpoints removed:
  - `AddAccountWatch`
  - `AddAccountWithMnemonic`
  - `AddAccountWithMnemonicPasswordVerified`
  - `AddAccountWithMnemonicAndPath`
  - `AddAccountWithMnemonicAndPathPasswordVerified`
  - `AddAccountWithPrivateKeyPasswordVerified`
  - `AddAccountWithPrivateKey`
  - `GenerateAccount`
  - `GenerateAccountPasswordVerified`
  - `GenerateAccountWithDerivedPath`
  - `GetDerivedAddressForPath`
  - `GetDerivedAddressesForPath`
  - `GetDerivedAddressesForMnemonicWithPath`
  - `GetDerivedAddressForPrivateKey`
  - `GetDerivedAddressDetails`
This commit is contained in:
Sale Djenic 2023-03-22 16:24:23 +01:00 committed by saledjenic
parent 7b16a93cc0
commit 44e00b9538
13 changed files with 332 additions and 338 deletions

View File

@ -684,12 +684,12 @@ proc updateKeycardUid*(self: Controller, keyUid: string, keycardUid: string) =
self.tmpKeycardUid = keycardUid
info "update keycard uid failed", oldKeycardUid=self.tmpKeycardUid, newKeycardUid=keycardUid
proc addWalletAccount*(self: Controller, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType,
color, emoji: string): bool =
proc addWalletAccount*(self: Controller, name, keyPairName, address, path: string, lastUsedDerivationIndex: int,
rootWalletMasterKey, publicKey, keyUid, accountType, color, emoji: string): bool =
if not serviceApplicable(self.walletAccountService):
return false
let err = self.walletAccountService.addWalletAccount(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid,
accountType, color, emoji)
let err = self.walletAccountService.addWalletAccount(password = "", doPasswordHashing = false, name, keyPairName,
address, path, lastUsedDerivationIndex, rootWalletMasterKey, publicKey, keyUid, accountType, color, emoji)
if err.len > 0:
info "adding wallet account failed", name=name, path=path
return false

View File

@ -43,17 +43,21 @@ proc resolveAddresses(self: CreatingAccountNewSeedPhraseState, controller: Contr
proc addAccountsToWallet(self: CreatingAccountNewSeedPhraseState, controller: Controller): bool =
let kpForProcessing = controller.getKeyPairForProcessing()
var index = 0
for account in kpForProcessing.getAccountsModel().getItems():
if not controller.addWalletAccount(name = account.getName(),
keyPairName = kpForProcessing.getName(),
address = account.getAddress(),
path = account.getPath(),
addressAccountIsDerivedFrom = kpForProcessing.getDerivedFrom(),
lastUsedDerivationIndex = index,
rootWalletMasterKey = kpForProcessing.getDerivedFrom(),
publicKey = account.getPubKey(),
keyUid = kpForProcessing.getKeyUid(),
accountType = if account.getPath() == PATH_DEFAULT_WALLET: SEED else: GENERATED,
accountType = SEED,
color = account.getColor(),
emoji = account.getEmoji()):
return false
index.inc
return true
proc doMigration(self: CreatingAccountNewSeedPhraseState, controller: Controller) =

View File

@ -43,17 +43,21 @@ proc resolveAddresses(self: CreatingAccountOldSeedPhraseState, controller: Contr
proc addAccountsToWallet(self: CreatingAccountOldSeedPhraseState, controller: Controller): bool =
let kpForProcessing = controller.getKeyPairForProcessing()
var index = 0
for account in kpForProcessing.getAccountsModel().getItems():
if not controller.addWalletAccount(name = account.getName(),
keyPairName = kpForProcessing.getName(),
address = account.getAddress(),
path = account.getPath(),
addressAccountIsDerivedFrom = kpForProcessing.getDerivedFrom(),
lastUsedDerivationIndex = index,
rootWalletMasterKey = kpForProcessing.getDerivedFrom(),
publicKey = account.getPubKey(),
keyUid = kpForProcessing.getKeyUid(),
accountType = if account.getPath() == PATH_DEFAULT_WALLET: SEED else: GENERATED,
accountType = SEED,
color = account.getColor(),
emoji = account.getEmoji()):
return false
index.inc
return true
proc doMigration(self: CreatingAccountOldSeedPhraseState, controller: Controller) =

View File

@ -13,18 +13,22 @@ proc delete*(self: ImportingFromKeycardState) =
proc addAccountsToWallet(self: ImportingFromKeycardState, controller: Controller): bool =
let kpForProcessing = controller.getKeyPairForProcessing()
let kpHelper = controller.getKeyPairHelper()
var index = 0
for account in kpForProcessing.getAccountsModel().getItems():
self.addresses.add(account.getAddress())
if not controller.addWalletAccount(name = account.getName(),
keyPairName = kpForProcessing.getName(),
address = account.getAddress(),
path = account.getPath(),
addressAccountIsDerivedFrom = kpForProcessing.getDerivedFrom(),
lastUsedDerivationIndex = index,
rootWalletMasterKey = kpForProcessing.getDerivedFrom(),
publicKey = account.getPubKey(),
keyUid = kpForProcessing.getKeyUid(),
accountType = if account.getPath() == PATH_DEFAULT_WALLET: SEED else: GENERATED,
accountType = SEED,
color = account.getColor(),
emoji = account.getEmoji()):
return false
index.inc
return true
proc doMigration(self: ImportingFromKeycardState, controller: Controller) =

View File

@ -17,4 +17,27 @@ const convertToKeycardAccountTask*: Task = proc(argEncoded: string) {.gcsafe, ni
arg.finish(response)
except Exception as e:
error "error converting profile keypair: ", message = e.msg
arg.finish("")
arg.finish("")
#################################################
# Async load derived addreses
#################################################
type
FetchAddressesFromNotImportedMnemonicArg* = ref object of QObjectTaskArg
mnemonic: string
paths: seq[string]
const fetchAddressesFromNotImportedMnemonicTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[FetchAddressesFromNotImportedMnemonicArg](argEncoded)
var output = %*{
"derivedAddress": "",
"error": ""
}
try:
let response = status_account.createAccountFromMnemonicAndDeriveAccountsForPaths(arg.mnemonic, arg.paths)
output["derivedAddresses"] = response.result
except Exception as e:
output["error"] = %* fmt"Error fetching address from not imported mnemonic: {e.msg}"
arg.finish(output)

View File

@ -1,4 +1,4 @@
import NimQml, os, json, sequtils, strutils, uuids, times
import NimQml, Tables, os, json, strformat, sequtils, strutils, uuids, times
import json_serialization, chronicles
import ../../../app/global/global_singleton
@ -35,10 +35,15 @@ const KDF_ITERATIONS* {.intdefine.} = 256_000
let TEST_PEER_ENR = getEnv("TEST_PEER_ENR").string
const SIGNAL_CONVERTING_PROFILE_KEYPAIR* = "convertingProfileKeypair"
const SIGNAL_DERIVED_ADDRESSES_FROM_NOT_IMPORTED_MNEMONIC_FETCHED* = "derivedAddressesFromNotImportedMnemonicFetched"
type ResultArgs* = ref object of Args
success*: bool
type DerivedAddressesFromNotImportedMnemonicArgs* = ref object of Args
error*: string
derivations*: Table[string, DerivedAccountDetails]
include utils
include async_tasks
@ -496,7 +501,20 @@ QtObject:
except Exception as e:
error "error: ", procName="setupAccount", errName = e.name, errDesription = e.msg
proc createAccountFromPrivateKey*(self: Service, privateKey: string): GeneratedAccountDto =
if privateKey.len == 0:
error "empty private key"
return
try:
let response = status_account.createAccountFromPrivateKey(privateKey)
return toGeneratedAccountDto(response.result)
except Exception as e:
error "error: ", procName="createAccountFromPrivateKey", errName = e.name, errDesription = e.msg
proc createAccountFromMnemonic*(self: Service, mnemonic: string, paths: seq[string]): GeneratedAccountDto =
if mnemonic.len == 0:
error "empty mnemonic"
return
try:
let response = status_account.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic, paths)
return toGeneratedAccountDto(response.result)
@ -505,9 +523,6 @@ QtObject:
proc createAccountFromMnemonic*(self: Service, mnemonic: string, includeEncryption = false, includeWhisper = false,
includeRoot = false, includeDefaultWallet = false, includeEip1581 = false): GeneratedAccountDto =
if mnemonic.len == 0:
error "empty mnemonic"
return
var paths: seq[string]
if includeEncryption:
paths.add(PATH_ENCRYPTION)
@ -519,7 +534,29 @@ QtObject:
paths.add(PATH_DEFAULT_WALLET)
if includeEip1581:
paths.add(PATH_EIP_1581)
return self.createAccountFromMnemonic(mnemonic, paths)
return self.createAccountFromMnemonic(mnemonic, paths)
proc fetchAddressesFromNotImportedMnemonic*(self: Service, mnemonic: string, paths: seq[string])=
let arg = FetchAddressesFromNotImportedMnemonicArg(
mnemonic: mnemonic,
paths: paths,
tptr: cast[ByteAddress](fetchAddressesFromNotImportedMnemonicTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAddressesFromNotImportedMnemonicFetched",
)
self.threadpool.start(arg)
proc onAddressesFromNotImportedMnemonicFetched*(self: Service, jsonString: string) {.slot.} =
var data = DerivedAddressesFromNotImportedMnemonicArgs()
try:
let response = parseJson(jsonString)
data.error = response["error"].getStr()
if data.error.len == 0:
data.derivations = toGeneratedAccountDto(response["derivedAddresses"]).derivedAccounts.derivations
except Exception as e:
error "error: ", procName="fetchAddressesFromNotImportedMnemonic", errName = e.name, errDesription = e.msg
data.error = e.msg
self.events.emit(SIGNAL_DERIVED_ADDRESSES_FROM_NOT_IMPORTED_MNEMONIC_FETCHED, data)
proc importMnemonic*(self: Service, mnemonic: string): string =
if mnemonic.len == 0:

View File

@ -2,108 +2,65 @@
# Async load derivedAddreses
#################################################
type
GetDerivedAddressTaskArg* = ref object of QObjectTaskArg
FetchAddressesArg* = ref object of QObjectTaskArg
paths: seq[string]
type
FetchDerivedAddressesTaskArg* = ref object of FetchAddressesArg
password: string
derivedFrom: string
path: string
const getDerivedAddressTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[GetDerivedAddressTaskArg](argEncoded)
const fetchDerivedAddressesTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[FetchDerivedAddressesTaskArg](argEncoded)
var output = %*{
"derivedAddress": "",
"error": ""
}
try:
let response = status_go_accounts.getDerivedAddress(arg.password, arg.derivedFrom, arg.path)
let response = status_go_accounts.getDerivedAddresses(arg.password, arg.derivedFrom, arg.paths)
output["derivedAddresses"] = response.result
except Exception as e:
output["error"] = %* fmt"Error getting derived address list: {e.msg}"
output["error"] = %* fmt"Error fetching derived address: {e.msg}"
arg.finish(output)
type
GetDerivedAddressesTaskArg* = ref object of GetDerivedAddressTaskArg
pageSize: int
pageNumber: int
const getDerivedAddressesTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[GetDerivedAddressesTaskArg](argEncoded)
try:
let response = status_go_accounts.getDerivedAddressList(arg.password, arg.derivedFrom, arg.path, arg.pageSize, arg.pageNumber)
let output = %*{
"derivedAddresses": response.result,
"error": ""
}
arg.finish(output)
except Exception as e:
let output = %* {
"derivedAddresses": "",
"error": fmt"Error getting derived address list: {e.msg}"
}
arg.finish(output)
type
GetDerivedAddressesForMnemonicTaskArg* = ref object of QObjectTaskArg
FetchDerivedAddressesForMnemonicTaskArg* = ref object of FetchAddressesArg
mnemonic: string
path: string
pageSize: int
pageNumber: int
const getDerivedAddressesForMnemonicTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[GetDerivedAddressesForMnemonicTaskArg](argEncoded)
try:
let response = status_go_accounts.getDerivedAddressListForMnemonic(arg.mnemonic, arg.path, arg.pageSize, arg.pageNumber)
let output = %*{
"derivedAddresses": response.result,
"error": ""
}
arg.finish(output)
except Exception as e:
let output = %* {
"derivedAddresses": "",
"error": fmt"Error getting derived address list for mnemonic: {e.msg}"
}
arg.finish(output)
type
GetDerivedAddressForPrivateKeyTaskArg* = ref object of QObjectTaskArg
privateKey: string
const getDerivedAddressForPrivateKeyTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[GetDerivedAddressForPrivateKeyTaskArg](argEncoded)
try:
let response = status_go_accounts.getDerivedAddressForPrivateKey(arg.privateKey)
let output = %*{
"derivedAddresses": response.result,
"error": ""
}
arg.finish(output)
except Exception as e:
let output = %* {
"derivedAddresses": "",
"error": fmt"Error getting derived address list for private key: {e.msg}"
}
arg.finish(output)
type
FetchDerivedAddressDetailsTaskArg* = ref object of QObjectTaskArg
address: string
const fetchDerivedAddressDetailsTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[FetchDerivedAddressDetailsTaskArg](argEncoded)
var data = %* {
"details": "",
const fetchDerivedAddressesForMnemonicTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[FetchDerivedAddressesForMnemonicTaskArg](argEncoded)
var output = %*{
"derivedAddress": "",
"error": ""
}
try:
let response = status_go_accounts.getDerivedAddressDetails(arg.address)
data["details"] = response.result
let response = status_go_accounts.getDerivedAddressesForMnemonic(arg.mnemonic, arg.paths)
output["derivedAddresses"] = response.result
except Exception as e:
let err = fmt"Error getting details for an address: {e.msg}"
data["error"] = %* err
arg.finish(data)
output["error"] = %* fmt"Error fetching derived address for mnemonic: {e.msg}"
arg.finish(output)
type
FetchDetailsForAddressesTaskArg* = ref object of QObjectTaskArg
uniqueId: string
addresses: seq[string]
const fetchDetailsForAddressesTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[FetchDetailsForAddressesTaskArg](argEncoded)
for address in arg.addresses:
var data = %* {
"uniqueId": arg.uniqueId,
"details": "",
"error": ""
}
try:
let response = status_go_accounts.getAddressDetails(address)
sleep(250)
data["details"] = response.result
except Exception as e:
let err = fmt"Error fetching details for an address: {e.msg}"
data["error"] = %* err
arg.finish(data)
#################################################
# Async building token

View File

@ -95,6 +95,8 @@ type
relatedAccounts*: seq[WalletAccountDto]
ens*: string
assetsLoading*: bool
keypairName*: string
lastUsedDerivationIndex*: int
proc newDto*(
name: string,
@ -137,6 +139,8 @@ proc toWalletAccountDto*(jsonObj: JsonNode): WalletAccountDto =
discard jsonObj.getProp("type", result.walletType)
discard jsonObj.getProp("emoji", result.emoji)
discard jsonObj.getProp("derived-from", result.derivedfrom)
discard jsonObj.getProp("keypair-name", result.keypairName)
discard jsonObj.getProp("last-used-derivation-index", result.lastUsedDerivationIndex)
result.assetsLoading = true
proc getCurrencyBalance*(self: BalanceDto, currencyPrice: float64): float64 =

View File

@ -30,9 +30,11 @@ const SIGNAL_WALLET_ACCOUNT_DELETED* = "walletAccount/accountDeleted"
const SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED* = "walletAccount/currencyUpdated"
const SIGNAL_WALLET_ACCOUNT_UPDATED* = "walletAccount/walletAccountUpdated"
const SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED* = "walletAccount/networkEnabledUpdated"
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_READY* = "walletAccount/derivedAddressesReady"
const SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT* = "walletAccount/tokensRebuilt"
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_DETAILS_FETCHED* = "walletAccount/derivedAddressDetailsFetched"
const SIGNAL_WALLET_ACCOUNT_TOKENS_BEING_FETCHED* = "walletAccount/tokenFetching"
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESSES_FETCHED* = "walletAccount/derivedAddressesFetched"
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESSES_FROM_MNEMONIC_FETCHED* = "walletAccount/derivedAddressesFromMnemonicFetched"
const SIGNAL_WALLET_ACCOUNT_ADDRESS_DETAILS_FETCHED* = "walletAccount/addressDetailsFetched"
const SIGNAL_KEYCARDS_SYNCHRONIZED* = "keycardsSynchronized"
const SIGNAL_NEW_KEYCARD_SET* = "newKeycardSet"
@ -83,6 +85,7 @@ type WalletAccountUpdated* = ref object of Args
account*: WalletAccountDto
type DerivedAddressesArgs* = ref object of Args
uniqueId*: string
derivedAddresses*: seq[DerivedAddressDto]
error*: string
@ -264,7 +267,7 @@ QtObject:
proc getIndex*(self: Service, address: string): int =
let accounts = self.getWalletAccounts()
for i in 0..accounts.len:
for i in 0 ..< accounts.len:
if(accounts[i].address == address):
return i
@ -308,101 +311,77 @@ QtObject:
self.buildAllTokens(@[newAccount.address], store = true)
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
proc addOrReplaceWalletAccount(self: Service, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType,
color, emoji: string, walletDefaultAccount = false, chatDefaultAccount = false): string =
## 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 =
try:
let response = status_go_accounts.saveAccount(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid,
accountType, color, emoji, walletDefaultAccount, chatDefaultAccount)
var response: RpcResponse[JsonNode]
if password.len == 0:
response = status_go_accounts.addAccountWithoutKeystoreFileCreation(name, keyPairName, address, path, lastUsedDerivationIndex,
rootWalletMasterKey, publicKey, keyUid, accountType, color, emoji)
else:
var finalPassword = password
if doPasswordHashing:
finalPassword = utils.hashPassword(password)
response = status_go_accounts.addAccount(finalPassword, name, keyPairName, address, path,
lastUsedDerivationIndex, rootWalletMasterKey, publicKey, keyUid, accountType, color, emoji)
if not response.error.isNil:
return "(" & $response.error.code & ") " & response.error.message
error "status-go error", procName="addWalletAccount", errCode=response.error.code, errDesription=response.error.message
return response.error.message
self.addNewAccountToLocalStore()
return ""
except Exception as e:
error "error: ", procName="addWalletAccount", errName = e.name, errDesription = e.msg
return "error: " & e.msg
error "error: ", procName="addWalletAccount", errName=e.name, errDesription=e.msg
return e.msg
proc generateNewAccount*(self: Service, password: string, accountName: string, color: string, emoji: string,
path: string, derivedFrom: string, skipPasswordVerification: bool): string =
proc addNewPrivateKeyAccount*(self: Service, privateKey, password: string, doPasswordHashing: bool, name, keyPairName, address, path: string,
lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey, keyUid, accountType, color, emoji: string): string =
if password.len == 0:
error "for adding new private key account, password must be provided"
return
var finalPassword = password
if doPasswordHashing:
finalPassword = utils.hashPassword(password)
try:
if skipPasswordVerification:
discard backend.generateAccountWithDerivedPathPasswordVerified(
password,
accountName,
color,
emoji,
path,
derivedFrom)
else:
discard backend.generateAccountWithDerivedPath(
utils.hashPassword(password),
accountName,
color,
emoji,
path,
derivedFrom)
let response = status_go_accounts.importPrivateKey(privateKey, finalPassword)
if not response.error.isNil:
error "status-go error importing private key", procName="addNewPrivateKeyAccount", errCode=response.error.code, errDesription=response.error.message
return response.error.message
return self.addWalletAccount(password, doPasswordHashing, name, keyPairName, address, path, lastUsedDerivationIndex, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji)
except Exception as e:
return fmt"Error generating new account: {e.msg}"
error "error: ", procName="addNewPrivateKeyAccount", errName=e.name, errDesription=e.msg
return e.msg
self.addNewAccountToLocalStore()
proc addAccountsFromPrivateKey*(self: Service, privateKey: string, password: string, accountName: string, color: string,
emoji: string, skipPasswordVerification: bool): string =
proc addNewSeedPhraseAccount*(self: Service, seedPhrase, password: string, doPasswordHashing: bool, name, keyPairName, address, path: string,
lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey, keyUid, accountType, color, emoji: string): string =
if password.len == 0:
error "for adding new seed phrase account, password must be provided"
return
var finalPassword = password
if doPasswordHashing:
finalPassword = utils.hashPassword(password)
try:
if skipPasswordVerification:
discard backend.addAccountWithPrivateKeyPasswordVerified(
privateKey,
password,
accountName,
color,
emoji)
else:
discard backend.addAccountWithPrivateKey(
privateKey,
utils.hashPassword(password),
accountName,
color,
emoji)
let response = status_go_accounts.importMnemonic(seedPhrase, finalPassword)
if not response.error.isNil:
error "status-go error importing private key", procName="addNewSeedPhraseAccount", errCode=response.error.code, errDesription=response.error.message
return response.error.message
return self.addWalletAccount(password, doPasswordHashing, name, keyPairName, address, path, lastUsedDerivationIndex, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji)
except Exception as e:
return fmt"Error adding account with private key: {e.msg}"
error "error: ", procName="addNewSeedPhraseAccount", errName=e.name, errDesription=e.msg
return e.msg
self.addNewAccountToLocalStore()
proc addAccountsFromSeed*(self: Service, mnemonic: string, password: string, accountName: string, color: string,
emoji: string, path: string, skipPasswordVerification: bool): string =
proc getRandomMnemonic*(self: Service): string =
try:
if skipPasswordVerification:
discard backend.addAccountWithMnemonicAndPathPasswordVerified(
mnemonic,
password,
accountName,
color,
emoji,
path
)
else:
discard backend.addAccountWithMnemonicAndPath(
mnemonic,
utils.hashPassword(password),
accountName,
color,
emoji,
path
)
let response = status_go_accounts.getRandomMnemonic()
if not response.error.isNil:
error "status-go error", procName="getRandomMnemonic", errCode=response.error.code, errDesription=response.error.message
return ""
return response.result.getStr
except Exception as e:
return fmt"Error adding account with mnemonic: {e.msg}"
self.addNewAccountToLocalStore()
proc addWatchOnlyAccount*(self: Service, address: string, accountName: string, color: string, emoji: string): string =
try:
discard backend.addAccountWatch(
address,
accountName,
color,
emoji
)
except Exception as e:
return fmt"Error adding account with mnemonic: {e.msg}"
self.addNewAccountToLocalStore()
error "error: ", procName="getRandomMnemonic", errName=e.name, errDesription=e.msg
return ""
proc deleteAccount*(self: Service, address: string, password = "") =
try:
@ -437,102 +416,83 @@ QtObject:
if not self.walletAccountsContainsAddress(address):
error "account's address is not among known addresses: ", address=address
return
var account = self.getAccountByAddress(address)
let res = self.addOrReplaceWalletAccount(accountName, account.address, account.path, account.derivedfrom,
account.publicKey, account.keyUid, account.walletType, color, emoji, account.isWallet, account.isChat)
if res.len == 0:
try:
var account = self.getAccountByAddress(address)
let response = status_go_accounts.updateAccount(accountName, account.keyPairName, account.address, account.path, account.lastUsedDerivationIndex,
account.derivedfrom, account.publicKey, account.keyUid, account.walletType, color, emoji, account.isWallet, account.isChat)
if not response.error.isNil:
error "status-go error", procName="updateWalletAccount", errCode=response.error.code, errDesription=response.error.message
return
account.name = accountName
account.color = color
account.emoji = emoji
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))
except Exception as e:
error "error: ", procName="updateWalletAccount", errName=e.name, errDesription=e.msg
proc getDerivedAddress*(self: Service, password: string, derivedFrom: string, path: string, hashPassword: bool)=
let arg = GetDerivedAddressTaskArg(
proc fetchDerivedAddresses*(self: Service, password: string, derivedFrom: string, paths: seq[string], hashPassword: bool)=
let arg = FetchDerivedAddressesTaskArg(
password: if hashPassword: utils.hashPassword(password) else: password,
derivedFrom: derivedFrom,
path: path,
tptr: cast[ByteAddress](getDerivedAddressTask),
paths: paths,
tptr: cast[ByteAddress](fetchDerivedAddressesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "setDerivedAddress",
slot: "onDerivedAddressesFetched",
)
self.threadpool.start(arg)
proc getDerivedAddressList*(self: Service, password: string, derivedFrom: string, path: string, pageSize: int, pageNumber: int, hashPassword: bool)=
let arg = GetDerivedAddressesTaskArg(
password: if hashPassword: utils.hashPassword(password) else: password,
derivedFrom: derivedFrom,
path: path,
pageSize: pageSize,
pageNumber: pageNumber,
tptr: cast[ByteAddress](getDerivedAddressesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "setDerivedAddresses",
)
self.threadpool.start(arg)
proc getDerivedAddressListForMnemonic*(self: Service, mnemonic: string, path: string, pageSize: int, pageNumber: int) =
let arg = GetDerivedAddressesForMnemonicTaskArg(
mnemonic: mnemonic,
path: path,
pageSize: pageSize,
pageNumber: pageNumber,
tptr: cast[ByteAddress](getDerivedAddressesForMnemonicTask),
vptr: cast[ByteAddress](self.vptr),
slot: "setDerivedAddresses",
)
self.threadpool.start(arg)
proc getDerivedAddressForPrivateKey*(self: Service, privateKey: string) =
let arg = GetDerivedAddressForPrivateKeyTaskArg(
privateKey: privateKey,
tptr: cast[ByteAddress](getDerivedAddressForPrivateKeyTask),
vptr: cast[ByteAddress](self.vptr),
slot: "setDerivedAddresses",
)
self.threadpool.start(arg)
proc setDerivedAddresses*(self: Service, derivedAddressesJson: string) {.slot.} =
let response = parseJson(derivedAddressesJson)
proc onDerivedAddressesFetched*(self: Service, jsonString: string) {.slot.} =
let response = parseJson(jsonString)
var derivedAddress: seq[DerivedAddressDto] = @[]
derivedAddress = response["derivedAddresses"].getElems().map(x => x.toDerivedAddressDto())
let error = response["error"].getStr()
# emit event
self.events.emit(SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_READY, DerivedAddressesArgs(
self.events.emit(SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESSES_FETCHED, DerivedAddressesArgs(
derivedAddresses: derivedAddress,
error: error
))
proc setDerivedAddress*(self: Service, derivedAddressesJson: string) {.slot.} =
let response = parseJson(derivedAddressesJson)
let derivedAddress = response["derivedAddresses"].toDerivedAddressDto()
let error = response["error"].getStr()
# emit event
self.events.emit(SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_READY, DerivedAddressesArgs(
derivedAddresses: @[derivedAddress],
error: error
))
proc fetchDerivedAddressDetails*(self: Service, address: string) =
let arg = FetchDerivedAddressDetailsTaskArg(
address: address,
tptr: cast[ByteAddress](fetchDerivedAddressDetailsTask),
proc fetchDerivedAddressesForMnemonic*(self: Service, mnemonic: string, paths: seq[string])=
let arg = FetchDerivedAddressesForMnemonicTaskArg(
mnemonic: mnemonic,
paths: paths,
tptr: cast[ByteAddress](fetchDerivedAddressesForMnemonicTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onDerivedAddressDetailsFetched",
slot: "onDerivedAddressesForMnemonicFetched",
)
self.threadpool.start(arg)
proc onDerivedAddressDetailsFetched*(self: Service, jsonString: string) {.slot.} =
proc onDerivedAddressesForMnemonicFetched*(self: Service, jsonString: string) {.slot.} =
let response = parseJson(jsonString)
var derivedAddress: seq[DerivedAddressDto] = @[]
derivedAddress = response["derivedAddresses"].getElems().map(x => x.toDerivedAddressDto())
let error = response["error"].getStr()
self.events.emit(SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESSES_FROM_MNEMONIC_FETCHED, DerivedAddressesArgs(
derivedAddresses: derivedAddress,
error: error
))
proc fetchDetailsForAddresses*(self: Service, uniqueId: string, addresses: seq[string]) =
let arg = FetchDetailsForAddressesTaskArg(
uniqueId: uniqueId,
addresses: addresses,
tptr: cast[ByteAddress](fetchDetailsForAddressesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAddressDetailsFetched",
)
self.threadpool.start(arg)
proc onAddressDetailsFetched*(self: Service, jsonString: string) {.slot.} =
var data = DerivedAddressesArgs()
try:
let response = parseJson(jsonString)
data.uniqueId = response["uniqueId"].getStr()
let addrDto = response{"details"}.toDerivedAddressDto()
data.derivedAddresses.add(addrDto)
data.error = response["error"].getStr()
except Exception as e:
error "error: ", procName="getDerivedAddressDetails", errName = e.name, errDesription = e.msg
error "error: ", procName="fetchAddressDetails", errName = e.name, errDesription = e.msg
data.error = e.msg
self.events.emit(SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_DETAILS_FETCHED, data)
self.events.emit(SIGNAL_WALLET_ACCOUNT_ADDRESS_DETAILS_FETCHED, data)
proc updateAssetsLoadingState(self: Service, wAddress: string, loading: bool) =
withLock self.walletAccountsLock:
@ -809,13 +769,6 @@ QtObject:
error "error: ", procName="deleteKeycard", errName = e.name, errDesription = e.msg
return false
proc addWalletAccount*(self: Service, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType,
color, emoji: string): string =
result = self.addOrReplaceWalletAccount(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid,
accountType, color, emoji)
if result.len == 0:
self.addNewAccountToLocalStore()
proc handleKeycardActions(self: Service, keycardActions: seq[KeycardActionDto]) =
if keycardActions.len == 0:
return

View File

@ -1,5 +1,6 @@
import json, json_serialization, chronicles, strutils
import ./core, ../app_service/common/utils
import ../app_service/common/account_constants
import ./response_type
import status_go
@ -25,22 +26,64 @@ proc deleteAccount*(address: string, password: string): RpcResponse[JsonNode] {.
let payload = %* [address, password]
return core.callPrivateRPC("accounts_deleteAccount", payload)
proc saveAccount*(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType, color, emoji: string,
walletDefaultAccount: bool, chatDefaultAccount: bool):
## Adds a new account and creates a Keystore file if password is provided, otherwise it only creates a new account
proc addAccount*(password, name, keyPairName, address, path: string, lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji: string):
RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [
password,
{
"address": address,
"key-uid": keyUid,
"wallet": false, #this refers to the default wallet account and it's set at the moment of Status chat account creation, cannot be changed later
"chat": false, #this refers to Status chat account, set when the Status account is created, cannot be changed later
"type": accountType,
#"storage" present on the status-go side, but we don't use it
"path": path,
"public-key": publicKey,
"name": name,
"emoji": emoji,
"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
#"removed" present on the status-go side, used for synchronization, no need to set it here
"keypair-name": keyPairName,
"last-used-derivation-index": lastUsedDerivationIndex
}
]
return core.callPrivateRPC("accounts_addAccount", payload)
## Adds a new account without creating a Keystore file
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
proc updateAccount*(name, keyPairName, address, path: string, lastUsedDerivationIndex: int, rootWalletMasterKey, publicKey,
keyUid, accountType, color, emoji: string, walletDefaultAccount: bool, chatDefaultAccount: bool):
RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [
[{
"name": name,
"address": address,
"path": path,
"derived-from": addressAccountIsDerivedFrom,
"public-key": publicKey,
"key-uid": keyUid,
"type": accountType,
"color": color,
"emoji": emoji,
"wallet": walletDefaultAccount,
"chat": chatDefaultAccount
"chat": chatDefaultAccount,
"type": accountType,
#"storage" present on the status-go side, but we don't use it
"path": path,
"public-key": publicKey,
"name": name,
"emoji": emoji,
"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
#"removed" present on the status-go side, used for synchronization, no need to set it here
"keypair-name": keyPairName,
"last-used-derivation-index": lastUsedDerivationIndex
}]
]
return core.callPrivateRPC("accounts_saveAccounts", payload)
@ -130,6 +173,10 @@ proc isAlias*(value: string): bool =
let r = Json.decode(response, JsonNode)
return r["result"].getBool()
proc getRandomMnemonic*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
return core.callPrivateRPC("accounts_getRandomMnemonic", payload)
proc multiAccountImportMnemonic*(mnemonic: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* {
"mnemonicPhrase": mnemonic,
@ -144,6 +191,12 @@ proc multiAccountImportMnemonic*(mnemonic: string): RpcResponse[JsonNode] {.rais
error "error doing rpc request", methodName = "multiAccountImportMnemonic", exception=e.msg
raise newException(RpcException, e.msg)
## Imports a new mnemonic and creates local keystore file.
proc importMnemonic*(mnemonic, password: string):
RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [mnemonic, password]
return core.callPrivateRPC("accounts_importMnemonic", payload)
proc createAccountFromMnemonicAndDeriveAccountsForPaths*(mnemonic: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* {
"mnemonicPhrase": mnemonic,
@ -158,6 +211,21 @@ proc createAccountFromMnemonicAndDeriveAccountsForPaths*(mnemonic: string, paths
error "error doing rpc request", methodName = "createAccountFromMnemonicAndDeriveAccountsForPaths", exception=e.msg
raise newException(RpcException, e.msg)
## Imports a new private key and creates local keystore file.
proc importPrivateKey*(privateKey, password: string):
RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [privateKey, password]
return core.callPrivateRPC("accounts_importPrivateKey", payload)
proc createAccountFromPrivateKey*(privateKey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* {"privateKey": privateKey}
try:
let response = status_go.createAccountFromPrivateKey($payload)
result.result = Json.decode(response, JsonNode)
except RpcException as e:
error "error doing rpc request", methodName = "createAccountFromPrivateKey", exception=e.msg
raise newException(RpcException, e.msg)
proc deriveAccounts*(accountId: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* {
"accountID": accountId,
@ -323,25 +391,17 @@ proc setDisplayName*(displayName: string): RpcResponse[JsonNode] {.raises: [Exce
let payload = %* [displayName]
result = core.callPrivateRPC("setDisplayName".prefix, payload)
proc getDerivedAddress*(password: string, derivedFrom: string, path: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [password, derivedFrom, path]
result = core.callPrivateRPC("wallet_getDerivedAddressForPath", payload)
proc getDerivedAddresses*(password: string, derivedFrom: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [password, derivedFrom, paths]
result = core.callPrivateRPC("wallet_getDerivedAddresses", payload)
proc getDerivedAddressList*(password: string, derivedFrom: string, path: string, pageSize: int = 0, pageNumber: int = 6,): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [password, derivedFrom, path, pageSize, pageNumber ]
result = core.callPrivateRPC("wallet_getDerivedAddressesForPath", payload)
proc getDerivedAddressesForMnemonic*(mnemonic: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [mnemonic, paths]
result = core.callPrivateRPC("wallet_getDerivedAddressesForMnemonic", payload)
proc getDerivedAddressListForMnemonic*(mnemonic: string, path: string, pageSize: int = 0, pageNumber: int = 6,): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [mnemonic, path, pageSize, pageNumber ]
result = core.callPrivateRPC("wallet_getDerivedAddressesForMnemonicWithPath", payload)
proc getDerivedAddressForPrivateKey*(privateKey: string,): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [privateKey]
result = core.callPrivateRPC("wallet_getDerivedAddressForPrivateKey", payload)
proc getDerivedAddressDetails*(address: string,): RpcResponse[JsonNode] {.raises: [Exception].} =
proc getAddressDetails*(address: string,): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [address]
result = core.callPrivateRPC("wallet_getDerivedAddressDetails", payload)
result = core.callPrivateRPC("wallet_getAddressDetails", payload)
proc verifyPassword*(password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [password]

View File

@ -113,58 +113,6 @@ rpc(fetchPrices, "wallet"):
symbols: seq[string]
currencies: seq[string]
rpc(generateAccountWithDerivedPath, "accounts"):
password: string
name: string
color: string
emoji: string
path: string
derivedFrom: string
rpc(generateAccountWithDerivedPathPasswordVerified, "accounts"):
password: string
name: string
color: string
emoji: string
path: string
derivedFrom: string
rpc(addAccountWithMnemonicAndPath, "accounts"):
mnemonic: string
password: string
name: string
color: string
emoji: string
path: string
rpc(addAccountWithMnemonicAndPathPasswordVerified, "accounts"):
mnemonic: string
password: string
name: string
color: string
emoji: string
path: string
rpc(addAccountWithPrivateKey, "accounts"):
privateKey: string
password: string
name: string
color: string
emoji: string
rpc(addAccountWithPrivateKeyPasswordVerified, "accounts"):
privateKey: string
password: string
name: string
color: string
emoji: string
rpc(addAccountWatch, "accounts"):
address: string
name: string
color: string
emoji: string
rpc(activityCenterNotifications, "wakuext"):
request: ActivityCenterNotificationsRequest

@ -1 +1 @@
Subproject commit 73fe79616ce6c7a6e5e79f6425d20cd74b788ffd
Subproject commit 534c04dc737f681ef49207e1f183e9fc53647fd5

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 8c85a62e108d9c54f6124117cf7a196fb3731732
Subproject commit e9482e3974a2f82bd6a23f0c9e861b5bca23f472