From 71b5bc9e713f86368676f37da97f2dc9dbd65004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 28 Apr 2022 16:46:02 +0200 Subject: [PATCH] wallet: backend account switching --- nym-wallet/src-tauri/src/main.rs | 1 + .../src/operations/mixnet/account.rs | 77 ++++++++++++++++++- nym-wallet/src-tauri/src/state.rs | 22 ++++++ .../src-tauri/src/wallet_storage/mod.rs | 1 + nym-wallet/src/types/rust/accountentry.ts | 4 + 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 nym-wallet/src/types/rust/accountentry.ts diff --git a/nym-wallet/src-tauri/src/main.rs b/nym-wallet/src-tauri/src/main.rs index 417cc416e9..d5c7d9ccf8 100644 --- a/nym-wallet/src-tauri/src/main.rs +++ b/nym-wallet/src-tauri/src/main.rs @@ -44,6 +44,7 @@ fn main() { mixnet::account::get_validator_api_urls, mixnet::account::get_validator_nymd_urls, mixnet::account::list_accounts_for_password, + mixnet::account::sign_in_decrypted_account, mixnet::account::logout, mixnet::account::remove_account_for_password, mixnet::account::remove_password, diff --git a/nym-wallet/src-tauri/src/operations/mixnet/account.rs b/nym-wallet/src-tauri/src/operations/mixnet/account.rs index 2c29d81d38..0a278cf7c7 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/account.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/account.rs @@ -3,7 +3,7 @@ use crate::config::Config; use crate::error::BackendError; use crate::network::Network as WalletNetwork; use crate::nymd_client; -use crate::state::State; +use crate::state::{DecryptedAccount, State}; use crate::wallet_storage::account_data::StoredLogin; use crate::wallet_storage::{self, DEFAULT_WALLET_ACCOUNT_ID}; @@ -14,7 +14,7 @@ use cosmrs::bip32::DerivationPath; use itertools::Itertools; use rand::seq::SliceRandom; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::convert::TryInto; use std::str::FromStr; use std::sync::Arc; @@ -51,6 +51,14 @@ pub struct CreatedAccount { mnemonic: String, } +#[cfg_attr(test, derive(ts_rs::TS))] +#[cfg_attr(test, ts(export, export_to = "../src/types/rust/createdaccount.ts"))] +#[derive(Clone, Serialize, Deserialize)] +pub struct AccountEntry { + id: String, + address: String, +} + #[cfg_attr(test, derive(ts_rs::TS))] #[cfg_attr(test, ts(export, export_to = "../src/types/rust/balance.ts"))] #[derive(Serialize, Deserialize)] @@ -432,6 +440,37 @@ pub async fn sign_in_with_password( .clone() } }; + + // Keep track of all accounts + // WIP(JON): simplify + let all_accounts: HashMap<_, _> = match stored_account { + StoredLogin::Mnemonic(ref account) => [( + id.to_string(), + DecryptedAccount { + id: id.to_string(), + mnemonic: account.mnemonic().clone(), + }, + )] + .into_iter() + .collect(), + StoredLogin::Multiple(ref accounts) => accounts + .get_accounts() + .map(|account| { + ( + account.id.to_string(), + DecryptedAccount { + id: account.id.to_string(), + mnemonic: account.account.mnemonic().clone(), + }, + ) + }) + .collect(), + }; + { + let mut w_state = state.write().await; + w_state.set_all_accounts(all_accounts); + } + _connect_with_mnemonic(mnemonic, state).await } @@ -468,6 +507,23 @@ pub fn remove_account_for_password(password: &str, inner_id: &str) -> Result<(), wallet_storage::remove_account_from_wallet_login(&id, &inner_id, &password) } +#[tauri::command] +pub async fn list_accounts( + state: tauri::State<'_, Arc>>, +) -> Result, BackendError> { + let state = state.read().await; + let all_accounts = state.get_all_accounts(); + let a = all_accounts + .values() + .map(|account| AccountEntry { + id: account.id.clone(), + address: "placeholder".to_string(), + }) + .collect(); + Ok(a) +} + +// WIP(JON): consider changing return type #[tauri::command] pub fn list_accounts_for_password(password: &str) -> Result, BackendError> { // Currently we only support a single, default, id in the wallet @@ -483,3 +539,20 @@ pub fn list_accounts_for_password(password: &str) -> Result, Backend }; Ok(ids) } + +#[tauri::command] +pub async fn sign_in_decrypted_account( + account_id: &str, + state: tauri::State<'_, Arc>>, +) -> Result { + let account = { + let state = state.read().await; + state + .get_all_accounts() + .get(account_id) + .ok_or(BackendError::NoSuchIdInWalletLoginEntry)? + .clone() + }; + let mnemonic = account.mnemonic; + _connect_with_mnemonic(mnemonic, state).await +} diff --git a/nym-wallet/src-tauri/src/state.rs b/nym-wallet/src-tauri/src/state.rs index 63e5a961c5..c1672d9391 100644 --- a/nym-wallet/src-tauri/src/state.rs +++ b/nym-wallet/src-tauri/src/state.rs @@ -2,6 +2,7 @@ use crate::config::{Config, OptionalValidators, ValidatorUrl}; use crate::error::BackendError; use crate::network::Network; +use bip39::Mnemonic; use strum::IntoEnumIterator; use validator_client::nymd::SigningNymdClient; use validator_client::Client; @@ -18,6 +19,10 @@ pub struct State { signing_clients: HashMap>, current_network: Network, + // All the accounts the we get from decrypting the wallet. We hold on to these for being able to + // switch accounts on-the-fly + all_accounts: HashMap, + /// Validators that have been fetched dynamically, probably during startup. fetched_validators: OptionalValidators, } @@ -63,6 +68,15 @@ impl State { self.current_network } + pub(crate) fn set_all_accounts(&mut self, all_accounts: HashMap) { + self.all_accounts.clear(); + self.all_accounts.extend(all_accounts) + } + + pub(crate) fn get_all_accounts(&self) -> &HashMap { + &self.all_accounts + } + pub fn logout(&mut self) { self.signing_clients = HashMap::new(); } @@ -162,6 +176,14 @@ macro_rules! client { }; } +// Keep track of mnemonics on the backend, so we can switch accounts +#[derive(Clone)] +pub(crate) struct DecryptedAccount { + pub id: String, + pub mnemonic: Mnemonic, + // address: String +} + #[macro_export] macro_rules! nymd_client { ($state:ident) => { diff --git a/nym-wallet/src-tauri/src/wallet_storage/mod.rs b/nym-wallet/src-tauri/src/wallet_storage/mod.rs index 8fb7d10775..82c7585d35 100644 --- a/nym-wallet/src-tauri/src/wallet_storage/mod.rs +++ b/nym-wallet/src-tauri/src/wallet_storage/mod.rs @@ -153,6 +153,7 @@ fn append_account_to_wallet_login_information_at_file( let mut decrypted_login = stored_wallet.decrypt_login(&id, password)?; + // WIP(JON): redo this since we now can clone the mnemonic // Since we can't clone the mnemonic, we have to perform a little dance were we add the mnemonic // to the inner enum payload, while also converting by swapping if necessary. if let StoredLogin::Multiple(ref mut accounts) = decrypted_login { diff --git a/nym-wallet/src/types/rust/accountentry.ts b/nym-wallet/src/types/rust/accountentry.ts new file mode 100644 index 0000000000..f6ad1b53a9 --- /dev/null +++ b/nym-wallet/src/types/rust/accountentry.ts @@ -0,0 +1,4 @@ +export interface AccountEntry { + id: string; + address: string; +}