diff --git a/README.md b/README.md index e35eacb..3416efa 100644 --- a/README.md +++ b/README.md @@ -138,16 +138,14 @@ If everything went well you should see an output similar to this: # Try the Wallet CLI ## Install + This repository includes a CLI for interacting with the Nescience sequencer. To install it, run the following command from the root of the repository: ```bash cargo install --path wallet --force ``` -Before using the CLI, set the environment variable `NSSA_WALLET_HOME_DIR` to the directory containing the wallet configuration file. A sample configuration is available at `integration_tests/configs/debug/wallet/`. To use it, run: -```bash -export NSSA_WALLET_HOME_DIR=$(pwd)/integration_tests/configs/debug/wallet/ -``` +Run `wallet help` to check everything went well. ## Tutorial @@ -519,7 +517,6 @@ wallet token new \ After it succeeds, we can check their values - ```bash wallet account get --addr Public/GQ3C8rbprTtQUCvkuVBRu3v9wvUvjafCMFqoSPvTEVii diff --git a/integration_tests/configs/debug/wallet/wallet_config.json b/integration_tests/configs/debug/wallet/wallet_config.json index 95c95e9..8b0b303 100644 --- a/integration_tests/configs/debug/wallet/wallet_config.json +++ b/integration_tests/configs/debug/wallet/wallet_config.json @@ -1,547 +1,546 @@ { - "home": "./node", - "override_rust_log": null, - "sequencer_addr": "http://127.0.0.1:3040", - "seq_poll_timeout_millis": 12000, - "seq_poll_max_blocks": 5, - "seq_poll_max_retries": 5, - "seq_poll_retry_delay_millis": 500, - "initial_accounts": [ - { - "Public": { - "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", - "pub_sign_key": [ - 16, - 162, - 106, - 154, - 236, - 125, - 52, - 184, - 35, - 100, - 238, - 174, - 69, - 197, - 41, - 77, - 187, - 10, - 118, - 75, - 0, - 11, - 148, - 238, - 185, - 181, - 133, - 17, - 220, - 72, - 124, - 77 - ] - } + "override_rust_log": null, + "sequencer_addr": "http://127.0.0.1:3040", + "seq_poll_timeout_millis": 12000, + "seq_poll_max_blocks": 5, + "seq_poll_max_retries": 5, + "seq_poll_retry_delay_millis": 500, + "initial_accounts": [ + { + "Public": { + "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "pub_sign_key": [ + 16, + 162, + 106, + 154, + 236, + 125, + 52, + 184, + 35, + 100, + 238, + 174, + 69, + 197, + 41, + 77, + 187, + 10, + 118, + 75, + 0, + 11, + 148, + 238, + 185, + 181, + 133, + 17, + 220, + 72, + 124, + 77 + ] + } + }, + { + "Public": { + "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "pub_sign_key": [ + 113, + 121, + 64, + 177, + 204, + 85, + 229, + 214, + 178, + 6, + 109, + 191, + 29, + 154, + 63, + 38, + 242, + 18, + 244, + 219, + 8, + 208, + 35, + 136, + 23, + 127, + 207, + 237, + 216, + 169, + 190, + 27 + ] + } + }, + { + "Private": { + "address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 10000, + "data": [], + "nonce": 0 }, - { - "Public": { - "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", - "pub_sign_key": [ - 113, - 121, - 64, - 177, - 204, - 85, - 229, - 214, - 178, - 6, - 109, - 191, - 29, - 154, - 63, - 38, - 242, - 18, - 244, - 219, - 8, - 208, - 35, - 136, - 23, - 127, - 207, - 237, - 216, - 169, - 190, - 27 - ] - } - }, - { - "Private": { - "address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 10000, - "data": [], - "nonce": 0 - }, - "key_chain": { - "secret_spending_key": [ - 251, - 82, - 235, - 1, - 146, - 96, - 30, - 81, - 162, - 234, - 33, - 15, - 123, - 129, - 116, - 0, - 84, - 136, - 176, - 70, - 190, - 224, - 161, - 54, - 134, - 142, - 154, - 1, - 18, - 251, - 242, - 189 - ], - "private_key_holder": { - "nullifier_secret_key": [ - 29, - 250, - 10, - 187, - 35, - 123, - 180, - 250, - 246, - 97, - 216, - 153, - 44, - 156, - 16, - 93, - 241, - 26, - 174, - 219, - 72, - 84, - 34, - 247, - 112, - 101, - 217, - 243, - 189, - 173, - 75, - 20 - ], - "incoming_viewing_secret_key": [ - 251, - 201, - 22, - 154, - 100, - 165, - 218, - 108, - 163, - 190, - 135, - 91, - 145, - 84, - 69, - 241, - 46, - 117, - 217, - 110, - 197, - 248, - 91, - 193, - 14, - 104, - 88, - 103, - 67, - 153, - 182, - 158 - ], - "outgoing_viewing_secret_key": [ - 25, - 67, - 121, - 76, - 175, - 100, - 30, - 198, - 105, - 123, - 49, - 169, - 75, - 178, - 75, - 210, - 100, - 143, - 210, - 243, - 228, - 243, - 21, - 18, - 36, - 84, - 164, - 186, - 139, - 113, - 214, - 12 - ] - }, - "nullifer_public_key": [ - 63, - 202, - 178, - 231, - 183, - 82, - 237, - 212, - 216, - 221, - 215, - 255, - 153, - 101, - 177, - 161, - 254, - 210, - 128, - 122, - 54, - 190, - 230, - 151, - 183, - 64, - 225, - 229, - 113, - 1, - 228, - 97 - ], - "incoming_viewing_public_key": [ - 3, - 235, - 139, - 131, - 237, - 177, - 122, - 189, - 6, - 177, - 167, - 178, - 202, - 117, - 246, - 58, - 28, - 65, - 132, - 79, - 220, - 139, - 119, - 243, - 187, - 160, - 212, - 121, - 61, - 247, - 116, - 72, - 205 - ] - } - } - }, - { - "Private": { - "address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 20000, - "data": [], - "nonce": 0 - }, - "key_chain": { - "secret_spending_key": [ - 238, - 171, - 241, - 69, - 111, - 217, - 85, - 64, - 19, - 82, - 18, - 189, - 32, - 91, - 78, - 175, - 107, - 7, - 109, - 60, - 52, - 44, - 243, - 230, - 72, - 244, - 192, - 92, - 137, - 33, - 118, - 254 - ], - "private_key_holder": { - "nullifier_secret_key": [ - 25, - 211, - 215, - 119, - 57, - 223, - 247, - 37, - 245, - 144, - 122, - 29, - 118, - 245, - 83, - 228, - 23, - 9, - 101, - 120, - 88, - 33, - 238, - 207, - 128, - 61, - 110, - 2, - 89, - 62, - 164, - 13 - ], - "incoming_viewing_secret_key": [ - 193, - 181, - 14, - 196, - 142, - 84, - 15, - 65, - 128, - 101, - 70, - 196, - 241, - 47, - 130, - 221, - 23, - 146, - 161, - 237, - 221, - 40, - 19, - 126, - 59, - 15, - 169, - 236, - 25, - 105, - 104, - 231 - ], - "outgoing_viewing_secret_key": [ - 20, - 170, - 220, - 108, - 41, - 23, - 155, - 217, - 247, - 190, - 175, - 168, - 247, - 34, - 105, - 134, - 114, - 74, - 104, - 91, - 211, - 62, - 126, - 13, - 130, - 100, - 241, - 214, - 250, - 236, - 38, - 150 - ] - }, - "nullifer_public_key": [ - 192, - 251, - 166, - 243, - 167, - 236, - 84, - 249, - 35, - 136, - 130, - 172, - 219, - 225, - 161, - 139, - 229, - 89, - 243, - 125, - 194, - 213, - 209, - 30, - 23, - 174, - 100, - 244, - 124, - 74, - 140, - 47 - ], - "incoming_viewing_public_key": [ - 2, - 181, - 98, - 93, - 216, - 241, - 241, - 110, - 58, - 198, - 119, - 174, - 250, - 184, - 1, - 204, - 200, - 173, - 44, - 238, - 37, - 247, - 170, - 156, - 100, - 254, - 116, - 242, - 28, - 183, - 187, - 77, - 255 - ] - } - } + "key_chain": { + "secret_spending_key": [ + 251, + 82, + 235, + 1, + 146, + 96, + 30, + 81, + 162, + 234, + 33, + 15, + 123, + 129, + 116, + 0, + 84, + 136, + 176, + 70, + 190, + 224, + 161, + 54, + 134, + 142, + 154, + 1, + 18, + 251, + 242, + 189 + ], + "private_key_holder": { + "nullifier_secret_key": [ + 29, + 250, + 10, + 187, + 35, + 123, + 180, + 250, + 246, + 97, + 216, + 153, + 44, + 156, + 16, + 93, + 241, + 26, + 174, + 219, + 72, + 84, + 34, + 247, + 112, + 101, + 217, + 243, + 189, + 173, + 75, + 20 + ], + "incoming_viewing_secret_key": [ + 251, + 201, + 22, + 154, + 100, + 165, + 218, + 108, + 163, + 190, + 135, + 91, + 145, + 84, + 69, + 241, + 46, + 117, + 217, + 110, + 197, + 248, + 91, + 193, + 14, + 104, + 88, + 103, + 67, + 153, + 182, + 158 + ], + "outgoing_viewing_secret_key": [ + 25, + 67, + 121, + 76, + 175, + 100, + 30, + 198, + 105, + 123, + 49, + 169, + 75, + 178, + 75, + 210, + 100, + 143, + 210, + 243, + 228, + 243, + 21, + 18, + 36, + 84, + 164, + 186, + 139, + 113, + 214, + 12 + ] + }, + "nullifer_public_key": [ + 63, + 202, + 178, + 231, + 183, + 82, + 237, + 212, + 216, + 221, + 215, + 255, + 153, + 101, + 177, + 161, + 254, + 210, + 128, + 122, + 54, + 190, + 230, + 151, + 183, + 64, + 225, + 229, + 113, + 1, + 228, + 97 + ], + "incoming_viewing_public_key": [ + 3, + 235, + 139, + 131, + 237, + 177, + 122, + 189, + 6, + 177, + 167, + 178, + 202, + 117, + 246, + 58, + 28, + 65, + 132, + 79, + 220, + 139, + 119, + 243, + 187, + 160, + 212, + 121, + 61, + 247, + 116, + 72, + 205 + ] } - ] + } + }, + { + "Private": { + "address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 20000, + "data": [], + "nonce": 0 + }, + "key_chain": { + "secret_spending_key": [ + 238, + 171, + 241, + 69, + 111, + 217, + 85, + 64, + 19, + 82, + 18, + 189, + 32, + 91, + 78, + 175, + 107, + 7, + 109, + 60, + 52, + 44, + 243, + 230, + 72, + 244, + 192, + 92, + 137, + 33, + 118, + 254 + ], + "private_key_holder": { + "nullifier_secret_key": [ + 25, + 211, + 215, + 119, + 57, + 223, + 247, + 37, + 245, + 144, + 122, + 29, + 118, + 245, + 83, + 228, + 23, + 9, + 101, + 120, + 88, + 33, + 238, + 207, + 128, + 61, + 110, + 2, + 89, + 62, + 164, + 13 + ], + "incoming_viewing_secret_key": [ + 193, + 181, + 14, + 196, + 142, + 84, + 15, + 65, + 128, + 101, + 70, + 196, + 241, + 47, + 130, + 221, + 23, + 146, + 161, + 237, + 221, + 40, + 19, + 126, + 59, + 15, + 169, + 236, + 25, + 105, + 104, + 231 + ], + "outgoing_viewing_secret_key": [ + 20, + 170, + 220, + 108, + 41, + 23, + 155, + 217, + 247, + 190, + 175, + 168, + 247, + 34, + 105, + 134, + 114, + 74, + 104, + 91, + 211, + 62, + 126, + 13, + 130, + 100, + 241, + 214, + 250, + 236, + 38, + 150 + ] + }, + "nullifer_public_key": [ + 192, + 251, + 166, + 243, + 167, + 236, + 84, + 249, + 35, + 136, + 130, + 172, + 219, + 225, + 161, + 139, + 229, + 89, + 243, + 125, + 194, + 213, + 209, + 30, + 23, + 174, + 100, + 244, + 124, + 74, + 140, + 47 + ], + "incoming_viewing_public_key": [ + 2, + 181, + 98, + 93, + 216, + 241, + 241, + 110, + 58, + 198, + 119, + 174, + 250, + 184, + 1, + 204, + 200, + 173, + 44, + 238, + 37, + 247, + 170, + 156, + 100, + 254, + 116, + 242, + 28, + 183, + 187, + 77, + 255 + ] + } + } + } + ] } \ No newline at end of file diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 0bbc8b0..affefc1 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -18,6 +18,7 @@ use wallet::{ Command, SubcommandReturnValue, WalletCore, cli::{ account::{AccountSubcommand, NewSubcommand}, + config::ConfigSubcommand, native_token_transfer_program::AuthTransferSubcommand, pinata_program::PinataProgramAgnosticSubcommand, token_program::TokenProgramAgnosticSubcommand, @@ -1188,11 +1189,6 @@ pub fn prepare_function_map() -> HashMap { .await .unwrap(); - let new_commitment1 = wallet_storage - .get_private_account_commitment(&from) - .unwrap(); - assert_eq!(tx.message.new_commitments[0], new_commitment1); - assert_eq!(tx.message.new_commitments.len(), 2); for commitment in tx.message.new_commitments.into_iter() { assert!(verify_commitment_is_in_state(commitment, &seq_client).await); @@ -1589,6 +1585,34 @@ pub fn prepare_function_map() -> HashMap { info!("Success!"); } + #[nssa_integration_test] + pub async fn test_modify_config_fields() { + info!("########## test_modify_config_fields ##########"); + + let wallet_config = fetch_config().await.unwrap(); + let old_seq_poll_retry_delay_millis = wallet_config.seq_poll_retry_delay_millis; + + //Change config field + let command = Command::Config(ConfigSubcommand::Set { + key: "seq_poll_retry_delay_millis".to_string(), + value: "1000".to_string(), + }); + wallet::execute_subcommand(command).await.unwrap(); + + let wallet_config = fetch_config().await.unwrap(); + + assert_eq!(wallet_config.seq_poll_retry_delay_millis, 1000); + + //Return how it was at the beginning + let command = Command::Config(ConfigSubcommand::Set { + key: "seq_poll_retry_delay_millis".to_string(), + value: old_seq_poll_retry_delay_millis.to_string(), + }); + wallet::execute_subcommand(command).await.unwrap(); + + info!("Success!"); + } + println!("{function_map:#?}"); function_map diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index 8fc8805..4a845af 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -71,8 +71,6 @@ mod tests { use crate::config::InitialAccountData; use super::*; - use std::path::PathBuf; - use tempfile::tempdir; fn create_initial_accounts() -> Vec { let initial_acc1 = serde_json::from_str( @@ -166,9 +164,8 @@ mod tests { initial_accounts } - fn create_sample_wallet_config(home: PathBuf) -> WalletConfig { + fn create_sample_wallet_config() -> WalletConfig { WalletConfig { - home, override_rust_log: None, sequencer_addr: "http://127.0.0.1".to_string(), seq_poll_timeout_millis: 12000, @@ -181,10 +178,7 @@ mod tests { #[test] fn test_new_initializes_correctly() { - let temp_dir = tempdir().unwrap(); - let path = temp_dir.path(); - - let config = create_sample_wallet_config(path.to_path_buf()); + let config = create_sample_wallet_config(); let _ = WalletChainStore::new(config.clone()).unwrap(); } diff --git a/wallet/src/cli/config.rs b/wallet/src/cli/config.rs new file mode 100644 index 0000000..47d7ef1 --- /dev/null +++ b/wallet/src/cli/config.rs @@ -0,0 +1,151 @@ +use anyhow::Result; +use clap::Subcommand; + +use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; + +///Represents generic config CLI subcommand +#[derive(Subcommand, Debug, Clone)] +pub enum ConfigSubcommand { + /// Command to explicitly setup config and storage + /// + /// Does nothing in case if both already present + Setup {}, + /// Getter of config fields + Get { key: String }, + /// Setter of config fields + Set { key: String, value: String }, + /// Prints description of corresponding field + Description { key: String }, +} + +impl WalletSubcommand for ConfigSubcommand { + async fn handle_subcommand( + self, + wallet_core: &mut WalletCore, + ) -> Result { + match self { + ConfigSubcommand::Setup {} => { + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent accounts at {path:#?}"); + } + ConfigSubcommand::Get { key } => match key.as_str() { + "all" => { + let config_str = + serde_json::to_string_pretty(&wallet_core.storage.wallet_config)?; + + println!("{config_str}"); + } + "override_rust_log" => { + if let Some(value) = &wallet_core.storage.wallet_config.override_rust_log { + println!("{value}"); + } else { + println!("Not set"); + } + } + "sequencer_addr" => { + println!("{}", wallet_core.storage.wallet_config.sequencer_addr); + } + "seq_poll_timeout_millis" => { + println!( + "{}", + wallet_core.storage.wallet_config.seq_poll_timeout_millis + ); + } + "seq_poll_max_blocks" => { + println!("{}", wallet_core.storage.wallet_config.seq_poll_max_blocks); + } + "seq_poll_max_retries" => { + println!("{}", wallet_core.storage.wallet_config.seq_poll_max_retries); + } + "seq_poll_retry_delay_millis" => { + println!( + "{}", + wallet_core + .storage + .wallet_config + .seq_poll_retry_delay_millis + ); + } + "initial_accounts" => { + println!("{:#?}", wallet_core.storage.wallet_config.initial_accounts); + } + _ => { + println!("Unknown field"); + } + }, + ConfigSubcommand::Set { key, value } => { + match key.as_str() { + "override_rust_log" => { + wallet_core.storage.wallet_config.override_rust_log = Some(value); + } + "sequencer_addr" => { + wallet_core.storage.wallet_config.sequencer_addr = value; + } + "seq_poll_timeout_millis" => { + wallet_core.storage.wallet_config.seq_poll_timeout_millis = + value.parse()?; + } + "seq_poll_max_blocks" => { + wallet_core.storage.wallet_config.seq_poll_max_blocks = value.parse()?; + } + "seq_poll_max_retries" => { + wallet_core.storage.wallet_config.seq_poll_max_retries = value.parse()?; + } + "seq_poll_retry_delay_millis" => { + wallet_core + .storage + .wallet_config + .seq_poll_retry_delay_millis = value.parse()?; + } + "initial_accounts" => { + anyhow::bail!("Setting this field from wallet is not supported"); + } + _ => { + anyhow::bail!("Unknown field"); + } + } + + let path = wallet_core.store_config_changes().await?; + + println!("Stored changed config at {path:#?}"); + } + ConfigSubcommand::Description { key } => match key.as_str() { + "override_rust_log" => { + println!("Value of variable RUST_LOG to override, affects logging"); + } + "sequencer_addr" => { + println!("HTTP V4 address of sequencer"); + } + "seq_poll_timeout_millis" => { + println!( + "Sequencer client retry variable: how much time to wait between retries in milliseconds(can be zero)" + ); + } + "seq_poll_max_blocks" => { + println!( + "Sequencer client polling variable: max number of blocks to poll in parallel" + ); + } + "seq_poll_max_retries" => { + println!( + "Sequencer client retry variable: MAX number of retries before failing(can be zero)" + ); + } + "seq_poll_retry_delay_millis" => { + println!( + "Sequencer client polling variable: how much time to wait in milliseconds between polling retries(can be zero)" + ); + } + "initial_accounts" => { + println!("List of initial accounts' keys(both public and private)"); + } + _ => { + println!("Unknown field"); + } + }, + } + + Ok(SubcommandReturnValue::Empty) + } +} diff --git a/wallet/src/cli/mod.rs b/wallet/src/cli/mod.rs index 3aa1b7f..fff14cb 100644 --- a/wallet/src/cli/mod.rs +++ b/wallet/src/cli/mod.rs @@ -4,6 +4,7 @@ use crate::{SubcommandReturnValue, WalletCore}; pub mod account; pub mod chain; +pub mod config; pub mod native_token_transfer_program; pub mod pinata_program; pub mod token_program; diff --git a/wallet/src/config.rs b/wallet/src/config.rs index af1f493..bf7f5d2 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -1,6 +1,5 @@ use key_protocol::key_management::KeyChain; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InitialAccountDataPublic { @@ -114,8 +113,6 @@ pub struct GasConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WalletConfig { - ///Home dir of sequencer storage - pub home: PathBuf, ///Override rust log (env var logging level) pub override_rust_log: Option, ///Sequencer URL @@ -131,3 +128,559 @@ pub struct WalletConfig { ///Initial accounts for wallet pub initial_accounts: Vec, } + +impl Default for WalletConfig { + fn default() -> Self { + Self { + override_rust_log: None, + sequencer_addr: "http://127.0.0.1:3040".to_string(), + seq_poll_timeout_millis: 12000, + seq_poll_max_blocks: 5, + seq_poll_max_retries: 5, + seq_poll_retry_delay_millis: 500, + initial_accounts: { + let init_acc_json = r#" + [ + { + "Public": { + "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "pub_sign_key": [ + 16, + 162, + 106, + 154, + 236, + 125, + 52, + 184, + 35, + 100, + 238, + 174, + 69, + 197, + 41, + 77, + 187, + 10, + 118, + 75, + 0, + 11, + 148, + 238, + 185, + 181, + 133, + 17, + 220, + 72, + 124, + 77 + ] + } + }, + { + "Public": { + "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "pub_sign_key": [ + 113, + 121, + 64, + 177, + 204, + 85, + 229, + 214, + 178, + 6, + 109, + 191, + 29, + 154, + 63, + 38, + 242, + 18, + 244, + 219, + 8, + 208, + 35, + 136, + 23, + 127, + 207, + 237, + 216, + 169, + 190, + 27 + ] + } + }, + { + "Private": { + "address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 10000, + "data": [], + "nonce": 0 + }, + "key_chain": { + "secret_spending_key": [ + 251, + 82, + 235, + 1, + 146, + 96, + 30, + 81, + 162, + 234, + 33, + 15, + 123, + 129, + 116, + 0, + 84, + 136, + 176, + 70, + 190, + 224, + 161, + 54, + 134, + 142, + 154, + 1, + 18, + 251, + 242, + 189 + ], + "private_key_holder": { + "nullifier_secret_key": [ + 29, + 250, + 10, + 187, + 35, + 123, + 180, + 250, + 246, + 97, + 216, + 153, + 44, + 156, + 16, + 93, + 241, + 26, + 174, + 219, + 72, + 84, + 34, + 247, + 112, + 101, + 217, + 243, + 189, + 173, + 75, + 20 + ], + "incoming_viewing_secret_key": [ + 251, + 201, + 22, + 154, + 100, + 165, + 218, + 108, + 163, + 190, + 135, + 91, + 145, + 84, + 69, + 241, + 46, + 117, + 217, + 110, + 197, + 248, + 91, + 193, + 14, + 104, + 88, + 103, + 67, + 153, + 182, + 158 + ], + "outgoing_viewing_secret_key": [ + 25, + 67, + 121, + 76, + 175, + 100, + 30, + 198, + 105, + 123, + 49, + 169, + 75, + 178, + 75, + 210, + 100, + 143, + 210, + 243, + 228, + 243, + 21, + 18, + 36, + 84, + 164, + 186, + 139, + 113, + 214, + 12 + ] + }, + "nullifer_public_key": [ + 63, + 202, + 178, + 231, + 183, + 82, + 237, + 212, + 216, + 221, + 215, + 255, + 153, + 101, + 177, + 161, + 254, + 210, + 128, + 122, + 54, + 190, + 230, + 151, + 183, + 64, + 225, + 229, + 113, + 1, + 228, + 97 + ], + "incoming_viewing_public_key": [ + 3, + 235, + 139, + 131, + 237, + 177, + 122, + 189, + 6, + 177, + 167, + 178, + 202, + 117, + 246, + 58, + 28, + 65, + 132, + 79, + 220, + 139, + 119, + 243, + 187, + 160, + 212, + 121, + 61, + 247, + 116, + 72, + 205 + ] + } + } + }, + { + "Private": { + "address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 20000, + "data": [], + "nonce": 0 + }, + "key_chain": { + "secret_spending_key": [ + 238, + 171, + 241, + 69, + 111, + 217, + 85, + 64, + 19, + 82, + 18, + 189, + 32, + 91, + 78, + 175, + 107, + 7, + 109, + 60, + 52, + 44, + 243, + 230, + 72, + 244, + 192, + 92, + 137, + 33, + 118, + 254 + ], + "private_key_holder": { + "nullifier_secret_key": [ + 25, + 211, + 215, + 119, + 57, + 223, + 247, + 37, + 245, + 144, + 122, + 29, + 118, + 245, + 83, + 228, + 23, + 9, + 101, + 120, + 88, + 33, + 238, + 207, + 128, + 61, + 110, + 2, + 89, + 62, + 164, + 13 + ], + "incoming_viewing_secret_key": [ + 193, + 181, + 14, + 196, + 142, + 84, + 15, + 65, + 128, + 101, + 70, + 196, + 241, + 47, + 130, + 221, + 23, + 146, + 161, + 237, + 221, + 40, + 19, + 126, + 59, + 15, + 169, + 236, + 25, + 105, + 104, + 231 + ], + "outgoing_viewing_secret_key": [ + 20, + 170, + 220, + 108, + 41, + 23, + 155, + 217, + 247, + 190, + 175, + 168, + 247, + 34, + 105, + 134, + 114, + 74, + 104, + 91, + 211, + 62, + 126, + 13, + 130, + 100, + 241, + 214, + 250, + 236, + 38, + 150 + ] + }, + "nullifer_public_key": [ + 192, + 251, + 166, + 243, + 167, + 236, + 84, + 249, + 35, + 136, + 130, + 172, + 219, + 225, + 161, + 139, + 229, + 89, + 243, + 125, + 194, + 213, + 209, + 30, + 23, + 174, + 100, + 244, + 124, + 74, + 140, + 47 + ], + "incoming_viewing_public_key": [ + 2, + 181, + 98, + 93, + 216, + 241, + 241, + 110, + 58, + 198, + 119, + 174, + 250, + 184, + 1, + 204, + 200, + 173, + 44, + 238, + 37, + 247, + 170, + 156, + 100, + 254, + 116, + 242, + 28, + 183, + 187, + 77, + 255 + ] + } + } + } + ] + "#; + serde_json::from_str(init_acc_json).unwrap() + }, + } + } +} diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 1d35efb..f959d17 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -2,7 +2,7 @@ use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use nssa_core::account::Nonce; use rand::{RngCore, rngs::OsRng}; use std::{path::PathBuf, str::FromStr}; -use tokio::io::AsyncReadExt; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; use anyhow::Result; use key_protocol::key_protocol_core::NSSAUserData; @@ -17,19 +17,78 @@ use crate::{ }; /// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. -pub fn get_home() -> Result { +pub fn get_home_nssa_var() -> Result { Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?) } -/// Fetch config from `NSSA_WALLET_HOME_DIR` -pub async fn fetch_config() -> Result { - let config_home = get_home()?; - let config_contents = tokio::fs::read(config_home.join("wallet_config.json")).await?; - - Ok(serde_json::from_slice(&config_contents)?) +/// Get home dir for wallet. Env var `HOME` must be set before execution to succeed. +pub fn get_home_default_path() -> Result { + std::env::home_dir() + .map(|path| path.join(".nssa").join("wallet")) + .ok_or(anyhow::anyhow!("Failed to get HOME")) } -/// Fetch data stored at `NSSA_WALLET_HOME_DIR/storage.json` +/// Get home dir for wallet. +pub fn get_home() -> Result { + if let Ok(home) = get_home_nssa_var() { + Ok(home) + } else { + get_home_default_path() + } +} + +/// Fetch config from default home +pub async fn fetch_config() -> Result { + let config_home = get_home()?; + let mut config_needs_setup = false; + + let config = match tokio::fs::OpenOptions::new() + .read(true) + .open(config_home.join("wallet_config.json")) + .await + { + Ok(mut file) => { + let mut config_contents = vec![]; + file.read_to_end(&mut config_contents).await?; + + serde_json::from_slice(&config_contents)? + } + Err(err) => match err.kind() { + std::io::ErrorKind::NotFound => { + config_needs_setup = true; + + println!("Config not found, setting up default config"); + + WalletConfig::default() + } + _ => anyhow::bail!("IO error {err:#?}"), + }, + }; + + if config_needs_setup { + tokio::fs::create_dir_all(&config_home).await?; + + println!("Created configs dir at path {config_home:#?}"); + + let mut file = tokio::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(config_home.join("wallet_config.json")) + .await?; + + let default_config_serialized = + serde_json::to_vec_pretty(&WalletConfig::default()).unwrap(); + + file.write_all(&default_config_serialized).await?; + + println!("Configs setted up"); + } + + Ok(config) +} + +/// Fetch data stored at home /// /// If file not present, it is considered as empty list of persistent accounts pub async fn fetch_persistent_storage() -> Result { diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 3beac67..dd6dd32 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -23,7 +23,7 @@ use tokio::io::AsyncWriteExt; use crate::{ cli::{ WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand, - native_token_transfer_program::AuthTransferSubcommand, + config::ConfigSubcommand, native_token_transfer_program::AuthTransferSubcommand, pinata_program::PinataProgramAgnosticSubcommand, token_program::TokenProgramAgnosticSubcommand, }, @@ -93,6 +93,20 @@ impl WalletCore { Ok(storage_path) } + ///Store persistent data at home + pub async fn store_config_changes(&self) -> Result { + let home = get_home()?; + let config_path = home.join("wallet_config.json"); + let config = serde_json::to_vec_pretty(&self.storage.wallet_config)?; + + let mut config_file = tokio::fs::File::create(config_path.as_path()).await?; + config_file.write_all(&config).await?; + + info!("Stored data at {config_path:#?}"); + + Ok(config_path) + } + pub fn create_new_account_public(&mut self) -> Address { self.storage .user_data @@ -216,6 +230,9 @@ pub enum Command { /// Check the wallet can connect to the node and builtin local programs /// match the remote versions CheckHealth {}, + /// Command to setup config, get and set config fields + #[command(subcommand)] + Config(ConfigSubcommand), } ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config @@ -300,6 +317,11 @@ pub async fn execute_subcommand(command: Command) -> Result { token_subcommand.handle_subcommand(&mut wallet_core).await? } + Command::Config(config_subcommand) => { + config_subcommand + .handle_subcommand(&mut wallet_core) + .await? + } }; Ok(subcommand_ret)