diff --git a/ant-bootstrap/src/initial_peers.rs b/ant-bootstrap/src/initial_peers.rs index 1a5b33ffe1..00241bb7af 100644 --- a/ant-bootstrap/src/initial_peers.rs +++ b/ant-bootstrap/src/initial_peers.rs @@ -53,7 +53,7 @@ pub struct PeersArgs { /// a bootstrap cache JSON file. #[clap(long, conflicts_with = "first", value_delimiter = ',')] pub network_contacts_url: Vec, - /// Set to indicate this is a local network. You could also set the `local` feature flag to set this to true. + /// Set to indicate this is a local network. /// /// This would use mDNS for peer discovery. #[clap(long, conflicts_with = "network_contacts_url", default_value = "false")] diff --git a/ant-cli/src/access/keys.rs b/ant-cli/src/access/keys.rs index cfaa5284b7..9bb3ba2ad5 100644 --- a/ant-cli/src/access/keys.rs +++ b/ant-cli/src/access/keys.rs @@ -9,7 +9,7 @@ use crate::wallet::load_wallet_private_key; use autonomi::client::registers::RegisterSecretKey; use autonomi::client::vault::VaultSecretKey; -use autonomi::{get_evm_network_from_env, Wallet}; +use autonomi::{Network, Wallet}; use color_eyre::eyre::{eyre, Context, Result}; use color_eyre::Section; use std::env; @@ -22,11 +22,10 @@ const REGISTER_SIGNING_KEY_ENV: &str = "REGISTER_SIGNING_KEY"; const REGISTER_SIGNING_KEY_FILE: &str = "register_signing_key"; /// EVM wallet -pub fn load_evm_wallet_from_env() -> Result { +pub fn load_evm_wallet_from_env(evm_network: &Network) -> Result { let secret_key = get_secret_key_from_env().wrap_err("The secret key is required to perform this action")?; - let network = get_evm_network_from_env()?; - let wallet = Wallet::new_from_private_key(network, &secret_key) + let wallet = Wallet::new_from_private_key(evm_network.clone(), &secret_key) .wrap_err("Failed to load EVM wallet from key")?; Ok(wallet) } diff --git a/ant-cli/src/commands/file.rs b/ant-cli/src/commands/file.rs index 5f9c966c8e..23ba6c7afe 100644 --- a/ant-cli/src/commands/file.rs +++ b/ant-cli/src/commands/file.rs @@ -32,8 +32,8 @@ pub async fn cost(file: &str, peers: NetworkPeers) -> Result<()> { } pub async fn upload(file: &str, public: bool, peers: NetworkPeers) -> Result<()> { - let wallet = load_wallet()?; let mut client = crate::actions::connect_to_network(peers).await?; + let wallet = load_wallet(&client.evm_network)?; let event_receiver = client.enable_client_events(); let (upload_summary_thread, upload_completed_tx) = collect_upload_summary(event_receiver); diff --git a/ant-cli/src/commands/register.rs b/ant-cli/src/commands/register.rs index 9e84d607b4..9b95fb7670 100644 --- a/ant-cli/src/commands/register.rs +++ b/ant-cli/src/commands/register.rs @@ -54,10 +54,10 @@ pub async fn cost(name: &str, peers: NetworkPeers) -> Result<()> { } pub async fn create(name: &str, value: &str, public: bool, peers: NetworkPeers) -> Result<()> { - let wallet = load_wallet()?; let register_key = crate::keys::get_register_signing_key() .wrap_err("The register key is required to perform this action")?; let mut client = crate::actions::connect_to_network(peers).await?; + let wallet = load_wallet(&client.evm_network)?; let event_receiver = client.enable_client_events(); let (upload_summary_thread, upload_completed_tx) = collect_upload_summary(event_receiver); diff --git a/ant-cli/src/commands/vault.rs b/ant-cli/src/commands/vault.rs index b1ad37257b..2c8ac619ba 100644 --- a/ant-cli/src/commands/vault.rs +++ b/ant-cli/src/commands/vault.rs @@ -29,7 +29,7 @@ pub async fn cost(peers: NetworkPeers) -> Result<()> { pub async fn create(peers: NetworkPeers) -> Result<()> { let client = crate::actions::connect_to_network(peers).await?; - let wallet = load_wallet()?; + let wallet = load_wallet(&client.evm_network)?; let vault_sk = crate::keys::get_vault_secret_key()?; println!("Retrieving local user data..."); @@ -58,7 +58,7 @@ pub async fn create(peers: NetworkPeers) -> Result<()> { pub async fn sync(force: bool, peers: NetworkPeers) -> Result<()> { let client = crate::actions::connect_to_network(peers).await?; let vault_sk = crate::keys::get_vault_secret_key()?; - let wallet = load_wallet()?; + let wallet = load_wallet(&client.evm_network)?; println!("Fetching vault from network..."); let net_user_data = client diff --git a/ant-cli/src/commands/wallet.rs b/ant-cli/src/commands/wallet.rs index b1a2caf70b..5f123dcb68 100644 --- a/ant-cli/src/commands/wallet.rs +++ b/ant-cli/src/commands/wallet.rs @@ -6,10 +6,10 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. -use crate::wallet::fs::{select_wallet, select_wallet_private_key, store_private_key}; +use crate::wallet::fs::{select_wallet_private_key, store_private_key}; use crate::wallet::input::request_password; use crate::wallet::DUMMY_NETWORK; -use autonomi::Wallet; +use autonomi::{get_evm_network_from_env, Wallet}; use color_eyre::eyre::eyre; use color_eyre::Result; use prettytable::{Cell, Row, Table}; @@ -81,7 +81,8 @@ pub fn export() -> Result<()> { } pub async fn balance() -> Result<()> { - let wallet = select_wallet()?; + let network = get_evm_network_from_env().unwrap_or_default(); + let wallet = crate::wallet::load_wallet(&network)?; let token_balance = wallet.balance_of_tokens().await?; let gas_balance = wallet.balance_of_gas_tokens().await?; diff --git a/ant-cli/src/wallet/encryption.rs b/ant-cli/src/wallet/encryption.rs index 88f53afa15..1ea081e088 100644 --- a/ant-cli/src/wallet/encryption.rs +++ b/ant-cli/src/wallet/encryption.rs @@ -6,7 +6,8 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. -use crate::wallet::error::Error; +use color_eyre::eyre::eyre; +use color_eyre::Result; use rand::Rng; use ring::aead::{BoundKey, Nonce, NonceSequence}; use ring::error::Unspecified; @@ -28,7 +29,7 @@ impl NonceSequence for NonceSeq { } } -pub fn encrypt_private_key(private_key: &str, password: &str) -> Result { +pub fn encrypt_private_key(private_key: &str, password: &str) -> Result { // Generate a random salt // Salt is used to ensure unique derived keys even for identical passwords let mut salt = [0u8; SALT_LENGTH]; @@ -55,7 +56,7 @@ pub fn encrypt_private_key(private_key: &str, password: &str) -> Result Result Result Result { +pub fn decrypt_private_key(encrypted_data: &str, password: &str) -> Result { let encrypted_data = hex::decode(encrypted_data) - .map_err(|_| Error::FailedToDecryptKey(String::from("Encrypted data is invalid")))?; + .map_err(|_| eyre!("Failed to decrypt key: Encrypted data is invalid"))?; let salt: [u8; SALT_LENGTH] = encrypted_data[..SALT_LENGTH] .try_into() - .map_err(|_| Error::FailedToDecryptKey(String::from("Could not find salt")))?; + .map_err(|_| eyre!("Failed to decrypt key: Could not find salt"))?; let nonce: [u8; NONCE_LENGTH] = encrypted_data[SALT_LENGTH..SALT_LENGTH + NONCE_LENGTH] .try_into() - .map_err(|_| Error::FailedToDecryptKey(String::from("Could not find nonce")))?; + .map_err(|_| eyre!("Failed to decrypt key: Could not find nonce"))?; let encrypted_private_key = &encrypted_data[SALT_LENGTH + NONCE_LENGTH..]; @@ -106,7 +107,7 @@ pub fn decrypt_private_key(encrypted_data: &str, password: &str) -> Result Result = OnceLock::new(); /// Creates the wallets folder if it is missing and returns the folder path. -pub(crate) fn get_client_wallet_dir_path() -> Result { - let mut home_dirs = dirs_next::data_dir().ok_or(Error::WalletsFolderNotFound)?; - home_dirs.push("autonomi"); - home_dirs.push("client"); +pub(crate) fn get_client_wallet_dir_path() -> Result { + let mut home_dirs = crate::access::data_dir::get_client_data_dir_path() + .wrap_err("Failed to get wallet directory")?; home_dirs.push("wallets"); - std::fs::create_dir_all(home_dirs.as_path()).map_err(|_| Error::FailedToCreateWalletsFolder)?; + std::fs::create_dir_all(home_dirs.as_path()) + .wrap_err("Failed to create wallets folder, make sure you have the correct permissions")?; Ok(home_dirs) } @@ -41,9 +41,9 @@ pub(crate) fn get_client_wallet_dir_path() -> Result { pub(crate) fn store_private_key( private_key: &str, encryption_password: Option, -) -> Result { +) -> Result { let wallet = Wallet::new_from_private_key(DUMMY_NETWORK, private_key) - .map_err(|_| Error::InvalidPrivateKey)?; + .map_err(|_| eyre!("Private key is invalid"))?; // Wallet address let wallet_address = wallet.address().to_string(); @@ -56,15 +56,13 @@ pub(crate) fn store_private_key( let file_name = format!("{wallet_address}{ENCRYPTED_PRIVATE_KEY_EXT}"); let file_path = wallets_folder.join(file_name); - std::fs::write(file_path.clone(), encrypted_key) - .map_err(|err| Error::FailedToStorePrivateKey(err.to_string()))?; + std::fs::write(file_path.clone(), encrypted_key).wrap_err("Failed to store private key")?; Ok(file_path.into_os_string()) } else { let file_path = wallets_folder.join(wallet_address); - std::fs::write(file_path.clone(), private_key) - .map_err(|err| Error::FailedToStorePrivateKey(err.to_string()))?; + std::fs::write(file_path.clone(), private_key).wrap_err("Failed to store private key")?; Ok(file_path.into_os_string()) } @@ -73,7 +71,7 @@ pub(crate) fn store_private_key( /// Loads the private key (hex-encoded) from disk. /// /// If the private key file is encrypted, the function will prompt for the decryption password in the CLI. -pub(crate) fn load_private_key(wallet_address: &str) -> Result { +pub(crate) fn load_private_key(wallet_address: &str) -> Result { let wallets_folder = get_client_wallet_dir_path()?; let mut file_name = wallet_address.to_string(); @@ -93,46 +91,42 @@ pub(crate) fn load_private_key(wallet_address: &str) -> Result { let file_path = wallets_folder.join(file_name); - let mut file = std::fs::File::open(&file_path).map_err(|_| Error::PrivateKeyFileNotFound)?; + let mut file = + std::fs::File::open(&file_path).map_err(|e| eyre!("Private key file not found: {e}"))?; let mut buffer = String::new(); file.read_to_string(&mut buffer) - .map_err(|_| Error::InvalidPrivateKeyFile)?; + .map_err(|_| eyre!("Invalid private key file"))?; // If the file is encrypted, prompt for the password and decrypt the key. if is_encrypted { let password = get_password_input("Enter password to decrypt wallet:"); decrypt_private_key(&buffer, &password) + .map_err(|e| eyre!("Failed to decrypt private key: {e}")) } else { Ok(buffer) } } -pub(crate) fn load_wallet_from_address(wallet_address: &str) -> Result { - let network = get_evm_network_from_env().expect("Could not load EVM network from environment"); +pub(crate) fn load_wallet_from_address(wallet_address: &str, network: &Network) -> Result { let private_key = load_private_key(wallet_address)?; - let wallet = - Wallet::new_from_private_key(network, &private_key).expect("Could not initialize wallet"); + let wallet = Wallet::new_from_private_key(network.clone(), &private_key) + .map_err(|e| eyre!("Could not initialize wallet: {e}"))?; Ok(wallet) } -pub(crate) fn select_wallet() -> Result { - // try if there is a wallet set in the ENV first - if let Ok(env_wallet) = load_evm_wallet_from_env() { - return Ok(env_wallet); - } - - let wallet_address = select_wallet_address()?; - load_wallet_from_address(&wallet_address) +pub(crate) fn select_wallet_from_disk(network: &Network) -> Result { + let wallet_address = select_local_wallet_address()?; + load_wallet_from_address(&wallet_address, network) } -pub(crate) fn select_wallet_private_key() -> Result { - let wallet_address = select_wallet_address()?; +pub(crate) fn select_wallet_private_key() -> Result { + let wallet_address = select_local_wallet_address()?; load_private_key(&wallet_address) } -pub(crate) fn select_wallet_address() -> Result { +pub(crate) fn select_local_wallet_address() -> Result { // Try if a wallet address was already selected this session if let Some(wallet_address) = SELECTED_WALLET_ADDRESS.get() { return Ok(wallet_address.clone()); @@ -142,7 +136,7 @@ pub(crate) fn select_wallet_address() -> Result { let wallet_files = get_wallet_files(&wallets_folder)?; let wallet_address = match wallet_files.len() { - 0 => Err(Error::NoWalletsFound), + 0 => bail!("No local wallets found."), 1 => Ok(filter_wallet_file_extension(&wallet_files[0])), _ => get_wallet_selection(wallet_files), }?; @@ -152,15 +146,15 @@ pub(crate) fn select_wallet_address() -> Result { .to_string()) } -fn get_wallet_selection(wallet_files: Vec) -> Result { +fn get_wallet_selection(wallet_files: Vec) -> Result { list_wallets(&wallet_files); let selected_index = get_wallet_selection_input("Select by index:") .parse::() - .map_err(|_| Error::InvalidSelection)?; + .map_err(|_| eyre!("Invalid wallet selection input"))?; if selected_index < 1 || selected_index > wallet_files.len() { - return Err(Error::InvalidSelection); + bail!("Invalid wallet selection input"); } Ok(filter_wallet_file_extension( @@ -192,9 +186,9 @@ fn list_wallets(wallet_files: &[String]) { table.printstd(); } -fn get_wallet_files(wallets_folder: &PathBuf) -> Result, Error> { +fn get_wallet_files(wallets_folder: &PathBuf) -> Result> { let wallet_files = std::fs::read_dir(wallets_folder) - .map_err(|_| Error::WalletsFolderNotFound)? + .map_err(|e| eyre!("Failed to read wallets folder: {e}"))? .filter_map(Result::ok) .filter_map(|dir_entry| dir_entry.file_name().into_string().ok()) .filter(|file_name| { diff --git a/ant-cli/src/wallet/mod.rs b/ant-cli/src/wallet/mod.rs index ae95594a1b..b24ecf9d97 100644 --- a/ant-cli/src/wallet/mod.rs +++ b/ant-cli/src/wallet/mod.rs @@ -7,24 +7,23 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::keys::{get_secret_key_from_env, load_evm_wallet_from_env}; -use crate::wallet::fs::{select_wallet, select_wallet_private_key}; +use crate::wallet::fs::{select_wallet_from_disk, select_wallet_private_key}; use autonomi::{Network, Wallet}; pub(crate) mod encryption; -pub(crate) mod error; pub(crate) mod fs; pub(crate) mod input; pub const DUMMY_NETWORK: Network = Network::ArbitrumSepolia; /// Load wallet from ENV or disk -pub(crate) fn load_wallet() -> color_eyre::Result { +pub(crate) fn load_wallet(evm_network: &Network) -> color_eyre::Result { // First try wallet from ENV - if let Ok(wallet) = load_evm_wallet_from_env() { + if let Ok(wallet) = load_evm_wallet_from_env(evm_network) { return Ok(wallet); } - let wallet = select_wallet()?; + let wallet = select_wallet_from_disk(evm_network)?; Ok(wallet) } diff --git a/autonomi/src/client/mod.rs b/autonomi/src/client/mod.rs index 697e405bbb..45f16a3f47 100644 --- a/autonomi/src/client/mod.rs +++ b/autonomi/src/client/mod.rs @@ -63,7 +63,8 @@ pub use ant_protocol::CLOSE_GROUP_SIZE; pub struct Client { pub(crate) network: Network, pub(crate) client_event_sender: Arc>>, - pub(crate) evm_network: EvmNetwork, + /// The EVM network to use for the client. + pub evm_network: EvmNetwork, } /// Configuration for [`Client::init_with_config`]. @@ -92,7 +93,7 @@ pub enum ConnectError { TimedOutWithIncompatibleProtocol(HashSet, String), /// An error occurred while bootstrapping the client. - #[error("Failed to bootstrap the client")] + #[error("Failed to bootstrap the client: {0}")] Bootstrap(#[from] ant_bootstrap::Error), } @@ -254,10 +255,6 @@ impl Client { client_event_receiver } - - pub fn set_evm_network(&mut self, evm_network: EvmNetwork) { - self.evm_network = evm_network; - } } fn build_client_and_run_swarm(local: bool) -> (Network, mpsc::Receiver) { diff --git a/test-utils/src/evm.rs b/test-utils/src/evm.rs index 05eb710bde..989da8b1a4 100644 --- a/test-utils/src/evm.rs +++ b/test-utils/src/evm.rs @@ -10,12 +10,11 @@ use color_eyre::{ eyre::{bail, Context}, Result, }; -use evmlib::{utils::get_evm_network_from_env, wallet::Wallet, Network}; +use evmlib::{utils::local_evm_network_from_csv, wallet::Wallet, Network}; use std::env; pub fn get_funded_wallet() -> evmlib::wallet::Wallet { - let network = - get_evm_network_from_env().expect("Failed to get EVM network from environment variables"); + let network = local_evm_network_from_csv().expect("Failed to get local EVM network from CSV"); if matches!(network, Network::ArbitrumOne) { panic!("You're trying to use ArbitrumOne network. Use a custom network for testing."); } @@ -29,8 +28,8 @@ pub fn get_funded_wallet() -> evmlib::wallet::Wallet { } pub fn get_new_wallet() -> Result { - let network = get_evm_network_from_env() - .wrap_err("Failed to get EVM network from environment variables")?; + let network = + local_evm_network_from_csv().wrap_err("Failed to get local EVM network from CSV")?; if matches!(network, Network::ArbitrumOne) { bail!("You're trying to use ArbitrumOne network. Use a custom network for testing."); }