diff --git a/completions/bash/wallet b/completions/bash/wallet index 57dd3636..b01e5607 100644 --- a/completions/bash/wallet +++ b/completions/bash/wallet @@ -22,6 +22,20 @@ _wallet_complete_account_id() { fi } +# Helper function to complete account labels +_wallet_complete_account_label() { + local cur="$1" + local labels + + if command -v wallet &>/dev/null; then + labels=$(wallet account list 2>/dev/null | grep -o '\[.*\]' | sed 's/^\[//;s/\]$//') + fi + + if [[ -n "$labels" ]]; then + COMPREPLY=($(compgen -W "$labels" -- "$cur")) + fi +} + _wallet() { local cur prev words cword _init_completion 2>/dev/null || { @@ -91,20 +105,32 @@ _wallet() { --account-id) _wallet_complete_account_id "$cur" ;; + --account-label) + _wallet_complete_account_label "$cur" + ;; *) - COMPREPLY=($(compgen -W "--account-id" -- "$cur")) + COMPREPLY=($(compgen -W "--account-id --account-label" -- "$cur")) ;; esac ;; send) case "$prev" in - --from | --to) + --from) _wallet_complete_account_id "$cur" ;; + --from-label) + _wallet_complete_account_label "$cur" + ;; + --to) + _wallet_complete_account_id "$cur" + ;; + --to-label) + _wallet_complete_account_label "$cur" + ;; --to-npk | --to-vpk | --amount) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--from --to --to-npk --to-vpk --amount" -- "$cur")) + COMPREPLY=($(compgen -W "--from --from-label --to --to-label --to-npk --to-vpk --amount" -- "$cur")) ;; esac ;; @@ -147,8 +173,11 @@ _wallet() { -a | --account-id) _wallet_complete_account_id "$cur" ;; + --account-label) + _wallet_complete_account_label "$cur" + ;; *) - COMPREPLY=($(compgen -W "-r --raw -k --keys -a --account-id" -- "$cur")) + COMPREPLY=($(compgen -W "-r --raw -k --keys -a --account-id --account-label" -- "$cur")) ;; esac ;; @@ -186,10 +215,13 @@ _wallet() { -a | --account-id) _wallet_complete_account_id "$cur" ;; + --account-label) + _wallet_complete_account_label "$cur" + ;; -l | --label) ;; # no specific completion for label value *) - COMPREPLY=($(compgen -W "-a --account-id -l --label" -- "$cur")) + COMPREPLY=($(compgen -W "-a --account-id --account-label -l --label" -- "$cur")) ;; esac ;; @@ -206,8 +238,11 @@ _wallet() { --to) _wallet_complete_account_id "$cur" ;; + --to-label) + _wallet_complete_account_label "$cur" + ;; *) - COMPREPLY=($(compgen -W "--to" -- "$cur")) + COMPREPLY=($(compgen -W "--to --to-label" -- "$cur")) ;; esac ;; @@ -221,49 +256,85 @@ _wallet() { ;; new) case "$prev" in - --definition-account-id | --supply-account-id) + --definition-account-id) _wallet_complete_account_id "$cur" ;; + --definition-account-label) + _wallet_complete_account_label "$cur" + ;; + --supply-account-id) + _wallet_complete_account_id "$cur" + ;; + --supply-account-label) + _wallet_complete_account_label "$cur" + ;; -n | --name | -t | --total-supply) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--definition-account-id --supply-account-id -n --name -t --total-supply" -- "$cur")) + COMPREPLY=($(compgen -W "--definition-account-id --definition-account-label --supply-account-id --supply-account-label -n --name -t --total-supply" -- "$cur")) ;; esac ;; send) case "$prev" in - --from | --to) + --from) _wallet_complete_account_id "$cur" ;; + --from-label) + _wallet_complete_account_label "$cur" + ;; + --to) + _wallet_complete_account_id "$cur" + ;; + --to-label) + _wallet_complete_account_label "$cur" + ;; --to-npk | --to-vpk | --amount) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--from --to --to-npk --to-vpk --amount" -- "$cur")) + COMPREPLY=($(compgen -W "--from --from-label --to --to-label --to-npk --to-vpk --amount" -- "$cur")) ;; esac ;; burn) case "$prev" in - --definition | --holder) + --definition) _wallet_complete_account_id "$cur" ;; + --definition-label) + _wallet_complete_account_label "$cur" + ;; + --holder) + _wallet_complete_account_id "$cur" + ;; + --holder-label) + _wallet_complete_account_label "$cur" + ;; --amount) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--definition --holder --amount" -- "$cur")) + COMPREPLY=($(compgen -W "--definition --definition-label --holder --holder-label --amount" -- "$cur")) ;; esac ;; mint) case "$prev" in - --definition | --holder) + --definition) _wallet_complete_account_id "$cur" ;; + --definition-label) + _wallet_complete_account_label "$cur" + ;; + --holder) + _wallet_complete_account_id "$cur" + ;; + --holder-label) + _wallet_complete_account_label "$cur" + ;; --holder-npk | --holder-vpk | --amount) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--definition --holder --holder-npk --holder-vpk --amount" -- "$cur")) + COMPREPLY=($(compgen -W "--definition --definition-label --holder --holder-label --holder-npk --holder-vpk --amount" -- "$cur")) ;; esac ;; @@ -277,49 +348,103 @@ _wallet() { ;; new) case "$prev" in - --user-holding-a | --user-holding-b | --user-holding-lp) + --user-holding-a) _wallet_complete_account_id "$cur" ;; + --user-holding-a-label) + _wallet_complete_account_label "$cur" + ;; + --user-holding-b) + _wallet_complete_account_id "$cur" + ;; + --user-holding-b-label) + _wallet_complete_account_label "$cur" + ;; + --user-holding-lp) + _wallet_complete_account_id "$cur" + ;; + --user-holding-lp-label) + _wallet_complete_account_label "$cur" + ;; --balance-a | --balance-b) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--user-holding-a --user-holding-b --user-holding-lp --balance-a --balance-b" -- "$cur")) + COMPREPLY=($(compgen -W "--user-holding-a --user-holding-a-label --user-holding-b --user-holding-b-label --user-holding-lp --user-holding-lp-label --balance-a --balance-b" -- "$cur")) ;; esac ;; swap) case "$prev" in - --user-holding-a | --user-holding-b) + --user-holding-a) _wallet_complete_account_id "$cur" ;; + --user-holding-a-label) + _wallet_complete_account_label "$cur" + ;; + --user-holding-b) + _wallet_complete_account_id "$cur" + ;; + --user-holding-b-label) + _wallet_complete_account_label "$cur" + ;; --amount-in | --min-amount-out | --token-definition) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--user-holding-a --user-holding-b --amount-in --min-amount-out --token-definition" -- "$cur")) + COMPREPLY=($(compgen -W "--user-holding-a --user-holding-a-label --user-holding-b --user-holding-b-label --amount-in --min-amount-out --token-definition" -- "$cur")) ;; esac ;; add-liquidity) case "$prev" in - --user-holding-a | --user-holding-b | --user-holding-lp) + --user-holding-a) _wallet_complete_account_id "$cur" ;; + --user-holding-a-label) + _wallet_complete_account_label "$cur" + ;; + --user-holding-b) + _wallet_complete_account_id "$cur" + ;; + --user-holding-b-label) + _wallet_complete_account_label "$cur" + ;; + --user-holding-lp) + _wallet_complete_account_id "$cur" + ;; + --user-holding-lp-label) + _wallet_complete_account_label "$cur" + ;; --max-amount-a | --max-amount-b | --min-amount-lp) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--user-holding-a --user-holding-b --user-holding-lp --max-amount-a --max-amount-b --min-amount-lp" -- "$cur")) + COMPREPLY=($(compgen -W "--user-holding-a --user-holding-a-label --user-holding-b --user-holding-b-label --user-holding-lp --user-holding-lp-label --max-amount-a --max-amount-b --min-amount-lp" -- "$cur")) ;; esac ;; remove-liquidity) case "$prev" in - --user-holding-a | --user-holding-b | --user-holding-lp) + --user-holding-a) _wallet_complete_account_id "$cur" ;; + --user-holding-a-label) + _wallet_complete_account_label "$cur" + ;; + --user-holding-b) + _wallet_complete_account_id "$cur" + ;; + --user-holding-b-label) + _wallet_complete_account_label "$cur" + ;; + --user-holding-lp) + _wallet_complete_account_id "$cur" + ;; + --user-holding-lp-label) + _wallet_complete_account_label "$cur" + ;; --balance-lp | --min-amount-a | --min-amount-b) ;; # no specific completion *) - COMPREPLY=($(compgen -W "--user-holding-a --user-holding-b --user-holding-lp --balance-lp --min-amount-a --min-amount-b" -- "$cur")) + COMPREPLY=($(compgen -W "--user-holding-a --user-holding-a-label --user-holding-b --user-holding-b-label --user-holding-lp --user-holding-lp-label --balance-lp --min-amount-a --min-amount-b" -- "$cur")) ;; esac ;; diff --git a/completions/zsh/_wallet b/completions/zsh/_wallet index 6e60cc53..2d4fe26b 100644 --- a/completions/zsh/_wallet +++ b/completions/zsh/_wallet @@ -90,12 +90,15 @@ _wallet_auth_transfer() { case $line[1] in init) _arguments \ - '--account-id[Account ID to initialize]:account_id:_wallet_account_ids' + '--account-id[Account ID to initialize]:account_id:_wallet_account_ids' \ + '--account-label[Account label (alternative to --account-id)]:label:_wallet_account_labels' ;; send) _arguments \ '--from[Source account ID]:from_account:_wallet_account_ids' \ + '--from-label[Source account label (alternative to --from)]:label:_wallet_account_labels' \ '--to[Destination account ID (for owned accounts)]:to_account:_wallet_account_ids' \ + '--to-label[Destination account label (alternative to --to)]:label:_wallet_account_labels' \ '--to-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \ '--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \ '--amount[Amount of native tokens to send]:amount:' @@ -165,7 +168,8 @@ _wallet_account() { _arguments \ '(-r --raw)'{-r,--raw}'[Get raw account data]' \ '(-k --keys)'{-k,--keys}'[Display keys (pk for public accounts, npk/vpk for private accounts)]' \ - '(-a --account-id)'{-a,--account-id}'[Account ID to query]:account_id:_wallet_account_ids' + '(-a --account-id)'{-a,--account-id}'[Account ID to query]:account_id:_wallet_account_ids' \ + '--account-label[Account label (alternative to --account-id)]:label:_wallet_account_labels' ;; list|ls) _arguments \ @@ -189,6 +193,7 @@ _wallet_account() { label) _arguments \ '(-a --account-id)'{-a,--account-id}'[Account ID to label]:account_id:_wallet_account_ids' \ + '--account-label[Account label (alternative to --account-id)]:label:_wallet_account_labels' \ '(-l --label)'{-l,--label}'[The label to assign to the account]:label:' ;; esac @@ -216,7 +221,8 @@ _wallet_pinata() { case $line[1] in claim) _arguments \ - '--to[Destination account ID to receive claimed tokens]:to_account:_wallet_account_ids' + '--to[Destination account ID to receive claimed tokens]:to_account:_wallet_account_ids' \ + '--to-label[Destination account label (alternative to --to)]:label:_wallet_account_labels' ;; esac ;; @@ -249,12 +255,16 @@ _wallet_token() { '--name[Token name]:name:' \ '--total-supply[Total supply of tokens to mint]:total_supply:' \ '--definition-account-id[Account ID for token definition]:definition_account:_wallet_account_ids' \ - '--supply-account-id[Account ID to receive initial supply]:supply_account:_wallet_account_ids' + '--definition-account-label[Definition account label (alternative to --definition-account-id)]:label:_wallet_account_labels' \ + '--supply-account-id[Account ID to receive initial supply]:supply_account:_wallet_account_ids' \ + '--supply-account-label[Supply account label (alternative to --supply-account-id)]:label:_wallet_account_labels' ;; send) _arguments \ '--from[Source holding account ID]:from_account:_wallet_account_ids' \ + '--from-label[Source account label (alternative to --from)]:label:_wallet_account_labels' \ '--to[Destination holding account ID (for owned accounts)]:to_account:_wallet_account_ids' \ + '--to-label[Destination account label (alternative to --to)]:label:_wallet_account_labels' \ '--to-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \ '--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \ '--amount[Amount of tokens to send]:amount:' @@ -262,13 +272,17 @@ _wallet_token() { burn) _arguments \ '--definition[Definition account ID]:definition_account:_wallet_account_ids' \ + '--definition-label[Definition account label (alternative to --definition)]:label:_wallet_account_labels' \ '--holder[Holder account ID]:holder_account:_wallet_account_ids' \ + '--holder-label[Holder account label (alternative to --holder)]:label:_wallet_account_labels' \ '--amount[Amount of tokens to burn]:amount:' ;; mint) _arguments \ '--definition[Definition account ID]:definition_account:_wallet_account_ids' \ + '--definition-label[Definition account label (alternative to --definition)]:label:_wallet_account_labels' \ '--holder[Holder account ID (for owned accounts)]:holder_account:_wallet_account_ids' \ + '--holder-label[Holder account label (alternative to --holder)]:label:_wallet_account_labels' \ '--holder-npk[Holder nullifier public key (for foreign private accounts)]:npk:' \ '--holder-vpk[Holder viewing public key (for foreign private accounts)]:vpk:' \ '--amount[Amount of tokens to mint]:amount:' @@ -302,15 +316,20 @@ _wallet_amm() { new) _arguments \ '--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ + '--user-holding-a-label[User holding A account label (alternative to --user-holding-a)]:label:_wallet_account_labels' \ '--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \ + '--user-holding-b-label[User holding B account label (alternative to --user-holding-b)]:label:_wallet_account_labels' \ '--user-holding-lp[User LP token holding account ID]:holding_lp:_wallet_account_ids' \ + '--user-holding-lp-label[User holding LP account label (alternative to --user-holding-lp)]:label:_wallet_account_labels' \ '--balance-a[Amount of token A to deposit]:balance_a:' \ '--balance-b[Amount of token B to deposit]:balance_b:' ;; swap) _arguments \ '--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ + '--user-holding-a-label[User holding A account label (alternative to --user-holding-a)]:label:_wallet_account_labels' \ '--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \ + '--user-holding-b-label[User holding B account label (alternative to --user-holding-b)]:label:_wallet_account_labels' \ '--amount-in[Amount of tokens to swap]:amount_in:' \ '--min-amount-out[Minimum tokens expected in return]:min_amount_out:' \ '--token-definition[Definition ID of the token being provided]:token_def:' @@ -318,8 +337,11 @@ _wallet_amm() { add-liquidity) _arguments \ '--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ + '--user-holding-a-label[User holding A account label (alternative to --user-holding-a)]:label:_wallet_account_labels' \ '--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \ + '--user-holding-b-label[User holding B account label (alternative to --user-holding-b)]:label:_wallet_account_labels' \ '--user-holding-lp[User LP token holding account ID]:holding_lp:_wallet_account_ids' \ + '--user-holding-lp-label[User holding LP account label (alternative to --user-holding-lp)]:label:_wallet_account_labels' \ '--max-amount-a[Maximum amount of token A to deposit]:max_amount_a:' \ '--max-amount-b[Maximum amount of token B to deposit]:max_amount_b:' \ '--min-amount-lp[Minimum LP tokens to receive]:min_amount_lp:' @@ -327,8 +349,11 @@ _wallet_amm() { remove-liquidity) _arguments \ '--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ + '--user-holding-a-label[User holding A account label (alternative to --user-holding-a)]:label:_wallet_account_labels' \ '--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \ + '--user-holding-b-label[User holding B account label (alternative to --user-holding-b)]:label:_wallet_account_labels' \ '--user-holding-lp[User LP token holding account ID]:holding_lp:_wallet_account_ids' \ + '--user-holding-lp-label[User holding LP account label (alternative to --user-holding-lp)]:label:_wallet_account_labels' \ '--balance-lp[Amount of LP tokens to burn]:balance_lp:' \ '--min-amount-a[Minimum token A to receive]:min_amount_a:' \ '--min-amount-b[Minimum token B to receive]:min_amount_b:' @@ -424,7 +449,7 @@ _wallet_help() { _wallet_account_ids() { local -a accounts local line - + # Try to get accounts from wallet account list command # Filter to lines starting with /N (numbered accounts) and extract the account ID if command -v wallet &>/dev/null; then @@ -433,14 +458,35 @@ _wallet_account_ids() { [[ -n "$line" ]] && accounts+=("${line%,}") done < <(wallet account list 2>/dev/null | grep '^/[0-9]' | awk '{print $2}') fi - + # Provide type prefixes as fallback if command fails or returns nothing if (( ${#accounts} == 0 )); then compadd -S '' -- 'Public/' 'Private/' return fi - + _multi_parts / accounts } +# Helper function to complete account labels +# Uses `wallet account list` to get available labels +_wallet_account_labels() { + local -a labels + local line + + if command -v wallet &>/dev/null; then + while IFS= read -r line; do + local label + # Extract label from [...] at end of line + label="${line##*\[}" + label="${label%\]}" + [[ -n "$label" && "$label" != "$line" ]] && labels+=("$label") + done < <(wallet account list 2>/dev/null) + fi + + if (( ${#labels} > 0 )); then + compadd -a labels + fi +} + _wallet "$@" diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 2a8ed2c7..86ae7e35 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -10,7 +10,10 @@ use crate::{ WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, config::Label, - helperfunctions::{AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, + helperfunctions::{ + AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix, + resolve_id_or_label, + }, }; /// Represents generic chain CLI subcommand. @@ -25,8 +28,16 @@ pub enum AccountSubcommand { #[arg(short, long)] keys: bool, /// Valid 32 byte base58 string with privacy prefix. - #[arg(short, long)] - account_id: String, + #[arg( + short, + long, + conflicts_with = "account_label", + required_unless_present = "account_label" + )] + account_id: Option, + /// Account label (alternative to --account-id). + #[arg(long, conflicts_with = "account_id")] + account_label: Option, }, /// Produce new public or private account. #[command(subcommand)] @@ -43,8 +54,16 @@ pub enum AccountSubcommand { /// Set a label for an account. Label { /// Valid 32 byte base58 string with privacy prefix. - #[arg(short, long)] - account_id: String, + #[arg( + short, + long, + conflicts_with = "account_label", + required_unless_present = "account_label" + )] + account_id: Option, + /// Account label (alternative to --account-id). + #[arg(long = "account-label", conflicts_with = "account_id")] + account_label: Option, /// The label to assign to the account. #[arg(short, long)] label: String, @@ -171,8 +190,15 @@ impl WalletSubcommand for AccountSubcommand { raw, keys, account_id, + account_label, } => { - let (account_id_str, addr_kind) = parse_addr_with_privacy_prefix(&account_id)?; + let resolved = resolve_id_or_label( + account_id, + account_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let (account_id_str, addr_kind) = parse_addr_with_privacy_prefix(&resolved)?; let account_id: nssa::AccountId = account_id_str.parse()?; @@ -371,8 +397,18 @@ impl WalletSubcommand for AccountSubcommand { Ok(SubcommandReturnValue::Empty) } - Self::Label { account_id, label } => { - let (account_id_str, _) = parse_addr_with_privacy_prefix(&account_id)?; + Self::Label { + account_id, + account_label, + label, + } => { + let resolved = resolve_id_or_label( + account_id, + account_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let (account_id_str, _) = parse_addr_with_privacy_prefix(&resolved)?; // Check if label is already used by a different account if let Some(existing_account) = wallet_core diff --git a/wallet/src/cli/programs/amm.rs b/wallet/src/cli/programs/amm.rs index 7307569d..bcd204de 100644 --- a/wallet/src/cli/programs/amm.rs +++ b/wallet/src/cli/programs/amm.rs @@ -5,7 +5,7 @@ use nssa::AccountId; use crate::{ WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, - helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, + helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix, resolve_id_or_label}, program_facades::amm::Amm, }; @@ -19,14 +19,35 @@ pub enum AmmProgramAgnosticSubcommand { /// Only public execution allowed. New { /// `user_holding_a` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_a: String, + #[arg( + long, + conflicts_with = "user_holding_a_label", + required_unless_present = "user_holding_a_label" + )] + user_holding_a: Option, + /// User holding A account label (alternative to --user-holding-a). + #[arg(long, conflicts_with = "user_holding_a")] + user_holding_a_label: Option, /// `user_holding_b` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_b: String, + #[arg( + long, + conflicts_with = "user_holding_b_label", + required_unless_present = "user_holding_b_label" + )] + user_holding_b: Option, + /// User holding B account label (alternative to --user-holding-b). + #[arg(long, conflicts_with = "user_holding_b")] + user_holding_b_label: Option, /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_lp: String, + #[arg( + long, + conflicts_with = "user_holding_lp_label", + required_unless_present = "user_holding_lp_label" + )] + user_holding_lp: Option, + /// User holding LP account label (alternative to --user-holding-lp). + #[arg(long, conflicts_with = "user_holding_lp")] + user_holding_lp_label: Option, #[arg(long)] balance_a: u128, #[arg(long)] @@ -39,11 +60,25 @@ pub enum AmmProgramAgnosticSubcommand { /// Only public execution allowed. Swap { /// `user_holding_a` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_a: String, + #[arg( + long, + conflicts_with = "user_holding_a_label", + required_unless_present = "user_holding_a_label" + )] + user_holding_a: Option, + /// User holding A account label (alternative to --user-holding-a). + #[arg(long, conflicts_with = "user_holding_a")] + user_holding_a_label: Option, /// `user_holding_b` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_b: String, + #[arg( + long, + conflicts_with = "user_holding_b_label", + required_unless_present = "user_holding_b_label" + )] + user_holding_b: Option, + /// User holding B account label (alternative to --user-holding-b). + #[arg(long, conflicts_with = "user_holding_b")] + user_holding_b_label: Option, #[arg(long)] amount_in: u128, #[arg(long)] @@ -59,14 +94,35 @@ pub enum AmmProgramAgnosticSubcommand { /// Only public execution allowed. AddLiquidity { /// `user_holding_a` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_a: String, + #[arg( + long, + conflicts_with = "user_holding_a_label", + required_unless_present = "user_holding_a_label" + )] + user_holding_a: Option, + /// User holding A account label (alternative to --user-holding-a). + #[arg(long, conflicts_with = "user_holding_a")] + user_holding_a_label: Option, /// `user_holding_b` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_b: String, + #[arg( + long, + conflicts_with = "user_holding_b_label", + required_unless_present = "user_holding_b_label" + )] + user_holding_b: Option, + /// User holding B account label (alternative to --user-holding-b). + #[arg(long, conflicts_with = "user_holding_b")] + user_holding_b_label: Option, /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_lp: String, + #[arg( + long, + conflicts_with = "user_holding_lp_label", + required_unless_present = "user_holding_lp_label" + )] + user_holding_lp: Option, + /// User holding LP account label (alternative to --user-holding-lp). + #[arg(long, conflicts_with = "user_holding_lp")] + user_holding_lp_label: Option, #[arg(long)] min_amount_lp: u128, #[arg(long)] @@ -81,14 +137,35 @@ pub enum AmmProgramAgnosticSubcommand { /// Only public execution allowed. RemoveLiquidity { /// `user_holding_a` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_a: String, + #[arg( + long, + conflicts_with = "user_holding_a_label", + required_unless_present = "user_holding_a_label" + )] + user_holding_a: Option, + /// User holding A account label (alternative to --user-holding-a). + #[arg(long, conflicts_with = "user_holding_a")] + user_holding_a_label: Option, /// `user_holding_b` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_b: String, + #[arg( + long, + conflicts_with = "user_holding_b_label", + required_unless_present = "user_holding_b_label" + )] + user_holding_b: Option, + /// User holding B account label (alternative to --user-holding-b). + #[arg(long, conflicts_with = "user_holding_b")] + user_holding_b_label: Option, /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - user_holding_lp: String, + #[arg( + long, + conflicts_with = "user_holding_lp_label", + required_unless_present = "user_holding_lp_label" + )] + user_holding_lp: Option, + /// User holding LP account label (alternative to --user-holding-lp). + #[arg(long, conflicts_with = "user_holding_lp")] + user_holding_lp_label: Option, #[arg(long)] balance_lp: u128, #[arg(long)] @@ -106,11 +183,32 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { match self { Self::New { user_holding_a, + user_holding_a_label, user_holding_b, + user_holding_b_label, user_holding_lp, + user_holding_lp_label, balance_a, balance_b, } => { + let user_holding_a = resolve_id_or_label( + user_holding_a, + user_holding_a_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let user_holding_b = resolve_id_or_label( + user_holding_b, + user_holding_b_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let user_holding_lp = resolve_id_or_label( + user_holding_lp, + user_holding_lp_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; let (user_holding_a, user_holding_a_privacy) = parse_addr_with_privacy_prefix(&user_holding_a)?; let (user_holding_b, user_holding_b_privacy) = @@ -152,11 +250,25 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { } Self::Swap { user_holding_a, + user_holding_a_label, user_holding_b, + user_holding_b_label, amount_in, min_amount_out, token_definition, } => { + let user_holding_a = resolve_id_or_label( + user_holding_a, + user_holding_a_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let user_holding_b = resolve_id_or_label( + user_holding_b, + user_holding_b_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; let (user_holding_a, user_holding_a_privacy) = parse_addr_with_privacy_prefix(&user_holding_a)?; let (user_holding_b, user_holding_b_privacy) = @@ -187,12 +299,33 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { } Self::AddLiquidity { user_holding_a, + user_holding_a_label, user_holding_b, + user_holding_b_label, user_holding_lp, + user_holding_lp_label, min_amount_lp, max_amount_a, max_amount_b, } => { + let user_holding_a = resolve_id_or_label( + user_holding_a, + user_holding_a_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let user_holding_b = resolve_id_or_label( + user_holding_b, + user_holding_b_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let user_holding_lp = resolve_id_or_label( + user_holding_lp, + user_holding_lp_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; let (user_holding_a, user_holding_a_privacy) = parse_addr_with_privacy_prefix(&user_holding_a)?; let (user_holding_b, user_holding_b_privacy) = @@ -235,12 +368,33 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand { } Self::RemoveLiquidity { user_holding_a, + user_holding_a_label, user_holding_b, + user_holding_b_label, user_holding_lp, + user_holding_lp_label, balance_lp, min_amount_a, min_amount_b, } => { + let user_holding_a = resolve_id_or_label( + user_holding_a, + user_holding_a_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let user_holding_b = resolve_id_or_label( + user_holding_b, + user_holding_b_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let user_holding_lp = resolve_id_or_label( + user_holding_lp, + user_holding_lp_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; let (user_holding_a, user_holding_a_privacy) = parse_addr_with_privacy_prefix(&user_holding_a)?; let (user_holding_b, user_holding_b_privacy) = diff --git a/wallet/src/cli/programs/native_token_transfer.rs b/wallet/src/cli/programs/native_token_transfer.rs index b3f833ac..41008eac 100644 --- a/wallet/src/cli/programs/native_token_transfer.rs +++ b/wallet/src/cli/programs/native_token_transfer.rs @@ -7,7 +7,10 @@ use crate::{ AccDecodeData::Decode, WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, - helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, + helperfunctions::{ + AccountPrivacyKind, parse_addr_with_privacy_prefix, resolve_account_label, + resolve_id_or_label, + }, program_facades::native_token_transfer::NativeTokenTransfer, }; @@ -17,8 +20,15 @@ pub enum AuthTransferSubcommand { /// Initialize account under authenticated transfer program. Init { /// `account_id` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - account_id: String, + #[arg( + long, + conflicts_with = "account_label", + required_unless_present = "account_label" + )] + account_id: Option, + /// Account label (alternative to --account-id). + #[arg(long, conflicts_with = "account_id")] + account_label: Option, }, /// Send native tokens from one account to another with variable privacy. /// @@ -28,11 +38,21 @@ pub enum AuthTransferSubcommand { /// First is used for owned accounts, second otherwise. Send { /// from - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - from: String, + #[arg( + long, + conflicts_with = "from_label", + required_unless_present = "from_label" + )] + from: Option, + /// From account label (alternative to --from). + #[arg(long, conflicts_with = "from")] + from_label: Option, /// to - valid 32 byte base58 string with privacy prefix. - #[arg(long)] + #[arg(long, conflicts_with = "to_label")] to: Option, + /// To account label (alternative to --to). + #[arg(long, conflicts_with = "to")] + to_label: Option, /// `to_npk` - valid 32 byte hex string. #[arg(long)] to_npk: Option, @@ -51,8 +71,17 @@ impl WalletSubcommand for AuthTransferSubcommand { wallet_core: &mut WalletCore, ) -> Result { match self { - Self::Init { account_id } => { - let (account_id, addr_privacy) = parse_addr_with_privacy_prefix(&account_id)?; + Self::Init { + account_id, + account_label, + } => { + let resolved = resolve_id_or_label( + account_id, + account_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let (account_id, addr_privacy) = parse_addr_with_privacy_prefix(&resolved)?; match addr_privacy { AccountPrivacyKind::Public => { @@ -98,11 +127,30 @@ impl WalletSubcommand for AuthTransferSubcommand { } Self::Send { from, + from_label, to, + to_label, to_npk, to_vpk, amount, } => { + let from = resolve_id_or_label( + from, + from_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let to = match (to, to_label) { + (v, None) => v, + (None, Some(label)) => Some(resolve_account_label( + &label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?), + (Some(_), Some(_)) => { + anyhow::bail!("Provide only one of --to or --to-label") + } + }; let underlying_subcommand = match (to, to_npk, to_vpk) { (None, None, None) => { anyhow::bail!( diff --git a/wallet/src/cli/programs/pinata.rs b/wallet/src/cli/programs/pinata.rs index 94cb0649..6171a0f2 100644 --- a/wallet/src/cli/programs/pinata.rs +++ b/wallet/src/cli/programs/pinata.rs @@ -7,7 +7,7 @@ use crate::{ AccDecodeData::Decode, WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, - helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, + helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix, resolve_id_or_label}, program_facades::pinata::Pinata, }; @@ -17,8 +17,15 @@ pub enum PinataProgramAgnosticSubcommand { /// Claim pinata. Claim { /// to - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - to: String, + #[arg( + long, + conflicts_with = "to_label", + required_unless_present = "to_label" + )] + to: Option, + /// To account label (alternative to --to). + #[arg(long, conflicts_with = "to")] + to_label: Option, }, } @@ -28,7 +35,13 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand { wallet_core: &mut WalletCore, ) -> Result { let underlying_subcommand = match self { - Self::Claim { to } => { + Self::Claim { to, to_label } => { + let to = resolve_id_or_label( + to, + to_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; let (to, to_addr_privacy) = parse_addr_with_privacy_prefix(&to)?; match to_addr_privacy { diff --git a/wallet/src/cli/programs/token.rs b/wallet/src/cli/programs/token.rs index 4274b1da..0575da09 100644 --- a/wallet/src/cli/programs/token.rs +++ b/wallet/src/cli/programs/token.rs @@ -7,7 +7,10 @@ use crate::{ AccDecodeData::Decode, WalletCore, cli::{SubcommandReturnValue, WalletSubcommand}, - helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, + helperfunctions::{ + AccountPrivacyKind, parse_addr_with_privacy_prefix, resolve_account_label, + resolve_id_or_label, + }, program_facades::token::Token, }; @@ -17,11 +20,25 @@ pub enum TokenProgramAgnosticSubcommand { /// Produce a new token. New { /// `definition_account_id` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - definition_account_id: String, + #[arg( + long, + conflicts_with = "definition_account_label", + required_unless_present = "definition_account_label" + )] + definition_account_id: Option, + /// Definition account label (alternative to --definition-account-id). + #[arg(long, conflicts_with = "definition_account_id")] + definition_account_label: Option, /// `supply_account_id` - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - supply_account_id: String, + #[arg( + long, + conflicts_with = "supply_account_label", + required_unless_present = "supply_account_label" + )] + supply_account_id: Option, + /// Supply account label (alternative to --supply-account-id). + #[arg(long, conflicts_with = "supply_account_id")] + supply_account_label: Option, #[arg(short, long)] name: String, #[arg(short, long)] @@ -35,11 +52,21 @@ pub enum TokenProgramAgnosticSubcommand { /// First is used for owned accounts, second otherwise. Send { /// from - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - from: String, + #[arg( + long, + conflicts_with = "from_label", + required_unless_present = "from_label" + )] + from: Option, + /// From account label (alternative to --from). + #[arg(long, conflicts_with = "from")] + from_label: Option, /// to - valid 32 byte base58 string with privacy prefix. - #[arg(long)] + #[arg(long, conflicts_with = "to_label")] to: Option, + /// To account label (alternative to --to). + #[arg(long, conflicts_with = "to")] + to_label: Option, /// `to_npk` - valid 32 byte hex string. #[arg(long)] to_npk: Option, @@ -58,11 +85,25 @@ pub enum TokenProgramAgnosticSubcommand { /// we can not modify foreign accounts. Burn { /// definition - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - definition: String, + #[arg( + long, + conflicts_with = "definition_label", + required_unless_present = "definition_label" + )] + definition: Option, + /// Definition account label (alternative to --definition). + #[arg(long, conflicts_with = "definition")] + definition_label: Option, /// holder - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - holder: String, + #[arg( + long, + conflicts_with = "holder_label", + required_unless_present = "holder_label" + )] + holder: Option, + /// Holder account label (alternative to --holder). + #[arg(long, conflicts_with = "holder")] + holder_label: Option, /// amount - amount of balance to burn. #[arg(long)] amount: u128, @@ -77,11 +118,21 @@ pub enum TokenProgramAgnosticSubcommand { /// First is used for owned accounts, second otherwise. Mint { /// definition - valid 32 byte base58 string with privacy prefix. - #[arg(long)] - definition: String, + #[arg( + long, + conflicts_with = "definition_label", + required_unless_present = "definition_label" + )] + definition: Option, + /// Definition account label (alternative to --definition). + #[arg(long, conflicts_with = "definition")] + definition_label: Option, /// holder - valid 32 byte base58 string with privacy prefix. - #[arg(long)] + #[arg(long, conflicts_with = "holder_label")] holder: Option, + /// Holder account label (alternative to --holder). + #[arg(long, conflicts_with = "holder")] + holder_label: Option, /// `holder_npk` - valid 32 byte hex string. #[arg(long)] holder_npk: Option, @@ -102,10 +153,24 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { match self { Self::New { definition_account_id, + definition_account_label, supply_account_id, + supply_account_label, name, total_supply, } => { + let definition_account_id = resolve_id_or_label( + definition_account_id, + definition_account_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let supply_account_id = resolve_id_or_label( + supply_account_id, + supply_account_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; let (definition_account_id, definition_addr_privacy) = parse_addr_with_privacy_prefix(&definition_account_id)?; let (supply_account_id, supply_addr_privacy) = @@ -158,11 +223,30 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { } Self::Send { from, + from_label, to, + to_label, to_npk, to_vpk, amount, } => { + let from = resolve_id_or_label( + from, + from_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let to = match (to, to_label) { + (v, None) => v, + (None, Some(label)) => Some(resolve_account_label( + &label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?), + (Some(_), Some(_)) => { + anyhow::bail!("Provide only one of --to or --to-label") + } + }; let underlying_subcommand = match (to, to_npk, to_vpk) { (None, None, None) => { anyhow::bail!( @@ -248,9 +332,23 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { } Self::Burn { definition, + definition_label, holder, + holder_label, amount, } => { + let definition = resolve_id_or_label( + definition, + definition_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let holder = resolve_id_or_label( + holder, + holder_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; let underlying_subcommand = { let (definition, definition_privacy) = parse_addr_with_privacy_prefix(&definition)?; @@ -300,11 +398,30 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { } Self::Mint { definition, + definition_label, holder, + holder_label, holder_npk, holder_vpk, amount, } => { + let definition = resolve_id_or_label( + definition, + definition_label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?; + let holder = match (holder, holder_label) { + (v, None) => v, + (None, Some(label)) => Some(resolve_account_label( + &label, + &wallet_core.storage.labels, + &wallet_core.storage.user_data, + )?), + (Some(_), Some(_)) => { + anyhow::bail!("Provide only one of --holder or --holder-label") + } + }; let underlying_subcommand = match (holder, holder_npk, holder_vpk) { (None, None, None) => { anyhow::bail!( diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 74f7bab3..2e0ed6cd 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -49,6 +49,66 @@ impl From for HumanReadableAccount { } } +/// Resolve an account id-or-label pair to a `Privacy/id` string. +/// +/// Exactly one of `id` or `label` must be `Some`. If `id` is provided it is +/// returned as-is; if `label` is provided it is resolved via +/// [`resolve_account_label`]. Any other combination returns an error. +pub fn resolve_id_or_label( + id: Option, + label: Option, + labels: &HashMap, + user_data: &NSSAUserData, +) -> Result { + match (id, label) { + (Some(id), None) => Ok(id), + (None, Some(label)) => resolve_account_label(&label, labels, user_data), + _ => anyhow::bail!("provide exactly one of account id or account label"), + } +} + +/// Resolve an account label to its full `Privacy/id` string representation. +/// +/// Looks up the label in the labels map and determines whether the account is +/// public or private by checking the user data key trees. +pub fn resolve_account_label( + label: &str, + labels: &HashMap, + user_data: &NSSAUserData, +) -> Result { + let account_id_str = labels + .iter() + .find(|(_, l)| l.to_string() == label) + .map(|(k, _)| k.clone()) + .ok_or_else(|| anyhow::anyhow!("No account found with label '{label}'"))?; + + let account_id: nssa::AccountId = account_id_str.parse()?; + + let privacy = if user_data + .public_key_tree + .account_id_map + .contains_key(&account_id) + || user_data + .default_pub_account_signing_keys + .contains_key(&account_id) + { + "Public" + } else if user_data + .private_key_tree + .account_id_map + .contains_key(&account_id) + || user_data + .default_user_private_accounts + .contains_key(&account_id) + { + "Private" + } else { + anyhow::bail!("Account with label '{label}' not found in wallet"); + }; + + Ok(format!("{privacy}/{account_id_str}")) +} + /// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. fn get_home_nssa_var() -> Result { Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?)