diff --git a/token/cli/src/bench.rs b/token/cli/src/bench.rs index 209591cefdd..54328cc1e8d 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::ArgMatches, - solana_clap_v3_utils::input_parsers::{pubkey_of_signer, Amount}, + solana_clap_v3_utils::input_parsers::{signer::SignerSource, Amount}, solana_client::{ nonblocking::rpc_client::RpcClient, rpc_client::RpcClient as BlockingRpcClient, tpu_client::TpuClient, tpu_client::TpuClientConfig, @@ -31,7 +31,7 @@ pub(crate) async fn bench_process_command( match matches.subcommand() { Some(("create-accounts", arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); let n = *arg_matches.get_one::("n").unwrap(); @@ -43,7 +43,7 @@ pub(crate) async fn bench_process_command( command_create_accounts(config, signers, &token, n, &owner).await?; } Some(("close-accounts", arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); let n = *arg_matches.get_one::("n").unwrap(); @@ -54,7 +54,7 @@ pub(crate) async fn bench_process_command( command_close_accounts(config, signers, &token, n, &owner).await?; } Some(("deposit-into", arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); let n = *arg_matches.get_one::("n").unwrap(); @@ -62,14 +62,14 @@ pub(crate) async fn bench_process_command( let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", wallet_manager); signers.push(owner_signer); - let from = pubkey_of_signer(arg_matches, "from", wallet_manager).unwrap(); + let from = SignerSource::try_get_pubkey(arg_matches, "from", wallet_manager).unwrap(); command_deposit_into_or_withdraw_from( config, signers, &token, n, &owner, ui_amount, from, true, ) .await?; } Some(("withdraw-from", arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", wallet_manager) .unwrap() .unwrap(); let n = *arg_matches.get_one::("n").unwrap(); @@ -77,7 +77,7 @@ pub(crate) async fn bench_process_command( let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", wallet_manager); signers.push(owner_signer); - let to = pubkey_of_signer(arg_matches, "to", wallet_manager).unwrap(); + let to = SignerSource::try_get_pubkey(arg_matches, "to", wallet_manager).unwrap(); command_deposit_into_or_withdraw_from( config, signers, &token, n, &owner, ui_amount, to, false, ) diff --git a/token/cli/src/clap_app.rs b/token/cli/src/clap_app.rs index 814c1c18c67..ff7abb32a7a 100644 --- a/token/cli/src/clap_app.rs +++ b/token/cli/src/clap_app.rs @@ -1,13 +1,14 @@ #![allow(deprecated)] use { + crate::print_error_and_exit, clap::{ crate_description, crate_name, crate_version, App, AppSettings, Arg, ArgGroup, SubCommand, }, solana_clap_v3_utils::{ fee_payer::fee_payer_arg, - input_parsers::Amount, - input_validators::{is_pubkey, is_url_or_moniker, is_valid_pubkey, is_valid_signer}, + input_parsers::{signer::SignerSourceParserBuilder, Amount}, + input_validators::{is_url_or_moniker, is_valid_signer}, memo::memo_arg, nonce::*, offline::{self, *}, @@ -187,38 +188,37 @@ impl fmt::Display for AccountMetaRole { write!(f, "{:?}", self) } } -pub fn parse_transfer_hook_account(string: T) -> Result -where - T: AsRef + fmt::Display, -{ - match string.as_ref().split(':').collect::>().as_slice() { - [address, role] => { - let address = Pubkey::from_str(address).map_err(|e| format!("{e}"))?; - let meta = match AccountMetaRole::from_str(role).map_err(|e| format!("{e}"))? { - AccountMetaRole::Readonly => AccountMeta::new_readonly(address, false), - AccountMetaRole::Writable => AccountMeta::new(address, false), - AccountMetaRole::ReadonlySigner => AccountMeta::new_readonly(address, true), - AccountMetaRole::WritableSigner => AccountMeta::new(address, true), - }; - Ok(meta) + +#[derive(Clone, Copy)] +pub(crate) struct TransferHookAccount { + address: Pubkey, + role: AccountMetaRole, +} +impl FromStr for TransferHookAccount { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.split(':').collect::>().as_slice() { + [address, role] => { + let address = Pubkey::from_str(address).map_err(|e| format!("{e}"))?; + let role = AccountMetaRole::from_str(role).map_err(|e| format!("{e}"))?; + Ok(Self { address, role }) + } + _ => Err("Transfer hook account must be present as
:".to_string()), } - _ => Err("Transfer hook account must be present as
:".to_string()), } } -fn validate_transfer_hook_account(string: T) -> Result<(), String> -where - T: AsRef + fmt::Display, -{ - match string.as_ref().split(':').collect::>().as_slice() { - [address, role] => { - is_valid_pubkey(address)?; - AccountMetaRole::from_str(role) - .map(|_| ()) - .map_err(|e| format!("{e}")) +impl TransferHookAccount { + pub(crate) fn create_account_meta(&self) -> AccountMeta { + match self.role { + AccountMetaRole::Readonly => AccountMeta::new_readonly(self.address, false), + AccountMetaRole::Writable => AccountMeta::new(self.address, false), + AccountMetaRole::ReadonlySigner => AccountMeta::new_readonly(self.address, true), + AccountMetaRole::WritableSigner => AccountMeta::new(self.address, true), } - _ => Err("Transfer hook account must be present as
:".to_string()), } } + #[derive(Debug, Clone, PartialEq, EnumIter, EnumString, IntoStaticStr)] #[strum(serialize_all = "kebab-case")] pub enum CliAuthorityType { @@ -278,7 +278,7 @@ pub fn owner_address_arg<'a>() -> Arg<'a> { .long(OWNER_ADDRESS_ARG.long) .takes_value(true) .value_name("OWNER_ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .help(OWNER_ADDRESS_ARG.help) } @@ -287,7 +287,7 @@ pub fn owner_keypair_arg_with_value_name<'a>(value_name: &'static str) -> Arg<'a .long(OWNER_KEYPAIR_ARG.long) .takes_value(true) .value_name(value_name) - .validator(|s| is_valid_signer(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .help(OWNER_KEYPAIR_ARG.help) } @@ -300,7 +300,7 @@ pub fn mint_address_arg<'a>() -> Arg<'a> { .long(MINT_ADDRESS_ARG.long) .takes_value(true) .value_name("MINT_ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .help(MINT_ADDRESS_ARG.help) } @@ -329,7 +329,7 @@ pub fn delegate_address_arg<'a>() -> Arg<'a> { .long(DELEGATE_ADDRESS_ARG.long) .takes_value(true) .value_name("DELEGATE_ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .help(DELEGATE_ADDRESS_ARG.help) } @@ -365,20 +365,12 @@ fn is_multisig_minimum_signers(string: &str) -> Result<(), String> { } } -fn is_valid_token_program_id(string: T) -> Result<(), String> -where - T: AsRef + fmt::Display, -{ - match is_pubkey(string.as_ref()) { - Ok(()) => { - let program_id = string.as_ref().parse::().unwrap(); - if VALID_TOKEN_PROGRAM_IDS.contains(&program_id) { - Ok(()) - } else { - Err(format!("Unrecognized token program id: {}", program_id)) - } - } - Err(e) => Err(e), +fn parse_token_program_id(arg: &str) -> Result { + let program_id = arg.parse::().unwrap_or_else(print_error_and_exit); + if VALID_TOKEN_PROGRAM_IDS.contains(&program_id) { + Ok(program_id) + } else { + Err(format!("Unrecognized token program id: {}", program_id)) } } @@ -462,7 +454,7 @@ impl BenchSubCommand for App<'_> { .about("Create multiple token accounts for benchmarking") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -485,7 +477,7 @@ impl BenchSubCommand for App<'_> { .about("Close multiple token accounts used for benchmarking") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -508,7 +500,7 @@ impl BenchSubCommand for App<'_> { .about("Deposit tokens into multiple accounts") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -536,7 +528,7 @@ impl BenchSubCommand for App<'_> { .arg( Arg::with_name("from") .long("from") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("SOURCE_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The source token account address [default: associated token account for --owner]") @@ -548,7 +540,7 @@ impl BenchSubCommand for App<'_> { .about("Withdraw tokens from multiple accounts") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -576,7 +568,7 @@ impl BenchSubCommand for App<'_> { .arg( Arg::with_name("to") .long("to") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The recipient token account address [default: associated token account for --owner]") @@ -638,7 +630,7 @@ pub fn app<'a>( .takes_value(true) .global(true) .conflicts_with("program_2022") - .validator(|s| is_valid_token_program_id(s)) + .value_parser(parse_token_program_id) .help("SPL Token program id"), ) .arg( @@ -701,7 +693,7 @@ pub fn app<'a>( .long("mint-authority") .alias("owner") .value_name("ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .takes_value(true) .help( "Specify the mint authority address. \ @@ -747,7 +739,7 @@ pub fn app<'a>( Arg::with_name("metadata_address") .long("metadata-address") .value_name("ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .takes_value(true) .conflicts_with("enable_metadata") .help( @@ -758,7 +750,7 @@ pub fn app<'a>( Arg::with_name("group_address") .long("group-address") .value_name("ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build()) .takes_value(true) .conflicts_with("enable_group") .help( @@ -769,7 +761,7 @@ pub fn app<'a>( Arg::with_name("member_address") .long("member-address") .value_name("ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build()) .takes_value(true) .conflicts_with("enable_member") .help( @@ -865,7 +857,7 @@ pub fn app<'a>( Arg::with_name("transfer_hook") .long("transfer-hook") .value_name("TRANSFER_HOOK_PROGRAM_ID") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .takes_value(true) .help("Enable the mint authority to set the transfer hook program for this mint"), ) @@ -899,7 +891,7 @@ pub fn app<'a>( .about("Set the interest rate for an interest-bearing token") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -929,7 +921,7 @@ pub fn app<'a>( .about("Set the transfer hook program id for a token") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -938,7 +930,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("new_program_id") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("NEW_PROGRAM_ID") .takes_value(true) .required_unless("disable") @@ -967,7 +959,7 @@ pub fn app<'a>( .about("Initialize metadata extension on a token mint") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1015,7 +1007,7 @@ pub fn app<'a>( Arg::with_name("update_authority") .long("update-authority") .value_name("ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .takes_value(true) .help( "Specify the update authority address. \ @@ -1028,7 +1020,7 @@ pub fn app<'a>( .about("Update metadata on a token mint that has the extension") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1075,7 +1067,7 @@ pub fn app<'a>( .about("Initialize group extension on a token mint") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1108,7 +1100,7 @@ pub fn app<'a>( Arg::with_name("update_authority") .long("update-authority") .value_name("ADDRESS") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .takes_value(true) .help( "Specify the update authority address. \ @@ -1121,7 +1113,7 @@ pub fn app<'a>( .about("Updates the maximum number of members for a group.") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1154,7 +1146,7 @@ pub fn app<'a>( .about("Initialize group member extension on a token mint") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -1163,7 +1155,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("group_token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("GROUP_TOKEN_ADDRESS") .takes_value(true) .required(true) @@ -1201,7 +1193,7 @@ pub fn app<'a>( .about("Create a new token account") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1246,7 +1238,7 @@ pub fn app<'a>( .arg( Arg::with_name("multisig_member") .value_name("MULTISIG_MEMBER_PUBKEY") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .takes_value(true) .index(2) .required(true) @@ -1273,7 +1265,7 @@ pub fn app<'a>( .about("Authorize a new signing keypair to a token or token account") .arg( Arg::with_name("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -1294,7 +1286,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("new_authority") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("AUTHORITY_ADDRESS") .takes_value(true) .index(3) @@ -1335,7 +1327,7 @@ pub fn app<'a>( .about("Transfer tokens between accounts") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1353,7 +1345,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("recipient") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("RECIPIENT_WALLET_ADDRESS or RECIPIENT_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(3) @@ -1364,7 +1356,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("from") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("SENDER_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("from") @@ -1436,7 +1428,7 @@ pub fn app<'a>( .arg( Arg::with_name("transfer_hook_account") .long("transfer-hook-account") - .validator(|s| validate_transfer_hook_account(s)) + .value_parser(clap::value_parser!(TransferHookAccount)) .value_name("PUBKEY:ROLE") .takes_value(true) .multiple(true) @@ -1465,7 +1457,7 @@ pub fn app<'a>( .about("Burn tokens from an account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1499,7 +1491,7 @@ pub fn app<'a>( .about("Mint new tokens") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1517,7 +1509,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("recipient") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("recipient_owner") @@ -1528,7 +1520,7 @@ pub fn app<'a>( .arg( Arg::with_name("recipient_owner") .long("recipient-owner") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("RECIPIENT_WALLET_ADDRESS") .takes_value(true) .conflicts_with("recipient") @@ -1558,7 +1550,7 @@ pub fn app<'a>( .about("Freeze a token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1588,7 +1580,7 @@ pub fn app<'a>( .about("Thaw a token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1661,7 +1653,7 @@ pub fn app<'a>( .about("Unwrap a SOL token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1691,7 +1683,7 @@ pub fn app<'a>( .about("Approve a delegate for a token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1709,7 +1701,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("delegate") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("DELEGATE_TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(3) @@ -1729,7 +1721,7 @@ pub fn app<'a>( .about("Revoke a delegate's authority") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1748,7 +1740,7 @@ pub fn app<'a>( .about("Close a token account") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1759,7 +1751,7 @@ pub fn app<'a>( .arg( Arg::with_name("recipient") .long("recipient") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("REFUND_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the account to receive remaining SOL [default: --owner]"), @@ -1780,7 +1772,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -1797,7 +1789,7 @@ pub fn app<'a>( .about("Close a token mint") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1807,7 +1799,7 @@ pub fn app<'a>( .arg( Arg::with_name("recipient") .long("recipient") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("REFUND_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the account to receive remaining SOL [default: --owner]"), @@ -1834,7 +1826,7 @@ pub fn app<'a>( .about("Get token account balance") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1844,7 +1836,7 @@ pub fn app<'a>( .arg(owner_address_arg().conflicts_with("address")) .arg( Arg::with_name("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("address") @@ -1858,7 +1850,7 @@ pub fn app<'a>( .about("Get token supply") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1871,7 +1863,7 @@ pub fn app<'a>( .about("List all token accounts by owner") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1912,7 +1904,7 @@ pub fn app<'a>( .about("Get wallet address") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .long("token") @@ -1933,7 +1925,7 @@ pub fn app<'a>( .setting(AppSettings::Hidden) .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -1956,7 +1948,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("address") @@ -1970,7 +1962,7 @@ pub fn app<'a>( .setting(AppSettings::Hidden) .arg( Arg::with_name("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("MULTISIG_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -1983,7 +1975,7 @@ pub fn app<'a>( .about("Query details of an SPL Token mint, account, or multisig by address") .arg( Arg::with_name("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ADDRESS") .takes_value(true) .index(1) @@ -2015,7 +2007,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .long("address") @@ -2028,7 +2020,7 @@ pub fn app<'a>( .about("Enable required transfer memos for token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2046,7 +2038,7 @@ pub fn app<'a>( .about("Disable required transfer memos for token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2064,7 +2056,7 @@ pub fn app<'a>( .about("Enable CPI Guard for token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2082,7 +2074,7 @@ pub fn app<'a>( .about("Disable CPI Guard for token account") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2100,7 +2092,7 @@ pub fn app<'a>( .about("Updates default account state for the mint. Requires the default account state extension.") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2138,7 +2130,7 @@ pub fn app<'a>( .about("Updates metadata pointer address for the mint. Requires the metadata pointer extension.") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2148,7 +2140,7 @@ pub fn app<'a>( .arg( Arg::with_name("metadata_address") .index(2) - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build()) .value_name("METADATA_ADDRESS") .takes_value(true) .required_unless("disable") @@ -2181,7 +2173,7 @@ pub fn app<'a>( .about("Updates group pointer address for the mint. Requires the group pointer extension.") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2191,7 +2183,7 @@ pub fn app<'a>( .arg( Arg::with_name("group_address") .index(2) - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build()) .value_name("GROUP_ADDRESS") .takes_value(true) .required_unless("disable") @@ -2224,7 +2216,7 @@ pub fn app<'a>( .about("Updates group member pointer address for the mint. Requires the group member pointer extension.") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2234,7 +2226,7 @@ pub fn app<'a>( .arg( Arg::with_name("member_address") .index(2) - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build()) .value_name("MEMBER_ADDRESS") .takes_value(true) .required_unless("disable") @@ -2267,7 +2259,7 @@ pub fn app<'a>( .about("Withdraw withheld transfer fee tokens from mint and / or account(s)") .arg( Arg::with_name("account") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .index(1) @@ -2276,7 +2268,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("source") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("ACCOUNT_ADDRESS") .takes_value(true) .multiple(true) @@ -2317,7 +2309,7 @@ pub fn app<'a>( .about("Set the transfer fee for a token with a configured transfer fee") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .required(true) @@ -2357,7 +2349,7 @@ pub fn app<'a>( .about("Withdraw lamports from a Token Program owned account") .arg( Arg::with_name("from") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("SOURCE_ACCOUNT_ADDRESS") .takes_value(true) .required(true) @@ -2365,7 +2357,7 @@ pub fn app<'a>( ) .arg( Arg::with_name("recipient") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("REFUND_ACCOUNT_ADDRESS") .takes_value(true) .required(true) @@ -2379,7 +2371,7 @@ pub fn app<'a>( .about("Update confidential transfer configuration for a token") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2439,7 +2431,7 @@ pub fn app<'a>( .about("Configure confidential transfers for token account") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2449,7 +2441,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2480,7 +2472,7 @@ pub fn app<'a>( for the first time, use `configure-confidential-transfer-account` instead.") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2490,7 +2482,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2508,7 +2500,7 @@ pub fn app<'a>( .about("Disable confidential transfers for token account") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2518,7 +2510,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2536,7 +2528,7 @@ pub fn app<'a>( .about("Enable non-confidential transfers for token account.") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2546,7 +2538,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2564,7 +2556,7 @@ pub fn app<'a>( .about("Disable non-confidential transfers for token account") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2574,7 +2566,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .conflicts_with("token") @@ -2592,7 +2584,7 @@ pub fn app<'a>( .about("Deposit amounts for confidential transfers") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2611,7 +2603,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the token account to configure confidential transfers for \ @@ -2629,7 +2621,7 @@ pub fn app<'a>( .about("Withdraw amounts for confidential transfers") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2648,7 +2640,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) .help("The address of the token account to configure confidential transfers for \ @@ -2666,7 +2658,7 @@ pub fn app<'a>( .about("Collect confidential tokens from pending to available balance") .arg( Arg::with_name("token") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .value_name("TOKEN_MINT_ADDRESS") .takes_value(true) .index(1) @@ -2676,7 +2668,7 @@ pub fn app<'a>( .arg( Arg::with_name("address") .long("address") - .validator(|s| is_valid_pubkey(s)) + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) .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 8a7cf30b5dd..670a76d66c6 100644 --- a/token/cli/src/command.rs +++ b/token/cli/src/command.rs @@ -6,6 +6,7 @@ use { config::{Config, MintInfo}, encryption_keypair::*, output::*, + print_error_and_exit, sort::{sort_and_parse_token_accounts, AccountFilter}, }, clap::{value_t, value_t_or_exit, ArgMatches}, @@ -17,7 +18,7 @@ use { UiAccountData, }, solana_clap_v3_utils::{ - input_parsers::{pubkey_of_signer, pubkeys_of_multiple_signers, Amount}, + input_parsers::{pubkey_of_signer, signer::SignerSource, Amount}, keypair::signer_from_path, }, solana_cli_output::{ @@ -79,11 +80,6 @@ use { std::{collections::HashMap, fmt::Display, process::exit, rc::Rc, str::FromStr, sync::Arc}, }; -fn print_error_and_exit(e: E) -> T { - eprintln!("error: {}", e); - exit(1) -} - fn amount_to_raw_amount(amount: Amount, decimals: u8, all_amount: Option, name: &str) -> u64 { match amount { Amount::Raw(ui_amount) => ui_amount, @@ -3566,9 +3562,15 @@ pub async fn process_command<'a>( config.pubkey_or_default(arg_matches, "mint_authority", &mut wallet_manager)?; let memo = value_t!(arg_matches, "memo", String).ok(); let rate_bps = value_t!(arg_matches, "interest_rate", i16).ok(); - let metadata_address = value_t!(arg_matches, "metadata_address", Pubkey).ok(); - let group_address = value_t!(arg_matches, "group_address", Pubkey).ok(); - let member_address = value_t!(arg_matches, "member_address", Pubkey).ok(); + let metadata_address = + SignerSource::try_get_pubkey(arg_matches, "metadata_address", &mut wallet_manager) + .unwrap(); + let group_address = + SignerSource::try_get_pubkey(arg_matches, "group_address", &mut wallet_manager) + .unwrap(); + let member_address = + SignerSource::try_get_pubkey(arg_matches, "member_address", &mut wallet_manager) + .unwrap(); let transfer_fee = arg_matches.values_of("transfer_fee").map(|mut v| { println_display(config,"transfer-fee has been deprecated and will be removed in a future release. Please specify --transfer-fee-basis-points and --transfer-fee-maximum-fee with a UI amount".to_string()); @@ -3605,7 +3607,8 @@ pub async fn process_command<'a>( _ => unreachable!(), }); let transfer_hook_program_id = - pubkey_of_signer(arg_matches, "transfer_hook", &mut wallet_manager).unwrap(); + SignerSource::try_get_pubkey(arg_matches, "transfer_hook", &mut wallet_manager) + .unwrap(); let confidential_transfer_auto_approve = arg_matches .value_of("enable_confidential_transfers") @@ -3637,9 +3640,10 @@ pub async fn process_command<'a>( .await } (CommandName::SetInterestRate, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let rate_bps = value_t_or_exit!(arg_matches, "rate", i16); let (rate_authority_signer, rate_authority_pubkey) = config.signer_or_default(arg_matches, "rate_authority", &mut wallet_manager); @@ -3655,11 +3659,13 @@ pub async fn process_command<'a>( .await } (CommandName::SetTransferHook, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let new_program_id = - pubkey_of_signer(arg_matches, "new_program_id", &mut wallet_manager).unwrap(); + SignerSource::try_get_pubkey(arg_matches, "new_program_id", &mut wallet_manager) + .unwrap(); let (authority_signer, authority_pubkey) = config.signer_or_default(arg_matches, "authority", &mut wallet_manager); let bulk_signers = vec![authority_signer]; @@ -3674,9 +3680,10 @@ pub async fn process_command<'a>( .await } (CommandName::InitializeMetadata, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let name = arg_matches.value_of("name").unwrap().to_string(); let symbol = arg_matches.value_of("symbol").unwrap().to_string(); let uri = arg_matches.value_of("uri").unwrap().to_string(); @@ -3699,9 +3706,10 @@ pub async fn process_command<'a>( .await } (CommandName::UpdateMetadata, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let (authority_signer, authority) = config.signer_or_default(arg_matches, "authority", &mut wallet_manager); let field = arg_matches.value_of("field").unwrap(); @@ -3729,9 +3737,10 @@ pub async fn process_command<'a>( .await } (CommandName::InitializeGroup, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let max_size = *arg_matches.get_one::("max_size").unwrap(); let (mint_authority_signer, mint_authority) = config.signer_or_default(arg_matches, "mint_authority", &mut wallet_manager); @@ -3750,9 +3759,10 @@ pub async fn process_command<'a>( .await } (CommandName::UpdateGroupMaxSize, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let new_max_size = *arg_matches.get_one::("new_max_size").unwrap(); let (update_authority_signer, update_authority) = config.signer_or_default(arg_matches, "update_authority", &mut wallet_manager); @@ -3768,11 +3778,12 @@ pub async fn process_command<'a>( .await } (CommandName::InitializeMember, arg_matches) => { - let member_token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let member_token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let group_token_pubkey = - pubkey_of_signer(arg_matches, "group_token", &mut wallet_manager) + SignerSource::try_get_pubkey(arg_matches, "group_token", &mut wallet_manager) .unwrap() .unwrap(); let (mint_authority_signer, mint_authority) = @@ -3796,7 +3807,7 @@ pub async fn process_command<'a>( .await } (CommandName::CreateAccount, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); @@ -3825,9 +3836,9 @@ pub async fn process_command<'a>( .map(|v: &String| v.parse::().unwrap()) .unwrap(); let multisig_members = - pubkeys_of_multiple_signers(arg_matches, "multisig_member", &mut wallet_manager) + SignerSource::try_get_pubkeys(arg_matches, "multisig_member", &mut wallet_manager) .unwrap_or_else(print_error_and_exit) - .unwrap(); + .unwrap_or_default(); if minimum_signers as usize > multisig_members.len() { eprintln!( "error: MINIMUM_SIGNERS cannot be greater than the number \ @@ -3842,7 +3853,7 @@ pub async fn process_command<'a>( command_create_multisig(config, signer, minimum_signers, multisig_members).await } (CommandName::Authorize, arg_matches) => { - let address = pubkey_of_signer(arg_matches, "address", &mut wallet_manager) + let address = SignerSource::try_get_pubkey(arg_matches, "address", &mut wallet_manager) .unwrap() .unwrap(); let authority_type = arg_matches.value_of("authority_type").unwrap(); @@ -3855,7 +3866,8 @@ pub async fn process_command<'a>( } let new_authority = - pubkey_of_signer(arg_matches, "new_authority", &mut wallet_manager).unwrap(); + SignerSource::try_get_pubkey(arg_matches, "new_authority", &mut wallet_manager) + .unwrap(); let force_authorize = arg_matches.is_present("force"); command_authorize( config, @@ -3869,14 +3881,16 @@ pub async fn process_command<'a>( .await } (CommandName::Transfer, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); let amount = *arg_matches.get_one::("amount").unwrap(); - let recipient = pubkey_of_signer(arg_matches, "recipient", &mut wallet_manager) - .unwrap() - .unwrap(); - let sender = pubkey_of_signer(arg_matches, "from", &mut wallet_manager).unwrap(); + let recipient = + SignerSource::try_get_pubkey(arg_matches, "recipient", &mut wallet_manager) + .unwrap() + .unwrap(); + let sender = + SignerSource::try_get_pubkey(arg_matches, "from", &mut wallet_manager).unwrap(); let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", &mut wallet_manager); @@ -3921,11 +3935,13 @@ pub async fn process_command<'a>( let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); let expected_fee = arg_matches.get_one::("expected_fee").copied(); 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() - .map(|s| parse_transfer_hook_account(s).unwrap()) - .collect::>() - }); + let transfer_hook_accounts = arg_matches + .get_many::("transfer_hook_account") + .map(|v| { + v.into_iter() + .map(|account| account.create_account_meta()) + .collect::>() + }); command_transfer( config, @@ -3950,7 +3966,7 @@ pub async fn process_command<'a>( .await } (CommandName::Burn, arg_matches) => { - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) + let account = SignerSource::try_get_pubkey(arg_matches, "account", &mut wallet_manager) .unwrap() .unwrap(); @@ -3988,18 +4004,19 @@ pub async fn process_command<'a>( push_signer_with_dedup(mint_authority_signer, &mut bulk_signers); } - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); let amount = *arg_matches.get_one::("amount").unwrap(); let mint_decimals = arg_matches.get_one::(MINT_DECIMALS_ARG.name).copied(); 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() + SignerSource::try_get_pubkey(arg_matches, "recipient", &mut wallet_manager).unwrap() { address } else if let Some(address) = - pubkey_of_signer(arg_matches, "recipient_owner", &mut wallet_manager).unwrap() + SignerSource::try_get_pubkey(arg_matches, "recipient_owner", &mut wallet_manager) + .unwrap() { get_associated_token_address_with_program_id(&address, &token, &config.program_id) } else { @@ -4033,7 +4050,7 @@ pub async fn process_command<'a>( push_signer_with_dedup(freeze_authority_signer, &mut bulk_signers); } - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) + let account = SignerSource::try_get_pubkey(arg_matches, "account", &mut wallet_manager) .unwrap() .unwrap(); let mint_address = @@ -4054,7 +4071,7 @@ pub async fn process_command<'a>( push_signer_with_dedup(freeze_authority_signer, &mut bulk_signers); } - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) + let account = SignerSource::try_get_pubkey(arg_matches, "account", &mut wallet_manager) .unwrap() .unwrap(); let mint_address = @@ -4098,7 +4115,8 @@ pub async fn process_command<'a>( config.signer_or_default(arg_matches, "wallet_keypair", &mut wallet_manager); push_signer_with_dedup(wallet_signer, &mut bulk_signers); - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager).unwrap(); + let account = + SignerSource::try_get_pubkey(arg_matches, "account", &mut wallet_manager).unwrap(); command_unwrap(config, wallet_address, account, bulk_signers).await } (CommandName::Approve, arg_matches) => { @@ -4108,15 +4126,20 @@ pub async fn process_command<'a>( push_signer_with_dedup(owner_signer, &mut bulk_signers); } - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) + let account = SignerSource::try_get_pubkey(arg_matches, "account", &mut wallet_manager) .unwrap() .unwrap(); let amount = *arg_matches.get_one::("amount").unwrap(); - let delegate = pubkey_of_signer(arg_matches, "delegate", &mut wallet_manager) - .unwrap() - .unwrap(); - let mint_address = - pubkey_of_signer(arg_matches, MINT_ADDRESS_ARG.name, &mut wallet_manager).unwrap(); + let delegate = + SignerSource::try_get_pubkey(arg_matches, "delegate", &mut wallet_manager) + .unwrap() + .unwrap(); + let mint_address = SignerSource::try_get_pubkey( + arg_matches, + MINT_ADDRESS_ARG.name, + &mut wallet_manager, + ) + .unwrap(); let mint_decimals = arg_matches .get_one(MINT_DECIMALS_ARG.name) .map(|v: &String| v.parse::().unwrap()); @@ -4141,7 +4164,7 @@ pub async fn process_command<'a>( push_signer_with_dedup(owner_signer, &mut bulk_signers); } - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) + let account = SignerSource::try_get_pubkey(arg_matches, "account", &mut wallet_manager) .unwrap() .unwrap(); let delegate_address = @@ -4171,7 +4194,7 @@ pub async fn process_command<'a>( command_close(config, address, close_authority, recipient, bulk_signers).await } (CommandName::CloseMint, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); let (close_authority_signer, close_authority) = @@ -4191,13 +4214,14 @@ pub async fn process_command<'a>( command_balance(config, address).await } (CommandName::Supply, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); command_supply(config, token).await } (CommandName::Accounts, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager).unwrap(); + let token = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager).unwrap(); let owner = config.pubkey_or_default(arg_matches, "owner", &mut wallet_manager)?; let filter = if arg_matches.is_present("delegated") { AccountFilter::Delegated @@ -4217,7 +4241,8 @@ pub async fn process_command<'a>( .await } (CommandName::Address, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager).unwrap(); + let token = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager).unwrap(); let owner = config.pubkey_or_default(arg_matches, "owner", &mut wallet_manager)?; command_address(config, token, owner).await } @@ -4228,13 +4253,13 @@ pub async fn process_command<'a>( command_display(config, address).await } (CommandName::MultisigInfo, arg_matches) => { - let address = pubkey_of_signer(arg_matches, "address", &mut wallet_manager) + let address = SignerSource::try_get_pubkey(arg_matches, "address", &mut wallet_manager) .unwrap() .unwrap(); command_display(config, address).await } (CommandName::Display, arg_matches) => { - let address = pubkey_of_signer(arg_matches, "address", &mut wallet_manager) + let address = SignerSource::try_get_pubkey(arg_matches, "address", &mut wallet_manager) .unwrap() .unwrap(); command_display(config, address).await @@ -4325,7 +4350,7 @@ pub async fn process_command<'a>( } (CommandName::UpdateDefaultAccountState, arg_matches) => { // Since account is required argument it will always be present - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); let (freeze_authority_signer, freeze_authority) = @@ -4350,7 +4375,7 @@ pub async fn process_command<'a>( } (CommandName::UpdateMetadataAddress, arg_matches) => { // Since account is required argument it will always be present - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); @@ -4359,7 +4384,9 @@ pub async fn process_command<'a>( if config.multisigner_pubkeys.is_empty() { push_signer_with_dedup(authority_signer, &mut bulk_signers); } - let metadata_address = value_t!(arg_matches, "metadata_address", Pubkey).ok(); + let metadata_address = + SignerSource::try_get_pubkey(arg_matches, "metadata_address", &mut wallet_manager) + .unwrap(); command_update_pointer_address( config, @@ -4373,7 +4400,7 @@ pub async fn process_command<'a>( } (CommandName::UpdateGroupAddress, arg_matches) => { // Since account is required argument it will always be present - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); @@ -4382,7 +4409,9 @@ pub async fn process_command<'a>( if config.multisigner_pubkeys.is_empty() { push_signer_with_dedup(authority_signer, &mut bulk_signers); } - let group_address = value_t!(arg_matches, "group_address", Pubkey).ok(); + let group_address = + SignerSource::try_get_pubkey(arg_matches, "group_address", &mut wallet_manager) + .unwrap(); command_update_pointer_address( config, @@ -4396,7 +4425,7 @@ pub async fn process_command<'a>( } (CommandName::UpdateMemberAddress, arg_matches) => { // Since account is required argument it will always be present - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); @@ -4405,7 +4434,9 @@ pub async fn process_command<'a>( if config.multisigner_pubkeys.is_empty() { push_signer_with_dedup(authority_signer, &mut bulk_signers); } - let member_address = value_t!(arg_matches, "member_address", Pubkey).ok(); + let member_address = + SignerSource::try_get_pubkey(arg_matches, "member_address", &mut wallet_manager) + .unwrap(); command_update_pointer_address( config, @@ -4428,15 +4459,14 @@ pub async fn process_command<'a>( } // Since destination is required it will always be present let destination_token_account = - pubkey_of_signer(arg_matches, "account", &mut wallet_manager) + SignerSource::try_get_pubkey(arg_matches, "account", &mut wallet_manager) .unwrap() .unwrap(); let include_mint = arg_matches.is_present("include_mint"); - let source_accounts = arg_matches - .values_of("source") - .unwrap_or_default() - .map(|s| Pubkey::from_str(s).unwrap_or_else(print_error_and_exit)) - .collect::>(); + let source_accounts = + SignerSource::try_get_pubkeys(arg_matches, "source", &mut wallet_manager) + .unwrap() + .unwrap_or_default(); command_withdraw_withheld_tokens( config, destination_token_account, @@ -4448,9 +4478,10 @@ pub async fn process_command<'a>( .await } (CommandName::SetTransferFee, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let transfer_fee_basis_points = value_t_or_exit!(arg_matches, "transfer_fee_basis_points", u16); let maximum_fee = *arg_matches.get_one::("maximum_fee").unwrap(); @@ -4485,9 +4516,10 @@ pub async fn process_command<'a>( .await } (CommandName::UpdateConfidentialTransferSettings, arg_matches) => { - let token_pubkey = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); + let token_pubkey = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) + .unwrap() + .unwrap(); let auto_approve = arg_matches.value_of("approve_policy").map(|b| b == "auto"); @@ -4515,12 +4547,14 @@ pub async fn process_command<'a>( .await } (CommandName::ConfigureConfidentialTransferAccount, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager).unwrap(); + let token = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager).unwrap(); let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - let account = pubkey_of_signer(arg_matches, "address", &mut wallet_manager).unwrap(); + let account = + SignerSource::try_get_pubkey(arg_matches, "address", &mut wallet_manager).unwrap(); // Deriving ElGamal and AES key from signer. Custom ElGamal and AES keys will be // supported in the future once upgrading to clap-v3. @@ -4561,12 +4595,14 @@ pub async fn process_command<'a>( | (c @ CommandName::DisableConfidentialCredits, arg_matches) | (c @ CommandName::EnableNonConfidentialCredits, arg_matches) | (c @ CommandName::DisableNonConfidentialCredits, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager).unwrap(); + let token = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager).unwrap(); let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - let account = pubkey_of_signer(arg_matches, "address", &mut wallet_manager).unwrap(); + let account = + SignerSource::try_get_pubkey(arg_matches, "address", &mut wallet_manager).unwrap(); if config.multisigner_pubkeys.is_empty() { push_signer_with_dedup(owner_signer, &mut bulk_signers); @@ -4593,11 +4629,12 @@ pub async fn process_command<'a>( } (c @ CommandName::DepositConfidentialTokens, arg_matches) | (c @ CommandName::WithdrawConfidentialTokens, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager) .unwrap() .unwrap(); let amount = *arg_matches.get_one::("amount").unwrap(); - let account = pubkey_of_signer(arg_matches, "address", &mut wallet_manager).unwrap(); + let account = + SignerSource::try_get_pubkey(arg_matches, "address", &mut wallet_manager).unwrap(); let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", &mut wallet_manager); @@ -4645,12 +4682,14 @@ pub async fn process_command<'a>( .await } (CommandName::ApplyPendingBalance, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager).unwrap(); + let token = + SignerSource::try_get_pubkey(arg_matches, "token", &mut wallet_manager).unwrap(); let (owner_signer, owner) = config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - let account = pubkey_of_signer(arg_matches, "address", &mut wallet_manager).unwrap(); + let account = + SignerSource::try_get_pubkey(arg_matches, "address", &mut wallet_manager).unwrap(); // Deriving ElGamal and AES key from signer. Custom ElGamal and AES keys will be // supported in the future once upgrading to clap-v3. diff --git a/token/cli/src/config.rs b/token/cli/src/config.rs index 0ea6284bb78..d8e6ae57d08 100644 --- a/token/cli/src/config.rs +++ b/token/cli/src/config.rs @@ -1,8 +1,14 @@ use { - crate::clap_app::{Error, COMPUTE_UNIT_LIMIT_ARG, COMPUTE_UNIT_PRICE_ARG, MULTISIG_SIGNER_ARG}, + crate::{ + clap_app::{Error, COMPUTE_UNIT_LIMIT_ARG, COMPUTE_UNIT_PRICE_ARG, MULTISIG_SIGNER_ARG}, + print_error_and_exit, + }, clap::ArgMatches, solana_clap_v3_utils::{ - input_parsers::pubkey_of_signer, + input_parsers::{ + pubkey_of_signer, + signer::{SignerSource, SignerSourceKind}, + }, input_validators::normalize_to_url_if_moniker, keypair::SignerFromPathConfig, nonce::{NONCE_ARG, NONCE_AUTHORITY_ARG}, @@ -180,13 +186,12 @@ impl<'a> Config<'a> { allow_null_signer: !multisigner_pubkeys.is_empty(), }; - let default_keypair = cli_config.keypair_path.clone(); - let default_signer: Option> = { - if let Some(owner_path) = matches.try_get_one::("owner").ok().flatten() { - signer_from_path_with_config(matches, owner_path, "owner", wallet_manager, &config) + if let Some(source) = matches.try_get_one::("owner").ok().flatten() { + signer_from_source_with_config(matches, source, "owner", wallet_manager, &config) .ok() } else { + let default_keypair = cli_config.keypair_path.clone(); signer_from_path_with_config( matches, &default_keypair, @@ -196,8 +201,7 @@ impl<'a> Config<'a> { ) .map_err(|e| { if std::fs::metadata(&default_keypair).is_ok() { - eprintln!("error: {}", e); - exit(1); + print_error_and_exit(e) } else { e } @@ -275,19 +279,17 @@ impl<'a> Config<'a> { .try_contains_id(DUMP_TRANSACTION_MESSAGE.name) .unwrap_or(false); - let pubkey_from_matches = |name| { - matches - .try_get_one::(name) + let mut pubkey_from_matches = |name| { + SignerSource::try_get_pubkey(matches, name, wallet_manager) .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) = pubkey_from_matches("program_id") { - (program_id, true) + } else if let Some(program_id) = matches.get_one::("program_id") { + (*program_id, true) } else if !sign_only { if let Some(address) = pubkey_from_matches("token") .or_else(|| pubkey_from_matches("account")) @@ -398,7 +400,7 @@ impl<'a> Config<'a> { override_name: &str, wallet_manager: &mut Option>, ) -> Result { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) + let token = SignerSource::try_get_pubkey(arg_matches, "token", wallet_manager) .map_err(|e| -> Error { e.to_string().into() })?; self.associated_token_address_for_token_or_override( arg_matches, @@ -418,8 +420,9 @@ impl<'a> Config<'a> { wallet_manager: &mut Option>, token: Option, ) -> Result { - if let Some(address) = pubkey_of_signer(arg_matches, override_name, wallet_manager) - .map_err(|e| -> Error { e.to_string().into() })? + if let Some(address) = + SignerSource::try_get_pubkey(arg_matches, override_name, wallet_manager) + .map_err(|e| -> Error { e.to_string().into() })? { return Ok(address); } @@ -449,8 +452,9 @@ impl<'a> Config<'a> { address_name: &str, wallet_manager: &mut Option>, ) -> Result { - if let Some(address) = pubkey_of_signer(arg_matches, address_name, wallet_manager) - .map_err(|e| -> Error { e.to_string().into() })? + if let Some(address) = + SignerSource::try_get_pubkey(arg_matches, address_name, wallet_manager) + .map_err(|e| -> Error { e.to_string().into() })? { return Ok(address); } @@ -615,3 +619,30 @@ fn signer_from_path_with_config( config, ) } + +/// A wrapper function around the `solana_clap_v3_utils` `signer_from_source +/// with_config` function. If the signer source is a pubkey, then it checks for +/// signing-only or if null signer is allowed and creates a null signer. +/// Otherwise, it invokes the `solana_clap_v3_utils` version of the function. +fn signer_from_source_with_config( + matches: &ArgMatches, + source: &SignerSource, + keypair_name: &str, + wallet_manager: &mut Option>, + config: &SignerFromPathConfig, +) -> Result, Box> { + if let SignerSourceKind::Pubkey(pubkey) = source.kind { + 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_source_with_config( + matches, + source, + keypair_name, + wallet_manager, + config, + ) +} diff --git a/token/cli/src/lib.rs b/token/cli/src/lib.rs index b38c26b44fd..d78b11215c7 100644 --- a/token/cli/src/lib.rs +++ b/token/cli/src/lib.rs @@ -5,3 +5,8 @@ pub mod config; mod encryption_keypair; mod output; mod sort; + +fn print_error_and_exit(e: E) -> T { + eprintln!("error: {}", e); + std::process::exit(1) +}