merge sprint branch updates£
This commit is contained in:
@@ -97,6 +97,8 @@ pub enum BackendError {
|
||||
WalletUnexpectedMultipleAccounts,
|
||||
#[error("Unexpted mnemonic account found")]
|
||||
WalletUnexpectedMnemonicAccount,
|
||||
#[error("Failed to derive address from mnemonic")]
|
||||
FailedToDeriveAddress,
|
||||
}
|
||||
|
||||
impl Serialize for BackendError {
|
||||
|
||||
@@ -48,11 +48,12 @@ fn main() {
|
||||
mixnet::account::logout,
|
||||
mixnet::account::remove_account_for_password,
|
||||
mixnet::account::remove_password,
|
||||
mixnet::account::show_mnemonic_for_account_in_password,
|
||||
mixnet::account::sign_in_decrypted_account,
|
||||
mixnet::account::sign_in_with_password,
|
||||
mixnet::account::switch_network,
|
||||
mixnet::account::update_validator_urls,
|
||||
mixnet::account::validate_mnemonic,
|
||||
mixnet::account::validate_mnemonic,
|
||||
mixnet::admin::get_contract_settings,
|
||||
mixnet::admin::update_contract_settings,
|
||||
mixnet::bond::bond_gateway,
|
||||
|
||||
@@ -3,8 +3,8 @@ use crate::config::Config;
|
||||
use crate::error::BackendError;
|
||||
use crate::network::Network as WalletNetwork;
|
||||
use crate::nymd_client;
|
||||
use crate::state::{DecryptedAccount, State};
|
||||
use crate::wallet_storage::account_data::StoredLogin;
|
||||
use crate::state::State;
|
||||
use crate::wallet_storage::account_data::{StoredLogin, WalletAccount};
|
||||
use crate::wallet_storage::{self, DEFAULT_WALLET_ACCOUNT_ID};
|
||||
|
||||
use bip39::{Language, Mnemonic};
|
||||
@@ -14,13 +14,14 @@ use cosmrs::bip32::DerivationPath;
|
||||
use itertools::Itertools;
|
||||
use rand::seq::SliceRandom;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use strum::IntoEnumIterator;
|
||||
use tokio::sync::RwLock;
|
||||
use url::Url;
|
||||
use validator_client::nymd::wallet::{AccountData, DirectSecp256k1HdWallet};
|
||||
|
||||
use validator_client::{nymd::SigningNymdClient, Client};
|
||||
|
||||
@@ -53,7 +54,7 @@ pub struct CreatedAccount {
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/createdaccount.ts"))]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AccountEntry {
|
||||
id: String,
|
||||
address: String,
|
||||
@@ -441,32 +442,14 @@ pub async fn sign_in_with_password(
|
||||
}
|
||||
};
|
||||
|
||||
// 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(),
|
||||
};
|
||||
{
|
||||
// Keep track of all accounts for that id
|
||||
let all_accounts: HashMap<String, WalletAccount> = stored_account
|
||||
.unwrap_into_multiple_accounts(id)
|
||||
.into_accounts()
|
||||
.map(|a| (a.id.to_string(), a))
|
||||
.collect();
|
||||
|
||||
let mut w_state = state.write().await;
|
||||
w_state.set_all_accounts(all_accounts);
|
||||
}
|
||||
@@ -487,6 +470,7 @@ pub fn add_account_for_password(
|
||||
password: &str,
|
||||
inner_id: &str,
|
||||
) -> Result<(), BackendError> {
|
||||
log::info!("Adding account for the current password: {inner_id}");
|
||||
let mnemonic = Mnemonic::from_str(mnemonic)?;
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
// Currently we only support a single, default, id in the wallet
|
||||
@@ -500,6 +484,7 @@ pub fn add_account_for_password(
|
||||
|
||||
#[tauri::command]
|
||||
pub fn remove_account_for_password(password: &str, inner_id: &str) -> Result<(), BackendError> {
|
||||
log::info!("Removing account: {inner_id}");
|
||||
// Currently we only support a single, default, id in the wallet
|
||||
let id = wallet_storage::AccountId::new(DEFAULT_WALLET_ACCOUNT_ID.to_string());
|
||||
let inner_id = wallet_storage::AccountId::new(inner_id.to_string());
|
||||
@@ -507,37 +492,62 @@ pub fn remove_account_for_password(password: &str, inner_id: &str) -> Result<(),
|
||||
wallet_storage::remove_account_from_wallet_login(&id, &inner_id, &password)
|
||||
}
|
||||
|
||||
fn derive_address(
|
||||
mnemonic: bip39::Mnemonic,
|
||||
prefix: &str,
|
||||
) -> Result<cosmrs::AccountId, BackendError> {
|
||||
DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic)?
|
||||
.try_derive_accounts()?
|
||||
.first()
|
||||
.map(AccountData::address)
|
||||
.cloned()
|
||||
.ok_or(BackendError::FailedToDeriveAddress)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_accounts(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Vec<AccountEntry>, BackendError> {
|
||||
let state = state.read().await;
|
||||
let all_accounts = state.get_all_accounts();
|
||||
let a = all_accounts
|
||||
let network: Network = state.current_network().into();
|
||||
let prefix = network.bech32_prefix();
|
||||
|
||||
let all_accounts = state
|
||||
.get_all_accounts()
|
||||
.values()
|
||||
.map(|account| AccountEntry {
|
||||
id: account.id.clone(),
|
||||
address: "placeholder".to_string(),
|
||||
id: account.id.to_string(),
|
||||
address: derive_address(account.account.mnemonic().clone(), prefix)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
})
|
||||
.collect();
|
||||
Ok(a)
|
||||
|
||||
Ok(all_accounts)
|
||||
}
|
||||
|
||||
// WIP(JON): consider changing return type
|
||||
#[tauri::command]
|
||||
pub fn list_accounts_for_password(password: &str) -> Result<Vec<String>, BackendError> {
|
||||
// Currently we only support a single, default, id in the wallet
|
||||
pub fn show_mnemonic_for_account_in_password(
|
||||
account_id: String,
|
||||
password: String,
|
||||
) -> Result<String, BackendError> {
|
||||
log::info!("Getting mnemonic for: {account_id}");
|
||||
let id = wallet_storage::AccountId::new(DEFAULT_WALLET_ACCOUNT_ID.to_string());
|
||||
let password = wallet_storage::UserPassword::new(password.to_string());
|
||||
let login = wallet_storage::load_existing_wallet_login_information(&id, &password)?;
|
||||
let ids = match login {
|
||||
StoredLogin::Mnemonic(_) => vec![id.to_string()],
|
||||
let account_id = wallet_storage::AccountId::new(account_id);
|
||||
let password = wallet_storage::UserPassword::new(password);
|
||||
let stored_account = wallet_storage::load_existing_wallet_login_information(&id, &password)?;
|
||||
|
||||
let mnemonic = match stored_account {
|
||||
StoredLogin::Mnemonic(_) => return Err(BackendError::WalletUnexpectedMnemonicAccount),
|
||||
StoredLogin::Multiple(ref accounts) => accounts
|
||||
.get_accounts()
|
||||
.map(|account| account.id.to_string())
|
||||
.collect::<Vec<_>>(),
|
||||
.get_account(&account_id)
|
||||
.ok_or(BackendError::NoSuchIdInWalletLoginEntry)?
|
||||
.account
|
||||
.mnemonic()
|
||||
.clone(),
|
||||
};
|
||||
Ok(ids)
|
||||
|
||||
Ok(mnemonic.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -545,14 +555,16 @@ pub async fn sign_in_decrypted_account(
|
||||
account_id: &str,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Account, BackendError> {
|
||||
let account = {
|
||||
log::info!("Signing in to already decrypted account: {account_id}");
|
||||
let mnemonic = {
|
||||
let state = state.read().await;
|
||||
state
|
||||
.get_all_accounts()
|
||||
.get(account_id)
|
||||
.ok_or(BackendError::NoSuchIdInWalletLoginEntry)?
|
||||
.account
|
||||
.mnemonic()
|
||||
.clone()
|
||||
};
|
||||
let mnemonic = account.mnemonic;
|
||||
_connect_with_mnemonic(mnemonic, state).await
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::config::{Config, OptionalValidators, ValidatorUrl};
|
||||
use crate::error::BackendError;
|
||||
use crate::network::Network;
|
||||
use crate::wallet_storage::account_data::WalletAccount;
|
||||
|
||||
use bip39::Mnemonic;
|
||||
use strum::IntoEnumIterator;
|
||||
use validator_client::nymd::SigningNymdClient;
|
||||
use validator_client::Client;
|
||||
@@ -21,7 +21,7 @@ pub struct State {
|
||||
|
||||
// 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<String, DecryptedAccount>,
|
||||
all_accounts: HashMap<String, WalletAccount>,
|
||||
|
||||
/// Validators that have been fetched dynamically, probably during startup.
|
||||
fetched_validators: OptionalValidators,
|
||||
@@ -68,12 +68,12 @@ impl State {
|
||||
self.current_network
|
||||
}
|
||||
|
||||
pub(crate) fn set_all_accounts(&mut self, all_accounts: HashMap<String, DecryptedAccount>) {
|
||||
pub(crate) fn set_all_accounts(&mut self, all_accounts: HashMap<String, WalletAccount>) {
|
||||
self.all_accounts.clear();
|
||||
self.all_accounts.extend(all_accounts)
|
||||
}
|
||||
|
||||
pub(crate) fn get_all_accounts(&self) -> &HashMap<String, DecryptedAccount> {
|
||||
pub(crate) fn get_all_accounts(&self) -> &HashMap<String, WalletAccount> {
|
||||
&self.all_accounts
|
||||
}
|
||||
|
||||
@@ -176,14 +176,6 @@ 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) => {
|
||||
|
||||
@@ -159,10 +159,17 @@ impl StoredLogin {
|
||||
StoredLogin::Multiple(accounts) => Some(accounts),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unwrap_into_multiple_accounts(self, id: AccountId) -> MultipleAccounts {
|
||||
match self {
|
||||
StoredLogin::Mnemonic(ref account) => account.clone().into_multiple(id),
|
||||
StoredLogin::Multiple(ref accounts) => accounts.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An account backed by a unique mnemonic.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct MnemonicAccount {
|
||||
mnemonic: bip39::Mnemonic,
|
||||
#[serde(with = "display_hd_path")]
|
||||
@@ -170,17 +177,11 @@ pub(crate) struct MnemonicAccount {
|
||||
}
|
||||
|
||||
impl MnemonicAccount {
|
||||
pub(crate) fn generate_new(&self) -> MnemonicAccount {
|
||||
MnemonicAccount {
|
||||
mnemonic: bip39::Mnemonic::generate(self.mnemonic().word_count()).unwrap(),
|
||||
hd_path: self.hd_path().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mnemonic(&self) -> &bip39::Mnemonic {
|
||||
&self.mnemonic
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn hd_path(&self) -> &DerivationPath {
|
||||
&self.hd_path
|
||||
}
|
||||
@@ -215,7 +216,7 @@ impl Drop for MnemonicAccount {
|
||||
}
|
||||
|
||||
/// Multiple stored accounts, each entry having an id and a data field.
|
||||
#[derive(Serialize, Deserialize, Debug, Zeroize, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, PartialEq, Eq)]
|
||||
pub(crate) struct MultipleAccounts {
|
||||
accounts: Vec<WalletAccount>,
|
||||
}
|
||||
@@ -235,6 +236,10 @@ impl MultipleAccounts {
|
||||
self.accounts.iter().find(|account| &account.id == id)
|
||||
}
|
||||
|
||||
pub(crate) fn into_accounts(self) -> impl Iterator<Item = WalletAccount> {
|
||||
self.accounts.into_iter()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.accounts.len()
|
||||
@@ -274,7 +279,7 @@ impl From<Vec<WalletAccount>> for MultipleAccounts {
|
||||
}
|
||||
|
||||
/// An entry in the list of stored accounts
|
||||
#[derive(Serialize, Deserialize, Debug, Zeroize, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, PartialEq, Eq)]
|
||||
pub(crate) struct WalletAccount {
|
||||
pub id: AccountId,
|
||||
pub account: AccountData,
|
||||
@@ -293,7 +298,7 @@ impl WalletAccount {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Zeroize, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, PartialEq, Eq)]
|
||||
#[serde(untagged)]
|
||||
#[zeroize(drop)]
|
||||
pub(crate) enum AccountData {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user