feat: add --account-label as alternative to --account-id across all wallet subcommands

Allow users to identify accounts by their human-readable label instead of the
full `Privacy/base58` account ID. This makes the CLI much more ergonomic for
users who have labeled their accounts.

- [x] Add `resolve_account_label()` in `helperfunctions.rs` that looks up a label,
  determines account privacy (public/private), and returns the full `Privacy/id` string
- [x] Add `--account-label` (or `--from-label`, `--to-label`, `--definition-label`,
  `--holder-label`, `--user-holding-*-label`) as mutually exclusive alternative to
  every `--account-id`-style flag across all subcommands:
  - `account get`, `account label`
  - `auth-transfer init`, `auth-transfer send`
  - `token new`, `token send`, `token burn`, `token mint`
  - `pinata claim`
  - `amm new`, `amm swap`, `amm add-liquidity`, `amm remove-liquidity`
- [x] Update zsh completion script with `_wallet_account_labels()` helper
- [x] Add bash completion script with `_wallet_get_account_labels()` helper

1. Start a local sequencer
2. Create accounts and label them: `wallet account new public --label alice`
3. Use labels in commands: `wallet account get --account-label alice`
4. Verify mutual exclusivity: `wallet account get --account-id <id> --account-label alice` should error
5. Test shell completions: `wallet account get --account-label <TAB>` should list labels

None

None

- [x] Complete PR description
- [x] Implement the core functionality
- [ ] Add/update tests
- [x] Add/update documentation and inline comments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
fryorcraken 2026-03-13 13:33:51 +11:00
parent 6f77c75b9c
commit ea4a149585
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
8 changed files with 686 additions and 87 deletions

View File

@ -22,6 +22,20 @@ _wallet_complete_account_id() {
fi 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() { _wallet() {
local cur prev words cword local cur prev words cword
_init_completion 2>/dev/null || { _init_completion 2>/dev/null || {
@ -91,20 +105,32 @@ _wallet() {
--account-id) --account-id)
_wallet_complete_account_id "$cur" _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 esac
;; ;;
send) send)
case "$prev" in case "$prev" in
--from | --to) --from)
_wallet_complete_account_id "$cur" _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) --to-npk | --to-vpk | --amount)
;; # no specific completion ;; # 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 esac
;; ;;
@ -147,8 +173,11 @@ _wallet() {
-a | --account-id) -a | --account-id)
_wallet_complete_account_id "$cur" _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 esac
;; ;;
@ -186,10 +215,13 @@ _wallet() {
-a | --account-id) -a | --account-id)
_wallet_complete_account_id "$cur" _wallet_complete_account_id "$cur"
;; ;;
--account-label)
_wallet_complete_account_label "$cur"
;;
-l | --label) -l | --label)
;; # no specific completion for label value ;; # 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 esac
;; ;;
@ -206,8 +238,11 @@ _wallet() {
--to) --to)
_wallet_complete_account_id "$cur" _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 esac
;; ;;
@ -221,49 +256,85 @@ _wallet() {
;; ;;
new) new)
case "$prev" in case "$prev" in
--definition-account-id | --supply-account-id) --definition-account-id)
_wallet_complete_account_id "$cur" _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) -n | --name | -t | --total-supply)
;; # no specific completion ;; # 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 esac
;; ;;
send) send)
case "$prev" in case "$prev" in
--from | --to) --from)
_wallet_complete_account_id "$cur" _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) --to-npk | --to-vpk | --amount)
;; # no specific completion ;; # 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 esac
;; ;;
burn) burn)
case "$prev" in case "$prev" in
--definition | --holder) --definition)
_wallet_complete_account_id "$cur" _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) --amount)
;; # no specific completion ;; # no specific completion
*) *)
COMPREPLY=($(compgen -W "--definition --holder --amount" -- "$cur")) COMPREPLY=($(compgen -W "--definition --definition-label --holder --holder-label --amount" -- "$cur"))
;; ;;
esac esac
;; ;;
mint) mint)
case "$prev" in case "$prev" in
--definition | --holder) --definition)
_wallet_complete_account_id "$cur" _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) --holder-npk | --holder-vpk | --amount)
;; # no specific completion ;; # 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 esac
;; ;;
@ -277,49 +348,103 @@ _wallet() {
;; ;;
new) new)
case "$prev" in case "$prev" in
--user-holding-a | --user-holding-b | --user-holding-lp) --user-holding-a)
_wallet_complete_account_id "$cur" _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) --balance-a | --balance-b)
;; # no specific completion ;; # 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 esac
;; ;;
swap) swap)
case "$prev" in case "$prev" in
--user-holding-a | --user-holding-b) --user-holding-a)
_wallet_complete_account_id "$cur" _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) --amount-in | --min-amount-out | --token-definition)
;; # no specific completion ;; # 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 esac
;; ;;
add-liquidity) add-liquidity)
case "$prev" in case "$prev" in
--user-holding-a | --user-holding-b | --user-holding-lp) --user-holding-a)
_wallet_complete_account_id "$cur" _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) --max-amount-a | --max-amount-b | --min-amount-lp)
;; # no specific completion ;; # 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 esac
;; ;;
remove-liquidity) remove-liquidity)
case "$prev" in case "$prev" in
--user-holding-a | --user-holding-b | --user-holding-lp) --user-holding-a)
_wallet_complete_account_id "$cur" _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) --balance-lp | --min-amount-a | --min-amount-b)
;; # no specific completion ;; # 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 esac
;; ;;

View File

@ -90,12 +90,15 @@ _wallet_auth_transfer() {
case $line[1] in case $line[1] in
init) init)
_arguments \ _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) send)
_arguments \ _arguments \
'--from[Source account ID]:from_account:_wallet_account_ids' \ '--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[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-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \
'--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \ '--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \
'--amount[Amount of native tokens to send]:amount:' '--amount[Amount of native tokens to send]:amount:'
@ -165,7 +168,8 @@ _wallet_account() {
_arguments \ _arguments \
'(-r --raw)'{-r,--raw}'[Get raw account data]' \ '(-r --raw)'{-r,--raw}'[Get raw account data]' \
'(-k --keys)'{-k,--keys}'[Display keys (pk for public accounts, npk/vpk for private accounts)]' \ '(-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) list|ls)
_arguments \ _arguments \
@ -189,6 +193,7 @@ _wallet_account() {
label) label)
_arguments \ _arguments \
'(-a --account-id)'{-a,--account-id}'[Account ID to label]:account_id:_wallet_account_ids' \ '(-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:' '(-l --label)'{-l,--label}'[The label to assign to the account]:label:'
;; ;;
esac esac
@ -216,7 +221,8 @@ _wallet_pinata() {
case $line[1] in case $line[1] in
claim) claim)
_arguments \ _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 esac
;; ;;
@ -249,12 +255,16 @@ _wallet_token() {
'--name[Token name]:name:' \ '--name[Token name]:name:' \
'--total-supply[Total supply of tokens to mint]:total_supply:' \ '--total-supply[Total supply of tokens to mint]:total_supply:' \
'--definition-account-id[Account ID for token definition]:definition_account:_wallet_account_ids' \ '--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) send)
_arguments \ _arguments \
'--from[Source holding account ID]:from_account:_wallet_account_ids' \ '--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[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-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \
'--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \ '--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \
'--amount[Amount of tokens to send]:amount:' '--amount[Amount of tokens to send]:amount:'
@ -262,13 +272,17 @@ _wallet_token() {
burn) burn)
_arguments \ _arguments \
'--definition[Definition account ID]:definition_account:_wallet_account_ids' \ '--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[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:' '--amount[Amount of tokens to burn]:amount:'
;; ;;
mint) mint)
_arguments \ _arguments \
'--definition[Definition account ID]:definition_account:_wallet_account_ids' \ '--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[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-npk[Holder nullifier public key (for foreign private accounts)]:npk:' \
'--holder-vpk[Holder viewing public key (for foreign private accounts)]:vpk:' \ '--holder-vpk[Holder viewing public key (for foreign private accounts)]:vpk:' \
'--amount[Amount of tokens to mint]:amount:' '--amount[Amount of tokens to mint]:amount:'
@ -302,15 +316,20 @@ _wallet_amm() {
new) new)
_arguments \ _arguments \
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ '--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[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[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-a[Amount of token A to deposit]:balance_a:' \
'--balance-b[Amount of token B to deposit]:balance_b:' '--balance-b[Amount of token B to deposit]:balance_b:'
;; ;;
swap) swap)
_arguments \ _arguments \
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ '--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[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:' \ '--amount-in[Amount of tokens to swap]:amount_in:' \
'--min-amount-out[Minimum tokens expected in return]:min_amount_out:' \ '--min-amount-out[Minimum tokens expected in return]:min_amount_out:' \
'--token-definition[Definition ID of the token being provided]:token_def:' '--token-definition[Definition ID of the token being provided]:token_def:'
@ -318,8 +337,11 @@ _wallet_amm() {
add-liquidity) add-liquidity)
_arguments \ _arguments \
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ '--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[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[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-a[Maximum amount of token A to deposit]:max_amount_a:' \
'--max-amount-b[Maximum amount of token B to deposit]:max_amount_b:' \ '--max-amount-b[Maximum amount of token B to deposit]:max_amount_b:' \
'--min-amount-lp[Minimum LP tokens to receive]:min_amount_lp:' '--min-amount-lp[Minimum LP tokens to receive]:min_amount_lp:'
@ -327,8 +349,11 @@ _wallet_amm() {
remove-liquidity) remove-liquidity)
_arguments \ _arguments \
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \ '--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[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[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:' \ '--balance-lp[Amount of LP tokens to burn]:balance_lp:' \
'--min-amount-a[Minimum token A to receive]:min_amount_a:' \ '--min-amount-a[Minimum token A to receive]:min_amount_a:' \
'--min-amount-b[Minimum token B to receive]:min_amount_b:' '--min-amount-b[Minimum token B to receive]:min_amount_b:'
@ -443,4 +468,25 @@ _wallet_account_ids() {
_multi_parts / accounts _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 "$@" _wallet "$@"

View File

@ -10,7 +10,10 @@ use crate::{
WalletCore, WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand}, cli::{SubcommandReturnValue, WalletSubcommand},
config::Label, 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. /// Represents generic chain CLI subcommand.
@ -25,8 +28,16 @@ pub enum AccountSubcommand {
#[arg(short, long)] #[arg(short, long)]
keys: bool, keys: bool,
/// Valid 32 byte base58 string with privacy prefix. /// Valid 32 byte base58 string with privacy prefix.
#[arg(short, long)] #[arg(
account_id: String, short,
long,
conflicts_with = "account_label",
required_unless_present = "account_label"
)]
account_id: Option<String>,
/// Account label (alternative to --account-id).
#[arg(long, conflicts_with = "account_id")]
account_label: Option<String>,
}, },
/// Produce new public or private account. /// Produce new public or private account.
#[command(subcommand)] #[command(subcommand)]
@ -43,8 +54,16 @@ pub enum AccountSubcommand {
/// Set a label for an account. /// Set a label for an account.
Label { Label {
/// Valid 32 byte base58 string with privacy prefix. /// Valid 32 byte base58 string with privacy prefix.
#[arg(short, long)] #[arg(
account_id: String, short,
long,
conflicts_with = "account_label",
required_unless_present = "account_label"
)]
account_id: Option<String>,
/// Account label (alternative to --account-id).
#[arg(long = "account-label", conflicts_with = "account_id")]
account_label: Option<String>,
/// The label to assign to the account. /// The label to assign to the account.
#[arg(short, long)] #[arg(short, long)]
label: String, label: String,
@ -171,8 +190,15 @@ impl WalletSubcommand for AccountSubcommand {
raw, raw,
keys, keys,
account_id, 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()?; let account_id: nssa::AccountId = account_id_str.parse()?;
@ -371,8 +397,18 @@ impl WalletSubcommand for AccountSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
Self::Label { account_id, label } => { Self::Label {
let (account_id_str, _) = parse_addr_with_privacy_prefix(&account_id)?; 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 // Check if label is already used by a different account
if let Some(existing_account) = wallet_core if let Some(existing_account) = wallet_core

View File

@ -5,7 +5,7 @@ use nssa::AccountId;
use crate::{ use crate::{
WalletCore, WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand}, 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, program_facades::amm::Amm,
}; };
@ -19,14 +19,35 @@ pub enum AmmProgramAgnosticSubcommand {
/// Only public execution allowed. /// Only public execution allowed.
New { New {
/// `user_holding_a` - valid 32 byte base58 string with privacy prefix. /// `user_holding_a` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_a: String, long,
conflicts_with = "user_holding_a_label",
required_unless_present = "user_holding_a_label"
)]
user_holding_a: Option<String>,
/// User holding A account label (alternative to --user-holding-a).
#[arg(long, conflicts_with = "user_holding_a")]
user_holding_a_label: Option<String>,
/// `user_holding_b` - valid 32 byte base58 string with privacy prefix. /// `user_holding_b` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_b: String, long,
conflicts_with = "user_holding_b_label",
required_unless_present = "user_holding_b_label"
)]
user_holding_b: Option<String>,
/// User holding B account label (alternative to --user-holding-b).
#[arg(long, conflicts_with = "user_holding_b")]
user_holding_b_label: Option<String>,
/// `user_holding_lp` - valid 32 byte base58 string with privacy prefix. /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_lp: String, long,
conflicts_with = "user_holding_lp_label",
required_unless_present = "user_holding_lp_label"
)]
user_holding_lp: Option<String>,
/// User holding LP account label (alternative to --user-holding-lp).
#[arg(long, conflicts_with = "user_holding_lp")]
user_holding_lp_label: Option<String>,
#[arg(long)] #[arg(long)]
balance_a: u128, balance_a: u128,
#[arg(long)] #[arg(long)]
@ -39,11 +60,25 @@ pub enum AmmProgramAgnosticSubcommand {
/// Only public execution allowed. /// Only public execution allowed.
Swap { Swap {
/// `user_holding_a` - valid 32 byte base58 string with privacy prefix. /// `user_holding_a` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_a: String, long,
conflicts_with = "user_holding_a_label",
required_unless_present = "user_holding_a_label"
)]
user_holding_a: Option<String>,
/// User holding A account label (alternative to --user-holding-a).
#[arg(long, conflicts_with = "user_holding_a")]
user_holding_a_label: Option<String>,
/// `user_holding_b` - valid 32 byte base58 string with privacy prefix. /// `user_holding_b` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_b: String, long,
conflicts_with = "user_holding_b_label",
required_unless_present = "user_holding_b_label"
)]
user_holding_b: Option<String>,
/// User holding B account label (alternative to --user-holding-b).
#[arg(long, conflicts_with = "user_holding_b")]
user_holding_b_label: Option<String>,
#[arg(long)] #[arg(long)]
amount_in: u128, amount_in: u128,
#[arg(long)] #[arg(long)]
@ -59,14 +94,35 @@ pub enum AmmProgramAgnosticSubcommand {
/// Only public execution allowed. /// Only public execution allowed.
AddLiquidity { AddLiquidity {
/// `user_holding_a` - valid 32 byte base58 string with privacy prefix. /// `user_holding_a` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_a: String, long,
conflicts_with = "user_holding_a_label",
required_unless_present = "user_holding_a_label"
)]
user_holding_a: Option<String>,
/// User holding A account label (alternative to --user-holding-a).
#[arg(long, conflicts_with = "user_holding_a")]
user_holding_a_label: Option<String>,
/// `user_holding_b` - valid 32 byte base58 string with privacy prefix. /// `user_holding_b` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_b: String, long,
conflicts_with = "user_holding_b_label",
required_unless_present = "user_holding_b_label"
)]
user_holding_b: Option<String>,
/// User holding B account label (alternative to --user-holding-b).
#[arg(long, conflicts_with = "user_holding_b")]
user_holding_b_label: Option<String>,
/// `user_holding_lp` - valid 32 byte base58 string with privacy prefix. /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_lp: String, long,
conflicts_with = "user_holding_lp_label",
required_unless_present = "user_holding_lp_label"
)]
user_holding_lp: Option<String>,
/// User holding LP account label (alternative to --user-holding-lp).
#[arg(long, conflicts_with = "user_holding_lp")]
user_holding_lp_label: Option<String>,
#[arg(long)] #[arg(long)]
min_amount_lp: u128, min_amount_lp: u128,
#[arg(long)] #[arg(long)]
@ -81,14 +137,35 @@ pub enum AmmProgramAgnosticSubcommand {
/// Only public execution allowed. /// Only public execution allowed.
RemoveLiquidity { RemoveLiquidity {
/// `user_holding_a` - valid 32 byte base58 string with privacy prefix. /// `user_holding_a` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_a: String, long,
conflicts_with = "user_holding_a_label",
required_unless_present = "user_holding_a_label"
)]
user_holding_a: Option<String>,
/// User holding A account label (alternative to --user-holding-a).
#[arg(long, conflicts_with = "user_holding_a")]
user_holding_a_label: Option<String>,
/// `user_holding_b` - valid 32 byte base58 string with privacy prefix. /// `user_holding_b` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_b: String, long,
conflicts_with = "user_holding_b_label",
required_unless_present = "user_holding_b_label"
)]
user_holding_b: Option<String>,
/// User holding B account label (alternative to --user-holding-b).
#[arg(long, conflicts_with = "user_holding_b")]
user_holding_b_label: Option<String>,
/// `user_holding_lp` - valid 32 byte base58 string with privacy prefix. /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
user_holding_lp: String, long,
conflicts_with = "user_holding_lp_label",
required_unless_present = "user_holding_lp_label"
)]
user_holding_lp: Option<String>,
/// User holding LP account label (alternative to --user-holding-lp).
#[arg(long, conflicts_with = "user_holding_lp")]
user_holding_lp_label: Option<String>,
#[arg(long)] #[arg(long)]
balance_lp: u128, balance_lp: u128,
#[arg(long)] #[arg(long)]
@ -106,11 +183,32 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
match self { match self {
Self::New { Self::New {
user_holding_a, user_holding_a,
user_holding_a_label,
user_holding_b, user_holding_b,
user_holding_b_label,
user_holding_lp, user_holding_lp,
user_holding_lp_label,
balance_a, balance_a,
balance_b, 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) = let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?; parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) = let (user_holding_b, user_holding_b_privacy) =
@ -152,11 +250,25 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
} }
Self::Swap { Self::Swap {
user_holding_a, user_holding_a,
user_holding_a_label,
user_holding_b, user_holding_b,
user_holding_b_label,
amount_in, amount_in,
min_amount_out, min_amount_out,
token_definition, 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) = let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?; parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) = let (user_holding_b, user_holding_b_privacy) =
@ -187,12 +299,33 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
} }
Self::AddLiquidity { Self::AddLiquidity {
user_holding_a, user_holding_a,
user_holding_a_label,
user_holding_b, user_holding_b,
user_holding_b_label,
user_holding_lp, user_holding_lp,
user_holding_lp_label,
min_amount_lp, min_amount_lp,
max_amount_a, max_amount_a,
max_amount_b, 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) = let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?; parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) = let (user_holding_b, user_holding_b_privacy) =
@ -235,12 +368,33 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
} }
Self::RemoveLiquidity { Self::RemoveLiquidity {
user_holding_a, user_holding_a,
user_holding_a_label,
user_holding_b, user_holding_b,
user_holding_b_label,
user_holding_lp, user_holding_lp,
user_holding_lp_label,
balance_lp, balance_lp,
min_amount_a, min_amount_a,
min_amount_b, 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) = let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?; parse_addr_with_privacy_prefix(&user_holding_a)?;
let (user_holding_b, user_holding_b_privacy) = let (user_holding_b, user_holding_b_privacy) =

View File

@ -7,7 +7,10 @@ use crate::{
AccDecodeData::Decode, AccDecodeData::Decode,
WalletCore, WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand}, 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, program_facades::native_token_transfer::NativeTokenTransfer,
}; };
@ -17,8 +20,15 @@ pub enum AuthTransferSubcommand {
/// Initialize account under authenticated transfer program. /// Initialize account under authenticated transfer program.
Init { Init {
/// `account_id` - valid 32 byte base58 string with privacy prefix. /// `account_id` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
account_id: String, long,
conflicts_with = "account_label",
required_unless_present = "account_label"
)]
account_id: Option<String>,
/// Account label (alternative to --account-id).
#[arg(long, conflicts_with = "account_id")]
account_label: Option<String>,
}, },
/// Send native tokens from one account to another with variable privacy. /// 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. /// First is used for owned accounts, second otherwise.
Send { Send {
/// from - valid 32 byte base58 string with privacy prefix. /// from - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
from: String, long,
conflicts_with = "from_label",
required_unless_present = "from_label"
)]
from: Option<String>,
/// From account label (alternative to --from).
#[arg(long, conflicts_with = "from")]
from_label: Option<String>,
/// to - valid 32 byte base58 string with privacy prefix. /// to - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(long, conflicts_with = "to_label")]
to: Option<String>, to: Option<String>,
/// To account label (alternative to --to).
#[arg(long, conflicts_with = "to")]
to_label: Option<String>,
/// `to_npk` - valid 32 byte hex string. /// `to_npk` - valid 32 byte hex string.
#[arg(long)] #[arg(long)]
to_npk: Option<String>, to_npk: Option<String>,
@ -51,8 +71,17 @@ impl WalletSubcommand for AuthTransferSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
Self::Init { account_id } => { Self::Init {
let (account_id, addr_privacy) = parse_addr_with_privacy_prefix(&account_id)?; 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 { match addr_privacy {
AccountPrivacyKind::Public => { AccountPrivacyKind::Public => {
@ -98,11 +127,30 @@ impl WalletSubcommand for AuthTransferSubcommand {
} }
Self::Send { Self::Send {
from, from,
from_label,
to, to,
to_label,
to_npk, to_npk,
to_vpk, to_vpk,
amount, 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) { let underlying_subcommand = match (to, to_npk, to_vpk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( anyhow::bail!(

View File

@ -7,7 +7,7 @@ use crate::{
AccDecodeData::Decode, AccDecodeData::Decode,
WalletCore, WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand}, 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, program_facades::pinata::Pinata,
}; };
@ -17,8 +17,15 @@ pub enum PinataProgramAgnosticSubcommand {
/// Claim pinata. /// Claim pinata.
Claim { Claim {
/// to - valid 32 byte base58 string with privacy prefix. /// to - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
to: String, long,
conflicts_with = "to_label",
required_unless_present = "to_label"
)]
to: Option<String>,
/// To account label (alternative to --to).
#[arg(long, conflicts_with = "to")]
to_label: Option<String>,
}, },
} }
@ -28,7 +35,13 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let underlying_subcommand = match self { 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)?; let (to, to_addr_privacy) = parse_addr_with_privacy_prefix(&to)?;
match to_addr_privacy { match to_addr_privacy {

View File

@ -7,7 +7,10 @@ use crate::{
AccDecodeData::Decode, AccDecodeData::Decode,
WalletCore, WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand}, 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, program_facades::token::Token,
}; };
@ -17,11 +20,25 @@ pub enum TokenProgramAgnosticSubcommand {
/// Produce a new token. /// Produce a new token.
New { New {
/// `definition_account_id` - valid 32 byte base58 string with privacy prefix. /// `definition_account_id` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
definition_account_id: String, long,
conflicts_with = "definition_account_label",
required_unless_present = "definition_account_label"
)]
definition_account_id: Option<String>,
/// Definition account label (alternative to --definition-account-id).
#[arg(long, conflicts_with = "definition_account_id")]
definition_account_label: Option<String>,
/// `supply_account_id` - valid 32 byte base58 string with privacy prefix. /// `supply_account_id` - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
supply_account_id: String, long,
conflicts_with = "supply_account_label",
required_unless_present = "supply_account_label"
)]
supply_account_id: Option<String>,
/// Supply account label (alternative to --supply-account-id).
#[arg(long, conflicts_with = "supply_account_id")]
supply_account_label: Option<String>,
#[arg(short, long)] #[arg(short, long)]
name: String, name: String,
#[arg(short, long)] #[arg(short, long)]
@ -35,11 +52,21 @@ pub enum TokenProgramAgnosticSubcommand {
/// First is used for owned accounts, second otherwise. /// First is used for owned accounts, second otherwise.
Send { Send {
/// from - valid 32 byte base58 string with privacy prefix. /// from - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
from: String, long,
conflicts_with = "from_label",
required_unless_present = "from_label"
)]
from: Option<String>,
/// From account label (alternative to --from).
#[arg(long, conflicts_with = "from")]
from_label: Option<String>,
/// to - valid 32 byte base58 string with privacy prefix. /// to - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(long, conflicts_with = "to_label")]
to: Option<String>, to: Option<String>,
/// To account label (alternative to --to).
#[arg(long, conflicts_with = "to")]
to_label: Option<String>,
/// `to_npk` - valid 32 byte hex string. /// `to_npk` - valid 32 byte hex string.
#[arg(long)] #[arg(long)]
to_npk: Option<String>, to_npk: Option<String>,
@ -58,11 +85,25 @@ pub enum TokenProgramAgnosticSubcommand {
/// we can not modify foreign accounts. /// we can not modify foreign accounts.
Burn { Burn {
/// definition - valid 32 byte base58 string with privacy prefix. /// definition - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
definition: String, long,
conflicts_with = "definition_label",
required_unless_present = "definition_label"
)]
definition: Option<String>,
/// Definition account label (alternative to --definition).
#[arg(long, conflicts_with = "definition")]
definition_label: Option<String>,
/// holder - valid 32 byte base58 string with privacy prefix. /// holder - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
holder: String, long,
conflicts_with = "holder_label",
required_unless_present = "holder_label"
)]
holder: Option<String>,
/// Holder account label (alternative to --holder).
#[arg(long, conflicts_with = "holder")]
holder_label: Option<String>,
/// amount - amount of balance to burn. /// amount - amount of balance to burn.
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
@ -77,11 +118,21 @@ pub enum TokenProgramAgnosticSubcommand {
/// First is used for owned accounts, second otherwise. /// First is used for owned accounts, second otherwise.
Mint { Mint {
/// definition - valid 32 byte base58 string with privacy prefix. /// definition - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(
definition: String, long,
conflicts_with = "definition_label",
required_unless_present = "definition_label"
)]
definition: Option<String>,
/// Definition account label (alternative to --definition).
#[arg(long, conflicts_with = "definition")]
definition_label: Option<String>,
/// holder - valid 32 byte base58 string with privacy prefix. /// holder - valid 32 byte base58 string with privacy prefix.
#[arg(long)] #[arg(long, conflicts_with = "holder_label")]
holder: Option<String>, holder: Option<String>,
/// Holder account label (alternative to --holder).
#[arg(long, conflicts_with = "holder")]
holder_label: Option<String>,
/// `holder_npk` - valid 32 byte hex string. /// `holder_npk` - valid 32 byte hex string.
#[arg(long)] #[arg(long)]
holder_npk: Option<String>, holder_npk: Option<String>,
@ -102,10 +153,24 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
match self { match self {
Self::New { Self::New {
definition_account_id, definition_account_id,
definition_account_label,
supply_account_id, supply_account_id,
supply_account_label,
name, name,
total_supply, 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) = let (definition_account_id, definition_addr_privacy) =
parse_addr_with_privacy_prefix(&definition_account_id)?; parse_addr_with_privacy_prefix(&definition_account_id)?;
let (supply_account_id, supply_addr_privacy) = let (supply_account_id, supply_addr_privacy) =
@ -158,11 +223,30 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
} }
Self::Send { Self::Send {
from, from,
from_label,
to, to,
to_label,
to_npk, to_npk,
to_vpk, to_vpk,
amount, 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) { let underlying_subcommand = match (to, to_npk, to_vpk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( anyhow::bail!(
@ -248,9 +332,23 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
} }
Self::Burn { Self::Burn {
definition, definition,
definition_label,
holder, holder,
holder_label,
amount, 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 underlying_subcommand = {
let (definition, definition_privacy) = let (definition, definition_privacy) =
parse_addr_with_privacy_prefix(&definition)?; parse_addr_with_privacy_prefix(&definition)?;
@ -300,11 +398,30 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
} }
Self::Mint { Self::Mint {
definition, definition,
definition_label,
holder, holder,
holder_label,
holder_npk, holder_npk,
holder_vpk, holder_vpk,
amount, 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) { let underlying_subcommand = match (holder, holder_npk, holder_vpk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( anyhow::bail!(

View File

@ -49,6 +49,66 @@ impl From<Account> 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<String>,
label: Option<String>,
labels: &HashMap<String, Label>,
user_data: &NSSAUserData,
) -> Result<String> {
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<String, Label>,
user_data: &NSSAUserData,
) -> Result<String> {
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. /// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed.
fn get_home_nssa_var() -> Result<PathBuf> { fn get_home_nssa_var() -> Result<PathBuf> {
Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?) Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?)