From 6c2bdb1b20c438316fa8f0ae478e42dd7ee13afc Mon Sep 17 00:00:00 2001 From: r4bbit <445106+0x-r4bbit@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:04:43 +0100 Subject: [PATCH] feat: add `--label` option to `wallet account new` sub command Following the work done in https://github.com/logos-blockchain/lssa/pull/292 and the comment on extending the work https://github.com/logos-blockchain/lssa/pull/292#pullrequestreview-3672282664, this commit introduces a new `--label` option to the `wallet account new` sub command. **Usage**: ``` wallet account new public --label "Public test account" wallet account new private --label "Private test account" ``` Labels have to be unique across all accounts in the wallet storage. The commit also adds tests, which make use of the `WalletSubCommand` trait functions (hence the change to make it a `pub trait`). --- .gitignore | 1 + examples/program_deployment/README.md | 6 ++ integration_tests/tests/account.rs | 102 ++++++++++++++++++ integration_tests/tests/amm.rs | 35 ++++-- .../tests/auth_transfer/private.rs | 15 ++- .../tests/auth_transfer/public.rs | 10 +- integration_tests/tests/keys_restoration.rs | 4 + integration_tests/tests/pinata.rs | 5 +- integration_tests/tests/token.rs | 102 ++++++++++++++---- wallet/src/cli/account.rs | 58 +++++++++- 10 files changed, 303 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 40be2daa..e4898102 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ storage.json result wallet-ffi/wallet_ffi.h bedrock_signing_key +integration_tests/configs/debug/ diff --git a/examples/program_deployment/README.md b/examples/program_deployment/README.md index b0d59151..63a14db7 100644 --- a/examples/program_deployment/README.md +++ b/examples/program_deployment/README.md @@ -93,6 +93,9 @@ Generated new account with account_id Public/BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1 ``` The relevant part is the account id `BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9` +> [!NOTE] +> You can optionally assign a label to the account for easier identification using the `--label` option: `wallet account new public --label "my-account"`. Labels must be unique across all accounts. + ## Check the account state New accounts are always Uninitialized. Verify: ```bash @@ -269,6 +272,9 @@ Generated new account with account_id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8 ``` The relevant part for this tutorial is the account id `7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr` +> [!NOTE] +> As with public accounts, you can use the `--label` option to assign a label: `wallet account new private --label "my-private-account"`. + You can check it's uninitialized with ```bash diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index ec53da78..36dcca5e 100644 --- a/integration_tests/tests/account.rs +++ b/integration_tests/tests/account.rs @@ -3,6 +3,11 @@ use integration_tests::TestContext; use log::info; use nssa::program::Program; use tokio::test; +use wallet::cli::{ + Command, + account::{AccountSubcommand, NewSubcommand}, + execute_subcommand, +}; #[test] async fn get_existing_account() -> Result<()> { @@ -26,3 +31,100 @@ async fn get_existing_account() -> Result<()> { Ok(()) } + +#[test] +async fn new_public_account_with_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let label = "my-test-public-account".to_string(); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(label.clone()), + })); + + let result = execute_subcommand(ctx.wallet_mut(), command).await?; + + // Extract the account_id from the result + let account_id = match result { + wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, + _ => panic!("Expected RegisterAccount return value"), + }; + + // Verify the label was stored + let stored_label = ctx + .wallet() + .storage() + .labels + .get(&account_id.to_string()) + .expect("Label should be stored for the new account"); + + assert_eq!(stored_label.to_string(), label); + + info!("Successfully created public account with label"); + + Ok(()) +} + +#[test] +async fn new_private_account_with_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let label = "my-test-private-account".to_string(); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: Some(label.clone()), + })); + + let result = execute_subcommand(ctx.wallet_mut(), command).await?; + + // Extract the account_id from the result + let account_id = match result { + wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, + _ => panic!("Expected RegisterAccount return value"), + }; + + // Verify the label was stored + let stored_label = ctx + .wallet() + .storage() + .labels + .get(&account_id.to_string()) + .expect("Label should be stored for the new account"); + + assert_eq!(stored_label.to_string(), label); + + info!("Successfully created private account with label"); + + Ok(()) +} + +#[test] +async fn new_public_account_without_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })); + + let result = execute_subcommand(ctx.wallet_mut(), command).await?; + + // Extract the account_id from the result + let account_id = match result { + wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, + _ => panic!("Expected RegisterAccount return value"), + }; + + // Verify no label was stored + assert!( + !ctx.wallet() + .storage() + .labels + .contains_key(&account_id.to_string()), + "No label should be stored when not provided" + ); + + info!("Successfully created public account without label"); + + Ok(()) +} diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index 3f513d70..ecea91b3 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -19,7 +19,10 @@ async fn amm_public() -> Result<()> { account_id: definition_account_id_1, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -31,7 +34,10 @@ async fn amm_public() -> Result<()> { account_id: supply_account_id_1, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -43,7 +49,10 @@ async fn amm_public() -> Result<()> { account_id: recipient_account_id_1, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -55,7 +64,10 @@ async fn amm_public() -> Result<()> { account_id: definition_account_id_2, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -67,7 +79,10 @@ async fn amm_public() -> Result<()> { account_id: supply_account_id_2, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -79,7 +94,10 @@ async fn amm_public() -> Result<()> { account_id: recipient_account_id_2, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -144,7 +162,10 @@ async fn amm_public() -> Result<()> { account_id: user_holding_lp, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index bf2ed8b1..aa8ca180 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -149,7 +149,10 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> { let from: AccountId = ctx.existing_private_accounts()[0]; // Create a new private account - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })); let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -306,7 +309,10 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { let from: AccountId = ctx.existing_private_accounts()[0]; // Create a new private account - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })); let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -366,7 +372,10 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { async fn initialize_private_account() -> Result<()> { let mut ctx = TestContext::new().await?; - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { account_id } = result else { anyhow::bail!("Expected RegisterAccount return value"); diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index da30fe5a..ed8296ec 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -51,7 +51,10 @@ async fn successful_transfer_to_existing_account() -> Result<()> { pub async fn successful_transfer_to_new_account() -> Result<()> { let mut ctx = TestContext::new().await?; - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })); wallet::cli::execute_subcommand(ctx.wallet_mut(), command) .await @@ -212,7 +215,10 @@ async fn two_consecutive_successful_transfers() -> Result<()> { async fn initialize_public_account() -> Result<()> { let mut ctx = TestContext::new().await?; - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { account_id } = result else { anyhow::bail!("Expected RegisterAccount return value"); diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index b1d9edcb..24299a56 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -24,6 +24,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create first private account at root let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: Some(ChainIndex::root()), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -36,6 +37,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create second private account at /0 let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: Some(ChainIndex::from_str("/0")?), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -70,6 +72,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create first public account at root let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: Some(ChainIndex::root()), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -82,6 +85,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create second public account at /0 let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: Some(ChainIndex::from_str("/0")?), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { diff --git a/integration_tests/tests/pinata.rs b/integration_tests/tests/pinata.rs index bf88536c..002dd2c7 100644 --- a/integration_tests/tests/pinata.rs +++ b/integration_tests/tests/pinata.rs @@ -112,7 +112,10 @@ async fn claim_pinata_to_new_private_account() -> Result<()> { // Create new private account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 506c250f..0ff6eee5 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -23,7 +23,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Create new account for the token definition let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -36,7 +39,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Create new account for the token supply holder let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -49,7 +55,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Create new account for receiving a token transaction let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -262,7 +271,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Create new account for the token definition (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -275,7 +287,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Create new account for the token supply holder (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -288,7 +303,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Create new account for receiving a token transaction (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -429,6 +447,7 @@ async fn create_token_with_private_definition() -> Result<()> { ctx.wallet_mut(), Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: Some(ChainIndex::root()), + label: None, })), ) .await?; @@ -444,6 +463,7 @@ async fn create_token_with_private_definition() -> Result<()> { ctx.wallet_mut(), Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: Some(ChainIndex::root()), + label: None, })), ) .await?; @@ -496,7 +516,10 @@ async fn create_token_with_private_definition() -> Result<()> { // Create private recipient account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -509,7 +532,10 @@ async fn create_token_with_private_definition() -> Result<()> { // Create public recipient account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -615,7 +641,10 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { // Create token definition account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -628,7 +657,10 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { // Create supply account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -685,7 +717,10 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { // Create recipient account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -762,7 +797,10 @@ async fn shielded_token_transfer() -> Result<()> { // Create token definition account (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -775,7 +813,10 @@ async fn shielded_token_transfer() -> Result<()> { // Create supply account (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -788,7 +829,10 @@ async fn shielded_token_transfer() -> Result<()> { // Create recipient account (private) for shielded transfer let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -876,7 +920,10 @@ async fn deshielded_token_transfer() -> Result<()> { // Create token definition account (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -889,7 +936,10 @@ async fn deshielded_token_transfer() -> Result<()> { // Create supply account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -902,7 +952,10 @@ async fn deshielded_token_transfer() -> Result<()> { // Create recipient account (public) for deshielded transfer let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -990,7 +1043,10 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { // Create token definition account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -1003,7 +1059,10 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { // Create supply account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -1031,7 +1090,10 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { // Create new private account for claiming path let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 8ef45c29..7f936284 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -58,12 +58,18 @@ pub enum NewSubcommand { #[arg(long)] /// Chain index of a parent node cci: Option, + #[arg(short, long)] + /// Label to assign to the new account + label: Option, }, /// Register new private account Private { #[arg(long)] /// Chain index of a parent node cci: Option, + #[arg(short, long)] + /// Label to assign to the new account + label: Option, }, } @@ -73,7 +79,17 @@ impl WalletSubcommand for NewSubcommand { wallet_core: &mut WalletCore, ) -> Result { match self { - NewSubcommand::Public { cci } => { + NewSubcommand::Public { cci, label } => { + if let Some(ref label) = label + && wallet_core + .storage + .labels + .values() + .any(|l| l.to_string() == *label) + { + anyhow::bail!("Label '{label}' is already in use by another account"); + } + let (account_id, chain_index) = wallet_core.create_new_account_public(cci); let private_key = wallet_core @@ -84,6 +100,13 @@ impl WalletSubcommand for NewSubcommand { let public_key = PublicKey::new_from_private_key(private_key); + if let Some(label) = label { + wallet_core + .storage + .labels + .insert(account_id.to_string(), Label::new(label)); + } + println!( "Generated new account with account_id Public/{account_id} at path {chain_index}" ); @@ -93,9 +116,26 @@ impl WalletSubcommand for NewSubcommand { Ok(SubcommandReturnValue::RegisterAccount { account_id }) } - NewSubcommand::Private { cci } => { + NewSubcommand::Private { cci, label } => { + if let Some(ref label) = label + && wallet_core + .storage + .labels + .values() + .any(|l| l.to_string() == *label) + { + anyhow::bail!("Label '{label}' is already in use by another account"); + } + let (account_id, chain_index) = wallet_core.create_new_account_private(cci); + if let Some(label) = label { + wallet_core + .storage + .labels + .insert(account_id.to_string(), Label::new(label)); + } + let (key, _) = wallet_core .storage .user_data @@ -379,6 +419,20 @@ impl WalletSubcommand for AccountSubcommand { AccountSubcommand::Label { account_id, label } => { let (account_id_str, _) = parse_addr_with_privacy_prefix(&account_id)?; + // Check if label is already used by a different account + if let Some(existing_account) = wallet_core + .storage + .labels + .iter() + .find(|(_, l)| l.to_string() == label) + .map(|(a, _)| a.clone()) + && existing_account != account_id_str + { + anyhow::bail!( + "Label '{label}' is already in use by account {existing_account}" + ); + } + let old_label = wallet_core .storage .labels