From 60a7ffe46169e1092e480874172fb92b82e62123 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Wed, 30 Oct 2024 17:11:56 +0900 Subject: [PATCH] [token-cli] Upgrade to clap-v3 (#6376) * upgrade clap version to `3.2.23` * remove lifetime parameters from `ArgMatches` * remove extra lifetime parameters from `Arg` * remove extra lifetime parameters from `App` * use `usize` type parameters for `min_values` and `max_values` * use `char` type parameters for `short` arguments * update syntax for custom validator functions * update pattern matching syntax for `subcommand` * update for new `possible_values` syntax * allow deprecated input validation for now * resolve lifetime specifier issue with higher order validator functions * directly specify positional parameter indices * remove non-functioning `owner` alias in some subcommands * remove long names for positional arguments * remove potential panice from `value_of` and `is_present` * add custom `signer_from_path` and `signer_from_path_with_config` * cargo fmt * remove duplicate addition of args in invalid config test * use `try_get_one` to parse `compute_unit_price` and `compute_unit_limit` * hard-code `signer_arg` and `OfflineArgs` * replace `value_of` function * revert direct parser for `is_amount` validation --- Cargo.lock | 4 +- token/cli/Cargo.toml | 4 +- token/cli/src/bench.rs | 12 +- token/cli/src/clap_app.rs | 416 ++++++++++++++++++++----------------- token/cli/src/command.rs | 61 ++++-- token/cli/src/config.rs | 146 ++++++++++--- token/cli/src/main.rs | 3 +- token/cli/tests/command.rs | 9 +- token/cli/tests/config.rs | 7 +- 9 files changed, 395 insertions(+), 267 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 783195fa858..26701f60895 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7650,7 +7650,7 @@ version = "4.1.1" dependencies = [ "assert_cmd", "base64 0.22.1", - "clap 2.34.0", + "clap 3.2.25", "console", "futures 0.3.31", "libtest-mimic", @@ -7659,7 +7659,7 @@ dependencies = [ "serde_json", "serial_test", "solana-account-decoder", - "solana-clap-utils", + "solana-clap-v3-utils", "solana-cli-config", "solana-cli-output", "solana-client", diff --git a/token/cli/Cargo.toml b/token/cli/Cargo.toml index 364a6dadee0..aa3bef21f90 100644 --- a/token/cli/Cargo.toml +++ b/token/cli/Cargo.toml @@ -13,14 +13,14 @@ walkdir = "2" [dependencies] base64 = "0.22.1" -clap = "2.33.3" +clap = "3.2.23" console = "0.15.8" futures = "0.3" serde = "1.0.214" serde_derive = "1.0.103" serde_json = "1.0.132" solana-account-decoder = "2.0.3" -solana-clap-utils = "2.0.3" +solana-clap-v3-utils = "2.0.3" solana-cli-config = "2.0.3" solana-cli-output = "2.0.3" solana-client = "2.0.3" diff --git a/token/cli/src/bench.rs b/token/cli/src/bench.rs index e6e04ebe241..db58f5db97f 100644 --- a/token/cli/src/bench.rs +++ b/token/cli/src/bench.rs @@ -2,7 +2,7 @@ use { crate::{clap_app::Error, command::CommandResult, config::Config}, clap::{value_t_or_exit, ArgMatches}, - solana_clap_utils::input_parsers::pubkey_of_signer, + solana_clap_v3_utils::input_parsers::pubkey_of_signer, solana_client::{ nonblocking::rpc_client::RpcClient, rpc_client::RpcClient as BlockingRpcClient, tpu_client::TpuClient, tpu_client::TpuClientConfig, @@ -22,7 +22,7 @@ use { }; pub(crate) async fn bench_process_command( - matches: &ArgMatches<'_>, + matches: &ArgMatches, config: &Config<'_>, mut signers: Vec>, wallet_manager: &mut Option>, @@ -30,7 +30,7 @@ pub(crate) async fn bench_process_command( assert!(!config.sign_only); match matches.subcommand() { - ("create-accounts", Some(arg_matches)) => { + Some(("create-accounts", arg_matches)) => { let token = pubkey_of_signer(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); @@ -42,7 +42,7 @@ pub(crate) async fn bench_process_command( command_create_accounts(config, signers, &token, n, &owner).await?; } - ("close-accounts", Some(arg_matches)) => { + Some(("close-accounts", arg_matches)) => { let token = pubkey_of_signer(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); @@ -53,7 +53,7 @@ pub(crate) async fn bench_process_command( command_close_accounts(config, signers, &token, n, &owner).await?; } - ("deposit-into", Some(arg_matches)) => { + Some(("deposit-into", arg_matches)) => { let token = pubkey_of_signer(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); @@ -68,7 +68,7 @@ pub(crate) async fn bench_process_command( ) .await?; } - ("withdraw-from", Some(arg_matches)) => { + Some(("withdraw-from", arg_matches)) => { let token = pubkey_of_signer(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); diff --git a/token/cli/src/clap_app.rs b/token/cli/src/clap_app.rs index 74c5f4bf186..83183d88aa5 100644 --- a/token/cli/src/clap_app.rs +++ b/token/cli/src/clap_app.rs @@ -1,8 +1,10 @@ +#![allow(deprecated)] + use { clap::{ crate_description, crate_name, crate_version, App, AppSettings, Arg, ArgGroup, SubCommand, }, - solana_clap_utils::{ + solana_clap_v3_utils::{ fee_payer::fee_payer_arg, input_validators::{ is_amount, is_amount_or_all, is_parsable, is_pubkey, is_url_or_moniker, @@ -76,6 +78,41 @@ pub const COMPUTE_UNIT_LIMIT_ARG: ArgConstant<'static> = ArgConstant { help: "Set compute unit limit for transaction, in compute units.", }; +// The `signer_arg` in clap-v3-utils` specifies the argument as a +// `PubkeySignature` type, but supporting `PubkeySignature` in the token-cli +// requires a significant re-structuring of the code. Therefore, hard-code the +// `signer_arg` and `OfflineArgs` from clap-utils` here and remove +// it in a subsequent PR. +fn signer_arg<'a>() -> Arg<'a> { + Arg::new(SIGNER_ARG.name) + .long(SIGNER_ARG.long) + .takes_value(true) + .value_name("PUBKEY=SIGNATURE") + .requires(BLOCKHASH_ARG.name) + .action(clap::ArgAction::Append) + .multiple_values(false) + .help(SIGNER_ARG.help) +} + +pub trait OfflineArgs { + fn offline_args(self) -> Self; + fn offline_args_config(self, config: &dyn ArgsConfig) -> Self; +} + +impl OfflineArgs for clap::Command<'_> { + fn offline_args_config(self, config: &dyn ArgsConfig) -> Self { + self.arg(config.blockhash_arg(blockhash_arg())) + .arg(config.sign_only_arg(sign_only_arg())) + .arg(config.signer_arg(signer_arg())) + .arg(config.dump_transaction_message_arg(dump_transaction_message())) + } + fn offline_args(self) -> Self { + struct NullArgsConfig {} + impl ArgsConfig for NullArgsConfig {} + self.offline_args_config(&NullArgsConfig {}) + } +} + pub static VALID_TOKEN_PROGRAM_IDS: [Pubkey; 2] = [spl_token_2022::ID, spl_token::ID]; #[derive(AsRefStr, Debug, Clone, Copy, PartialEq, EnumString, IntoStaticStr)] @@ -238,42 +275,42 @@ impl TryFrom for AuthorityType { } } -pub fn owner_address_arg<'a, 'b>() -> Arg<'a, 'b> { +pub fn owner_address_arg<'a>() -> Arg<'a> { Arg::with_name(OWNER_ADDRESS_ARG.name) .long(OWNER_ADDRESS_ARG.long) .takes_value(true) .value_name("OWNER_ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .help(OWNER_ADDRESS_ARG.help) } -pub fn owner_keypair_arg_with_value_name<'a, 'b>(value_name: &'static str) -> Arg<'a, 'b> { +pub fn owner_keypair_arg_with_value_name<'a>(value_name: &'static str) -> Arg<'a> { Arg::with_name(OWNER_KEYPAIR_ARG.name) .long(OWNER_KEYPAIR_ARG.long) .takes_value(true) .value_name(value_name) - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .help(OWNER_KEYPAIR_ARG.help) } -pub fn owner_keypair_arg<'a, 'b>() -> Arg<'a, 'b> { +pub fn owner_keypair_arg<'a>() -> Arg<'a> { owner_keypair_arg_with_value_name("OWNER_KEYPAIR") } -pub fn mint_address_arg<'a, 'b>() -> Arg<'a, 'b> { +pub fn mint_address_arg<'a>() -> Arg<'a> { Arg::with_name(MINT_ADDRESS_ARG.name) .long(MINT_ADDRESS_ARG.long) .takes_value(true) .value_name("MINT_ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .help(MINT_ADDRESS_ARG.help) } -fn is_mint_decimals(string: String) -> Result<(), String> { +fn is_mint_decimals(string: &str) -> Result<(), String> { is_parsable::(string) } -pub fn mint_decimals_arg<'a, 'b>() -> Arg<'a, 'b> { +pub fn mint_decimals_arg<'a>() -> Arg<'a> { Arg::with_name(MINT_DECIMALS_ARG.name) .long(MINT_DECIMALS_ARG.long) .takes_value(true) @@ -286,45 +323,45 @@ pub trait MintArgs { fn mint_args(self) -> Self; } -impl MintArgs for App<'_, '_> { +impl MintArgs for App<'_> { fn mint_args(self) -> Self { self.arg(mint_address_arg().requires(MINT_DECIMALS_ARG.name)) .arg(mint_decimals_arg().requires(MINT_ADDRESS_ARG.name)) } } -pub fn delegate_address_arg<'a, 'b>() -> Arg<'a, 'b> { +pub fn delegate_address_arg<'a>() -> Arg<'a> { Arg::with_name(DELEGATE_ADDRESS_ARG.name) .long(DELEGATE_ADDRESS_ARG.long) .takes_value(true) .value_name("DELEGATE_ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .help(DELEGATE_ADDRESS_ARG.help) } -pub fn transfer_lamports_arg<'a, 'b>() -> Arg<'a, 'b> { +pub fn transfer_lamports_arg<'a>() -> Arg<'a> { Arg::with_name(TRANSFER_LAMPORTS_ARG.name) .long(TRANSFER_LAMPORTS_ARG.long) .takes_value(true) .value_name("LAMPORTS") - .validator(is_amount) + .validator(|s| is_amount(s)) .help(TRANSFER_LAMPORTS_ARG.help) } -pub fn multisig_signer_arg<'a, 'b>() -> Arg<'a, 'b> { +pub fn multisig_signer_arg<'a>() -> Arg<'a> { Arg::with_name(MULTISIG_SIGNER_ARG.name) .long(MULTISIG_SIGNER_ARG.long) - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .value_name("MULTISIG_SIGNER") .takes_value(true) .multiple(true) - .min_values(0u64) - .max_values(MAX_SIGNERS as u64) + .min_values(0_usize) + .max_values(MAX_SIGNERS) .help(MULTISIG_SIGNER_ARG.help) } -fn is_multisig_minimum_signers(string: String) -> Result<(), String> { - let v = u8::from_str(&string).map_err(|e| e.to_string())? as usize; +fn is_multisig_minimum_signers(string: &str) -> Result<(), String> { + let v = u8::from_str(string).map_err(|e| e.to_string())? as usize; if v < MIN_SIGNERS { Err(format!("must be at least {}", MIN_SIGNERS)) } else if v > MAX_SIGNERS { @@ -353,50 +390,50 @@ where struct SignOnlyNeedsFullMintSpec {} impl offline::ArgsConfig for SignOnlyNeedsFullMintSpec { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[MINT_ADDRESS_ARG.name, MINT_DECIMALS_ARG.name]) } - fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[MINT_ADDRESS_ARG.name, MINT_DECIMALS_ARG.name]) } } struct SignOnlyNeedsMintDecimals {} impl offline::ArgsConfig for SignOnlyNeedsMintDecimals { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[MINT_DECIMALS_ARG.name]) } - fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[MINT_DECIMALS_ARG.name]) } } struct SignOnlyNeedsMintAddress {} impl offline::ArgsConfig for SignOnlyNeedsMintAddress { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[MINT_ADDRESS_ARG.name]) } - fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[MINT_ADDRESS_ARG.name]) } } struct SignOnlyNeedsDelegateAddress {} impl offline::ArgsConfig for SignOnlyNeedsDelegateAddress { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[DELEGATE_ADDRESS_ARG.name]) } - fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[DELEGATE_ADDRESS_ARG.name]) } } struct SignOnlyNeedsTransferLamports {} impl offline::ArgsConfig for SignOnlyNeedsTransferLamports { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[TRANSFER_LAMPORTS_ARG.name]) } - fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { + fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> { arg.requires_all(&[TRANSFER_LAMPORTS_ARG.name]) } } @@ -419,7 +456,7 @@ pub(crate) trait BenchSubCommand { fn bench_subcommand(self) -> Self; } -impl BenchSubCommand for App<'_, '_> { +impl BenchSubCommand for App<'_> { fn bench_subcommand(self) -> Self { self.subcommand( SubCommand::with_name("bench") @@ -431,7 +468,7 @@ impl BenchSubCommand for App<'_, '_> { .about("Create multiple token accounts for benchmarking") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -454,7 +491,7 @@ impl BenchSubCommand for App<'_, '_> { .about("Close multiple token accounts used for benchmarking") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -477,7 +514,7 @@ impl BenchSubCommand for App<'_, '_> { .about("Deposit tokens into multiple accounts") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -495,7 +532,7 @@ impl BenchSubCommand for App<'_, '_> { ) .arg( Arg::with_name("amount") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(3) @@ -505,7 +542,7 @@ impl BenchSubCommand for App<'_, '_> { .arg( Arg::with_name("from") .long("from") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("SOURCE_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The source token account address [default: associated token account for --owner]") @@ -517,7 +554,7 @@ impl BenchSubCommand for App<'_, '_> { .about("Withdraw tokens from multiple accounts") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -535,7 +572,7 @@ impl BenchSubCommand for App<'_, '_> { ) .arg( Arg::with_name("amount") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(3) @@ -545,7 +582,7 @@ impl BenchSubCommand for App<'_, '_> { .arg( Arg::with_name("to") .long("to") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The recipient token account address [default: associated token account for --owner]") @@ -556,18 +593,18 @@ impl BenchSubCommand for App<'_, '_> { } } -pub fn app<'a, 'b>( +pub fn app<'a>( default_decimals: &'a str, - minimum_signers_help: &'b str, - multisig_member_help: &'b str, -) -> App<'a, 'b> { + minimum_signers_help: &'a str, + multisig_member_help: &'a str, +) -> App<'a> { App::new(crate_name!()) .about(crate_description!()) .version(crate_version!()) .setting(AppSettings::SubcommandRequiredElseHelp) .arg( Arg::with_name("config_file") - .short("C") + .short('C') .long("config") .value_name("PATH") .takes_value(true) @@ -576,7 +613,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("verbose") - .short("v") + .short('v') .long("verbose") .takes_value(false) .global(true) @@ -588,7 +625,7 @@ pub fn app<'a, 'b>( .value_name("FORMAT") .global(true) .takes_value(true) - .possible_values(&["json", "json-compact"]) + .possible_values(["json", "json-compact"]) .help("Return information in specified output format"), ) .arg( @@ -601,23 +638,23 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("program_id") - .short("p") + .short('p') .long("program-id") .value_name("ADDRESS") .takes_value(true) .global(true) - .validator(is_valid_token_program_id) .conflicts_with("program_2022") + .validator(|s| is_valid_token_program_id(s)) .help("SPL Token program id"), ) .arg( Arg::with_name("json_rpc_url") - .short("u") + .short('u') .long("url") .value_name("URL_OR_MONIKER") .takes_value(true) .global(true) - .validator(is_url_or_moniker) + .validator(|s| is_url_or_moniker(s)) .help( "URL for Solana's JSON RPC or moniker (or their first letter): \ [mainnet-beta, testnet, devnet, localhost] \ @@ -656,7 +693,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("token_keypair") .value_name("TOKEN_KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .index(1) .help( @@ -670,7 +707,7 @@ pub fn app<'a, 'b>( .long("mint-authority") .alias("owner") .value_name("ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .help( "Specify the mint authority address. \ @@ -716,7 +753,7 @@ pub fn app<'a, 'b>( Arg::with_name("metadata_address") .long("metadata-address") .value_name("ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .conflicts_with("enable_metadata") .help( @@ -727,7 +764,7 @@ pub fn app<'a, 'b>( Arg::with_name("group_address") .long("group-address") .value_name("ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .conflicts_with("enable_group") .help( @@ -738,7 +775,7 @@ pub fn app<'a, 'b>( Arg::with_name("member_address") .long("member-address") .value_name("ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .conflicts_with("enable_member") .help( @@ -759,7 +796,7 @@ pub fn app<'a, 'b>( .long("default-account-state") .requires("enable_freeze") .takes_value(true) - .possible_values(&["initialized", "frozen"]) + .possible_values(["initialized", "frozen"]) .help("Specify that accounts have a default state. \ Note: specifying \"initialized\" adds an extension, which gives \ the option of specifying default frozen accounts in the future. \ @@ -788,7 +825,7 @@ pub fn app<'a, 'b>( .number_of_values(1) .conflicts_with("transfer_fee") .requires("transfer_fee_maximum_fee") - .validator(is_parsable::) + .value_parser(clap::value_parser!(u16)) .help( "Add transfer fee to the mint. \ The mint authority can set the fee.", @@ -802,7 +839,7 @@ pub fn app<'a, 'b>( .number_of_values(1) .conflicts_with("transfer_fee") .requires("transfer_fee_basis_points") - .validator(is_amount) + .validator(|s| is_amount(s)) .help( "Add a UI amount maximum transfer fee to the mint. \ The mint authority can set and collect fees" @@ -821,7 +858,7 @@ pub fn app<'a, 'b>( .long("enable-confidential-transfers") .value_names(&["APPROVE-POLICY"]) .takes_value(true) - .possible_values(&["auto", "manual"]) + .possible_values(["auto", "manual"]) .help( "Enable accounts to make confidential transfers. If \"auto\" \ is selected, then accounts are automatically approved to make \ @@ -834,7 +871,7 @@ pub fn app<'a, 'b>( Arg::with_name("transfer_hook") .long("transfer-hook") .value_name("TRANSFER_HOOK_PROGRAM_ID") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .help("Enable the mint authority to set the transfer hook program for this mint"), ) @@ -859,6 +896,7 @@ pub fn app<'a, 'b>( .takes_value(false) .help("Enables group member configurations in the mint. The mint authority must initialize the member."), ) + .arg(multisig_signer_arg()) .nonce_args(true) .arg(memo_arg()) ) @@ -867,7 +905,7 @@ pub fn app<'a, 'b>( .about("Set the interest rate for an interest-bearing token") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -883,7 +921,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("rate_authority") .long("rate-authority") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .value_name("SIGNER") .takes_value(true) .help( @@ -897,7 +935,7 @@ pub fn app<'a, 'b>( .about("Set the transfer hook program id for a token") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -906,7 +944,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("new_program_id") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("NEW_PROGRAM_ID") .takes_value(true) .required_unless("disable") @@ -924,7 +962,7 @@ pub fn app<'a, 'b>( Arg::with_name("authority") .long("authority") .alias("owner") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .value_name("SIGNER") .takes_value(true) .help("Specify the authority keypair. Defaults to the client keypair address.") @@ -935,7 +973,7 @@ pub fn app<'a, 'b>( .about("Initialize metadata extension on a token mint") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -971,7 +1009,7 @@ pub fn app<'a, 'b>( .long("mint-authority") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the mint authority keypair. \ @@ -983,7 +1021,7 @@ pub fn app<'a, 'b>( Arg::with_name("update_authority") .long("update-authority") .value_name("ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .help( "Specify the update authority address. \ @@ -996,7 +1034,7 @@ pub fn app<'a, 'b>( .about("Update metadata on a token mint that has the extension") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1029,7 +1067,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("authority") .long("authority") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .value_name("SIGNER") .takes_value(true) .help("Specify the metadata update authority keypair. Defaults to the client keypair.") @@ -1043,7 +1081,7 @@ pub fn app<'a, 'b>( .about("Initialize group extension on a token mint") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1052,7 +1090,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("max_size") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("MAX_SIZE") .takes_value(true) .required(true) @@ -1064,7 +1102,7 @@ pub fn app<'a, 'b>( .long("mint-authority") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the mint authority keypair. \ @@ -1076,7 +1114,7 @@ pub fn app<'a, 'b>( Arg::with_name("update_authority") .long("update-authority") .value_name("ADDRESS") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .help( "Specify the update authority address. \ @@ -1089,7 +1127,7 @@ pub fn app<'a, 'b>( .about("Updates the maximum number of members for a group.") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1098,7 +1136,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("new_max_size") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("NEW_MAX_SIZE") .takes_value(true) .required(true) @@ -1109,7 +1147,7 @@ pub fn app<'a, 'b>( Arg::with_name("update_authority") .long("update-authority") .value_name("SIGNER") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the update authority address. \ @@ -1122,7 +1160,7 @@ pub fn app<'a, 'b>( .about("Initialize group member extension on a token mint") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1131,7 +1169,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("group_token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("GROUP_TOKEN_ADDRESS") .takes_value(true) .required(true) @@ -1143,7 +1181,7 @@ pub fn app<'a, 'b>( .long("mint-authority") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the mint authority keypair. \ @@ -1155,7 +1193,7 @@ pub fn app<'a, 'b>( Arg::with_name("group_update_authority") .long("group-update-authority") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the update authority keypair. \ @@ -1169,7 +1207,7 @@ pub fn app<'a, 'b>( .about("Create a new token account") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1179,7 +1217,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("account_keypair") .value_name("ACCOUNT_KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .index(2) .help( @@ -1214,19 +1252,19 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("multisig_member") .value_name("MULTISIG_MEMBER_PUBKEY") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .takes_value(true) .index(2) .required(true) - .min_values(MIN_SIGNERS as u64) - .max_values(MAX_SIGNERS as u64) + .min_values(MIN_SIGNERS) + .max_values(MAX_SIGNERS) .help(multisig_member_help), ) .arg( Arg::with_name("address_keypair") .long("address-keypair") .value_name("ADDRESS_KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the address keypair. \ @@ -1241,7 +1279,7 @@ pub fn app<'a, 'b>( .about("Authorize a new signing keypair to a token or token account") .arg( Arg::with_name("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -1252,7 +1290,7 @@ pub fn app<'a, 'b>( Arg::with_name("authority_type") .value_name("AUTHORITY_TYPE") .takes_value(true) - .possible_values(&CliAuthorityType::iter().map(Into::into).collect::>()) + .possible_values(CliAuthorityType::iter().map(Into::<&str>::into).collect::>()) .index(2) .required(true) .help("The new authority type. \ @@ -1262,7 +1300,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("new_authority") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("AUTHORITY_ADDRESS") .takes_value(true) .index(3) @@ -1274,7 +1312,7 @@ pub fn app<'a, 'b>( .long("authority") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the current authority keypair. \ @@ -1303,7 +1341,7 @@ pub fn app<'a, 'b>( .about("Transfer tokens between accounts") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1312,7 +1350,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("amount") - .validator(is_amount_or_all) + .validator(|s| is_amount_or_all(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(2) @@ -1321,7 +1359,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("recipient") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("RECIPIENT_WALLET_ADDRESS or RECIPIENT_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(3) @@ -1332,7 +1370,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("from") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("SENDER_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("from") @@ -1396,7 +1434,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("expected_fee") .long("expected-fee") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .help("Expected fee amount collected during the transfer"), @@ -1404,11 +1442,11 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("transfer_hook_account") .long("transfer-hook-account") - .validator(validate_transfer_hook_account) + .validator(|s| validate_transfer_hook_account(s)) .value_name("PUBKEY:ROLE") .takes_value(true) .multiple(true) - .min_values(0u64) + .min_values(0_usize) .help("Additional pubkey(s) required for a transfer hook and their \ role, in the format \":\". The role must be \ \"readonly\", \"writable\". \"readonly-signer\", or \"writable-signer\".\ @@ -1433,7 +1471,7 @@ pub fn app<'a, 'b>( .about("Burn tokens from an account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1442,7 +1480,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("amount") - .validator(is_amount_or_all) + .validator(|s| is_amount_or_all(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(2) @@ -1467,7 +1505,7 @@ pub fn app<'a, 'b>( .about("Mint new tokens") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1476,7 +1514,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("amount") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(2) @@ -1485,7 +1523,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("recipient") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("recipient_owner") @@ -1496,7 +1534,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("recipient_owner") .long("recipient-owner") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("RECIPIENT_WALLET_ADDRESS") .takes_value(true) .conflicts_with("recipient") @@ -1507,7 +1545,7 @@ pub fn app<'a, 'b>( .long("mint-authority") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the mint authority keypair. \ @@ -1526,7 +1564,7 @@ pub fn app<'a, 'b>( .about("Freeze a token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1538,7 +1576,7 @@ pub fn app<'a, 'b>( .long("freeze-authority") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the freeze authority keypair. \ @@ -1556,7 +1594,7 @@ pub fn app<'a, 'b>( .about("Thaw a token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1568,7 +1606,7 @@ pub fn app<'a, 'b>( .long("freeze-authority") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the freeze authority keypair. \ @@ -1586,7 +1624,7 @@ pub fn app<'a, 'b>( .about("Wrap native SOL in a SOL token account") .arg( Arg::with_name("amount") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("AMOUNT") .takes_value(true) .index(1) @@ -1597,8 +1635,9 @@ pub fn app<'a, 'b>( Arg::with_name("wallet_keypair") .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) + .index(2) .help( "Specify the keypair for the wallet which will have its native SOL wrapped. \ This wallet will be assigned as the owner of the wrapped SOL token account. \ @@ -1628,7 +1667,7 @@ pub fn app<'a, 'b>( .about("Unwrap a SOL token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1637,10 +1676,10 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("wallet_keypair") - .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) + .index(2) .help( "Specify the keypair for the wallet which owns the wrapped SOL. \ This wallet will receive the unwrapped SOL. \ @@ -1658,7 +1697,7 @@ pub fn app<'a, 'b>( .about("Approve a delegate for a token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1667,7 +1706,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("amount") - .validator(is_amount) + .validator(|s| is_amount(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(2) @@ -1676,7 +1715,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("delegate") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("DELEGATE_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(3) @@ -1696,7 +1735,7 @@ pub fn app<'a, 'b>( .about("Revoke a delegate's authority") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1715,7 +1754,7 @@ pub fn app<'a, 'b>( .about("Close a token account") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1726,7 +1765,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("recipient") .long("recipient") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("REFUND_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the account to receive remaining SOL [default: --owner]"), @@ -1734,9 +1773,8 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("close_authority") .long("close-authority") - .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the token's close authority if it has one, \ @@ -1748,7 +1786,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -1764,7 +1802,7 @@ pub fn app<'a, 'b>( .about("Close a token mint") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1774,7 +1812,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("recipient") .long("recipient") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("REFUND_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the account to receive remaining SOL [default: --owner]"), @@ -1783,7 +1821,7 @@ pub fn app<'a, 'b>( Arg::with_name("close_authority") .long("close-authority") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the token's close authority. \ @@ -1801,7 +1839,7 @@ pub fn app<'a, 'b>( .about("Get token account balance") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1811,7 +1849,7 @@ pub fn app<'a, 'b>( .arg(owner_address_arg().conflicts_with("address")) .arg( Arg::with_name("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("address") @@ -1825,7 +1863,7 @@ pub fn app<'a, 'b>( .about("Get token supply") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1838,7 +1876,7 @@ pub fn app<'a, 'b>( .about("List all token accounts by owner") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1879,7 +1917,7 @@ pub fn app<'a, 'b>( .about("Get wallet address") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .long("token") @@ -1900,7 +1938,7 @@ pub fn app<'a, 'b>( .setting(AppSettings::Hidden) .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1913,7 +1951,7 @@ pub fn app<'a, 'b>( Arg::with_name(OWNER_ADDRESS_ARG.name) .takes_value(true) .value_name("OWNER_ADDRESS") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .help(OWNER_ADDRESS_ARG.help) .index(2) .conflicts_with("address") @@ -1923,7 +1961,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("address") @@ -1937,7 +1975,7 @@ pub fn app<'a, 'b>( .setting(AppSettings::Hidden) .arg( Arg::with_name("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("MULTISIG_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1950,7 +1988,7 @@ pub fn app<'a, 'b>( .about("Query details of an SPL Token mint, account, or multisig by address") .arg( Arg::with_name("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -1982,7 +2020,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("address") @@ -1995,7 +2033,7 @@ pub fn app<'a, 'b>( .about("Enable required transfer memos for token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2013,7 +2051,7 @@ pub fn app<'a, 'b>( .about("Disable required transfer memos for token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2031,7 +2069,7 @@ pub fn app<'a, 'b>( .about("Enable CPI Guard for token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2049,7 +2087,7 @@ pub fn app<'a, 'b>( .about("Disable CPI Guard for token account") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2067,7 +2105,7 @@ pub fn app<'a, 'b>( .about("Updates default account state for the mint. Requires the default account state extension.") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2078,7 +2116,7 @@ pub fn app<'a, 'b>( Arg::with_name("state") .value_name("STATE") .takes_value(true) - .possible_values(&["initialized", "frozen"]) + .possible_values(["initialized", "frozen"]) .index(2) .required(true) .help("The new default account state."), @@ -2087,7 +2125,7 @@ pub fn app<'a, 'b>( Arg::with_name("freeze_authority") .long("freeze-authority") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the token's freeze authority. \ @@ -2105,7 +2143,7 @@ pub fn app<'a, 'b>( .about("Updates metadata pointer address for the mint. Requires the metadata pointer extension.") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2115,7 +2153,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("metadata_address") .index(2) - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("METADATA_ADDRESS") .takes_value(true) .required_unless("disable") @@ -2132,7 +2170,7 @@ pub fn app<'a, 'b>( Arg::with_name("authority") .long("authority") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the token's metadata-pointer authority. \ @@ -2148,7 +2186,7 @@ pub fn app<'a, 'b>( .about("Updates group pointer address for the mint. Requires the group pointer extension.") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2158,7 +2196,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("group_address") .index(2) - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("GROUP_ADDRESS") .takes_value(true) .required_unless("disable") @@ -2175,7 +2213,7 @@ pub fn app<'a, 'b>( Arg::with_name("authority") .long("authority") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the token's group-pointer authority. \ @@ -2191,7 +2229,7 @@ pub fn app<'a, 'b>( .about("Updates group member pointer address for the mint. Requires the group member pointer extension.") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2201,7 +2239,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("member_address") .index(2) - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("MEMBER_ADDRESS") .takes_value(true) .required_unless("disable") @@ -2218,7 +2256,7 @@ pub fn app<'a, 'b>( Arg::with_name("authority") .long("authority") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the token's group-member-pointer authority. \ @@ -2234,7 +2272,7 @@ pub fn app<'a, 'b>( .about("Withdraw withheld transfer fee tokens from mint and / or account(s)") .arg( Arg::with_name("account") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2243,11 +2281,12 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("source") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("ACCOUNT_ADDRESS") .takes_value(true) .multiple(true) - .min_values(0u64) + .min_values(0_usize) + .index(2) .help("The token accounts to withdraw from") ) .arg( @@ -2259,9 +2298,8 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("withdraw_withheld_authority") .long("withdraw-withheld-authority") - .alias("owner") .value_name("KEYPAIR") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .takes_value(true) .help( "Specify the withdraw withheld authority keypair. \ @@ -2284,7 +2322,7 @@ pub fn app<'a, 'b>( .about("Set the transfer fee for a token with a configured transfer fee") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -2300,7 +2338,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("maximum_fee") .value_name("TOKEN_AMOUNT") - .validator(is_amount) + .validator(|s| is_amount(s)) .takes_value(true) .required(true) .help("The new maximum transfer fee in UI amount"), @@ -2308,7 +2346,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("transfer_fee_authority") .long("transfer-fee-authority") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .value_name("SIGNER") .takes_value(true) .help( @@ -2324,7 +2362,7 @@ pub fn app<'a, 'b>( .about("Withdraw lamports from a Token Program owned account") .arg( Arg::with_name("from") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("SOURCE_ACCOUNT_ADDRESS") .takes_value(true) .required(true) @@ -2332,7 +2370,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("recipient") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("REFUND_ACCOUNT_ADDRESS") .takes_value(true) .required(true) @@ -2346,7 +2384,7 @@ pub fn app<'a, 'b>( .about("Update confidential transfer configuration for a token") .arg( Arg::with_name("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2358,7 +2396,7 @@ pub fn app<'a, 'b>( .long("approve-policy") .value_name("APPROVE_POLICY") .takes_value(true) - .possible_values(&["auto", "manual"]) + .possible_values(["auto", "manual"]) .help( "Policy for enabling accounts to make confidential transfers. If \"auto\" \ is selected, then accounts are automatically approved to make \ @@ -2390,7 +2428,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("confidential_transfer_authority") .long("confidential-transfer-authority") - .validator(is_valid_signer) + .validator(|s| is_valid_signer(s)) .value_name("SIGNER") .takes_value(true) .help( @@ -2406,8 +2444,7 @@ pub fn app<'a, 'b>( .about("Configure confidential transfers for token account") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2417,7 +2454,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2448,8 +2485,7 @@ pub fn app<'a, 'b>( for the first time, use `configure-confidential-transfer-account` instead.") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2459,7 +2495,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2477,8 +2513,7 @@ pub fn app<'a, 'b>( .about("Disable confidential transfers for token account") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2488,7 +2523,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2506,8 +2541,7 @@ pub fn app<'a, 'b>( .about("Enable non-confidential transfers for token account.") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2517,7 +2551,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2535,8 +2569,7 @@ pub fn app<'a, 'b>( .about("Disable non-confidential transfers for token account") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2546,7 +2579,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2564,8 +2597,7 @@ pub fn app<'a, 'b>( .about("Deposit amounts for confidential transfers") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2574,7 +2606,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("amount") - .validator(is_amount_or_all) + .validator(|s| is_amount_or_all(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(2) @@ -2584,7 +2616,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the token account to configure confidential transfers for \ @@ -2602,8 +2634,7 @@ pub fn app<'a, 'b>( .about("Withdraw amounts for confidential transfers") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2612,7 +2643,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("amount") - .validator(is_amount_or_all) + .validator(|s| is_amount_or_all(s)) .value_name("TOKEN_AMOUNT") .takes_value(true) .index(2) @@ -2622,7 +2653,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the token account to configure confidential transfers for \ @@ -2640,8 +2671,7 @@ pub fn app<'a, 'b>( .about("Collect confidential tokens from pending to available balance") .arg( Arg::with_name("token") - .long("token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2651,7 +2681,7 @@ pub fn app<'a, 'b>( .arg( Arg::with_name("address") .long("address") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the token account to configure confidential transfers for \ diff --git a/token/cli/src/command.rs b/token/cli/src/command.rs index cd9c9f12252..e30eb7eb2ab 100644 --- a/token/cli/src/command.rs +++ b/token/cli/src/command.rs @@ -16,8 +16,8 @@ use { parse_token::{get_token_account_mint, parse_token_v2, TokenAccountType, UiAccountState}, UiAccountData, }, - solana_clap_utils::{ - input_parsers::{pubkey_of_signer, pubkeys_of_multiple_signers, value_of}, + solana_clap_v3_utils::{ + input_parsers::{pubkey_of_signer, pubkeys_of_multiple_signers}, keypair::signer_from_path, }, solana_cli_output::{ @@ -97,7 +97,7 @@ fn new_throwaway_signer() -> (Arc, Pubkey) { } fn get_signer( - matches: &ArgMatches<'_>, + matches: &ArgMatches, keypair_name: &str, wallet_manager: &mut Option>, ) -> Option<(Arc, Pubkey)> { @@ -109,7 +109,7 @@ fn get_signer( }) } -fn parse_amount_or_all(matches: &ArgMatches<'_>) -> Option { +fn parse_amount_or_all(matches: &ArgMatches) -> Option { match matches.value_of("amount").unwrap() { "ALL" => None, amount => Some(amount.parse::().unwrap()), @@ -3494,7 +3494,7 @@ struct ConfidentialTransferArgs { pub async fn process_command<'a>( sub_command: &CommandName, - sub_matches: &ArgMatches<'_>, + sub_matches: &ArgMatches, config: &Config<'a>, mut wallet_manager: Option>, mut bulk_signers: Vec>, @@ -3533,11 +3533,15 @@ pub async fn process_command<'a>( ) }); - let tranfer_fee_basis_point = value_of::(arg_matches, "transfer_fee_basis_points"); - let transfer_fee_maximum_fee = value_of::(arg_matches, "transfer_fee_maximum_fee") - .map(|v| spl_token::ui_amount_to_amount(v, decimals)); - let transfer_fee = tranfer_fee_basis_point - .map(|v| (v, transfer_fee_maximum_fee.unwrap())) + let transfer_fee_basis_point = arg_matches.get_one::("transfer_fee_basis_points"); + let transfer_fee_maximum_fee = arg_matches + .get_one::("transfer_fee_maximum_fee") + .map(|str| { + let v = str.parse::().unwrap(); // inputs are validated so this is safe + spl_token::ui_amount_to_amount(v, decimals) + }); + let transfer_fee = transfer_fee_basis_point + .map(|v| (*v, transfer_fee_maximum_fee.unwrap())) .or(transfer_fee); let (token_signer, token) = @@ -3660,7 +3664,9 @@ pub async fn process_command<'a>( _ => Field::Key(field.to_string()), }; let value = arg_matches.value_of("value").map(|v| v.to_string()); - let transfer_lamports = value_of::(arg_matches, TRANSFER_LAMPORTS_ARG.name); + let transfer_lamports = arg_matches + .get_one(TRANSFER_LAMPORTS_ARG.name) + .map(|v: &String| v.parse::().unwrap()); let bulk_signers = vec![authority_signer]; command_update_metadata( @@ -3766,7 +3772,10 @@ pub async fn process_command<'a>( .await } (CommandName::CreateMultisig, arg_matches) => { - let minimum_signers = value_of::(arg_matches, "minimum_signers").unwrap(); + let minimum_signers = arg_matches + .get_one("minimum_signers") + .map(|v: &String| v.parse::().unwrap()) + .unwrap(); let multisig_members = pubkeys_of_multiple_signers(arg_matches, "multisig_member", &mut wallet_manager) .unwrap_or_else(print_error_and_exit) @@ -3850,7 +3859,9 @@ pub async fn process_command<'a>( push_signer_with_dedup(owner_signer, &mut bulk_signers); } - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); + let mint_decimals = arg_matches + .get_one(MINT_DECIMALS_ARG.name) + .map(|v: &String| v.parse::().unwrap()); let fund_recipient = arg_matches.is_present("fund_recipient"); let allow_unfunded_recipient = arg_matches.is_present("allow_empty_recipient") || arg_matches.is_present("allow_unfunded_recipient"); @@ -3862,7 +3873,9 @@ pub async fn process_command<'a>( println_display(config, "recipient-is-ata-owner is now the default behavior. The option has been deprecated and will be removed in a future release.".to_string()); } let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); - let expected_fee = value_of::(arg_matches, "expected_fee"); + let expected_fee = arg_matches + .get_one::("expected_fee") + .map(|str| str.parse::().unwrap()); // unwrap safe since inputs are validated let memo = value_t!(arg_matches, "memo", String).ok(); let transfer_hook_accounts = arg_matches.values_of("transfer_hook_account").map(|v| { v.into_iter() @@ -3906,7 +3919,9 @@ pub async fn process_command<'a>( let amount = parse_amount_or_all(arg_matches); let mint_address = pubkey_of_signer(arg_matches, MINT_ADDRESS_ARG.name, &mut wallet_manager).unwrap(); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); + let mint_decimals = arg_matches + .get_one(MINT_DECIMALS_ARG.name) + .map(|v: &String| v.parse::().unwrap()); let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); let memo = value_t!(arg_matches, "memo", String).ok(); command_burn( @@ -3933,7 +3948,9 @@ pub async fn process_command<'a>( .unwrap() .unwrap(); let amount = value_t_or_exit!(arg_matches, "amount", f64); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); + let mint_decimals = arg_matches + .get_one(MINT_DECIMALS_ARG.name) + .map(|v: &String| v.parse::().unwrap()); let mint_info = config.get_mint_info(&token, mint_decimals).await?; let recipient = if let Some(address) = pubkey_of_signer(arg_matches, "recipient", &mut wallet_manager).unwrap() @@ -4058,7 +4075,9 @@ pub async fn process_command<'a>( .unwrap(); let mint_address = pubkey_of_signer(arg_matches, MINT_ADDRESS_ARG.name, &mut wallet_manager).unwrap(); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); + let mint_decimals = arg_matches + .get_one(MINT_DECIMALS_ARG.name) + .map(|v: &String| v.parse::().unwrap()); let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); command_approve( config, @@ -4395,7 +4414,9 @@ pub async fn process_command<'a>( let maximum_fee = value_t_or_exit!(arg_matches, "maximum_fee", f64); let (transfer_fee_authority_signer, transfer_fee_authority_pubkey) = config .signer_or_default(arg_matches, "transfer_fee_authority", &mut wallet_manager); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); + let mint_decimals = arg_matches + .get_one(MINT_DECIMALS_ARG.name) + .map(|v: &String| v.parse::().unwrap()); let bulk_signers = vec![transfer_fee_authority_signer]; command_set_transfer_fee( @@ -4541,7 +4562,9 @@ pub async fn process_command<'a>( let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); + let mint_decimals = arg_matches + .get_one(MINT_DECIMALS_ARG.name) + .map(|v: &String| v.parse::().unwrap()); let (instruction_type, elgamal_keypair, aes_key) = match c { CommandName::DepositConfidentialTokens => { diff --git a/token/cli/src/config.rs b/token/cli/src/config.rs index 8157551d74b..97fd435a952 100644 --- a/token/cli/src/config.rs +++ b/token/cli/src/config.rs @@ -1,19 +1,19 @@ use { crate::clap_app::{Error, COMPUTE_UNIT_LIMIT_ARG, COMPUTE_UNIT_PRICE_ARG, MULTISIG_SIGNER_ARG}, clap::ArgMatches, - solana_clap_utils::{ - input_parsers::{pubkey_of_signer, value_of}, + solana_clap_v3_utils::{ + input_parsers::pubkey_of_signer, input_validators::normalize_to_url_if_moniker, - keypair::{signer_from_path, signer_from_path_with_config, SignerFromPathConfig}, + keypair::SignerFromPathConfig, nonce::{NONCE_ARG, NONCE_AUTHORITY_ARG}, - offline::{BLOCKHASH_ARG, DUMP_TRANSACTION_MESSAGE, SIGN_ONLY_ARG}, + offline::{BLOCKHASH_ARG, DUMP_TRANSACTION_MESSAGE, SIGNER_ARG, SIGN_ONLY_ARG}, }, solana_cli_output::OutputFormat, solana_client::nonblocking::rpc_client::RpcClient, solana_remote_wallet::remote_wallet::RemoteWalletManager, solana_sdk::{ account::Account as RawAccount, commitment_config::CommitmentConfig, hash::Hash, - pubkey::Pubkey, signature::Signer, + pubkey::Pubkey, signature::Signer, signer::null_signer::NullSigner, }, spl_associated_token_account_client::address::get_associated_token_address_with_program_id, spl_token_2022::{ @@ -26,12 +26,12 @@ use { }, token::ComputeUnitLimit, }, - std::{process::exit, rc::Rc, sync::Arc}, + std::{process::exit, rc::Rc, str::FromStr, sync::Arc}, }; type SignersOf = Vec<(Arc, Pubkey)>; fn signers_of( - matches: &ArgMatches<'_>, + matches: &ArgMatches, name: &str, wallet_manager: &mut Option>, ) -> Result, Box> { @@ -76,7 +76,7 @@ pub struct Config<'a> { impl<'a> Config<'a> { pub async fn new( - matches: &ArgMatches<'_>, + matches: &ArgMatches, wallet_manager: &mut Option>, bulk_signers: &mut Vec>, multisigner_ids: &'a mut Vec, @@ -103,7 +103,10 @@ impl<'a> Config<'a> { )); let sign_only = matches.is_present(SIGN_ONLY_ARG.name); let program_client: Arc> = if sign_only { - let blockhash = value_of(matches, BLOCKHASH_ARG.name).unwrap_or_default(); + let blockhash = matches + .get_one::(BLOCKHASH_ARG.name) + .copied() + .unwrap_or_default(); Arc::new(ProgramOfflineClient::new( blockhash, ProgramRpcClientSendTransaction, @@ -127,7 +130,7 @@ impl<'a> Config<'a> { } fn extract_multisig_signers( - matches: &ArgMatches<'_>, + matches: &ArgMatches, wallet_manager: &mut Option>, bulk_signers: &mut Vec>, multisigner_ids: &'a mut Vec, @@ -147,7 +150,7 @@ impl<'a> Config<'a> { } pub async fn new_with_clients_and_ws_url( - matches: &ArgMatches<'_>, + matches: &ArgMatches, wallet_manager: &mut Option>, bulk_signers: &mut Vec>, multisigner_ids: &'a mut Vec, @@ -175,7 +178,7 @@ impl<'a> Config<'a> { let default_keypair = cli_config.keypair_path.clone(); let default_signer: Option> = { - if let Some(owner_path) = matches.value_of("owner") { + if let Some(owner_path) = matches.try_get_one::("owner").ok().flatten() { signer_from_path_with_config(matches, owner_path, "owner", wallet_manager, &config) .ok() } else { @@ -227,11 +230,17 @@ impl<'a> Config<'a> { OutputFormat::Display }); - let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); + let nonce_account = match pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager) { + Ok(account) => account, + Err(e) => { + if e.is::() { + None + } else { + eprintln!("error: {}", e); + exit(1); + } + } + }; let nonce_authority = if nonce_account.is_some() { let (nonce_authority, _) = signer_from_path( matches, @@ -256,18 +265,28 @@ impl<'a> Config<'a> { None }; - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name); + let sign_only = matches.try_contains_id(SIGN_ONLY_ARG.name).unwrap_or(false); + let dump_transaction_message = matches + .try_contains_id(DUMP_TRANSACTION_MESSAGE.name) + .unwrap_or(false); + + let pubkey_from_matches = |name| { + matches + .try_get_one::(name) + .ok() + .flatten() + .and_then(|pubkey| Pubkey::from_str(pubkey).ok()) + }; let default_program_id = spl_token::id(); let (program_id, restrict_to_program_id) = if matches.is_present("program_2022") { (spl_token_2022::id(), true) - } else if let Some(program_id) = value_of(matches, "program_id") { + } else if let Some(program_id) = pubkey_from_matches("program_id") { (program_id, true) } else if !sign_only { - if let Some(address) = value_of(matches, "token") - .or_else(|| value_of(matches, "account")) - .or_else(|| value_of(matches, "address")) + if let Some(address) = pubkey_from_matches("token") + .or_else(|| pubkey_from_matches("account")) + .or_else(|| pubkey_from_matches("address")) { ( rpc_client @@ -284,13 +303,16 @@ impl<'a> Config<'a> { (default_program_id, false) }; - // need to specify a compute limit if compute price and blockhash are specified - if matches.is_present(BLOCKHASH_ARG.name) - && matches.is_present(COMPUTE_UNIT_PRICE_ARG.name) - && !matches.is_present(COMPUTE_UNIT_LIMIT_ARG.name) + if matches.try_contains_id(BLOCKHASH_ARG.name).unwrap_or(false) + && matches + .try_contains_id(COMPUTE_UNIT_PRICE_ARG.name) + .unwrap_or(false) + && !matches + .try_contains_id(COMPUTE_UNIT_LIMIT_ARG.name) + .unwrap_or(false) { clap::Error::with_description( - &format!( + format!( "Need to set `{}` if `{}` and `--{}` are set", COMPUTE_UNIT_LIMIT_ARG.long, COMPUTE_UNIT_PRICE_ARG.long, BLOCKHASH_ARG.long, ), @@ -299,9 +321,23 @@ impl<'a> Config<'a> { .exit(); } - let nonce_blockhash = value_of(matches, BLOCKHASH_ARG.name); - let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name); - let compute_unit_limit = value_of(matches, COMPUTE_UNIT_LIMIT_ARG.name) + let nonce_blockhash = matches + .try_get_one::(BLOCKHASH_ARG.name) + .ok() + .flatten() + .copied(); + + let compute_unit_price = matches + .try_get_one::(COMPUTE_UNIT_PRICE_ARG.name) + .ok() + .flatten() + .copied(); + + let compute_unit_limit = matches + .try_get_one::(COMPUTE_UNIT_PRICE_ARG.name) + .ok() + .flatten() + .copied() .map(ComputeUnitLimit::Static) .unwrap_or_else(|| { if nonce_blockhash.is_some() { @@ -310,6 +346,7 @@ impl<'a> Config<'a> { ComputeUnitLimit::Simulated } }); + Self { default_signer, rpc_client, @@ -358,7 +395,7 @@ impl<'a> Config<'a> { // return the associated token address for the default address. pub(crate) async fn associated_token_address_or_override( &self, - arg_matches: &ArgMatches<'_>, + arg_matches: &ArgMatches, override_name: &str, wallet_manager: &mut Option>, ) -> Result { @@ -377,7 +414,7 @@ impl<'a> Config<'a> { // return the associated token address for the default address. pub(crate) async fn associated_token_address_for_token_or_override( &self, - arg_matches: &ArgMatches<'_>, + arg_matches: &ArgMatches, override_name: &str, wallet_manager: &mut Option>, token: Option, @@ -409,7 +446,7 @@ impl<'a> Config<'a> { // address if there is one pub(crate) fn pubkey_or_default( &self, - arg_matches: &ArgMatches<'_>, + arg_matches: &ArgMatches, address_name: &str, wallet_manager: &mut Option>, ) -> Result { @@ -538,3 +575,44 @@ impl<'a> Config<'a> { } } } + +// In clap v2, `value_of` returns `None` if the argument id is not previously +// specified in `Arg`. In contrast, in clap v3, `value_of` panics in this case. +// Therefore, compared to the same function in solana-clap-utils, +// `signer_from_path` in solana-clap-v3-utils errors early when `path` is a +// valid pubkey, but `SIGNER_ARG.name` is not specified in the args. +// This function behaves exactly as `signer_from_path` from solana-clap-utils by +// catching this special case. +fn signer_from_path( + matches: &ArgMatches, + path: &str, + keypair_name: &str, + wallet_manager: &mut Option>, +) -> Result, Box> { + let config = SignerFromPathConfig::default(); + signer_from_path_with_config(matches, path, keypair_name, wallet_manager, &config) +} + +fn signer_from_path_with_config( + matches: &ArgMatches, + path: &str, + keypair_name: &str, + wallet_manager: &mut Option>, + config: &SignerFromPathConfig, +) -> Result, Box> { + if let Ok(pubkey) = Pubkey::from_str(path) { + if matches.try_contains_id(SIGNER_ARG.name).is_err() + && (config.allow_null_signer || matches.try_contains_id(SIGN_ONLY_ARG.name)?) + { + return Ok(Box::new(NullSigner::new(&pubkey))); + } + } + + solana_clap_v3_utils::keypair::signer_from_path_with_config( + matches, + path, + keypair_name, + wallet_manager, + config, + ) +} diff --git a/token/cli/src/main.rs b/token/cli/src/main.rs index 6566efe8d1e..1f93fad01e5 100644 --- a/token/cli/src/main.rs +++ b/token/cli/src/main.rs @@ -19,9 +19,8 @@ async fn main() -> Result<(), Error> { let mut wallet_manager = None; let mut bulk_signers: Vec> = Vec::new(); - let (sub_command, sub_matches) = app_matches.subcommand(); + let (sub_command, matches) = app_matches.subcommand().unwrap(); let sub_command = CommandName::from_str(sub_command).unwrap(); - let matches = sub_matches.unwrap(); let mut multisigner_ids = Vec::new(); let config = Config::new( diff --git a/token/cli/tests/command.rs b/token/cli/tests/command.rs index 1f8f41e1c6d..64b4b33e1ce 100644 --- a/token/cli/tests/command.rs +++ b/token/cli/tests/command.rs @@ -440,9 +440,8 @@ where &multisig_member_help, ) .get_matches_from(args); - let (sub_command, sub_matches) = app_matches.subcommand(); + let (sub_command, matches) = app_matches.subcommand().unwrap(); let sub_command = CommandName::from_str(sub_command).unwrap(); - let matches = sub_matches.unwrap(); let wallet_manager = None; let bulk_signers: Vec> = vec![Arc::new(clone_keypair(payer))]; @@ -460,9 +459,8 @@ async fn exec_test_cmd>(config: &Config<'_>, args: &[T]) -> Comm &multisig_member_help, ) .get_matches_from(args); - let (sub_command, sub_matches) = app_matches.subcommand(); + let (sub_command, matches) = app_matches.subcommand().unwrap(); let sub_command = CommandName::from_str(sub_command).unwrap(); - let matches = sub_matches.unwrap(); let mut wallet_manager = None; let mut bulk_signers: Vec> = Vec::new(); @@ -520,9 +518,10 @@ async fn create_token_2022(test_validator: &TestValidator, payer: &Keypair) { &multisig_member_help, ) .get_matches_from(args); + let (_, matches) = app_matches.subcommand().unwrap(); let config = Config::new_with_clients_and_ws_url( - &app_matches, + matches, &mut wallet_manager, &mut bulk_signers, &mut multisigner_ids, diff --git a/token/cli/tests/config.rs b/token/cli/tests/config.rs index ff0bfad9dfb..78c765abe0d 100644 --- a/token/cli/tests/config.rs +++ b/token/cli/tests/config.rs @@ -3,9 +3,8 @@ use assert_cmd::cmd::Command; #[test] fn invalid_config_will_cause_commands_to_fail() { let mut cmd = Command::cargo_bin("spl-token").unwrap(); - let args = &["address", "--config", "~/nonexistent/config.yml"]; - cmd.args(args) - .assert() + cmd.args(["address", "--config", "~/nonexistent/config.yml"]); + cmd.assert() .stderr("error: Could not find config file `~/nonexistent/config.yml`\n"); - cmd.args(args).assert().code(1).failure(); + cmd.assert().code(1).failure(); }