1#![allow(deprecated)]
2
3use {
4 clap::{
5 crate_description, crate_name, crate_version, App, AppSettings, Arg, ArgGroup, SubCommand,
6 },
7 solana_clap_v3_utils::{
8 fee_payer::fee_payer_arg,
9 input_parsers::Amount,
10 input_validators::{is_pubkey, is_url_or_moniker, is_valid_pubkey, is_valid_signer},
11 memo::memo_arg,
12 nonce::*,
13 offline::{self, *},
14 ArgConstant,
15 },
16 solana_sdk::{instruction::AccountMeta, pubkey::Pubkey},
17 spl_token_2022_interface::instruction::{AuthorityType, MAX_SIGNERS, MIN_SIGNERS},
18 std::{fmt, str::FromStr},
19 strum::IntoEnumIterator,
20 strum_macros::{AsRefStr, EnumIter, EnumString, IntoStaticStr},
21};
22
23pub type Error = Box<dyn std::error::Error + Send + Sync>;
24
25pub const OWNER_ADDRESS_ARG: ArgConstant<'static> = ArgConstant {
26 name: "owner",
27 long: "owner",
28 help: "Address of the primary authority controlling a mint or account. Defaults to the client keypair address.",
29};
30
31pub const OWNER_KEYPAIR_ARG: ArgConstant<'static> = ArgConstant {
32 name: "owner",
33 long: "owner",
34 help: "Keypair of the primary authority controlling a mint or account. Defaults to the client keypair.",
35};
36
37pub const MINT_ADDRESS_ARG: ArgConstant<'static> = ArgConstant {
38 name: "mint_address",
39 long: "mint-address",
40 help: "Address of mint that token account is associated with. Required by --sign-only",
41};
42
43pub const MINT_DECIMALS_ARG: ArgConstant<'static> = ArgConstant {
44 name: "mint_decimals",
45 long: "mint-decimals",
46 help: "Decimals of mint that token account is associated with. Required by --sign-only",
47};
48
49pub const DELEGATE_ADDRESS_ARG: ArgConstant<'static> = ArgConstant {
50 name: "delegate_address",
51 long: "delegate-address",
52 help: "Address of delegate currently assigned to token account. Required by --sign-only",
53};
54
55pub const TRANSFER_LAMPORTS_ARG: ArgConstant<'static> = ArgConstant {
56 name: "transfer_lamports",
57 long: "transfer-lamports",
58 help: "Additional lamports to transfer to make account rent-exempt after reallocation. Required by --sign-only",
59};
60
61pub const MULTISIG_SIGNER_ARG: ArgConstant<'static> = ArgConstant {
62 name: "multisig_signer",
63 long: "multisig-signer",
64 help: "Member signer of a multisig account",
65};
66
67pub const COMPUTE_UNIT_PRICE_ARG: ArgConstant<'static> = ArgConstant {
68 name: "compute_unit_price",
69 long: "--with-compute-unit-price",
70 help: "Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.",
71};
72
73pub const COMPUTE_UNIT_LIMIT_ARG: ArgConstant<'static> = ArgConstant {
74 name: "compute_unit_limit",
75 long: "--with-compute-unit-limit",
76 help: "Set compute unit limit for transaction, in compute units.",
77};
78
79fn signer_arg<'a>() -> Arg<'a> {
85 Arg::new(SIGNER_ARG.name)
86 .long(SIGNER_ARG.long)
87 .takes_value(true)
88 .value_name("PUBKEY=SIGNATURE")
89 .requires(BLOCKHASH_ARG.name)
90 .action(clap::ArgAction::Append)
91 .multiple_values(false)
92 .help(SIGNER_ARG.help)
93}
94
95pub trait OfflineArgs {
96 fn offline_args(self) -> Self;
97 fn offline_args_config(self, config: &dyn ArgsConfig) -> Self;
98}
99
100impl OfflineArgs for clap::Command<'_> {
101 fn offline_args_config(self, config: &dyn ArgsConfig) -> Self {
102 self.arg(config.blockhash_arg(blockhash_arg()))
103 .arg(config.sign_only_arg(sign_only_arg()))
104 .arg(config.signer_arg(signer_arg()))
105 .arg(config.dump_transaction_message_arg(dump_transaction_message()))
106 }
107 fn offline_args(self) -> Self {
108 struct NullArgsConfig {}
109 impl ArgsConfig for NullArgsConfig {}
110 self.offline_args_config(&NullArgsConfig {})
111 }
112}
113
114pub static VALID_TOKEN_PROGRAM_IDS: [Pubkey; 2] =
115 [spl_token_2022_interface::ID, spl_token_interface::ID];
116
117#[derive(AsRefStr, Debug, Clone, Copy, PartialEq, EnumString, IntoStaticStr)]
118#[strum(serialize_all = "kebab-case")]
119pub enum CommandName {
120 CreateToken,
121 Close,
122 CloseMint,
123 Bench,
124 CreateAccount,
125 CreateMultisig,
126 Authorize,
127 SetInterestRate,
128 Transfer,
129 Burn,
130 Mint,
131 Freeze,
132 Thaw,
133 Wrap,
134 Unwrap,
135 Approve,
136 Revoke,
137 Balance,
138 Supply,
139 Accounts,
140 Address,
141 AccountInfo,
142 MultisigInfo,
143 Display,
144 Gc,
145 SyncNative,
146 EnableRequiredTransferMemos,
147 DisableRequiredTransferMemos,
148 EnableCpiGuard,
149 DisableCpiGuard,
150 UpdateDefaultAccountState,
151 UpdateMetadataAddress,
152 WithdrawWithheldTokens,
153 SetTransferFee,
154 WithdrawExcessLamports,
155 SetTransferHook,
156 InitializeMetadata,
157 UpdateMetadata,
158 InitializeGroup,
159 UpdateGroupMaxSize,
160 InitializeMember,
161 UpdateConfidentialTransferSettings,
162 ConfigureConfidentialTransferAccount,
163 EnableConfidentialCredits,
164 DisableConfidentialCredits,
165 EnableNonConfidentialCredits,
166 DisableNonConfidentialCredits,
167 DepositConfidentialTokens,
168 WithdrawConfidentialTokens,
169 ApplyPendingBalance,
170 UpdateGroupAddress,
171 UpdateMemberAddress,
172 UpdateUiAmountMultiplier,
173 Pause,
174 Resume,
175}
176impl fmt::Display for CommandName {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 write!(f, "{:?}", self)
179 }
180}
181#[derive(Debug, Clone, Copy, PartialEq, EnumString, IntoStaticStr)]
182#[strum(serialize_all = "kebab-case")]
183pub enum AccountMetaRole {
184 Readonly,
185 Writable,
186 ReadonlySigner,
187 WritableSigner,
188}
189impl fmt::Display for AccountMetaRole {
190 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191 write!(f, "{:?}", self)
192 }
193}
194pub fn parse_transfer_hook_account<T>(string: T) -> Result<AccountMeta, String>
195where
196 T: AsRef<str> + fmt::Display,
197{
198 match string.as_ref().split(':').collect::<Vec<_>>().as_slice() {
199 [address, role] => {
200 let address = Pubkey::from_str(address).map_err(|e| format!("{e}"))?;
201 let meta = match AccountMetaRole::from_str(role).map_err(|e| format!("{e}"))? {
202 AccountMetaRole::Readonly => AccountMeta::new_readonly(address, false),
203 AccountMetaRole::Writable => AccountMeta::new(address, false),
204 AccountMetaRole::ReadonlySigner => AccountMeta::new_readonly(address, true),
205 AccountMetaRole::WritableSigner => AccountMeta::new(address, true),
206 };
207 Ok(meta)
208 }
209 _ => Err("Transfer hook account must be present as <ADDRESS>:<ROLE>".to_string()),
210 }
211}
212fn validate_transfer_hook_account<T>(string: T) -> Result<(), String>
213where
214 T: AsRef<str> + fmt::Display,
215{
216 match string.as_ref().split(':').collect::<Vec<_>>().as_slice() {
217 [address, role] => {
218 is_valid_pubkey(address)?;
219 AccountMetaRole::from_str(role)
220 .map(|_| ())
221 .map_err(|e| format!("{e}"))
222 }
223 _ => Err("Transfer hook account must be present as <ADDRESS>:<ROLE>".to_string()),
224 }
225}
226#[derive(Debug, Clone, PartialEq, EnumIter, EnumString, IntoStaticStr)]
227#[strum(serialize_all = "kebab-case")]
228pub enum CliAuthorityType {
229 Mint,
230 Freeze,
231 Owner,
232 Close,
233 CloseMint,
234 TransferFeeConfig,
235 WithheldWithdraw,
236 InterestRate,
237 PermanentDelegate,
238 ConfidentialTransferMint,
239 TransferHookProgramId,
240 ConfidentialTransferFee,
241 MetadataPointer,
242 Metadata,
243 GroupPointer,
244 GroupMemberPointer,
245 Group,
246 ScaledUiAmount,
247 Pause,
248}
249impl TryFrom<CliAuthorityType> for AuthorityType {
250 type Error = Error;
251 fn try_from(authority_type: CliAuthorityType) -> Result<Self, Error> {
252 match authority_type {
253 CliAuthorityType::Mint => Ok(AuthorityType::MintTokens),
254 CliAuthorityType::Freeze => Ok(AuthorityType::FreezeAccount),
255 CliAuthorityType::Owner => Ok(AuthorityType::AccountOwner),
256 CliAuthorityType::Close => Ok(AuthorityType::CloseAccount),
257 CliAuthorityType::CloseMint => Ok(AuthorityType::CloseMint),
258 CliAuthorityType::TransferFeeConfig => Ok(AuthorityType::TransferFeeConfig),
259 CliAuthorityType::WithheldWithdraw => Ok(AuthorityType::WithheldWithdraw),
260 CliAuthorityType::InterestRate => Ok(AuthorityType::InterestRate),
261 CliAuthorityType::PermanentDelegate => Ok(AuthorityType::PermanentDelegate),
262 CliAuthorityType::ConfidentialTransferMint => {
263 Ok(AuthorityType::ConfidentialTransferMint)
264 }
265 CliAuthorityType::TransferHookProgramId => Ok(AuthorityType::TransferHookProgramId),
266 CliAuthorityType::ConfidentialTransferFee => {
267 Ok(AuthorityType::ConfidentialTransferFeeConfig)
268 }
269 CliAuthorityType::MetadataPointer => Ok(AuthorityType::MetadataPointer),
270 CliAuthorityType::Metadata => {
271 Err("Metadata authority does not map to a token authority type".into())
272 }
273 CliAuthorityType::GroupPointer => Ok(AuthorityType::GroupPointer),
274 CliAuthorityType::GroupMemberPointer => Ok(AuthorityType::GroupMemberPointer),
275 CliAuthorityType::Group => {
276 Err("Group update authority does not map to a token authority type".into())
277 }
278 CliAuthorityType::ScaledUiAmount => Ok(AuthorityType::ScaledUiAmount),
279 CliAuthorityType::Pause => Ok(AuthorityType::Pause),
280 }
281 }
282}
283
284pub fn owner_address_arg<'a>() -> Arg<'a> {
285 Arg::with_name(OWNER_ADDRESS_ARG.name)
286 .long(OWNER_ADDRESS_ARG.long)
287 .takes_value(true)
288 .value_name("OWNER_ADDRESS")
289 .validator(|s| is_valid_pubkey(s))
290 .help(OWNER_ADDRESS_ARG.help)
291}
292
293pub fn owner_keypair_arg_with_value_name<'a>(value_name: &'static str) -> Arg<'a> {
294 Arg::with_name(OWNER_KEYPAIR_ARG.name)
295 .long(OWNER_KEYPAIR_ARG.long)
296 .takes_value(true)
297 .value_name(value_name)
298 .validator(|s| is_valid_signer(s))
299 .help(OWNER_KEYPAIR_ARG.help)
300}
301
302pub fn owner_keypair_arg<'a>() -> Arg<'a> {
303 owner_keypair_arg_with_value_name("OWNER_KEYPAIR")
304}
305
306pub fn mint_address_arg<'a>() -> Arg<'a> {
307 Arg::with_name(MINT_ADDRESS_ARG.name)
308 .long(MINT_ADDRESS_ARG.long)
309 .takes_value(true)
310 .value_name("MINT_ADDRESS")
311 .validator(|s| is_valid_pubkey(s))
312 .help(MINT_ADDRESS_ARG.help)
313}
314
315pub fn mint_decimals_arg<'a>() -> Arg<'a> {
316 Arg::with_name(MINT_DECIMALS_ARG.name)
317 .long(MINT_DECIMALS_ARG.long)
318 .takes_value(true)
319 .value_name("MINT_DECIMALS")
320 .value_parser(clap::value_parser!(u8))
321 .help(MINT_DECIMALS_ARG.help)
322}
323
324pub trait MintArgs {
325 fn mint_args(self) -> Self;
326}
327
328impl MintArgs for App<'_> {
329 fn mint_args(self) -> Self {
330 self.arg(mint_address_arg().requires(MINT_DECIMALS_ARG.name))
331 .arg(mint_decimals_arg().requires(MINT_ADDRESS_ARG.name))
332 }
333}
334
335pub fn delegate_address_arg<'a>() -> Arg<'a> {
336 Arg::with_name(DELEGATE_ADDRESS_ARG.name)
337 .long(DELEGATE_ADDRESS_ARG.long)
338 .takes_value(true)
339 .value_name("DELEGATE_ADDRESS")
340 .validator(|s| is_valid_pubkey(s))
341 .help(DELEGATE_ADDRESS_ARG.help)
342}
343
344pub fn transfer_lamports_arg<'a>() -> Arg<'a> {
345 Arg::with_name(TRANSFER_LAMPORTS_ARG.name)
346 .long(TRANSFER_LAMPORTS_ARG.long)
347 .takes_value(true)
348 .value_name("LAMPORTS")
349 .value_parser(clap::value_parser!(u64))
350 .help(TRANSFER_LAMPORTS_ARG.help)
351}
352
353pub fn multisig_signer_arg<'a>() -> Arg<'a> {
354 Arg::with_name(MULTISIG_SIGNER_ARG.name)
355 .long(MULTISIG_SIGNER_ARG.long)
356 .validator(|s| is_valid_signer(s))
357 .value_name("MULTISIG_SIGNER")
358 .takes_value(true)
359 .multiple(true)
360 .min_values(0_usize)
361 .max_values(MAX_SIGNERS)
362 .help(MULTISIG_SIGNER_ARG.help)
363}
364
365fn is_multisig_minimum_signers(string: &str) -> Result<(), String> {
366 let v = u8::from_str(string).map_err(|e| e.to_string())? as usize;
367 if v < MIN_SIGNERS {
368 Err(format!("must be at least {}", MIN_SIGNERS))
369 } else if v > MAX_SIGNERS {
370 Err(format!("must be at most {}", MAX_SIGNERS))
371 } else {
372 Ok(())
373 }
374}
375
376fn is_valid_token_program_id<T>(string: T) -> Result<(), String>
377where
378 T: AsRef<str> + fmt::Display,
379{
380 match is_pubkey(string.as_ref()) {
381 Ok(()) => {
382 let program_id = string.as_ref().parse::<Pubkey>().unwrap();
383 if VALID_TOKEN_PROGRAM_IDS.contains(&program_id) {
384 Ok(())
385 } else {
386 Err(format!("Unrecognized token program id: {}", program_id))
387 }
388 }
389 Err(e) => Err(e),
390 }
391}
392
393struct SignOnlyNeedsFullMintSpec {}
394impl offline::ArgsConfig for SignOnlyNeedsFullMintSpec {
395 fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
396 arg.requires_all(&[MINT_ADDRESS_ARG.name, MINT_DECIMALS_ARG.name])
397 }
398 fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
399 arg.requires_all(&[MINT_ADDRESS_ARG.name, MINT_DECIMALS_ARG.name])
400 }
401}
402
403struct SignOnlyNeedsMintDecimals {}
404impl offline::ArgsConfig for SignOnlyNeedsMintDecimals {
405 fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
406 arg.requires_all(&[MINT_DECIMALS_ARG.name])
407 }
408 fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
409 arg.requires_all(&[MINT_DECIMALS_ARG.name])
410 }
411}
412
413struct SignOnlyNeedsMintAddress {}
414impl offline::ArgsConfig for SignOnlyNeedsMintAddress {
415 fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
416 arg.requires_all(&[MINT_ADDRESS_ARG.name])
417 }
418 fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
419 arg.requires_all(&[MINT_ADDRESS_ARG.name])
420 }
421}
422
423struct SignOnlyNeedsDelegateAddress {}
424impl offline::ArgsConfig for SignOnlyNeedsDelegateAddress {
425 fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
426 arg.requires_all(&[DELEGATE_ADDRESS_ARG.name])
427 }
428 fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
429 arg.requires_all(&[DELEGATE_ADDRESS_ARG.name])
430 }
431}
432
433struct SignOnlyNeedsTransferLamports {}
434impl offline::ArgsConfig for SignOnlyNeedsTransferLamports {
435 fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
436 arg.requires_all(&[TRANSFER_LAMPORTS_ARG.name])
437 }
438 fn signer_arg<'a, 'b>(&self, arg: Arg<'a>) -> Arg<'a> {
439 arg.requires_all(&[TRANSFER_LAMPORTS_ARG.name])
440 }
441}
442
443pub fn minimum_signers_help_string() -> String {
444 format!(
445 "The minimum number of signers required to allow the operation. [{} <= M <= N]",
446 MIN_SIGNERS
447 )
448}
449
450pub fn multisig_member_help_string() -> String {
451 format!(
452 "The public keys for each of the N signing members of this account. [{} <= N <= {}]",
453 MIN_SIGNERS, MAX_SIGNERS
454 )
455}
456
457pub(crate) trait BenchSubCommand {
458 fn bench_subcommand(self) -> Self;
459}
460
461impl BenchSubCommand for App<'_> {
462 fn bench_subcommand(self) -> Self {
463 self.subcommand(
464 SubCommand::with_name("bench")
465 .about("Token benchmarking facilities")
466 .setting(AppSettings::InferSubcommands)
467 .setting(AppSettings::SubcommandRequiredElseHelp)
468 .subcommand(
469 SubCommand::with_name("create-accounts")
470 .about("Create multiple token accounts for benchmarking")
471 .arg(
472 Arg::with_name("token")
473 .validator(|s| is_valid_pubkey(s))
474 .value_name("TOKEN_ADDRESS")
475 .takes_value(true)
476 .index(1)
477 .required(true)
478 .help("The token that the accounts will hold"),
479 )
480 .arg(
481 Arg::with_name("n")
482 .value_parser(clap::value_parser!(usize))
483 .value_name("N")
484 .takes_value(true)
485 .index(2)
486 .required(true)
487 .help("The number of accounts to create"),
488 )
489 .arg(owner_address_arg()),
490 )
491 .subcommand(
492 SubCommand::with_name("close-accounts")
493 .about("Close multiple token accounts used for benchmarking")
494 .arg(
495 Arg::with_name("token")
496 .validator(|s| is_valid_pubkey(s))
497 .value_name("TOKEN_ADDRESS")
498 .takes_value(true)
499 .index(1)
500 .required(true)
501 .help("The token that the accounts held"),
502 )
503 .arg(
504 Arg::with_name("n")
505 .value_parser(clap::value_parser!(usize))
506 .value_name("N")
507 .takes_value(true)
508 .index(2)
509 .required(true)
510 .help("The number of accounts to close"),
511 )
512 .arg(owner_address_arg()),
513 )
514 .subcommand(
515 SubCommand::with_name("deposit-into")
516 .about("Deposit tokens into multiple accounts")
517 .arg(
518 Arg::with_name("token")
519 .validator(|s| is_valid_pubkey(s))
520 .value_name("TOKEN_ADDRESS")
521 .takes_value(true)
522 .index(1)
523 .required(true)
524 .help("The token that the accounts will hold"),
525 )
526 .arg(
527 Arg::with_name("n")
528 .value_parser(clap::value_parser!(usize))
529 .value_name("N")
530 .takes_value(true)
531 .index(2)
532 .required(true)
533 .help("The number of accounts to deposit into"),
534 )
535 .arg(
536 Arg::with_name("amount")
537 .value_parser(Amount::parse)
538 .value_name("TOKEN_AMOUNT")
539 .takes_value(true)
540 .index(3)
541 .required(true)
542 .help("Amount to deposit into each account, in tokens"),
543 )
544 .arg(
545 Arg::with_name("from")
546 .long("from")
547 .validator(|s| is_valid_pubkey(s))
548 .value_name("SOURCE_TOKEN_ACCOUNT_ADDRESS")
549 .takes_value(true)
550 .help("The source token account address [default: associated token account for --owner]")
551 )
552 .arg(owner_address_arg()),
553 )
554 .subcommand(
555 SubCommand::with_name("withdraw-from")
556 .about("Withdraw tokens from multiple accounts")
557 .arg(
558 Arg::with_name("token")
559 .validator(|s| is_valid_pubkey(s))
560 .value_name("TOKEN_ADDRESS")
561 .takes_value(true)
562 .index(1)
563 .required(true)
564 .help("The token that the accounts hold"),
565 )
566 .arg(
567 Arg::with_name("n")
568 .value_parser(clap::value_parser!(usize))
569 .value_name("N")
570 .takes_value(true)
571 .index(2)
572 .required(true)
573 .help("The number of accounts to withdraw from"),
574 )
575 .arg(
576 Arg::with_name("amount")
577 .value_parser(Amount::parse)
578 .value_name("TOKEN_AMOUNT")
579 .takes_value(true)
580 .index(3)
581 .required(true)
582 .help("Amount to withdraw from each account, in tokens"),
583 )
584 .arg(
585 Arg::with_name("to")
586 .long("to")
587 .validator(|s| is_valid_pubkey(s))
588 .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS")
589 .takes_value(true)
590 .help("The recipient token account address [default: associated token account for --owner]")
591 )
592 .arg(owner_address_arg()),
593 ),
594 )
595 }
596}
597
598pub fn app<'a>(
599 default_decimals: &'a str,
600 minimum_signers_help: &'a str,
601 multisig_member_help: &'a str,
602) -> App<'a> {
603 App::new(crate_name!())
604 .about(crate_description!())
605 .version(crate_version!())
606 .setting(AppSettings::SubcommandRequiredElseHelp)
607 .arg(
608 Arg::with_name("config_file")
609 .short('C')
610 .long("config")
611 .value_name("PATH")
612 .takes_value(true)
613 .global(true)
614 .help("Configuration file to use"),
615 )
616 .arg(
617 Arg::with_name("verbose")
618 .short('v')
619 .long("verbose")
620 .takes_value(false)
621 .global(true)
622 .help("Show additional information"),
623 )
624 .arg(
625 Arg::with_name("output_format")
626 .long("output")
627 .value_name("FORMAT")
628 .global(true)
629 .takes_value(true)
630 .possible_values(["json", "json-compact"])
631 .help("Return information in specified output format"),
632 )
633 .arg(
634 Arg::with_name("program_2022")
635 .long("program-2022")
636 .takes_value(false)
637 .global(true)
638 .conflicts_with("program_id")
639 .help("Use token extension program token 2022 with program id: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
640 )
641 .arg(
642 Arg::with_name("program_id")
643 .short('p')
644 .long("program-id")
645 .value_name("ADDRESS")
646 .takes_value(true)
647 .global(true)
648 .conflicts_with("program_2022")
649 .validator(|s| is_valid_token_program_id(s))
650 .help("SPL Token program id"),
651 )
652 .arg(
653 Arg::with_name("json_rpc_url")
654 .short('u')
655 .long("url")
656 .value_name("URL_OR_MONIKER")
657 .takes_value(true)
658 .global(true)
659 .validator(|s| is_url_or_moniker(s))
660 .help(
661 "URL for Solana's JSON RPC or moniker (or their first letter): \
662 [mainnet-beta, testnet, devnet, localhost] \
663 Default from the configuration file."
664 ),
665 )
666 .arg(fee_payer_arg().global(true))
667 .arg(
668 Arg::with_name("use_unchecked_instruction")
669 .long("use-unchecked-instruction")
670 .takes_value(false)
671 .global(true)
672 .hidden(true)
673 .help("Use unchecked instruction if appropriate. Supports transfer, burn, mint, and approve."),
674 )
675 .arg(
676 Arg::with_name(COMPUTE_UNIT_LIMIT_ARG.name)
677 .long(COMPUTE_UNIT_LIMIT_ARG.long)
678 .takes_value(true)
679 .global(true)
680 .value_name("COMPUTE-UNIT-LIMIT")
681 .value_parser(clap::value_parser!(u32))
682 .help(COMPUTE_UNIT_LIMIT_ARG.help)
683 )
684 .arg(
685 Arg::with_name(COMPUTE_UNIT_PRICE_ARG.name)
686 .long(COMPUTE_UNIT_PRICE_ARG.long)
687 .takes_value(true)
688 .global(true)
689 .value_name("COMPUTE-UNIT-PRICE")
690 .value_parser(clap::value_parser!(u64))
691 .help(COMPUTE_UNIT_PRICE_ARG.help)
692 )
693 .bench_subcommand()
694 .subcommand(SubCommand::with_name(CommandName::CreateToken.into()).about("Create a new token")
695 .arg(
696 Arg::with_name("token_keypair")
697 .value_name("TOKEN_KEYPAIR")
698 .validator(|s| is_valid_signer(s))
699 .takes_value(true)
700 .index(1)
701 .help(
702 "Specify the token keypair. \
703 This may be a keypair file or the ASK keyword. \
704 [default: randomly generated keypair]"
705 ),
706 )
707 .arg(
708 Arg::with_name("mint_authority")
709 .long("mint-authority")
710 .alias("owner")
711 .value_name("ADDRESS")
712 .validator(|s| is_valid_pubkey(s))
713 .takes_value(true)
714 .help(
715 "Specify the mint authority address. \
716 Defaults to the client keypair address."
717 ),
718 )
719 .arg(
720 Arg::with_name("decimals")
721 .long("decimals")
722 .value_parser(clap::value_parser!(u8))
723 .value_name("DECIMALS")
724 .takes_value(true)
725 .default_value(default_decimals)
726 .help("Number of base 10 digits to the right of the decimal place"),
727 )
728 .arg(
729 Arg::with_name("enable_freeze")
730 .long("enable-freeze")
731 .takes_value(false)
732 .help(
733 "Enable the mint authority to freeze token accounts for this mint"
734 ),
735 )
736 .arg(
737 Arg::with_name("enable_close")
738 .long("enable-close")
739 .takes_value(false)
740 .help(
741 "Enable the mint authority to close this mint"
742 ),
743 )
744 .arg(
745 Arg::with_name("interest_rate")
746 .long("interest-rate")
747 .value_name("RATE_BPS")
748 .takes_value(true)
749 .conflicts_with("ui_amount_multiplier")
750 .help(
751 "Specify the interest rate in basis points. \
752 Rate authority defaults to the mint authority."
753 ),
754 )
755 .arg(
756 Arg::with_name("metadata_address")
757 .long("metadata-address")
758 .value_name("ADDRESS")
759 .validator(|s| is_valid_pubkey(s))
760 .takes_value(true)
761 .conflicts_with("enable_metadata")
762 .help(
763 "Specify address that stores token metadata."
764 ),
765 )
766 .arg(
767 Arg::with_name("group_address")
768 .long("group-address")
769 .value_name("ADDRESS")
770 .validator(|s| is_valid_pubkey(s))
771 .takes_value(true)
772 .conflicts_with("enable_group")
773 .help(
774 "Specify address that stores token group configurations."
775 ),
776 )
777 .arg(
778 Arg::with_name("member_address")
779 .long("member-address")
780 .value_name("ADDRESS")
781 .validator(|s| is_valid_pubkey(s))
782 .takes_value(true)
783 .conflicts_with("enable_member")
784 .help(
785 "Specify address that stores token member configurations."
786 ),
787 )
788 .arg(
789 Arg::with_name("enable_non_transferable")
790 .long("enable-non-transferable")
791 .alias("enable-nontransferable")
792 .takes_value(false)
793 .help(
794 "Permanently force tokens to be non-transferable. They may still be burned."
795 ),
796 )
797 .arg(
798 Arg::with_name("default_account_state")
799 .long("default-account-state")
800 .requires("enable_freeze")
801 .takes_value(true)
802 .possible_values(["initialized", "frozen"])
803 .help("Specify that accounts have a default state. \
804 Note: specifying \"initialized\" adds an extension, which gives \
805 the option of specifying default frozen accounts in the future. \
806 This behavior is not the same as the default, which makes it \
807 impossible to specify a default account state in the future."),
808 )
809 .arg(
810 Arg::with_name("transfer_fee")
811 .long("transfer-fee")
812 .value_names(&["FEE_IN_BASIS_POINTS", "MAXIMUM_FEE"])
813 .takes_value(true)
814 .number_of_values(2)
815 .hidden(true)
816 .conflicts_with("transfer_fee_basis_points")
817 .conflicts_with("transfer_fee_maximum_fee")
818 .help(
819 "Add a transfer fee to the mint. \
820 The mint authority can set the fee and withdraw collected fees.",
821 ),
822 )
823 .arg(
824 Arg::with_name("transfer_fee_basis_points")
825 .long("transfer-fee-basis-points")
826 .value_names(&["FEE_IN_BASIS_POINTS"])
827 .takes_value(true)
828 .number_of_values(1)
829 .conflicts_with("transfer_fee")
830 .requires("transfer_fee_maximum_fee")
831 .value_parser(clap::value_parser!(u16))
832 .help(
833 "Add transfer fee to the mint. \
834 The mint authority can set the fee.",
835 ),
836 )
837 .arg(
838 Arg::with_name("transfer_fee_maximum_fee")
839 .long("transfer-fee-maximum-fee")
840 .value_names(&["MAXIMUM_FEE"])
841 .takes_value(true)
842 .number_of_values(1)
843 .conflicts_with("transfer_fee")
844 .requires("transfer_fee_basis_points")
845 .value_parser(Amount::parse)
846 .help(
847 "Add a UI amount maximum transfer fee to the mint. \
848 The mint authority can set and collect fees"
849 )
850 )
851 .arg(
852 Arg::with_name("enable_permanent_delegate")
853 .long("enable-permanent-delegate")
854 .takes_value(false)
855 .help(
856 "Enable the mint authority to be permanent delegate for this mint"
857 ),
858 )
859 .arg(
860 Arg::with_name("enable_confidential_transfers")
861 .long("enable-confidential-transfers")
862 .value_names(&["APPROVE-POLICY"])
863 .takes_value(true)
864 .possible_values(["auto", "manual"])
865 .help(
866 "Enable accounts to make confidential transfers. If \"auto\" \
867 is selected, then accounts are automatically approved to make \
868 confidential transfers. If \"manual\" is selected, then the \
869 confidential transfer mint authority must approve each account \
870 before it can make confidential transfers."
871 )
872 )
873 .arg(
874 Arg::with_name("transfer_hook")
875 .long("transfer-hook")
876 .value_name("TRANSFER_HOOK_PROGRAM_ID")
877 .validator(|s| is_valid_pubkey(s))
878 .takes_value(true)
879 .help("Set a transfer hook program for this mint. The mint authority can set the program id."),
880 )
881 .arg(
882 Arg::with_name("enable_transfer_hook")
883 .long("enable-transfer-hook")
884 .conflicts_with("transfer_hook")
885 .takes_value(false)
886 .help("Enables the transfer hook in the mint. The mint authority can set the program id."),
887 )
888 .arg(
889 Arg::with_name("enable_metadata")
890 .long("enable-metadata")
891 .conflicts_with("metadata_address")
892 .takes_value(false)
893 .help("Enables metadata in the mint. The mint authority must initialize the metadata."),
894 )
895 .arg(
896 Arg::with_name("enable_group")
897 .long("enable-group")
898 .conflicts_with("group_address")
899 .takes_value(false)
900 .help("Enables group configurations in the mint. The mint authority must initialize the group."),
901 )
902 .arg(
903 Arg::with_name("enable_member")
904 .long("enable-member")
905 .conflicts_with("member_address")
906 .takes_value(false)
907 .help("Enables group member configurations in the mint. The mint authority must initialize the member."),
908 )
909 .arg(
910 Arg::with_name("ui_amount_multiplier")
911 .long("ui-amount-multiplier")
912 .value_name("MULTIPLIER")
913 .takes_value(true)
914 .conflicts_with("interest_rate")
915 .help(
916 "Specify the UI multiplier. \
917 Multiplier authority defaults to the mint authority."
918 ),
919 )
920 .arg(
921 Arg::with_name("enable_pause")
922 .long("enable-pause")
923 .takes_value(false)
924 .help(
925 "Enable the mint authority to pause mint, burn, and transfer for this mint"
926 )
927 )
928 .arg(multisig_signer_arg())
929 .nonce_args(true)
930 .arg(memo_arg())
931 )
932 .subcommand(
933 SubCommand::with_name(CommandName::SetInterestRate.into())
934 .about("Set the interest rate for an interest-bearing token")
935 .arg(
936 Arg::with_name("token")
937 .validator(|s| is_valid_pubkey(s))
938 .value_name("TOKEN_MINT_ADDRESS")
939 .takes_value(true)
940 .required(true)
941 .help("The interest-bearing token address"),
942 )
943 .arg(
944 Arg::with_name("rate")
945 .value_name("RATE")
946 .takes_value(true)
947 .required(true)
948 .help("The new interest rate in basis points"),
949 )
950 .arg(
951 Arg::with_name("rate_authority")
952 .long("rate-authority")
953 .validator(|s| is_valid_signer(s))
954 .value_name("SIGNER")
955 .takes_value(true)
956 .help(
957 "Specify the rate authority keypair. \
958 Defaults to the client keypair address."
959 )
960 )
961 )
962 .subcommand(
963 SubCommand::with_name(CommandName::SetTransferHook.into())
964 .about("Set the transfer hook program id for a token")
965 .arg(
966 Arg::with_name("token")
967 .validator(|s| is_valid_pubkey(s))
968 .value_name("TOKEN_MINT_ADDRESS")
969 .takes_value(true)
970 .required(true)
971 .index(1)
972 .help("The token address with an existing transfer hook"),
973 )
974 .arg(
975 Arg::with_name("new_program_id")
976 .validator(|s| is_valid_pubkey(s))
977 .value_name("NEW_PROGRAM_ID")
978 .takes_value(true)
979 .required_unless("disable")
980 .index(2)
981 .help("The new transfer hook program id to set for this mint"),
982 )
983 .arg(
984 Arg::with_name("disable")
985 .long("disable")
986 .takes_value(false)
987 .conflicts_with("new_program_id")
988 .help("Disable transfer hook functionality by setting the program id to None.")
989 )
990 .arg(
991 Arg::with_name("authority")
992 .long("authority")
993 .alias("owner")
994 .validator(|s| is_valid_signer(s))
995 .value_name("SIGNER")
996 .takes_value(true)
997 .help("Specify the authority keypair. Defaults to the client keypair address.")
998 )
999 )
1000 .subcommand(
1001 SubCommand::with_name(CommandName::InitializeMetadata.into())
1002 .about("Initialize metadata extension on a token mint")
1003 .arg(
1004 Arg::with_name("token")
1005 .validator(|s| is_valid_pubkey(s))
1006 .value_name("TOKEN_MINT_ADDRESS")
1007 .takes_value(true)
1008 .required(true)
1009 .index(1)
1010 .help("The token address with no metadata present"),
1011 )
1012 .arg(
1013 Arg::with_name("name")
1014 .value_name("TOKEN_NAME")
1015 .takes_value(true)
1016 .required(true)
1017 .index(2)
1018 .help("The name of the token to set in metadata"),
1019 )
1020 .arg(
1021 Arg::with_name("symbol")
1022 .value_name("TOKEN_SYMBOL")
1023 .takes_value(true)
1024 .required(true)
1025 .index(3)
1026 .help("The symbol of the token to set in metadata"),
1027 )
1028 .arg(
1029 Arg::with_name("uri")
1030 .value_name("TOKEN_URI")
1031 .takes_value(true)
1032 .required(true)
1033 .index(4)
1034 .help("The URI of the token to set in metadata"),
1035 )
1036 .arg(
1037 Arg::with_name("mint_authority")
1038 .long("mint-authority")
1039 .alias("owner")
1040 .value_name("KEYPAIR")
1041 .validator(|s| is_valid_signer(s))
1042 .takes_value(true)
1043 .help(
1044 "Specify the mint authority keypair. \
1045 This may be a keypair file or the ASK keyword. \
1046 Defaults to the client keypair."
1047 ),
1048 )
1049 .arg(
1050 Arg::with_name("update_authority")
1051 .long("update-authority")
1052 .value_name("ADDRESS")
1053 .validator(|s| is_valid_pubkey(s))
1054 .takes_value(true)
1055 .help(
1056 "Specify the update authority address. \
1057 Defaults to the client keypair address."
1058 ),
1059 )
1060 )
1061 .subcommand(
1062 SubCommand::with_name(CommandName::UpdateMetadata.into())
1063 .about("Update metadata on a token mint that has the extension")
1064 .arg(
1065 Arg::with_name("token")
1066 .validator(|s| is_valid_pubkey(s))
1067 .value_name("TOKEN_MINT_ADDRESS")
1068 .takes_value(true)
1069 .required(true)
1070 .index(1)
1071 .help("The token address with no metadata present"),
1072 )
1073 .arg(
1074 Arg::with_name("field")
1075 .value_name("FIELD_NAME")
1076 .takes_value(true)
1077 .required(true)
1078 .index(2)
1079 .help("The name of the field to update. Can be a base field (\"name\", \"symbol\", or \"uri\") or any new field to add."),
1080 )
1081 .arg(
1082 Arg::with_name("value")
1083 .value_name("VALUE_STRING")
1084 .takes_value(true)
1085 .index(3)
1086 .required_unless("remove")
1087 .help("The value for the field"),
1088 )
1089 .arg(
1090 Arg::with_name("remove")
1091 .long("remove")
1092 .takes_value(false)
1093 .conflicts_with("value")
1094 .help("Remove the key and value for the given field. Does not work with base fields: \"name\", \"symbol\", or \"uri\".")
1095 )
1096 .arg(
1097 Arg::with_name("authority")
1098 .long("authority")
1099 .validator(|s| is_valid_signer(s))
1100 .value_name("SIGNER")
1101 .takes_value(true)
1102 .help("Specify the metadata update authority keypair. Defaults to the client keypair.")
1103 )
1104 .nonce_args(true)
1105 .arg(transfer_lamports_arg())
1106 .offline_args_config(&SignOnlyNeedsTransferLamports{}),
1107 )
1108 .subcommand(
1109 SubCommand::with_name(CommandName::InitializeGroup.into())
1110 .about("Initialize group extension on a token mint")
1111 .arg(
1112 Arg::with_name("token")
1113 .validator(|s| is_valid_pubkey(s))
1114 .value_name("TOKEN_MINT_ADDRESS")
1115 .takes_value(true)
1116 .required(true)
1117 .index(1)
1118 .help("The token address of the group account."),
1119 )
1120 .arg(
1121 Arg::with_name("max_size")
1122 .value_parser(clap::value_parser!(u64))
1123 .value_name("MAX_SIZE")
1124 .takes_value(true)
1125 .required(true)
1126 .index(2)
1127 .help("The number of members in the group."),
1128 )
1129 .arg(
1130 Arg::with_name("mint_authority")
1131 .long("mint-authority")
1132 .alias("owner")
1133 .value_name("KEYPAIR")
1134 .validator(|s| is_valid_signer(s))
1135 .takes_value(true)
1136 .help(
1137 "Specify the mint authority keypair. \
1138 This may be a keypair file or the ASK keyword. \
1139 Defaults to the client keypair."
1140 ),
1141 )
1142 .arg(
1143 Arg::with_name("update_authority")
1144 .long("update-authority")
1145 .value_name("ADDRESS")
1146 .validator(|s| is_valid_pubkey(s))
1147 .takes_value(true)
1148 .help(
1149 "Specify the update authority address. \
1150 Defaults to the client keypair address."
1151 ),
1152 )
1153 )
1154 .subcommand(
1155 SubCommand::with_name(CommandName::UpdateGroupMaxSize.into())
1156 .about("Updates the maximum number of members for a group.")
1157 .arg(
1158 Arg::with_name("token")
1159 .validator(|s| is_valid_pubkey(s))
1160 .value_name("TOKEN_MINT_ADDRESS")
1161 .takes_value(true)
1162 .required(true)
1163 .index(1)
1164 .help("The token address of the group account."),
1165 )
1166 .arg(
1167 Arg::with_name("new_max_size")
1168 .value_parser(clap::value_parser!(u64))
1169 .value_name("NEW_MAX_SIZE")
1170 .takes_value(true)
1171 .required(true)
1172 .index(2)
1173 .help("The number of members in the group."),
1174 )
1175 .arg(
1176 Arg::with_name("update_authority")
1177 .long("update-authority")
1178 .value_name("SIGNER")
1179 .validator(|s| is_valid_signer(s))
1180 .takes_value(true)
1181 .help(
1182 "Specify the update authority address. \
1183 Defaults to the client keypair address."
1184 ),
1185 )
1186 )
1187 .subcommand(
1188 SubCommand::with_name(CommandName::InitializeMember.into())
1189 .about("Initialize group member extension on a token mint")
1190 .arg(
1191 Arg::with_name("token")
1192 .validator(|s| is_valid_pubkey(s))
1193 .value_name("TOKEN_MINT_ADDRESS")
1194 .takes_value(true)
1195 .required(true)
1196 .index(1)
1197 .help("The token address of the member account."),
1198 )
1199 .arg(
1200 Arg::with_name("group_token")
1201 .validator(|s| is_valid_pubkey(s))
1202 .value_name("GROUP_TOKEN_ADDRESS")
1203 .takes_value(true)
1204 .required(true)
1205 .index(2)
1206 .help("The token address of the group account that the token will join."),
1207 )
1208 .arg(
1209 Arg::with_name("mint_authority")
1210 .long("mint-authority")
1211 .alias("owner")
1212 .value_name("KEYPAIR")
1213 .validator(|s| is_valid_signer(s))
1214 .takes_value(true)
1215 .help(
1216 "Specify the mint authority keypair. \
1217 This may be a keypair file or the ASK keyword. \
1218 Defaults to the client keypair."
1219 ),
1220 )
1221 .arg(
1222 Arg::with_name("group_update_authority")
1223 .long("group-update-authority")
1224 .value_name("KEYPAIR")
1225 .validator(|s| is_valid_signer(s))
1226 .takes_value(true)
1227 .help(
1228 "Specify the update authority keypair. \
1229 This may be a keypair file or the ASK keyword. \
1230 Defaults to the client keypair address."
1231 ),
1232 )
1233 )
1234 .subcommand(
1235 SubCommand::with_name(CommandName::CreateAccount.into())
1236 .about("Create a new token account")
1237 .arg(
1238 Arg::with_name("token")
1239 .validator(|s| is_valid_pubkey(s))
1240 .value_name("TOKEN_MINT_ADDRESS")
1241 .takes_value(true)
1242 .index(1)
1243 .required(true)
1244 .help("The token that the account will hold"),
1245 )
1246 .arg(
1247 Arg::with_name("account_keypair")
1248 .value_name("ACCOUNT_KEYPAIR")
1249 .validator(|s| is_valid_signer(s))
1250 .takes_value(true)
1251 .index(2)
1252 .help(
1253 "Specify the account keypair. \
1254 This may be a keypair file or the ASK keyword. \
1255 [default: associated token account for --owner]"
1256 ),
1257 )
1258 .arg(
1259 Arg::with_name("immutable")
1260 .long("immutable")
1261 .takes_value(false)
1262 .help(
1263 "Lock the owner of this token account from ever being changed"
1264 ),
1265 )
1266 .arg(owner_address_arg())
1267 .nonce_args(true)
1268 )
1269 .subcommand(
1270 SubCommand::with_name(CommandName::CreateMultisig.into())
1271 .about("Create a new account describing an M:N multisignature")
1272 .arg(
1273 Arg::with_name("minimum_signers")
1274 .value_name("MINIMUM_SIGNERS")
1275 .validator(is_multisig_minimum_signers)
1276 .takes_value(true)
1277 .index(1)
1278 .required(true)
1279 .help(minimum_signers_help),
1280 )
1281 .arg(
1282 Arg::with_name("multisig_member")
1283 .value_name("MULTISIG_MEMBER_PUBKEY")
1284 .validator(|s| is_valid_pubkey(s))
1285 .takes_value(true)
1286 .index(2)
1287 .required(true)
1288 .min_values(MIN_SIGNERS)
1289 .max_values(MAX_SIGNERS)
1290 .help(multisig_member_help),
1291 )
1292 .arg(
1293 Arg::with_name("address_keypair")
1294 .long("address-keypair")
1295 .value_name("ADDRESS_KEYPAIR")
1296 .validator(|s| is_valid_signer(s))
1297 .takes_value(true)
1298 .help(
1299 "Specify the address keypair. \
1300 This may be a keypair file or the ASK keyword. \
1301 [default: randomly generated keypair]"
1302 ),
1303 )
1304 .nonce_args(true)
1305 )
1306 .subcommand(
1307 SubCommand::with_name(CommandName::Authorize.into())
1308 .about("Authorize a new signing keypair to a token or token account")
1309 .arg(
1310 Arg::with_name("address")
1311 .validator(|s| is_valid_pubkey(s))
1312 .value_name("TOKEN_ADDRESS")
1313 .takes_value(true)
1314 .index(1)
1315 .required(true)
1316 .help("The address of the token mint or account"),
1317 )
1318 .arg(
1319 Arg::with_name("authority_type")
1320 .value_name("AUTHORITY_TYPE")
1321 .takes_value(true)
1322 .possible_values(CliAuthorityType::iter().map(Into::<&str>::into).collect::<Vec<_>>())
1323 .index(2)
1324 .required(true)
1325 .help("The new authority type. \
1326 Token mints support `mint`, `freeze`, and mint extension authorities; \
1327 Token accounts support `owner`, `close`, and account extension \
1328 authorities."),
1329 )
1330 .arg(
1331 Arg::with_name("new_authority")
1332 .validator(|s| is_valid_pubkey(s))
1333 .value_name("AUTHORITY_ADDRESS")
1334 .takes_value(true)
1335 .index(3)
1336 .required_unless("disable")
1337 .help("The address of the new authority"),
1338 )
1339 .arg(
1340 Arg::with_name("authority")
1341 .long("authority")
1342 .alias("owner")
1343 .value_name("KEYPAIR")
1344 .validator(|s| is_valid_signer(s))
1345 .takes_value(true)
1346 .help(
1347 "Specify the current authority keypair. \
1348 Defaults to the client keypair."
1349 ),
1350 )
1351 .arg(
1352 Arg::with_name("disable")
1353 .long("disable")
1354 .takes_value(false)
1355 .conflicts_with("new_authority")
1356 .help("Disable mint, freeze, or close functionality by setting authority to None.")
1357 )
1358 .arg(
1359 Arg::with_name("force")
1360 .long("force")
1361 .hidden(true)
1362 .help("Force re-authorize the wallet's associate token account. Don't use this flag"),
1363 )
1364 .arg(multisig_signer_arg())
1365 .nonce_args(true)
1366 .offline_args(),
1367 )
1368 .subcommand(
1369 SubCommand::with_name(CommandName::Transfer.into())
1370 .about("Transfer tokens between accounts")
1371 .arg(
1372 Arg::with_name("token")
1373 .validator(|s| is_valid_pubkey(s))
1374 .value_name("TOKEN_MINT_ADDRESS")
1375 .takes_value(true)
1376 .index(1)
1377 .required(true)
1378 .help("Token to transfer"),
1379 )
1380 .arg(
1381 Arg::with_name("amount")
1382 .value_parser(Amount::parse)
1383 .value_name("TOKEN_AMOUNT")
1384 .takes_value(true)
1385 .index(2)
1386 .required(true)
1387 .help("Amount to send, in tokens; accepts keyword ALL"),
1388 )
1389 .arg(
1390 Arg::with_name("recipient")
1391 .validator(|s| is_valid_pubkey(s))
1392 .value_name("RECIPIENT_WALLET_ADDRESS or RECIPIENT_TOKEN_ACCOUNT_ADDRESS")
1393 .takes_value(true)
1394 .index(3)
1395 .required(true)
1396 .help("If a token account address is provided, use it as the recipient. \
1397 Otherwise assume the recipient address is a user wallet and transfer to \
1398 the associated token account")
1399 )
1400 .arg(
1401 Arg::with_name("from")
1402 .validator(|s| is_valid_pubkey(s))
1403 .value_name("SENDER_TOKEN_ACCOUNT_ADDRESS")
1404 .takes_value(true)
1405 .long("from")
1406 .help("Specify the sending token account \
1407 [default: owner's associated token account]")
1408 )
1409 .arg(owner_keypair_arg_with_value_name("SENDER_TOKEN_OWNER_KEYPAIR")
1410 .help(
1411 "Specify the owner of the sending token account. \
1412 This may be a keypair file or the ASK keyword. \
1413 Defaults to the client keypair.",
1414 ),
1415 )
1416 .arg(
1417 Arg::with_name("allow_unfunded_recipient")
1418 .long("allow-unfunded-recipient")
1419 .takes_value(false)
1420 .help("Complete the transfer even if the recipient address is not funded")
1421 )
1422 .arg(
1423 Arg::with_name("allow_empty_recipient")
1424 .long("allow-empty-recipient")
1425 .takes_value(false)
1426 .hidden(true) )
1428 .arg(
1429 Arg::with_name("fund_recipient")
1430 .long("fund-recipient")
1431 .takes_value(false)
1432 .conflicts_with("confidential")
1433 .help("Create the associated token account for the recipient if doesn't already exist")
1434 )
1435 .arg(
1436 Arg::with_name("no_wait")
1437 .long("no-wait")
1438 .takes_value(false)
1439 .help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
1440 )
1441 .arg(
1442 Arg::with_name("allow_non_system_account_recipient")
1443 .long("allow-non-system-account-recipient")
1444 .takes_value(false)
1445 .help("Send tokens to the recipient even if the recipient is not a wallet owned by System Program."),
1446 )
1447 .arg(
1448 Arg::with_name("no_recipient_is_ata_owner")
1449 .long("no-recipient-is-ata-owner")
1450 .takes_value(false)
1451 .requires("sign_only")
1452 .help("In sign-only mode, specifies that the recipient is the owner of the associated token account rather than an actual token account"),
1453 )
1454 .arg(
1455 Arg::with_name("recipient_is_ata_owner")
1456 .long("recipient-is-ata-owner")
1457 .takes_value(false)
1458 .hidden(true)
1459 .conflicts_with("no_recipient_is_ata_owner")
1460 .requires("sign_only")
1461 .help("recipient-is-ata-owner is now the default behavior. The option has been deprecated and will be removed in a future release."),
1462 )
1463 .arg(
1464 Arg::with_name("expected_fee")
1465 .long("expected-fee")
1466 .value_parser(Amount::parse)
1467 .value_name("EXPECTED_FEE")
1468 .takes_value(true)
1469 .help("Expected fee amount collected during the transfer"),
1470 )
1471 .arg(
1472 Arg::with_name("transfer_hook_account")
1473 .long("transfer-hook-account")
1474 .validator(|s| validate_transfer_hook_account(s))
1475 .value_name("PUBKEY:ROLE")
1476 .takes_value(true)
1477 .multiple(true)
1478 .min_values(0_usize)
1479 .help("Additional pubkey(s) required for a transfer hook and their \
1480 role, in the format \"<PUBKEY>:<ROLE>\". The role must be \
1481 \"readonly\", \"writable\". \"readonly-signer\", or \"writable-signer\".\
1482 Used for offline transaction creation and signing.")
1483 )
1484 .arg(
1485 Arg::with_name("confidential")
1486 .long("confidential")
1487 .takes_value(false)
1488 .conflicts_with("fund_recipient")
1489 .help("Send tokens confidentially. Both sender and recipient accounts must \
1490 be pre-configured for confidential transfers.")
1491 )
1492 .arg(multisig_signer_arg())
1493 .arg(mint_decimals_arg())
1494 .nonce_args(true)
1495 .arg(memo_arg())
1496 .offline_args_config(&SignOnlyNeedsMintDecimals{}),
1497 )
1498 .subcommand(
1499 SubCommand::with_name(CommandName::Burn.into())
1500 .about("Burn tokens from an account")
1501 .arg(
1502 Arg::with_name("account")
1503 .validator(|s| is_valid_pubkey(s))
1504 .value_name("TOKEN_ACCOUNT_ADDRESS")
1505 .takes_value(true)
1506 .index(1)
1507 .required(true)
1508 .help("The token account address to burn from"),
1509 )
1510 .arg(
1511 Arg::with_name("amount")
1512 .value_parser(Amount::parse)
1513 .value_name("TOKEN_AMOUNT")
1514 .takes_value(true)
1515 .index(2)
1516 .required(true)
1517 .help("Amount to burn, in tokens; accepts keyword ALL"),
1518 )
1519 .arg(owner_keypair_arg_with_value_name("TOKEN_OWNER_KEYPAIR")
1520 .help(
1521 "Specify the burnt token owner account. \
1522 This may be a keypair file or the ASK keyword. \
1523 Defaults to the client keypair.",
1524 ),
1525 )
1526 .arg(multisig_signer_arg())
1527 .mint_args()
1528 .nonce_args(true)
1529 .arg(memo_arg())
1530 .offline_args_config(&SignOnlyNeedsFullMintSpec{}),
1531 )
1532 .subcommand(
1533 SubCommand::with_name(CommandName::Mint.into())
1534 .about("Mint new tokens")
1535 .arg(
1536 Arg::with_name("token")
1537 .validator(|s| is_valid_pubkey(s))
1538 .value_name("TOKEN_MINT_ADDRESS")
1539 .takes_value(true)
1540 .index(1)
1541 .required(true)
1542 .help("The token to mint"),
1543 )
1544 .arg(
1545 Arg::with_name("amount")
1546 .value_parser(Amount::parse)
1547 .value_name("TOKEN_AMOUNT")
1548 .takes_value(true)
1549 .index(2)
1550 .required(true)
1551 .help("Amount to mint, in tokens"),
1552 )
1553 .arg(
1554 Arg::with_name("recipient")
1555 .validator(|s| is_valid_pubkey(s))
1556 .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS")
1557 .takes_value(true)
1558 .conflicts_with("recipient_owner")
1559 .index(3)
1560 .help("The token account address of recipient \
1561 [default: associated token account for --mint-authority]"),
1562 )
1563 .arg(
1564 Arg::with_name("recipient_owner")
1565 .long("recipient-owner")
1566 .validator(|s| is_valid_pubkey(s))
1567 .value_name("RECIPIENT_WALLET_ADDRESS")
1568 .takes_value(true)
1569 .conflicts_with("recipient")
1570 .help("The owner of the recipient associated token account"),
1571 )
1572 .arg(
1573 Arg::with_name("mint_authority")
1574 .long("mint-authority")
1575 .alias("owner")
1576 .value_name("KEYPAIR")
1577 .validator(|s| is_valid_signer(s))
1578 .takes_value(true)
1579 .help(
1580 "Specify the mint authority keypair. \
1581 This may be a keypair file or the ASK keyword. \
1582 Defaults to the client keypair."
1583 ),
1584 )
1585 .arg(mint_decimals_arg())
1586 .arg(multisig_signer_arg())
1587 .nonce_args(true)
1588 .arg(memo_arg())
1589 .offline_args_config(&SignOnlyNeedsMintDecimals{}),
1590 )
1591 .subcommand(
1592 SubCommand::with_name(CommandName::Freeze.into())
1593 .about("Freeze a token account")
1594 .arg(
1595 Arg::with_name("account")
1596 .validator(|s| is_valid_pubkey(s))
1597 .value_name("TOKEN_ACCOUNT_ADDRESS")
1598 .takes_value(true)
1599 .index(1)
1600 .required(true)
1601 .help("The address of the token account to freeze"),
1602 )
1603 .arg(
1604 Arg::with_name("freeze_authority")
1605 .long("freeze-authority")
1606 .alias("owner")
1607 .value_name("KEYPAIR")
1608 .validator(|s| is_valid_signer(s))
1609 .takes_value(true)
1610 .help(
1611 "Specify the freeze authority keypair. \
1612 This may be a keypair file or the ASK keyword. \
1613 Defaults to the client keypair."
1614 ),
1615 )
1616 .arg(mint_address_arg())
1617 .arg(multisig_signer_arg())
1618 .nonce_args(true)
1619 .offline_args_config(&SignOnlyNeedsMintAddress{}),
1620 )
1621 .subcommand(
1622 SubCommand::with_name(CommandName::Thaw.into())
1623 .about("Thaw a token account")
1624 .arg(
1625 Arg::with_name("account")
1626 .validator(|s| is_valid_pubkey(s))
1627 .value_name("TOKEN_ACCOUNT_ADDRESS")
1628 .takes_value(true)
1629 .index(1)
1630 .required(true)
1631 .help("The address of the token account to thaw"),
1632 )
1633 .arg(
1634 Arg::with_name("freeze_authority")
1635 .long("freeze-authority")
1636 .alias("owner")
1637 .value_name("KEYPAIR")
1638 .validator(|s| is_valid_signer(s))
1639 .takes_value(true)
1640 .help(
1641 "Specify the freeze authority keypair. \
1642 This may be a keypair file or the ASK keyword. \
1643 Defaults to the client keypair."
1644 ),
1645 )
1646 .arg(mint_address_arg())
1647 .arg(multisig_signer_arg())
1648 .nonce_args(true)
1649 .offline_args_config(&SignOnlyNeedsMintAddress{}),
1650 )
1651 .subcommand(
1652 SubCommand::with_name(CommandName::Wrap.into())
1653 .about("Wrap native SOL in a SOL token account")
1654 .arg(
1655 Arg::with_name("amount")
1656 .value_parser(Amount::parse)
1657 .value_name("AMOUNT")
1658 .takes_value(true)
1659 .index(1)
1660 .required(true)
1661 .help("Amount of SOL to wrap"),
1662 )
1663 .arg(
1664 Arg::with_name("wallet_keypair")
1665 .alias("owner")
1666 .value_name("KEYPAIR")
1667 .validator(|s| is_valid_signer(s))
1668 .takes_value(true)
1669 .index(2)
1670 .help(
1671 "Specify the keypair for the wallet which will have its native SOL wrapped. \
1672 This wallet will be assigned as the owner of the wrapped SOL token account. \
1673 This may be a keypair file or the ASK keyword. \
1674 Defaults to the client keypair."
1675 ),
1676 )
1677 .arg(
1678 Arg::with_name("create_aux_account")
1679 .takes_value(false)
1680 .long("create-aux-account")
1681 .help("Wrap SOL in an auxiliary account instead of associated token account"),
1682 )
1683 .arg(
1684 Arg::with_name("immutable")
1685 .long("immutable")
1686 .takes_value(false)
1687 .help(
1688 "Lock the owner of this token account from ever being changed"
1689 ),
1690 )
1691 .nonce_args(true)
1692 .offline_args(),
1693 )
1694 .subcommand(
1695 SubCommand::with_name(CommandName::Unwrap.into())
1696 .about("Unwrap a SOL token account")
1697 .arg(
1698 Arg::with_name("account")
1699 .validator(|s| is_valid_pubkey(s))
1700 .value_name("TOKEN_ACCOUNT_ADDRESS")
1701 .takes_value(true)
1702 .index(1)
1703 .help("The address of the auxiliary token account to unwrap \
1704 [default: associated token account for --owner]"),
1705 )
1706 .arg(
1707 Arg::with_name("wallet_keypair")
1708 .value_name("KEYPAIR")
1709 .validator(|s| is_valid_signer(s))
1710 .takes_value(true)
1711 .index(2)
1712 .help(
1713 "Specify the keypair for the wallet which owns the wrapped SOL. \
1714 This wallet will receive the unwrapped SOL. \
1715 This may be a keypair file or the ASK keyword. \
1716 Defaults to the client keypair."
1717 ),
1718 )
1719 .arg(owner_address_arg())
1720 .arg(multisig_signer_arg())
1721 .nonce_args(true)
1722 .offline_args(),
1723 )
1724 .subcommand(
1725 SubCommand::with_name(CommandName::Approve.into())
1726 .about("Approve a delegate for a token account")
1727 .arg(
1728 Arg::with_name("account")
1729 .validator(|s| is_valid_pubkey(s))
1730 .value_name("TOKEN_ACCOUNT_ADDRESS")
1731 .takes_value(true)
1732 .index(1)
1733 .required(true)
1734 .help("The address of the token account to delegate"),
1735 )
1736 .arg(
1737 Arg::with_name("amount")
1738 .value_parser(Amount::parse)
1739 .value_name("TOKEN_AMOUNT")
1740 .takes_value(true)
1741 .index(2)
1742 .required(true)
1743 .help("Amount to approve, in tokens"),
1744 )
1745 .arg(
1746 Arg::with_name("delegate")
1747 .validator(|s| is_valid_pubkey(s))
1748 .value_name("DELEGATE_TOKEN_ACCOUNT_ADDRESS")
1749 .takes_value(true)
1750 .index(3)
1751 .required(true)
1752 .help("The token account address of delegate"),
1753 )
1754 .arg(
1755 owner_keypair_arg()
1756 )
1757 .arg(multisig_signer_arg())
1758 .mint_args()
1759 .nonce_args(true)
1760 .offline_args_config(&SignOnlyNeedsFullMintSpec{}),
1761 )
1762 .subcommand(
1763 SubCommand::with_name(CommandName::Revoke.into())
1764 .about("Revoke a delegate's authority")
1765 .arg(
1766 Arg::with_name("account")
1767 .validator(|s| is_valid_pubkey(s))
1768 .value_name("TOKEN_ACCOUNT_ADDRESS")
1769 .takes_value(true)
1770 .index(1)
1771 .required(true)
1772 .help("The address of the token account"),
1773 )
1774 .arg(owner_keypair_arg()
1775 )
1776 .arg(delegate_address_arg())
1777 .arg(multisig_signer_arg())
1778 .nonce_args(true)
1779 .offline_args_config(&SignOnlyNeedsDelegateAddress{}),
1780 )
1781 .subcommand(
1782 SubCommand::with_name(CommandName::Close.into())
1783 .about("Close a token account")
1784 .arg(
1785 Arg::with_name("token")
1786 .validator(|s| is_valid_pubkey(s))
1787 .value_name("TOKEN_MINT_ADDRESS")
1788 .takes_value(true)
1789 .index(1)
1790 .required_unless("address")
1791 .help("Token of the associated account to close. \
1792 To close a specific account, use the `--address` parameter instead"),
1793 )
1794 .arg(
1795 Arg::with_name("recipient")
1796 .long("recipient")
1797 .validator(|s| is_valid_pubkey(s))
1798 .value_name("REFUND_ACCOUNT_ADDRESS")
1799 .takes_value(true)
1800 .help("The address of the account to receive remaining SOL [default: --owner]"),
1801 )
1802 .arg(
1803 Arg::with_name("close_authority")
1804 .long("close-authority")
1805 .value_name("KEYPAIR")
1806 .validator(|s| is_valid_signer(s))
1807 .takes_value(true)
1808 .help(
1809 "Specify the token's close authority if it has one, \
1810 otherwise specify the token's owner keypair. \
1811 This may be a keypair file or the ASK keyword. \
1812 Defaults to the client keypair.",
1813 ),
1814 )
1815 .arg(
1816 Arg::with_name("address")
1817 .long("address")
1818 .validator(|s| is_valid_pubkey(s))
1819 .value_name("TOKEN_ACCOUNT_ADDRESS")
1820 .takes_value(true)
1821 .conflicts_with("token")
1822 .help("Specify the token account to close \
1823 [default: owner's associated token account]"),
1824 )
1825 .arg(owner_address_arg())
1826 .arg(multisig_signer_arg())
1827 .nonce_args(true)
1828 .offline_args(),
1829 )
1830 .subcommand(
1831 SubCommand::with_name(CommandName::CloseMint.into())
1832 .about("Close a token mint")
1833 .arg(
1834 Arg::with_name("token")
1835 .validator(|s| is_valid_pubkey(s))
1836 .value_name("TOKEN_MINT_ADDRESS")
1837 .takes_value(true)
1838 .index(1)
1839 .required(true)
1840 .help("Token to close"),
1841 )
1842 .arg(
1843 Arg::with_name("recipient")
1844 .long("recipient")
1845 .validator(|s| is_valid_pubkey(s))
1846 .value_name("REFUND_ACCOUNT_ADDRESS")
1847 .takes_value(true)
1848 .help("The address of the account to receive remaining SOL [default: --owner]"),
1849 )
1850 .arg(
1851 Arg::with_name("close_authority")
1852 .long("close-authority")
1853 .value_name("KEYPAIR")
1854 .validator(|s| is_valid_signer(s))
1855 .takes_value(true)
1856 .help(
1857 "Specify the token's close authority. \
1858 This may be a keypair file or the ASK keyword. \
1859 Defaults to the client keypair.",
1860 ),
1861 )
1862 .arg(owner_address_arg())
1863 .arg(multisig_signer_arg())
1864 .nonce_args(true)
1865 .offline_args(),
1866 )
1867 .subcommand(
1868 SubCommand::with_name(CommandName::Balance.into())
1869 .about("Get token account balance")
1870 .arg(
1871 Arg::with_name("token")
1872 .validator(|s| is_valid_pubkey(s))
1873 .value_name("TOKEN_MINT_ADDRESS")
1874 .takes_value(true)
1875 .index(1)
1876 .required_unless("address")
1877 .help("Token of associated account. To query a specific account, use the `--address` parameter instead"),
1878 )
1879 .arg(owner_address_arg().conflicts_with("address"))
1880 .arg(
1881 Arg::with_name("address")
1882 .validator(|s| is_valid_pubkey(s))
1883 .value_name("TOKEN_ACCOUNT_ADDRESS")
1884 .takes_value(true)
1885 .long("address")
1886 .conflicts_with("token")
1887 .help("Specify the token account to query \
1888 [default: owner's associated token account]"),
1889 ),
1890 )
1891 .subcommand(
1892 SubCommand::with_name(CommandName::Supply.into())
1893 .about("Get token supply")
1894 .arg(
1895 Arg::with_name("token")
1896 .validator(|s| is_valid_pubkey(s))
1897 .value_name("TOKEN_MINT_ADDRESS")
1898 .takes_value(true)
1899 .index(1)
1900 .required(true)
1901 .help("The token address"),
1902 ),
1903 )
1904 .subcommand(
1905 SubCommand::with_name(CommandName::Accounts.into())
1906 .about("List all token accounts by owner")
1907 .arg(
1908 Arg::with_name("token")
1909 .validator(|s| is_valid_pubkey(s))
1910 .value_name("TOKEN_MINT_ADDRESS")
1911 .takes_value(true)
1912 .index(1)
1913 .help("Limit results to the given token. [Default: list accounts for all tokens]"),
1914 )
1915 .arg(
1916 Arg::with_name("delegated")
1917 .long("delegated")
1918 .takes_value(false)
1919 .conflicts_with("externally_closeable")
1920 .help(
1921 "Limit results to accounts with transfer delegations"
1922 ),
1923 )
1924 .arg(
1925 Arg::with_name("externally_closeable")
1926 .long("externally-closeable")
1927 .takes_value(false)
1928 .conflicts_with("delegated")
1929 .help(
1930 "Limit results to accounts with external close authorities"
1931 ),
1932 )
1933 .arg(
1934 Arg::with_name("addresses_only")
1935 .long("addresses-only")
1936 .takes_value(false)
1937 .conflicts_with("verbose")
1938 .conflicts_with("output_format")
1939 .help(
1940 "Print token account addresses only"
1941 ),
1942 )
1943 .arg(owner_address_arg())
1944 )
1945 .subcommand(
1946 SubCommand::with_name(CommandName::Address.into())
1947 .about("Get wallet address")
1948 .arg(
1949 Arg::with_name("token")
1950 .validator(|s| is_valid_pubkey(s))
1951 .value_name("TOKEN_MINT_ADDRESS")
1952 .takes_value(true)
1953 .long("token")
1954 .requires("verbose")
1955 .help("Return the associated token address for the given token. \
1956 [Default: return the client keypair address]")
1957 )
1958 .arg(
1959 owner_address_arg()
1960 .requires("token")
1961 .help("Return the associated token address for the given owner. \
1962 [Default: return the associated token address for the client keypair]"),
1963 ),
1964 )
1965 .subcommand(
1966 SubCommand::with_name(CommandName::AccountInfo.into())
1967 .about("Query details of an SPL Token account by address (DEPRECATED: use `spl-token display`)")
1968 .setting(AppSettings::Hidden)
1969 .arg(
1970 Arg::with_name("token")
1971 .validator(|s| is_valid_pubkey(s))
1972 .value_name("TOKEN_MINT_ADDRESS")
1973 .takes_value(true)
1974 .index(1)
1975 .conflicts_with("address")
1976 .required_unless("address")
1977 .help("Token of associated account. \
1978 To query a specific account, use the `--address` parameter instead"),
1979 )
1980 .arg(
1981 Arg::with_name(OWNER_ADDRESS_ARG.name)
1982 .takes_value(true)
1983 .value_name("OWNER_ADDRESS")
1984 .validator(|s| is_valid_signer(s))
1985 .help(OWNER_ADDRESS_ARG.help)
1986 .index(2)
1987 .conflicts_with("address")
1988 .help("Owner of the associated account for the specified token. \
1989 To query a specific account, use the `--address` parameter instead. \
1990 Defaults to the client keypair."),
1991 )
1992 .arg(
1993 Arg::with_name("address")
1994 .validator(|s| is_valid_pubkey(s))
1995 .value_name("TOKEN_ACCOUNT_ADDRESS")
1996 .takes_value(true)
1997 .long("address")
1998 .conflicts_with("token")
1999 .help("Specify the token account to query"),
2000 ),
2001 )
2002 .subcommand(
2003 SubCommand::with_name(CommandName::MultisigInfo.into())
2004 .about("Query details of an SPL Token multisig account by address (DEPRECATED: use `spl-token display`)")
2005 .setting(AppSettings::Hidden)
2006 .arg(
2007 Arg::with_name("address")
2008 .validator(|s| is_valid_pubkey(s))
2009 .value_name("MULTISIG_ACCOUNT_ADDRESS")
2010 .takes_value(true)
2011 .index(1)
2012 .required(true)
2013 .help("The address of the SPL Token multisig account to query"),
2014 ),
2015 )
2016 .subcommand(
2017 SubCommand::with_name(CommandName::Display.into())
2018 .about("Query details of an SPL Token mint, account, or multisig by address")
2019 .arg(
2020 Arg::with_name("address")
2021 .validator(|s| is_valid_pubkey(s))
2022 .value_name("TOKEN_ADDRESS")
2023 .takes_value(true)
2024 .index(1)
2025 .required(true)
2026 .help("The address of the SPL Token mint, account, or multisig to query"),
2027 ),
2028 )
2029 .subcommand(
2030 SubCommand::with_name(CommandName::Gc.into())
2031 .about("Cleanup unnecessary token accounts")
2032 .arg(owner_keypair_arg())
2033 .arg(
2034 Arg::with_name("close_empty_associated_accounts")
2035 .long("close-empty-associated-accounts")
2036 .takes_value(false)
2037 .help("close all empty associated token accounts (to get SOL back)")
2038 )
2039 )
2040 .subcommand(
2041 SubCommand::with_name(CommandName::SyncNative.into())
2042 .about("Sync a native SOL token account to its underlying lamports")
2043 .arg(
2044 owner_address_arg()
2045 .index(1)
2046 .conflicts_with("address")
2047 .help("Owner of the associated account for the native token. \
2048 To query a specific account, use the `--address` parameter instead. \
2049 Defaults to the client keypair."),
2050 )
2051 .arg(
2052 Arg::with_name("address")
2053 .validator(|s| is_valid_pubkey(s))
2054 .value_name("TOKEN_ACCOUNT_ADDRESS")
2055 .takes_value(true)
2056 .long("address")
2057 .conflicts_with("owner")
2058 .help("Specify the specific token account address to sync"),
2059 ),
2060 )
2061 .subcommand(
2062 SubCommand::with_name(CommandName::EnableRequiredTransferMemos.into())
2063 .about("Enable required transfer memos for token account")
2064 .arg(
2065 Arg::with_name("account")
2066 .validator(|s| is_valid_pubkey(s))
2067 .value_name("TOKEN_ACCOUNT_ADDRESS")
2068 .takes_value(true)
2069 .index(1)
2070 .required(true)
2071 .help("The address of the token account to require transfer memos for")
2072 )
2073 .arg(
2074 owner_address_arg()
2075 )
2076 .arg(multisig_signer_arg())
2077 .nonce_args(true)
2078 )
2079 .subcommand(
2080 SubCommand::with_name(CommandName::DisableRequiredTransferMemos.into())
2081 .about("Disable required transfer memos for token account")
2082 .arg(
2083 Arg::with_name("account")
2084 .validator(|s| is_valid_pubkey(s))
2085 .value_name("TOKEN_ACCOUNT_ADDRESS")
2086 .takes_value(true)
2087 .index(1)
2088 .required(true)
2089 .help("The address of the token account to stop requiring transfer memos for"),
2090 )
2091 .arg(
2092 owner_address_arg()
2093 )
2094 .arg(multisig_signer_arg())
2095 .nonce_args(true)
2096 )
2097 .subcommand(
2098 SubCommand::with_name(CommandName::EnableCpiGuard.into())
2099 .about("Enable CPI Guard for token account")
2100 .arg(
2101 Arg::with_name("account")
2102 .validator(|s| is_valid_pubkey(s))
2103 .value_name("TOKEN_ACCOUNT_ADDRESS")
2104 .takes_value(true)
2105 .index(1)
2106 .required(true)
2107 .help("The address of the token account to enable CPI Guard for")
2108 )
2109 .arg(
2110 owner_address_arg()
2111 )
2112 .arg(multisig_signer_arg())
2113 .nonce_args(true)
2114 )
2115 .subcommand(
2116 SubCommand::with_name(CommandName::DisableCpiGuard.into())
2117 .about("Disable CPI Guard for token account")
2118 .arg(
2119 Arg::with_name("account")
2120 .validator(|s| is_valid_pubkey(s))
2121 .value_name("TOKEN_ACCOUNT_ADDRESS")
2122 .takes_value(true)
2123 .index(1)
2124 .required(true)
2125 .help("The address of the token account to disable CPI Guard for"),
2126 )
2127 .arg(
2128 owner_address_arg()
2129 )
2130 .arg(multisig_signer_arg())
2131 .nonce_args(true)
2132 )
2133 .subcommand(
2134 SubCommand::with_name(CommandName::UpdateDefaultAccountState.into())
2135 .about("Updates default account state for the mint. Requires the default account state extension.")
2136 .arg(
2137 Arg::with_name("token")
2138 .validator(|s| is_valid_pubkey(s))
2139 .value_name("TOKEN_MINT_ADDRESS")
2140 .takes_value(true)
2141 .index(1)
2142 .required(true)
2143 .help("The address of the token mint to update default account state"),
2144 )
2145 .arg(
2146 Arg::with_name("state")
2147 .value_name("STATE")
2148 .takes_value(true)
2149 .possible_values(["initialized", "frozen"])
2150 .index(2)
2151 .required(true)
2152 .help("The new default account state."),
2153 )
2154 .arg(
2155 Arg::with_name("freeze_authority")
2156 .long("freeze-authority")
2157 .value_name("KEYPAIR")
2158 .validator(|s| is_valid_signer(s))
2159 .takes_value(true)
2160 .help(
2161 "Specify the token's freeze authority. \
2162 This may be a keypair file or the ASK keyword. \
2163 Defaults to the client keypair.",
2164 ),
2165 )
2166 .arg(owner_address_arg())
2167 .arg(multisig_signer_arg())
2168 .nonce_args(true)
2169 .offline_args(),
2170 )
2171 .subcommand(
2172 SubCommand::with_name(CommandName::UpdateMetadataAddress.into())
2173 .about("Updates metadata pointer address for the mint. Requires the metadata pointer extension.")
2174 .arg(
2175 Arg::with_name("token")
2176 .validator(|s| is_valid_pubkey(s))
2177 .value_name("TOKEN_MINT_ADDRESS")
2178 .takes_value(true)
2179 .index(1)
2180 .required(true)
2181 .help("The address of the token mint to update the metadata pointer address"),
2182 )
2183 .arg(
2184 Arg::with_name("metadata_address")
2185 .index(2)
2186 .validator(|s| is_valid_pubkey(s))
2187 .value_name("METADATA_ADDRESS")
2188 .takes_value(true)
2189 .required_unless("disable")
2190 .help("Specify address that stores token's metadata-pointer"),
2191 )
2192 .arg(
2193 Arg::with_name("disable")
2194 .long("disable")
2195 .takes_value(false)
2196 .conflicts_with("metadata_address")
2197 .help("Unset metadata pointer address.")
2198 )
2199 .arg(
2200 Arg::with_name("authority")
2201 .long("authority")
2202 .value_name("KEYPAIR")
2203 .validator(|s| is_valid_signer(s))
2204 .takes_value(true)
2205 .help(
2206 "Specify the token's metadata-pointer authority. \
2207 This may be a keypair file or the ASK keyword. \
2208 Defaults to the client keypair.",
2209 ),
2210 )
2211 .arg(multisig_signer_arg())
2212 .nonce_args(true)
2213 )
2214 .subcommand(
2215 SubCommand::with_name(CommandName::UpdateGroupAddress.into())
2216 .about("Updates group pointer address for the mint. Requires the group pointer extension.")
2217 .arg(
2218 Arg::with_name("token")
2219 .validator(|s| is_valid_pubkey(s))
2220 .value_name("TOKEN_MINT_ADDRESS")
2221 .takes_value(true)
2222 .index(1)
2223 .required(true)
2224 .help("The address of the token mint to update the group pointer address"),
2225 )
2226 .arg(
2227 Arg::with_name("group_address")
2228 .index(2)
2229 .validator(|s| is_valid_pubkey(s))
2230 .value_name("GROUP_ADDRESS")
2231 .takes_value(true)
2232 .required_unless("disable")
2233 .help("Specify address that stores token's group-pointer"),
2234 )
2235 .arg(
2236 Arg::with_name("disable")
2237 .long("disable")
2238 .takes_value(false)
2239 .conflicts_with("group_address")
2240 .help("Unset group pointer address.")
2241 )
2242 .arg(
2243 Arg::with_name("authority")
2244 .long("authority")
2245 .value_name("KEYPAIR")
2246 .validator(|s| is_valid_signer(s))
2247 .takes_value(true)
2248 .help(
2249 "Specify the token's group-pointer authority. \
2250 This may be a keypair file or the ASK keyword. \
2251 Defaults to the client keypair.",
2252 ),
2253 )
2254 .arg(multisig_signer_arg())
2255 .nonce_args(true)
2256 )
2257 .subcommand(
2258 SubCommand::with_name(CommandName::UpdateMemberAddress.into())
2259 .about("Updates group member pointer address for the mint. Requires the group member pointer extension.")
2260 .arg(
2261 Arg::with_name("token")
2262 .validator(|s| is_valid_pubkey(s))
2263 .value_name("TOKEN_MINT_ADDRESS")
2264 .takes_value(true)
2265 .index(1)
2266 .required(true)
2267 .help("The address of the token mint to update the group member pointer address"),
2268 )
2269 .arg(
2270 Arg::with_name("member_address")
2271 .index(2)
2272 .validator(|s| is_valid_pubkey(s))
2273 .value_name("MEMBER_ADDRESS")
2274 .takes_value(true)
2275 .required_unless("disable")
2276 .help("Specify address that stores token's group-member-pointer"),
2277 )
2278 .arg(
2279 Arg::with_name("disable")
2280 .long("disable")
2281 .takes_value(false)
2282 .conflicts_with("member_address")
2283 .help("Unset group member pointer address.")
2284 )
2285 .arg(
2286 Arg::with_name("authority")
2287 .long("authority")
2288 .value_name("KEYPAIR")
2289 .validator(|s| is_valid_signer(s))
2290 .takes_value(true)
2291 .help(
2292 "Specify the token's group-member-pointer authority. \
2293 This may be a keypair file or the ASK keyword. \
2294 Defaults to the client keypair.",
2295 ),
2296 )
2297 .arg(multisig_signer_arg())
2298 .nonce_args(true)
2299 )
2300 .subcommand(
2301 SubCommand::with_name(CommandName::WithdrawWithheldTokens.into())
2302 .about("Withdraw withheld transfer fee tokens from mint and / or account(s)")
2303 .arg(
2304 Arg::with_name("account")
2305 .validator(|s| is_valid_pubkey(s))
2306 .value_name("FEE_RECIPIENT_ADDRESS")
2307 .takes_value(true)
2308 .index(1)
2309 .required(true)
2310 .help("The token account to send withdrawn fees to."),
2311 )
2312 .arg(
2313 Arg::with_name("source")
2314 .validator(|s| is_valid_pubkey(s))
2315 .value_name("SOURCE_ADDRESS")
2316 .takes_value(true)
2317 .multiple(true)
2318 .min_values(0_usize)
2319 .index(2)
2320 .help("The token account(s) to withdraw fees from.")
2321 )
2322 .arg(
2323 Arg::with_name("include_mint")
2324 .long("include-mint")
2325 .takes_value(false)
2326 .help("Also withdraw withheld tokens from the mint"),
2327 )
2328 .arg(
2329 Arg::with_name("withdraw_withheld_authority")
2330 .long("withdraw-withheld-authority")
2331 .value_name("KEYPAIR")
2332 .validator(|s| is_valid_signer(s))
2333 .takes_value(true)
2334 .help(
2335 "Specify the withdraw withheld authority keypair. \
2336 This may be a keypair file or the ASK keyword. \
2337 Defaults to the client keypair."
2338 ),
2339 )
2340 .arg(owner_address_arg())
2341 .arg(multisig_signer_arg())
2342 .group(
2344 ArgGroup::with_name("account_group")
2345 .arg("account")
2346 .required(true)
2347 )
2348 .group(
2349 ArgGroup::with_name("source_or_mint")
2350 .arg("source")
2351 .arg("include_mint")
2352 .multiple(true)
2353 .required(true)
2354 )
2355 )
2356 .subcommand(
2357 SubCommand::with_name(CommandName::SetTransferFee.into())
2358 .about("Set the transfer fee for a token with a configured transfer fee")
2359 .arg(
2360 Arg::with_name("token")
2361 .validator(|s| is_valid_pubkey(s))
2362 .value_name("TOKEN_MINT_ADDRESS")
2363 .takes_value(true)
2364 .required(true)
2365 .help("The interest-bearing token address"),
2366 )
2367 .arg(
2368 Arg::with_name("transfer_fee_basis_points")
2369 .value_name("FEE_IN_BASIS_POINTS")
2370 .takes_value(true)
2371 .required(true)
2372 .help("The new transfer fee in basis points"),
2373 )
2374 .arg(
2375 Arg::with_name("maximum_fee")
2376 .value_name("MAXIMUM_FEE")
2377 .value_parser(Amount::parse)
2378 .takes_value(true)
2379 .required(true)
2380 .help("The new maximum transfer fee in UI amount"),
2381 )
2382 .arg(
2383 Arg::with_name("transfer_fee_authority")
2384 .long("transfer-fee-authority")
2385 .validator(|s| is_valid_signer(s))
2386 .value_name("SIGNER")
2387 .takes_value(true)
2388 .help(
2389 "Specify the rate authority keypair. \
2390 Defaults to the client keypair address."
2391 )
2392 )
2393 .arg(mint_decimals_arg())
2394 .offline_args_config(&SignOnlyNeedsMintDecimals{})
2395 )
2396 .subcommand(
2397 SubCommand::with_name(CommandName::WithdrawExcessLamports.into())
2398 .about("Withdraw lamports from a Token Program owned account")
2399 .arg(
2400 Arg::with_name("from")
2401 .validator(|s| is_valid_pubkey(s))
2402 .value_name("SOURCE_ACCOUNT_ADDRESS")
2403 .takes_value(true)
2404 .required(true)
2405 .help("Specify the address of the account to recover lamports from"),
2406 )
2407 .arg(
2408 Arg::with_name("recipient")
2409 .validator(|s| is_valid_pubkey(s))
2410 .value_name("REFUND_ACCOUNT_ADDRESS")
2411 .takes_value(true)
2412 .required(true)
2413 .help("Specify the address of the account to send lamports to"),
2414 )
2415 .arg(owner_address_arg())
2416 .arg(multisig_signer_arg())
2417 )
2418 .subcommand(
2419 SubCommand::with_name(CommandName::UpdateConfidentialTransferSettings.into())
2420 .about("Update confidential transfer configuration for a token")
2421 .arg(
2422 Arg::with_name("token")
2423 .validator(|s| is_valid_pubkey(s))
2424 .value_name("TOKEN_MINT_ADDRESS")
2425 .takes_value(true)
2426 .index(1)
2427 .required(true)
2428 .help("The address of the token mint to update confidential transfer configuration for")
2429 )
2430 .arg(
2431 Arg::with_name("approve_policy")
2432 .long("approve-policy")
2433 .value_name("APPROVE_POLICY")
2434 .takes_value(true)
2435 .possible_values(["auto", "manual"])
2436 .help(
2437 "Policy for enabling accounts to make confidential transfers. If \"auto\" \
2438 is selected, then accounts are automatically approved to make \
2439 confidential transfers. If \"manual\" is selected, then the \
2440 confidential transfer mint authority must approve each account \
2441 before it can make confidential transfers."
2442 )
2443 )
2444 .arg(
2445 Arg::with_name("auditor_pubkey")
2446 .long("auditor-pubkey")
2447 .value_name("AUDITOR_PUBKEY")
2448 .takes_value(true)
2449 .help(
2450 "The auditor encryption public key. The corresponding private key for \
2451 this auditor public key can be used to decrypt all confidential \
2452 transfers involving tokens from this mint. Currently, the auditor \
2453 public key can only be specified as a direct *base64* encoding of \
2454 an ElGamal public key. More methods of specifying the auditor public \
2455 key will be supported in a future version. To disable auditability \
2456 feature for the token, use \"none\"."
2457 )
2458 )
2459 .group(
2460 ArgGroup::with_name("update_fields").args(&["approve_policy", "auditor_pubkey"])
2461 .required(true)
2462 .multiple(true)
2463 )
2464 .arg(
2465 Arg::with_name("confidential_transfer_authority")
2466 .long("confidential-transfer-authority")
2467 .validator(|s| is_valid_signer(s))
2468 .value_name("SIGNER")
2469 .takes_value(true)
2470 .help(
2471 "Specify the confidential transfer authority keypair. \
2472 Defaults to the client keypair address."
2473 )
2474 )
2475 .nonce_args(true)
2476 .offline_args(),
2477 )
2478 .subcommand(
2479 SubCommand::with_name(CommandName::ConfigureConfidentialTransferAccount.into())
2480 .about("Configure confidential transfers for token account")
2481 .arg(
2482 Arg::with_name("token")
2483 .validator(|s| is_valid_pubkey(s))
2484 .value_name("TOKEN_MINT_ADDRESS")
2485 .takes_value(true)
2486 .index(1)
2487 .required_unless("address")
2488 .help("The token address with confidential transfers enabled"),
2489 )
2490 .arg(
2491 Arg::with_name("address")
2492 .long("address")
2493 .validator(|s| is_valid_pubkey(s))
2494 .value_name("TOKEN_ACCOUNT_ADDRESS")
2495 .takes_value(true)
2496 .conflicts_with("token")
2497 .help("The address of the token account to configure confidential transfers for \
2498 [default: owner's associated token account]")
2499 )
2500 .arg(
2501 owner_address_arg()
2502 )
2503 .arg(
2504 Arg::with_name("maximum_pending_balance_credit_counter")
2505 .long("maximum-pending-balance-credit-counter")
2506 .value_name("MAXIMUM-CREDIT-COUNTER")
2507 .takes_value(true)
2508 .help(
2509 "The maximum pending balance credit counter. \
2510 This parameter limits the number of confidential transfers that a token account \
2511 can receive to facilitate decryption of the encrypted balance. \
2512 Defaults to 65536 (2^16)"
2513 )
2514 )
2515 .arg(multisig_signer_arg())
2516 .nonce_args(true)
2517 )
2518 .subcommand(
2519 SubCommand::with_name(CommandName::EnableConfidentialCredits.into())
2520 .about("Enable confidential transfers for token account. To enable confidential transfers \
2521 for the first time, use `configure-confidential-transfer-account` instead.")
2522 .arg(
2523 Arg::with_name("token")
2524 .validator(|s| is_valid_pubkey(s))
2525 .value_name("TOKEN_MINT_ADDRESS")
2526 .takes_value(true)
2527 .index(1)
2528 .required_unless("address")
2529 .help("The token address with confidential transfers enabled"),
2530 )
2531 .arg(
2532 Arg::with_name("address")
2533 .long("address")
2534 .validator(|s| is_valid_pubkey(s))
2535 .value_name("TOKEN_ACCOUNT_ADDRESS")
2536 .takes_value(true)
2537 .conflicts_with("token")
2538 .help("The address of the token account to enable confidential transfers for \
2539 [default: owner's associated token account]")
2540 )
2541 .arg(
2542 owner_address_arg()
2543 )
2544 .arg(multisig_signer_arg())
2545 .nonce_args(true)
2546 )
2547 .subcommand(
2548 SubCommand::with_name(CommandName::DisableConfidentialCredits.into())
2549 .about("Disable confidential transfers for token account")
2550 .arg(
2551 Arg::with_name("token")
2552 .validator(|s| is_valid_pubkey(s))
2553 .value_name("TOKEN_MINT_ADDRESS")
2554 .takes_value(true)
2555 .index(1)
2556 .required_unless("address")
2557 .help("The token address with confidential transfers enabled"),
2558 )
2559 .arg(
2560 Arg::with_name("address")
2561 .long("address")
2562 .validator(|s| is_valid_pubkey(s))
2563 .value_name("TOKEN_ACCOUNT_ADDRESS")
2564 .takes_value(true)
2565 .conflicts_with("token")
2566 .help("The address of the token account to disable confidential transfers for \
2567 [default: owner's associated token account]")
2568 )
2569 .arg(
2570 owner_address_arg()
2571 )
2572 .arg(multisig_signer_arg())
2573 .nonce_args(true)
2574 )
2575 .subcommand(
2576 SubCommand::with_name(CommandName::EnableNonConfidentialCredits.into())
2577 .about("Enable non-confidential transfers for token account.")
2578 .arg(
2579 Arg::with_name("token")
2580 .validator(|s| is_valid_pubkey(s))
2581 .value_name("TOKEN_MINT_ADDRESS")
2582 .takes_value(true)
2583 .index(1)
2584 .required_unless("address")
2585 .help("The token address with confidential transfers enabled"),
2586 )
2587 .arg(
2588 Arg::with_name("address")
2589 .long("address")
2590 .validator(|s| is_valid_pubkey(s))
2591 .value_name("TOKEN_ACCOUNT_ADDRESS")
2592 .takes_value(true)
2593 .conflicts_with("token")
2594 .help("The address of the token account to enable non-confidential transfers for \
2595 [default: owner's associated token account]")
2596 )
2597 .arg(
2598 owner_address_arg()
2599 )
2600 .arg(multisig_signer_arg())
2601 .nonce_args(true)
2602 )
2603 .subcommand(
2604 SubCommand::with_name(CommandName::DisableNonConfidentialCredits.into())
2605 .about("Disable non-confidential transfers for token account")
2606 .arg(
2607 Arg::with_name("token")
2608 .validator(|s| is_valid_pubkey(s))
2609 .value_name("TOKEN_MINT_ADDRESS")
2610 .takes_value(true)
2611 .index(1)
2612 .required_unless("address")
2613 .help("The token address with confidential transfers enabled"),
2614 )
2615 .arg(
2616 Arg::with_name("address")
2617 .long("address")
2618 .validator(|s| is_valid_pubkey(s))
2619 .value_name("TOKEN_ACCOUNT_ADDRESS")
2620 .takes_value(true)
2621 .conflicts_with("token")
2622 .help("The address of the token account to disable non-confidential transfers for \
2623 [default: owner's associated token account]")
2624 )
2625 .arg(
2626 owner_address_arg()
2627 )
2628 .arg(multisig_signer_arg())
2629 .nonce_args(true)
2630 )
2631 .subcommand(
2632 SubCommand::with_name(CommandName::DepositConfidentialTokens.into())
2633 .about("Deposit amounts for confidential transfers")
2634 .arg(
2635 Arg::with_name("token")
2636 .validator(|s| is_valid_pubkey(s))
2637 .value_name("TOKEN_MINT_ADDRESS")
2638 .takes_value(true)
2639 .index(1)
2640 .required(true)
2641 .help("The token address with confidential transfers enabled"),
2642 )
2643 .arg(
2644 Arg::with_name("amount")
2645 .value_parser(Amount::parse)
2646 .value_name("TOKEN_AMOUNT")
2647 .takes_value(true)
2648 .index(2)
2649 .required(true)
2650 .help("Amount to deposit; accepts keyword ALL"),
2651 )
2652 .arg(
2653 Arg::with_name("address")
2654 .long("address")
2655 .validator(|s| is_valid_pubkey(s))
2656 .value_name("TOKEN_ACCOUNT_ADDRESS")
2657 .takes_value(true)
2658 .help("The address of the token account to configure confidential transfers for \
2659 [default: owner's associated token account]")
2660 )
2661 .arg(
2662 owner_address_arg()
2663 )
2664 .arg(multisig_signer_arg())
2665 .arg(mint_decimals_arg())
2666 .nonce_args(true)
2667 )
2668 .subcommand(
2669 SubCommand::with_name(CommandName::WithdrawConfidentialTokens.into())
2670 .about("Withdraw amounts for confidential transfers")
2671 .arg(
2672 Arg::with_name("token")
2673 .validator(|s| is_valid_pubkey(s))
2674 .value_name("TOKEN_MINT_ADDRESS")
2675 .takes_value(true)
2676 .index(1)
2677 .required(true)
2678 .help("The token address with confidential transfers enabled"),
2679 )
2680 .arg(
2681 Arg::with_name("amount")
2682 .value_parser(Amount::parse)
2683 .value_name("TOKEN_AMOUNT")
2684 .takes_value(true)
2685 .index(2)
2686 .required(true)
2687 .help("Amount to deposit; accepts keyword ALL"),
2688 )
2689 .arg(
2690 Arg::with_name("address")
2691 .long("address")
2692 .validator(|s| is_valid_pubkey(s))
2693 .value_name("TOKEN_ACCOUNT_ADDRESS")
2694 .takes_value(true)
2695 .help("The address of the token account to configure confidential transfers for \
2696 [default: owner's associated token account]")
2697 )
2698 .arg(
2699 owner_address_arg()
2700 )
2701 .arg(multisig_signer_arg())
2702 .arg(mint_decimals_arg())
2703 .nonce_args(true)
2704 )
2705 .subcommand(
2706 SubCommand::with_name(CommandName::ApplyPendingBalance.into())
2707 .about("Collect confidential tokens from pending to available balance")
2708 .arg(
2709 Arg::with_name("token")
2710 .validator(|s| is_valid_pubkey(s))
2711 .value_name("TOKEN_MINT_ADDRESS")
2712 .takes_value(true)
2713 .index(1)
2714 .required_unless("address")
2715 .help("The token address with confidential transfers enabled"),
2716 )
2717 .arg(
2718 Arg::with_name("address")
2719 .long("address")
2720 .validator(|s| is_valid_pubkey(s))
2721 .value_name("TOKEN_ACCOUNT_ADDRESS")
2722 .takes_value(true)
2723 .help("The address of the token account to configure confidential transfers for \
2724 [default: owner's associated token account]")
2725 )
2726 .arg(
2727 owner_address_arg()
2728 )
2729 .arg(multisig_signer_arg())
2730 .nonce_args(true)
2731 )
2732 .subcommand(
2733 SubCommand::with_name(CommandName::UpdateUiAmountMultiplier.into())
2734 .about("Update UI multiplier")
2735 .arg(
2736 Arg::with_name("token")
2737 .validator(|s| is_valid_pubkey(s))
2738 .value_name("TOKEN_MINT_ADDRESS")
2739 .takes_value(true)
2740 .index(1)
2741 .required(true)
2742 .help("The token address with scaled UI amount multiplier"),
2743 )
2744 .arg(
2745 Arg::with_name("multiplier")
2746 .value_name("MULTIPLIER")
2747 .takes_value(true)
2748 .index(2)
2749 .required(true)
2750 .help("The new multiplier"),
2751 )
2752 .arg(
2753 Arg::with_name("timestamp")
2754 .value_name("TIMESTAMP")
2755 .takes_value(true)
2756 .index(3)
2757 .help("The effective time for the new multiplier, given as a UNIX timestamp \
2758 [default: current time]",)
2759 )
2760 .arg(
2761 Arg::with_name("ui_multiplier_authority")
2762 .long("ui-multiplier-authority")
2763 .alias("owner")
2764 .validator(|s| is_valid_signer(s))
2765 .value_name("SIGNER")
2766 .takes_value(true)
2767 .help(
2768 "Specify the multiplier authority keypair. \
2769 Defaults to the client keypair address."
2770 )
2771 )
2772 .arg(multisig_signer_arg())
2773 .nonce_args(true)
2774 )
2775 .subcommand(
2776 SubCommand::with_name(CommandName::Pause.into())
2777 .about("Pause mint, burn, and transfer")
2778 .arg(
2779 Arg::with_name("token")
2780 .validator(|s| is_valid_pubkey(s))
2781 .value_name("TOKEN_MINT_ADDRESS")
2782 .takes_value(true)
2783 .index(1)
2784 .required(true)
2785 .help("The pausable token address"),
2786 )
2787 .arg(
2788 Arg::with_name("pause_authority")
2789 .long("pause-authority")
2790 .alias("owner")
2791 .validator(|s| is_valid_signer(s))
2792 .value_name("SIGNER")
2793 .takes_value(true)
2794 .help(
2795 "Specify the pause authority keypair. \
2796 Defaults to the client keypair address."
2797 )
2798 )
2799 .arg(multisig_signer_arg())
2800 .nonce_args(true)
2801 )
2802 .subcommand(
2803 SubCommand::with_name(CommandName::Resume.into())
2804 .about("Resume mint, burn, and transfer")
2805 .arg(
2806 Arg::with_name("token")
2807 .validator(|s| is_valid_pubkey(s))
2808 .value_name("TOKEN_MINT_ADDRESS")
2809 .takes_value(true)
2810 .index(1)
2811 .required(true)
2812 .help("The pausable token address"),
2813 )
2814 .arg(
2815 Arg::with_name("pause_authority")
2816 .long("pause-authority")
2817 .alias("owner")
2818 .validator(|s| is_valid_signer(s))
2819 .value_name("SIGNER")
2820 .takes_value(true)
2821 .help(
2822 "Specify the pause authority keypair. \
2823 Defaults to the client keypair address."
2824 )
2825 )
2826 .arg(multisig_signer_arg())
2827 .nonce_args(true)
2828 )
2829}