From ea4a149585b5c0c7d72397ccdc91c1effafecc7c Mon Sep 17 00:00:00 2001 From: fryorcraken Date: Fri, 13 Mar 2026 13:33:51 +1100 Subject: [PATCH 1/4] 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 --account-label alice` should error 5. Test shell completions: `wallet account get --account-label ` 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 --- completions/bash/wallet | 169 +++++++++++++-- completions/zsh/_wallet | 60 +++++- wallet/src/cli/account.rs | 52 ++++- wallet/src/cli/programs/amm.rs | 200 ++++++++++++++++-- .../src/cli/programs/native_token_transfer.rs | 64 +++++- wallet/src/cli/programs/pinata.rs | 21 +- wallet/src/cli/programs/token.rs | 147 +++++++++++-- wallet/src/helperfunctions.rs | 60 ++++++ 8 files changed, 686 insertions(+), 87 deletions(-) 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)?)?) From 31fb89e992e349151987a5cc95d48817b4da23af Mon Sep 17 00:00:00 2001 From: fryorcraken Date: Mon, 16 Mar 2026 15:20:00 +1100 Subject: [PATCH 2/4] fix tests --- integration_tests/tests/amm.rs | 65 +++++--- .../tests/auth_transfer/private.rs | 44 +++-- .../tests/auth_transfer/public.rs | 23 ++- integration_tests/tests/indexer.rs | 36 ++++- integration_tests/tests/keys_restoration.rs | 45 +++--- integration_tests/tests/pinata.rs | 20 ++- integration_tests/tests/token.rs | 153 +++++++++++------- 7 files changed, 263 insertions(+), 123 deletions(-) diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index 42aa5f3f..1c6c5410 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -113,9 +113,12 @@ async fn amm_public() -> Result<()> { // Create new token let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_public_account_id(definition_account_id_1), - supply_account_id: format_public_account_id(supply_account_id_1), - name: "A NAM1".to_owned(), + definition_account_id: Some(format_public_account_id(definition_account_id_1)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id_1)), + supply_account_label: None, + name: "A NAM1".to_string(), + total_supply: 37, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -124,8 +127,10 @@ async fn amm_public() -> Result<()> { // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id_1` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: format_public_account_id(supply_account_id_1), + from: Some(format_public_account_id(supply_account_id_1)), + from_label: None, to: Some(format_public_account_id(recipient_account_id_1)), + to_label: None, to_npk: None, to_vpk: None, amount: 7, @@ -137,9 +142,12 @@ async fn amm_public() -> Result<()> { // Create new token let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_public_account_id(definition_account_id_2), - supply_account_id: format_public_account_id(supply_account_id_2), - name: "A NAM2".to_owned(), + definition_account_id: Some(format_public_account_id(definition_account_id_2)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id_2)), + supply_account_label: None, + name: "A NAM2".to_string(), + total_supply: 37, }; wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; @@ -148,8 +156,10 @@ async fn amm_public() -> Result<()> { // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id_2` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: format_public_account_id(supply_account_id_2), + from: Some(format_public_account_id(supply_account_id_2)), + from_label: None, to: Some(format_public_account_id(recipient_account_id_2)), + to_label: None, to_npk: None, to_vpk: None, amount: 7, @@ -181,9 +191,12 @@ async fn amm_public() -> Result<()> { // Send creation tx let subcommand = AmmProgramAgnosticSubcommand::New { - user_holding_a: format_public_account_id(recipient_account_id_1), - user_holding_b: format_public_account_id(recipient_account_id_2), - user_holding_lp: format_public_account_id(user_holding_lp), + user_holding_a: Some(format_public_account_id(recipient_account_id_1)), + user_holding_a_label: None, + user_holding_b: Some(format_public_account_id(recipient_account_id_2)), + user_holding_b_label: None, + user_holding_lp: Some(format_public_account_id(user_holding_lp)), + user_holding_lp_label: None, balance_a: 3, balance_b: 3, }; @@ -224,8 +237,10 @@ async fn amm_public() -> Result<()> { // Make swap let subcommand = AmmProgramAgnosticSubcommand::Swap { - user_holding_a: format_public_account_id(recipient_account_id_1), - user_holding_b: format_public_account_id(recipient_account_id_2), + user_holding_a: Some(format_public_account_id(recipient_account_id_1)), + user_holding_a_label: None, + user_holding_b: Some(format_public_account_id(recipient_account_id_2)), + user_holding_b_label: None, amount_in: 2, min_amount_out: 1, token_definition: definition_account_id_1.to_string(), @@ -267,8 +282,10 @@ async fn amm_public() -> Result<()> { // Make swap let subcommand = AmmProgramAgnosticSubcommand::Swap { - user_holding_a: format_public_account_id(recipient_account_id_1), - user_holding_b: format_public_account_id(recipient_account_id_2), + user_holding_a: Some(format_public_account_id(recipient_account_id_1)), + user_holding_a_label: None, + user_holding_b: Some(format_public_account_id(recipient_account_id_2)), + user_holding_b_label: None, amount_in: 2, min_amount_out: 1, token_definition: definition_account_id_2.to_string(), @@ -310,9 +327,12 @@ async fn amm_public() -> Result<()> { // Add liquidity let subcommand = AmmProgramAgnosticSubcommand::AddLiquidity { - user_holding_a: format_public_account_id(recipient_account_id_1), - user_holding_b: format_public_account_id(recipient_account_id_2), - user_holding_lp: format_public_account_id(user_holding_lp), + user_holding_a: Some(format_public_account_id(recipient_account_id_1)), + user_holding_a_label: None, + user_holding_b: Some(format_public_account_id(recipient_account_id_2)), + user_holding_b_label: None, + user_holding_lp: Some(format_public_account_id(user_holding_lp)), + user_holding_lp_label: None, min_amount_lp: 1, max_amount_a: 2, max_amount_b: 2, @@ -354,9 +374,12 @@ async fn amm_public() -> Result<()> { // Remove liquidity let subcommand = AmmProgramAgnosticSubcommand::RemoveLiquidity { - user_holding_a: format_public_account_id(recipient_account_id_1), - user_holding_b: format_public_account_id(recipient_account_id_2), - user_holding_lp: format_public_account_id(user_holding_lp), + user_holding_a: Some(format_public_account_id(recipient_account_id_1)), + user_holding_a_label: None, + user_holding_b: Some(format_public_account_id(recipient_account_id_2)), + user_holding_b_label: None, + user_holding_lp: Some(format_public_account_id(user_holding_lp)), + user_holding_lp_label: None, balance_lp: 2, min_amount_a: 1, min_amount_b: 1, diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 59b4719a..01376386 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -8,7 +8,6 @@ use integration_tests::{ use log::info; use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; -use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -24,8 +23,10 @@ async fn private_transfer_to_owned_account() -> Result<()> { let to: AccountId = ctx.existing_private_accounts()[1]; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: Some(format_private_account_id(to)), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -63,8 +64,10 @@ async fn private_transfer_to_foreign_account() -> Result<()> { let to_vpk = Secp256k1Point::from_scalar(to_npk.0); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: None, + to_label: None, to_npk: Some(to_npk_string), to_vpk: Some(hex::encode(to_vpk.0)), amount: 100, @@ -87,7 +90,7 @@ async fn private_transfer_to_foreign_account() -> Result<()> { assert_eq!(tx.message.new_commitments[0], new_commitment1); assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments { + for commitment in tx.message.new_commitments.into_iter() { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } @@ -111,8 +114,10 @@ async fn deshielded_transfer_to_public_account() -> Result<()> { assert_eq!(from_acc.balance, 10000); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: Some(format_public_account_id(to)), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -136,7 +141,7 @@ async fn deshielded_transfer_to_public_account() -> Result<()> { let acc_2_balance = ctx.sequencer_client().get_account_balance(to).await?; assert_eq!(from_acc.balance, 9900); - assert_eq!(acc_2_balance, 20100); + assert_eq!(acc_2_balance.balance, 20100); info!("Successfully deshielded transfer to public account"); @@ -174,8 +179,10 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> { // Send to this account using claiming path (using npk and vpk instead of account ID) let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: None, + to_label: None, to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)), to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)), amount: 100, @@ -199,7 +206,7 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> { assert_eq!(tx.message.new_commitments[0], new_commitment1); assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments { + for commitment in tx.message.new_commitments.into_iter() { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } @@ -222,8 +229,10 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> { let to: AccountId = ctx.existing_private_accounts()[1]; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(from), + from: Some(format_public_account_id(from)), + from_label: None, to: Some(format_private_account_id(to)), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -246,7 +255,7 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> { let acc_from_balance = ctx.sequencer_client().get_account_balance(from).await?; - assert_eq!(acc_from_balance, 9900); + assert_eq!(acc_from_balance.balance, 9900); assert_eq!(acc_to.balance, 20100); info!("Successfully shielded transfer to owned private account"); @@ -264,8 +273,10 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> { let from: AccountId = ctx.existing_public_accounts()[0]; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(from), + from: Some(format_public_account_id(from)), + from_label: None, to: None, + to_label: None, to_npk: Some(to_npk_string), to_vpk: Some(hex::encode(to_vpk.0)), amount: 100, @@ -291,7 +302,7 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> { .await ); - assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_1_balance.balance, 9900); info!("Successfully shielded transfer to foreign account"); @@ -334,8 +345,10 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { // Send transfer using nullifier and viewing public keys let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: None, + to_label: None, to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)), to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)), amount: 100, @@ -354,7 +367,7 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { // Verify commitments are in state assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments { + for commitment in tx.message.new_commitments.into_iter() { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } @@ -383,7 +396,8 @@ async fn initialize_private_account() -> Result<()> { }; let command = Command::AuthTransfer(AuthTransferSubcommand::Init { - account_id: format_private_account_id(account_id), + account_id: Some(format_private_account_id(account_id)), + account_label: None, }); wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index 7f8c3836..80f9d4e4 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -17,8 +17,10 @@ async fn successful_transfer_to_existing_account() -> Result<()> { let mut ctx = TestContext::new().await?; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(ctx.existing_public_accounts()[0]), + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -73,8 +75,10 @@ pub async fn successful_transfer_to_new_account() -> Result<()> { .expect("Failed to find newly created account in the wallet storage"); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(ctx.existing_public_accounts()[0]), + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, to: Some(format_public_account_id(new_persistent_account_id)), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -109,8 +113,10 @@ async fn failed_transfer_with_insufficient_balance() -> Result<()> { let mut ctx = TestContext::new().await?; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(ctx.existing_public_accounts()[0]), + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + to_label: None, to_npk: None, to_vpk: None, amount: 1_000_000, @@ -147,8 +153,10 @@ async fn two_consecutive_successful_transfers() -> Result<()> { // First transfer let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(ctx.existing_public_accounts()[0]), + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -179,8 +187,10 @@ async fn two_consecutive_successful_transfers() -> Result<()> { // Second transfer let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(ctx.existing_public_accounts()[0]), + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -226,7 +236,8 @@ async fn initialize_public_account() -> Result<()> { }; let command = Command::AuthTransfer(AuthTransferSubcommand::Init { - account_id: format_public_account_id(account_id), + account_id: Some(format_public_account_id(account_id)), + account_label: None, }); wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index cb8cf0e9..4c9c5ee6 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -83,8 +83,10 @@ async fn indexer_state_consistency() -> Result<()> { let mut ctx = TestContext::new().await?; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(ctx.existing_public_accounts()[0]), + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -113,6 +115,38 @@ async fn indexer_state_consistency() -> Result<()> { assert_eq!(acc_1_balance, 9900); assert_eq!(acc_2_balance, 20100); + let from: AccountId = ctx.existing_private_accounts()[0]; + let to: AccountId = ctx.existing_private_accounts()[1]; + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: Some(format_private_account_id(from)), + from_label: None, + to: Some(format_private_account_id(to)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let new_commitment1 = ctx + .wallet() + .get_private_account_commitment(from) + .context("Failed to get private account commitment for sender")?; + assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await); + + let new_commitment2 = ctx + .wallet() + .get_private_account_commitment(to) + .context("Failed to get private account commitment for receiver")?; + assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await); + + info!("Successfully transferred privately to owned account"); + // WAIT info!("Waiting for indexer to parse blocks"); tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await; diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index cdbe2e6b..4e8d9bf9 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -1,12 +1,6 @@ -#![expect( - clippy::shadow_unrelated, - clippy::tests_outside_test_module, - reason = "We don't care about these in tests" -)] +use std::{str::FromStr, time::Duration}; -use std::{str::FromStr as _, time::Duration}; - -use anyhow::{Context as _, Result}; +use anyhow::{Context, Result}; use integration_tests::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, fetch_privacy_preserving_tx, format_private_account_id, format_public_account_id, verify_commitment_is_in_state, @@ -14,7 +8,6 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::{AccountId, program::Program}; -use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -69,8 +62,10 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> { // Send to this account using claiming path (using npk and vpk instead of account ID) let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: None, + to_label: None, to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)), to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)), amount: 100, @@ -94,7 +89,7 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> { assert_eq!(tx.message.new_commitments[0], new_commitment1); assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments { + for commitment in tx.message.new_commitments.into_iter() { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } @@ -143,8 +138,10 @@ async fn restore_keys_from_seed() -> Result<()> { // Send to first private account let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: Some(format_private_account_id(to_account_id1)), + to_label: None, to_npk: None, to_vpk: None, amount: 100, @@ -153,8 +150,10 @@ async fn restore_keys_from_seed() -> Result<()> { // Send to second private account let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(from), + from: Some(format_private_account_id(from)), + from_label: None, to: Some(format_private_account_id(to_account_id2)), + to_label: None, to_npk: None, to_vpk: None, amount: 101, @@ -191,8 +190,10 @@ async fn restore_keys_from_seed() -> Result<()> { // Send to first public account let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(from), + from: Some(format_public_account_id(from)), + from_label: None, to: Some(format_public_account_id(to_account_id3)), + to_label: None, to_npk: None, to_vpk: None, amount: 102, @@ -201,8 +202,10 @@ async fn restore_keys_from_seed() -> Result<()> { // Send to second public account let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(from), + from: Some(format_public_account_id(from)), + from_label: None, to: Some(format_public_account_id(to_account_id4)), + to_label: None, to_npk: None, to_vpk: None, amount: 103, @@ -264,8 +267,10 @@ async fn restore_keys_from_seed() -> Result<()> { // Test that restored accounts can send transactions let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_private_account_id(to_account_id1), + from: Some(format_private_account_id(to_account_id1)), + from_label: None, to: Some(format_private_account_id(to_account_id2)), + to_label: None, to_npk: None, to_vpk: None, amount: 10, @@ -273,8 +278,10 @@ async fn restore_keys_from_seed() -> Result<()> { wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: format_public_account_id(to_account_id3), + from: Some(format_public_account_id(to_account_id3)), + from_label: None, to: Some(format_public_account_id(to_account_id4)), + to_label: None, to_npk: None, to_vpk: None, amount: 11, @@ -306,8 +313,8 @@ async fn restore_keys_from_seed() -> Result<()> { .get_account_balance(to_account_id4) .await?; - assert_eq!(acc3, 91); // 102 - 11 - assert_eq!(acc4, 114); // 103 + 11 + assert_eq!(acc3.balance, 91); // 102 - 11 + assert_eq!(acc4.balance, 114); // 103 + 11 info!("Successfully restored keys and verified transactions"); diff --git a/integration_tests/tests/pinata.rs b/integration_tests/tests/pinata.rs index 3285c216..77c4a646 100644 --- a/integration_tests/tests/pinata.rs +++ b/integration_tests/tests/pinata.rs @@ -52,7 +52,8 @@ async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()> let claim_result = wallet::cli::execute_subcommand( ctx.wallet_mut(), Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to: winner_account_id_formatted, + to: Some(winner_account_id_formatted), + to_label: None, }), ) .await; @@ -106,7 +107,8 @@ async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<() let claim_result = wallet::cli::execute_subcommand( ctx.wallet_mut(), Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to: winner_account_id_formatted, + to: Some(winner_account_id_formatted), + to_label: None, }), ) .await; @@ -137,7 +139,8 @@ async fn claim_pinata_to_existing_public_account() -> Result<()> { let pinata_prize = 150; let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to: format_public_account_id(ctx.existing_public_accounts()[0]), + to: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + to_label: None, }); let pinata_balance_pre = ctx @@ -175,7 +178,10 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> { let pinata_prize = 150; let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to: format_private_account_id(ctx.existing_private_accounts()[0]), + to: Some(format_private_account_id( + ctx.existing_private_accounts()[0], + )), + to_label: None, }); let pinata_balance_pre = ctx @@ -239,7 +245,8 @@ async fn claim_pinata_to_new_private_account() -> Result<()> { // Initialize account under auth transfer program let command = Command::AuthTransfer(AuthTransferSubcommand::Init { - account_id: winner_account_id_formatted.clone(), + account_id: Some(winner_account_id_formatted.clone()), + account_label: None, }); wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; @@ -254,7 +261,8 @@ async fn claim_pinata_to_new_private_account() -> Result<()> { // Claim pinata to the new private account let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to: winner_account_id_formatted, + to: Some(winner_account_id_formatted), + to_label: None, }); let pinata_balance_pre = ctx diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index b638b6c9..43b47ee0 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -1,9 +1,3 @@ -#![expect( - clippy::shadow_unrelated, - clippy::tests_outside_test_module, - reason = "We don't care about these in tests" -)] - use std::time::Duration; use anyhow::{Context as _, Result}; @@ -14,7 +8,6 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::program::Program; -use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; use tokio::test; use wallet::cli::{ @@ -76,11 +69,13 @@ async fn create_and_transfer_public_token() -> Result<()> { }; // Create new token - let name = "A NAME".to_owned(); + let name = "A NAME".to_string(); let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_public_account_id(definition_account_id), - supply_account_id: format_public_account_id(supply_account_id), + definition_account_id: Some(format_public_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id)), + supply_account_label: None, name: name.clone(), total_supply, }; @@ -93,7 +88,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await?; + .await? + .account; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -110,7 +106,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await?; + .await? + .account; // The account must be owned by the token program assert_eq!(supply_acc.program_owner, Program::token().id()); @@ -126,8 +123,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Transfer 7 tokens from supply_acc to recipient_account_id let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { - from: format_public_account_id(supply_account_id), + from: Some(format_public_account_id(supply_account_id)), + from_label: None, to: Some(format_public_account_id(recipient_account_id)), + to_label: None, to_npk: None, to_vpk: None, amount: transfer_amount, @@ -142,7 +141,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await?; + .await? + .account; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( @@ -157,7 +157,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await?; + .await? + .account; assert_eq!(recipient_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -171,8 +172,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Burn 3 tokens from recipient_acc let burn_amount = 3; let subcommand = TokenProgramAgnosticSubcommand::Burn { - definition: format_public_account_id(definition_account_id), - holder: format_public_account_id(recipient_account_id), + definition: Some(format_public_account_id(definition_account_id)), + definition_label: None, + holder: Some(format_public_account_id(recipient_account_id)), + holder_label: None, amount: burn_amount, }; @@ -185,7 +188,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await?; + .await? + .account; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -201,7 +205,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await?; + .await? + .account; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -215,8 +220,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Mint 10 tokens at recipient_acc let mint_amount = 10; let subcommand = TokenProgramAgnosticSubcommand::Mint { - definition: format_public_account_id(definition_account_id), + definition: Some(format_public_account_id(definition_account_id)), + definition_label: None, holder: Some(format_public_account_id(recipient_account_id)), + holder_label: None, holder_npk: None, holder_vpk: None, amount: mint_amount, @@ -231,7 +238,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await?; + .await? + .account; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -247,7 +255,8 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await?; + .await? + .account; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -316,11 +325,13 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { }; // Create new token - let name = "A NAME".to_owned(); + let name = "A NAME".to_string(); let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_public_account_id(definition_account_id), - supply_account_id: format_private_account_id(supply_account_id), + definition_account_id: Some(format_public_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_private_account_id(supply_account_id)), + supply_account_label: None, name: name.clone(), total_supply, }; @@ -334,7 +345,8 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await?; + .await? + .account; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -356,8 +368,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Transfer 7 tokens from supply_acc to recipient_account_id let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { - from: format_private_account_id(supply_account_id), + from: Some(format_private_account_id(supply_account_id)), + from_label: None, to: Some(format_private_account_id(recipient_account_id)), + to_label: None, to_npk: None, to_vpk: None, amount: transfer_amount, @@ -383,8 +397,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Burn 3 tokens from recipient_acc let burn_amount = 3; let subcommand = TokenProgramAgnosticSubcommand::Burn { - definition: format_public_account_id(definition_account_id), - holder: format_private_account_id(recipient_account_id), + definition: Some(format_public_account_id(definition_account_id)), + definition_label: None, + holder: Some(format_private_account_id(recipient_account_id)), + holder_label: None, amount: burn_amount, }; @@ -397,7 +413,8 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await?; + .await? + .account; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -472,11 +489,13 @@ async fn create_token_with_private_definition() -> Result<()> { }; // Create token with private definition - let name = "A NAME".to_owned(); + let name = "A NAME".to_string(); let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_private_account_id(definition_account_id), - supply_account_id: format_public_account_id(supply_account_id), + definition_account_id: Some(format_private_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id)), + supply_account_label: None, name: name.clone(), total_supply, }; @@ -497,7 +516,8 @@ async fn create_token_with_private_definition() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await?; + .await? + .account; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; @@ -544,8 +564,10 @@ async fn create_token_with_private_definition() -> Result<()> { // Mint to public account let mint_amount_public = 10; let subcommand = TokenProgramAgnosticSubcommand::Mint { - definition: format_private_account_id(definition_account_id), + definition: Some(format_private_account_id(definition_account_id)), + definition_label: None, holder: Some(format_public_account_id(recipient_account_id_public)), + holder_label: None, holder_npk: None, holder_vpk: None, amount: mint_amount_public, @@ -576,7 +598,8 @@ async fn create_token_with_private_definition() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id_public) - .await?; + .await? + .account; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -590,8 +613,10 @@ async fn create_token_with_private_definition() -> Result<()> { // Mint to private account let mint_amount_private = 5; let subcommand = TokenProgramAgnosticSubcommand::Mint { - definition: format_private_account_id(definition_account_id), + definition: Some(format_private_account_id(definition_account_id)), + definition_label: None, holder: Some(format_private_account_id(recipient_account_id_private)), + holder_label: None, holder_npk: None, holder_vpk: None, amount: mint_amount_private, @@ -666,11 +691,13 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { }; // Create token with both private definition and supply - let name = "A NAME".to_owned(); + let name = "A NAME".to_string(); let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_private_account_id(definition_account_id), - supply_account_id: format_private_account_id(supply_account_id), + definition_account_id: Some(format_private_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_private_account_id(supply_account_id)), + supply_account_label: None, name, total_supply, }; @@ -728,8 +755,10 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { // Transfer tokens let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { - from: format_private_account_id(supply_account_id), + from: Some(format_private_account_id(supply_account_id)), + from_label: None, to: Some(format_private_account_id(recipient_account_id)), + to_label: None, to_npk: None, to_vpk: None, amount: transfer_amount, @@ -838,11 +867,13 @@ async fn shielded_token_transfer() -> Result<()> { }; // Create token - let name = "A NAME".to_owned(); + let name = "A NAME".to_string(); let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_public_account_id(definition_account_id), - supply_account_id: format_public_account_id(supply_account_id), + definition_account_id: Some(format_public_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id)), + supply_account_label: None, name, total_supply, }; @@ -855,8 +886,10 @@ async fn shielded_token_transfer() -> Result<()> { // Perform shielded transfer: public supply -> private recipient let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { - from: format_public_account_id(supply_account_id), + from: Some(format_public_account_id(supply_account_id)), + from_label: None, to: Some(format_private_account_id(recipient_account_id)), + to_label: None, to_npk: None, to_vpk: None, amount: transfer_amount, @@ -871,7 +904,8 @@ async fn shielded_token_transfer() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await?; + .await? + .account; let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( token_holding, @@ -960,11 +994,13 @@ async fn deshielded_token_transfer() -> Result<()> { }; // Create token with private supply - let name = "A NAME".to_owned(); + let name = "A NAME".to_string(); let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_public_account_id(definition_account_id), - supply_account_id: format_private_account_id(supply_account_id), + definition_account_id: Some(format_public_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_private_account_id(supply_account_id)), + supply_account_label: None, name, total_supply, }; @@ -977,8 +1013,10 @@ async fn deshielded_token_transfer() -> Result<()> { // Perform deshielded transfer: private supply -> public recipient let transfer_amount = 7; let subcommand = TokenProgramAgnosticSubcommand::Send { - from: format_private_account_id(supply_account_id), + from: Some(format_private_account_id(supply_account_id)), + from_label: None, to: Some(format_public_account_id(recipient_account_id)), + to_label: None, to_npk: None, to_vpk: None, amount: transfer_amount, @@ -1014,7 +1052,8 @@ async fn deshielded_token_transfer() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await?; + .await? + .account; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( token_holding, @@ -1066,11 +1105,13 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { }; // Create token - let name = "A NAME".to_owned(); + let name = "A NAME".to_string(); let total_supply = 37; let subcommand = TokenProgramAgnosticSubcommand::New { - definition_account_id: format_private_account_id(definition_account_id), - supply_account_id: format_private_account_id(supply_account_id), + definition_account_id: Some(format_private_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_private_account_id(supply_account_id)), + supply_account_label: None, name, total_supply, }; @@ -1108,8 +1149,10 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { // Mint using claiming path (foreign account) let mint_amount = 9; let subcommand = TokenProgramAgnosticSubcommand::Mint { - definition: format_private_account_id(definition_account_id), + definition: Some(format_private_account_id(definition_account_id)), + definition_label: None, holder: None, + holder_label: None, holder_npk: Some(hex::encode(holder_keys.nullifier_public_key.0)), holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.0)), amount: mint_amount, From bab6aaf947466892b7faa2accf221241dac5e8c2 Mon Sep 17 00:00:00 2001 From: fryorcraken Date: Tue, 24 Mar 2026 12:04:13 +1100 Subject: [PATCH 3/4] revert changes and add tests --- integration_tests/tests/amm.rs | 185 ++++++++++++++ .../tests/auth_transfer/private.rs | 104 +++++++- .../tests/auth_transfer/public.rs | 94 +++++++ integration_tests/tests/indexer.rs | 81 +++++- integration_tests/tests/keys_restoration.rs | 11 +- integration_tests/tests/token.rs | 239 ++++++++++++++++-- 6 files changed, 679 insertions(+), 35 deletions(-) diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index 1c6c5410..ef5af047 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -420,3 +420,188 @@ async fn amm_public() -> Result<()> { Ok(()) } + +#[test] +async fn amm_new_pool_using_labels() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create token 1 accounts + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id_1, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id_1, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create holding_a with a label + let holding_a_label = "amm-holding-a-label".to_owned(); + let SubcommandReturnValue::RegisterAccount { + account_id: holding_a_id, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(holding_a_label.clone()), + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token 2 accounts + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id_2, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id_2, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create holding_b with a label + let holding_b_label = "amm-holding-b-label".to_owned(); + let SubcommandReturnValue::RegisterAccount { + account_id: holding_b_id, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(holding_b_label.clone()), + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create holding_lp with a label + let holding_lp_label = "amm-holding-lp-label".to_owned(); + let SubcommandReturnValue::RegisterAccount { + account_id: holding_lp_id, + } = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(holding_lp_label.clone()), + })), + ) + .await? + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token 1 and distribute to holding_a + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: Some(format_public_account_id(definition_account_id_1)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id_1)), + supply_account_label: None, + name: "TOKEN1".to_string(), + total_supply: 10, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: Some(format_public_account_id(supply_account_id_1)), + from_label: None, + to: Some(format_public_account_id(holding_a_id)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 5, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // Create token 2 and distribute to holding_b + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: Some(format_public_account_id(definition_account_id_2)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id_2)), + supply_account_label: None, + name: "TOKEN2".to_string(), + total_supply: 10, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: Some(format_public_account_id(supply_account_id_2)), + from_label: None, + to: Some(format_public_account_id(holding_b_id)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 5, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // Create AMM pool using account labels instead of IDs + let subcommand = AmmProgramAgnosticSubcommand::New { + user_holding_a: None, + user_holding_a_label: Some(holding_a_label), + user_holding_b: None, + user_holding_b_label: Some(holding_b_label), + user_holding_lp: None, + user_holding_lp_label: Some(holding_lp_label), + balance_a: 3, + balance_b: 3, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::AMM(subcommand)).await?; + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let holding_lp_acc = ctx.sequencer_client().get_account(holding_lp_id).await?; + + // LP balance should be 3 (geometric mean of 3, 3) + assert_eq!( + u128::from_le_bytes(holding_lp_acc.data[33..].try_into().unwrap()), + 3 + ); + + info!("Successfully created AMM pool using account labels"); + + Ok(()) +} diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 01376386..9ffbcb0d 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -8,6 +8,7 @@ use integration_tests::{ use log::info; use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -141,7 +142,7 @@ async fn deshielded_transfer_to_public_account() -> Result<()> { let acc_2_balance = ctx.sequencer_client().get_account_balance(to).await?; assert_eq!(from_acc.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); + assert_eq!(acc_2_balance, 20100); info!("Successfully deshielded transfer to public account"); @@ -255,7 +256,7 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> { let acc_from_balance = ctx.sequencer_client().get_account_balance(from).await?; - assert_eq!(acc_from_balance.balance, 9900); + assert_eq!(acc_from_balance, 9900); assert_eq!(acc_to.balance, 20100); info!("Successfully shielded transfer to owned private account"); @@ -302,7 +303,7 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> { .await ); - assert_eq!(acc_1_balance.balance, 9900); + assert_eq!(acc_1_balance, 9900); info!("Successfully shielded transfer to foreign account"); @@ -429,3 +430,100 @@ async fn initialize_private_account() -> Result<()> { Ok(()) } + +#[test] +async fn private_transfer_using_from_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let from: AccountId = ctx.existing_private_accounts()[0]; + let to: AccountId = ctx.existing_private_accounts()[1]; + + // Assign a label to the sender account + let label = "private-sender-label".to_owned(); + let command = Command::Account(AccountSubcommand::Label { + account_id: Some(format_private_account_id(from)), + account_label: None, + label: label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + // Send using the label instead of account ID + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: None, + from_label: Some(label), + to: Some(format_private_account_id(to)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let new_commitment1 = ctx + .wallet() + .get_private_account_commitment(from) + .context("Failed to get private account commitment for sender")?; + assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await); + + let new_commitment2 = ctx + .wallet() + .get_private_account_commitment(to) + .context("Failed to get private account commitment for receiver")?; + assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await); + + info!("Successfully transferred privately using from_label"); + + Ok(()) +} + +#[test] +async fn initialize_private_account_using_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create a new private account with a label + let label = "init-private-label".to_owned(); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: Some(label.clone()), + })); + let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + let SubcommandReturnValue::RegisterAccount { account_id } = result else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Initialize using the label instead of account ID + let command = Command::AuthTransfer(AuthTransferSubcommand::Init { + account_id: None, + account_label: Some(label), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let command = Command::Account(AccountSubcommand::SyncPrivate {}); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + let new_commitment = ctx + .wallet() + .get_private_account_commitment(account_id) + .context("Failed to get private account commitment")?; + assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await); + + let account = ctx + .wallet() + .get_account_private(account_id) + .context("Failed to get private account")?; + + assert_eq!( + account.program_owner, + Program::authenticated_transfer_program().id() + ); + + info!("Successfully initialized private account using label"); + + Ok(()) +} diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index 80f9d4e4..416c4490 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -256,3 +256,97 @@ async fn initialize_public_account() -> Result<()> { Ok(()) } + +#[test] +async fn successful_transfer_using_from_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Assign a label to the sender account + let label = "sender-label".to_owned(); + let command = Command::Account(AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + account_label: None, + label: label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + // Send using the label instead of account ID + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: None, + from_label: Some(label), + to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + to_label: None, + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[0]) + .await?; + let acc_2_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[1]) + .await?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Successfully transferred using from_label"); + + Ok(()) +} + +#[test] +async fn successful_transfer_using_to_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Assign a label to the receiver account + let label = "receiver-label".to_owned(); + let command = Command::Account(AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + account_label: None, + label: label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + // Send using the label for the recipient + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + from_label: None, + to: None, + to_label: Some(label), + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[0]) + .await?; + let acc_2_balance = ctx + .sequencer_client() + .get_account_balance(ctx.existing_public_accounts()[1]) + .await?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Successfully transferred using to_label"); + + Ok(()) +} diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index 4c9c5ee6..5f814e32 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -5,10 +5,14 @@ use std::time::Duration; -use anyhow::Result; +use anyhow::{Context as _, Result}; use indexer_service_rpc::RpcClient as _; -use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_public_account_id}; +use integration_tests::{ + TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_private_account_id, + format_public_account_id, verify_commitment_is_in_state, +}; use log::info; +use nssa::AccountId; use tokio::test; use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand}; @@ -181,3 +185,76 @@ async fn indexer_state_consistency() -> Result<()> { Ok(()) } + +#[test] +async fn indexer_state_consistency_with_labels() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Assign labels to both accounts + let from_label = "idx-sender-label".to_owned(); + let to_label_str = "idx-receiver-label".to_owned(); + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[0])), + account_label: None, + label: from_label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: Some(format_public_account_id(ctx.existing_public_accounts()[1])), + account_label: None, + label: to_label_str.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; + + // Send using labels instead of account IDs + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: None, + from_label: Some(from_label), + to: None, + to_label: Some(to_label_str), + to_npk: None, + to_vpk: None, + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let acc_1_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + let acc_2_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + .await?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Waiting for indexer to parse blocks"); + tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await; + + let acc1_ind_state = ctx + .indexer_client() + .get_account(ctx.existing_public_accounts()[0].into()) + .await + .unwrap(); + let acc1_seq_state = sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + + assert_eq!(acc1_ind_state, acc1_seq_state.into()); + + info!("Indexer state is consistent after label-based transfer"); + + Ok(()) +} diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index 4e8d9bf9..7b9c3ab6 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -1,3 +1,9 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + use std::{str::FromStr, time::Duration}; use anyhow::{Context, Result}; @@ -8,6 +14,7 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::{AccountId, program::Program}; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -313,8 +320,8 @@ async fn restore_keys_from_seed() -> Result<()> { .get_account_balance(to_account_id4) .await?; - assert_eq!(acc3.balance, 91); // 102 - 11 - assert_eq!(acc4.balance, 114); // 103 + 11 + assert_eq!(acc3, 91); // 102 - 11 + assert_eq!(acc4, 114); // 103 + 11 info!("Successfully restored keys and verified transactions"); diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 43b47ee0..0e89259d 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -1,3 +1,9 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + use std::time::Duration; use anyhow::{Context as _, Result}; @@ -8,6 +14,7 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::program::Program; +use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; use tokio::test; use wallet::cli::{ @@ -88,8 +95,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -106,8 +112,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; // The account must be owned by the token program assert_eq!(supply_acc.program_owner, Program::token().id()); @@ -141,8 +146,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( @@ -157,8 +161,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; assert_eq!(recipient_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -188,8 +191,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -205,8 +207,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -238,8 +239,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -255,8 +255,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -345,8 +344,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -413,8 +411,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -516,8 +513,7 @@ async fn create_token_with_private_definition() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; @@ -598,8 +594,7 @@ async fn create_token_with_private_definition() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id_public) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -904,8 +899,7 @@ async fn shielded_token_transfer() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( token_holding, @@ -1052,8 +1046,7 @@ async fn deshielded_token_transfer() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( token_holding, @@ -1192,3 +1185,193 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { Ok(()) } + +#[test] +async fn create_token_using_labels() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create definition and supply accounts with labels + let def_label = "token-definition-label".to_owned(); + let supply_label = "token-supply-label".to_owned(); + + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(def_label.clone()), + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(supply_label.clone()), + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token using account labels instead of IDs + let name = "LABELED TOKEN".to_string(); + let total_supply = 100; + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: None, + definition_account_label: Some(def_label), + supply_account_id: None, + supply_account_label: Some(supply_label), + name: name.clone(), + total_supply, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let definition_acc = ctx + .sequencer_client() + .get_account(definition_account_id) + .await?; + let token_definition = TokenDefinition::try_from(&definition_acc.data)?; + + assert_eq!(definition_acc.program_owner, Program::token().id()); + assert_eq!( + token_definition, + TokenDefinition::Fungible { + name, + total_supply, + metadata_id: None + } + ); + + let supply_acc = ctx + .sequencer_client() + .get_account(supply_account_id) + .await?; + let token_holding = TokenHolding::try_from(&supply_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: total_supply + } + ); + + info!("Successfully created token using definition and supply account labels"); + + Ok(()) +} + +#[test] +async fn transfer_token_using_from_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Create definition account + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: definition_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create supply account with a label + let supply_label = "token-supply-sender".to_owned(); + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(supply_label.clone()), + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create recipient account + let result = wallet::cli::execute_subcommand( + ctx.wallet_mut(), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), + ) + .await?; + let SubcommandReturnValue::RegisterAccount { + account_id: recipient_account_id, + } = result + else { + anyhow::bail!("Expected RegisterAccount return value"); + }; + + // Create token + let total_supply = 50; + let subcommand = TokenProgramAgnosticSubcommand::New { + definition_account_id: Some(format_public_account_id(definition_account_id)), + definition_account_label: None, + supply_account_id: Some(format_public_account_id(supply_account_id)), + supply_account_label: None, + name: "LABEL TEST TOKEN".to_string(), + total_supply, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + // Transfer token using from_label instead of from + let transfer_amount = 20; + let subcommand = TokenProgramAgnosticSubcommand::Send { + from: None, + from_label: Some(supply_label), + to: Some(format_public_account_id(recipient_account_id)), + to_label: None, + to_npk: None, + to_vpk: None, + amount: transfer_amount, + }; + wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let recipient_acc = ctx + .sequencer_client() + .get_account(recipient_account_id) + .await?; + let token_holding = TokenHolding::try_from(&recipient_acc.data)?; + assert_eq!( + token_holding, + TokenHolding::Fungible { + definition_id: definition_account_id, + balance: transfer_amount + } + ); + + info!("Successfully transferred token using from_label"); + + Ok(()) +} From 86bfa20af9c13fdb952dd69b9343842f57d5ea13 Mon Sep 17 00:00:00 2001 From: fryorcraken Date: Tue, 24 Mar 2026 13:01:06 +1100 Subject: [PATCH 4/4] revert some changes --- integration_tests/tests/indexer.rs | 1 + integration_tests/tests/keys_restoration.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index 5f814e32..147cadec 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -1,4 +1,5 @@ #![expect( + clippy::shadow_unrelated, clippy::tests_outside_test_module, reason = "We don't care about these in tests" )] diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index 7b9c3ab6..8dca027c 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -4,9 +4,9 @@ reason = "We don't care about these in tests" )] -use std::{str::FromStr, time::Duration}; +use std::{str::FromStr as _, time::Duration}; -use anyhow::{Context, Result}; +use anyhow::{Context as _, Result}; use integration_tests::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, fetch_privacy_preserving_tx, format_private_account_id, format_public_account_id, verify_commitment_is_in_state, @@ -96,7 +96,7 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> { assert_eq!(tx.message.new_commitments[0], new_commitment1); assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { + for commitment in tx.message.new_commitments { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); }