diff --git a/Cargo.lock b/Cargo.lock index 7cf21564ad5..d11c6b44ebd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7605,7 +7605,7 @@ version = "3.4.1" dependencies = [ "assert_cmd", "base64 0.22.0", - "clap 2.34.0", + "clap 3.2.25", "console", "futures 0.3.30", "libtest-mimic", @@ -7614,7 +7614,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 ee1a6197df4..bb674430cd0 100644 --- a/token/cli/Cargo.toml +++ b/token/cli/Cargo.toml @@ -13,14 +13,14 @@ walkdir = "2" [dependencies] base64 = "0.22.0" -clap = "2.33.3" +clap = "3.2.23" console = "0.15.8" futures = "0.3" serde = "1.0.198" serde_derive = "1.0.103" serde_json = "1.0.116" solana-account-decoder = ">=1.18.11,<=2" -solana-clap-utils = ">=1.18.11,<=2" +solana-clap-v3-utils = ">=1.18.11,<=2" solana-cli-config = ">=1.18.11,<=2" solana-cli-output = ">=1.18.11,<=2" solana-client = ">=1.18.11,<=2" @@ -29,19 +29,19 @@ solana-remote-wallet = ">=1.18.11,<=2" solana-sdk = ">=1.18.11,<=2" solana-transaction-status = ">=1.18.11,<=2" spl-token = { version = "4.0", path = "../program", features = [ - "no-entrypoint", + "no-entrypoint", ] } spl-token-2022 = { version = "3.0.2", path = "../program-2022", features = [ - "no-entrypoint", + "no-entrypoint", ] } spl-token-client = { version = "0.10.0", path = "../client" } spl-token-metadata-interface = { version = "0.3.3", path = "../../token-metadata/interface" } spl-token-group-interface = { version = "0.2.3", path = "../../token-group/interface" } spl-associated-token-account = { version = "3.0.2", path = "../../associated-token-account/program", features = [ - "no-entrypoint", + "no-entrypoint", ] } spl-memo = { version = "4.0", path = "../../memo/program", features = [ - "no-entrypoint", + "no-entrypoint", ] } strum = "0.26" strum_macros = "0.26" diff --git a/token/cli/src/bench.rs b/token/cli/src/bench.rs index 644cdc55333..8eca7e0e81b 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 b9817bff002..92a945bd135 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,27 +625,27 @@ 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( 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) + .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] \ @@ -647,7 +684,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( @@ -661,7 +698,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. \ @@ -707,7 +744,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( @@ -718,7 +755,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( @@ -729,7 +766,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( @@ -750,7 +787,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. \ @@ -781,7 +818,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 \ @@ -794,7 +831,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"), ) @@ -827,7 +864,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) @@ -843,7 +880,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( @@ -857,7 +894,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) @@ -866,7 +903,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") @@ -884,7 +921,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.") @@ -895,7 +932,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) @@ -931,7 +968,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. \ @@ -943,7 +980,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. \ @@ -956,7 +993,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) @@ -989,7 +1026,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.") @@ -1003,7 +1040,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) @@ -1012,7 +1049,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) @@ -1024,7 +1061,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. \ @@ -1036,7 +1073,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. \ @@ -1049,7 +1086,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) @@ -1058,7 +1095,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) @@ -1069,7 +1106,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. \ @@ -1082,7 +1119,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) @@ -1091,7 +1128,7 @@ pub fn app<'a, 'b>( ) .arg( Arg::with_name("group_token") - .validator(is_valid_pubkey) + .validator(|s| is_valid_pubkey(s)) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1103,7 +1140,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. \ @@ -1115,7 +1152,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. \ @@ -1129,7 +1166,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) @@ -1139,7 +1176,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( @@ -1174,19 +1211,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. \ @@ -1201,7 +1238,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) @@ -1212,7 +1249,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. \ @@ -1222,7 +1259,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) @@ -1234,7 +1271,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. \ @@ -1263,7 +1300,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) @@ -1272,7 +1309,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) @@ -1281,7 +1318,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) @@ -1292,7 +1329,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") @@ -1356,7 +1393,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"), @@ -1364,11 +1401,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\".\ @@ -1393,7 +1430,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) @@ -1402,7 +1439,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) @@ -1427,7 +1464,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) @@ -1436,7 +1473,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) @@ -1445,7 +1482,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") @@ -1456,7 +1493,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") @@ -1467,7 +1504,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. \ @@ -1486,7 +1523,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) @@ -1498,7 +1535,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. \ @@ -1516,7 +1553,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) @@ -1528,7 +1565,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. \ @@ -1546,7 +1583,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) @@ -1557,8 +1594,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. \ @@ -1588,7 +1626,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) @@ -1597,10 +1635,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. \ @@ -1618,7 +1656,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) @@ -1627,7 +1665,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) @@ -1636,7 +1674,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) @@ -1656,7 +1694,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) @@ -1675,7 +1713,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) @@ -1686,7 +1724,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]"), @@ -1694,9 +1732,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, \ @@ -1708,7 +1745,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") @@ -1724,7 +1761,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) @@ -1734,7 +1771,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]"), @@ -1743,7 +1780,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. \ @@ -1761,7 +1798,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) @@ -1771,7 +1808,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") @@ -1785,7 +1822,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) @@ -1798,7 +1835,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) @@ -1839,7 +1876,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") @@ -1860,7 +1897,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) @@ -1873,7 +1910,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") @@ -1883,7 +1920,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") @@ -1897,7 +1934,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) @@ -1910,7 +1947,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) @@ -1942,7 +1979,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") @@ -1955,7 +1992,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) @@ -1973,7 +2010,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) @@ -1991,7 +2028,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) @@ -2009,7 +2046,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) @@ -2027,7 +2064,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) @@ -2038,7 +2075,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."), @@ -2047,7 +2084,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. \ @@ -2065,7 +2102,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) @@ -2075,7 +2112,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") @@ -2092,7 +2129,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. \ @@ -2108,7 +2145,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) @@ -2118,7 +2155,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") @@ -2135,7 +2172,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. \ @@ -2151,7 +2188,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) @@ -2161,7 +2198,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") @@ -2178,7 +2215,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. \ @@ -2194,7 +2231,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) @@ -2203,11 +2240,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( @@ -2219,9 +2257,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. \ @@ -2237,7 +2274,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) @@ -2253,7 +2290,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"), @@ -2261,7 +2298,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( @@ -2277,7 +2314,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) @@ -2285,7 +2322,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) @@ -2299,7 +2336,7 @@ pub fn app<'a, 'b>( .about("Update confidential transfer configuation 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) @@ -2311,7 +2348,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 \ @@ -2343,7 +2380,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( @@ -2359,8 +2396,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) @@ -2370,7 +2406,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") @@ -2401,8 +2437,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) @@ -2412,7 +2447,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") @@ -2430,8 +2465,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) @@ -2441,7 +2475,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") @@ -2459,8 +2493,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) @@ -2470,7 +2503,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") @@ -2488,8 +2521,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) @@ -2499,7 +2531,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") @@ -2517,8 +2549,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) @@ -2527,7 +2558,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) @@ -2537,7 +2568,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 \ @@ -2555,8 +2586,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) @@ -2565,7 +2595,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) @@ -2575,7 +2605,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 \ @@ -2593,8 +2623,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) @@ -2604,7 +2633,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 ee675b4e853..a6784cc93a8 100644 --- a/token/cli/src/command.rs +++ b/token/cli/src/command.rs @@ -15,7 +15,7 @@ use { parse_token::{get_token_account_mint, parse_token, TokenAccountType, UiAccountState}, UiAccountData, }, - solana_clap_utils::{ + solana_clap_v3_utils::{ input_parsers::{pubkey_of_signer, pubkeys_of_multiple_signers, value_of}, keypair::signer_from_path, }, @@ -96,7 +96,7 @@ fn new_throwaway_signer() -> (Arc, Pubkey) { } fn get_signer( - matches: &ArgMatches<'_>, + matches: &ArgMatches, keypair_name: &str, wallet_manager: &mut Option>, ) -> Option<(Arc, Pubkey)> { @@ -108,7 +108,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()), @@ -3444,7 +3444,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>, diff --git a/token/cli/src/config.rs b/token/cli/src/config.rs index 89137a51b31..e5726e4076e 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::{ + solana_clap_v3_utils::{ input_parsers::{pubkey_of_signer, value_of}, 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::*, 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, @@ -127,7 +127,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 +147,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, @@ -227,11 +227,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,17 +262,27 @@ 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 let Some(program_id) = value_of(matches, "program_id") { + 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 @@ -283,13 +299,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, ), @@ -298,9 +317,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() { @@ -309,6 +342,7 @@ impl<'a> Config<'a> { ComputeUnitLimit::Simulated } }); + Self { default_signer, rpc_client, @@ -357,7 +391,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 { @@ -376,7 +410,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, @@ -408,7 +442,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 { @@ -537,3 +571,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 f89d5b3d668..661b15c42c2 100644 --- a/token/cli/tests/command.rs +++ b/token/cli/tests/command.rs @@ -437,9 +437,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))]; @@ -457,9 +456,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(); 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(); }