diff --git a/stake-accounts/src/arg_parser.rs b/stake-accounts/src/arg_parser.rs new file mode 100644 index 000000000..89373bfd1 --- /dev/null +++ b/stake-accounts/src/arg_parser.rs @@ -0,0 +1,305 @@ +use crate::args::{ + Args, AuthorizeArgs, Command, CountArgs, MoveArgs, NewArgs, QueryArgs, RebaseArgs, +}; +use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand}; +use solana_clap_utils::input_validators::{is_amount, is_valid_pubkey, is_valid_signer}; +use solana_cli_config::CONFIG_FILE; +use solana_sdk::native_token::sol_to_lamports; +use std::ffi::OsString; +use std::process::exit; + +fn fee_payer_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("fee_payer") + .long("fee-payer") + .required(true) + .takes_value(true) + .value_name("KEYPAIR") + .validator(is_valid_signer) + .help("Fee payer") +} + +fn funding_keypair_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("funding_keypair") + .required(true) + .takes_value(true) + .value_name("FUNDING_KEYPAIR") + .validator(is_valid_signer) + .help("Keypair to fund accounts") +} + +fn base_pubkey_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("base_pubkey") + .required(true) + .takes_value(true) + .value_name("BASE_PUBKEY") + .validator(is_valid_pubkey) + .help("Public key which stake account addresses are derived from") +} + +fn new_base_keypair_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("new_base_keypair") + .required(true) + .takes_value(true) + .value_name("NEW_BASE_KEYPAIR") + .validator(is_valid_signer) + .help("New keypair which stake account addresses are derived from") +} + +fn stake_authority_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("stake_authority") + .long("stake-authority") + .required(true) + .takes_value(true) + .value_name("KEYPAIR") + .validator(is_valid_signer) + .help("Stake authority") +} + +fn withdraw_authority_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("withdraw_authority") + .long("withdraw-authority") + .required(true) + .takes_value(true) + .value_name("KEYPAIR") + .validator(is_valid_signer) + .help("Withdraw authority") +} + +fn new_stake_authority_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("new_stake_authority") + .long("new-stake-authority") + .required(true) + .takes_value(true) + .value_name("PUBKEY") + .validator(is_valid_pubkey) + .help("New stake authority") +} + +fn new_withdraw_authority_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("new_withdraw_authority") + .long("new-withdraw-authority") + .required(true) + .takes_value(true) + .value_name("PUBKEY") + .validator(is_valid_pubkey) + .help("New withdraw authority") +} + +fn num_accounts_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("num_accounts") + .long("num-accounts") + .required(true) + .takes_value(true) + .value_name("NUMBER") + .help("Number of derived stake accounts") +} + +pub(crate) fn get_matches<'a, I, T>(args: I) -> ArgMatches<'a> +where + I: IntoIterator, + T: Into + Clone, +{ + let default_config_file = CONFIG_FILE.as_ref().unwrap(); + App::new("solana-stake-accounts") + .about("about") + .version("version") + .arg( + Arg::with_name("config_file") + .long("config") + .takes_value(true) + .value_name("FILEPATH") + .default_value(default_config_file) + .help("Config file"), + ) + .arg( + Arg::with_name("url") + .long("url") + .global(true) + .takes_value(true) + .value_name("URL") + .help("RPC entrypoint address. i.e. http://devnet.solana.com"), + ) + .subcommand( + SubCommand::with_name("new") + .about("Create derived stake accounts") + .arg(fee_payer_arg()) + .arg(funding_keypair_arg().index(1)) + .arg( + Arg::with_name("base_keypair") + .required(true) + .index(2) + .takes_value(true) + .value_name("BASE_KEYPAIR") + .validator(is_valid_signer) + .help("Keypair which stake account addresses are derived from"), + ) + .arg( + Arg::with_name("amount") + .required(true) + .index(3) + .takes_value(true) + .value_name("AMOUNT") + .validator(is_amount) + .help("Amount to move into the new stake accounts, in SOL"), + ) + .arg( + Arg::with_name("stake_authority") + .long("stake-authority") + .required(true) + .takes_value(true) + .value_name("PUBKEY") + .validator(is_valid_pubkey) + .help("Stake authority"), + ) + .arg( + Arg::with_name("withdraw_authority") + .long("withdraw-authority") + .required(true) + .takes_value(true) + .value_name("PUBKEY") + .validator(is_valid_pubkey) + .help("Withdraw authority"), + ) + .arg( + Arg::with_name("index") + .long("index") + .takes_value(true) + .default_value("0") + .value_name("NUMBER") + .help("Index of the derived account to create"), + ), + ) + .subcommand( + SubCommand::with_name("count") + .about("Count derived stake accounts") + .arg(base_pubkey_arg().index(1)), + ) + .subcommand( + SubCommand::with_name("addresses") + .about("Show public keys of all derived stake accounts") + .arg(base_pubkey_arg().index(1)) + .arg(num_accounts_arg()), + ) + .subcommand( + SubCommand::with_name("balance") + .about("Sum balances of all derived stake accounts") + .arg(base_pubkey_arg().index(1)) + .arg(num_accounts_arg()), + ) + .subcommand( + SubCommand::with_name("authorize") + .about("Set new authorities in all derived stake accounts") + .arg(fee_payer_arg()) + .arg(base_pubkey_arg().index(1)) + .arg(stake_authority_arg()) + .arg(withdraw_authority_arg()) + .arg(new_stake_authority_arg()) + .arg(new_withdraw_authority_arg()) + .arg(num_accounts_arg()), + ) + .subcommand( + SubCommand::with_name("rebase") + .about("Relocate derived stake accounts") + .arg(fee_payer_arg()) + .arg(base_pubkey_arg().index(1)) + .arg(new_base_keypair_arg().index(2)) + .arg(stake_authority_arg()) + .arg(num_accounts_arg()), + ) + .subcommand( + SubCommand::with_name("move") + .about("Rebase and set new authorities in all derived stake accounts") + .arg(fee_payer_arg()) + .arg(base_pubkey_arg().index(1)) + .arg(new_base_keypair_arg().index(2)) + .arg(stake_authority_arg()) + .arg(withdraw_authority_arg()) + .arg(new_stake_authority_arg()) + .arg(new_withdraw_authority_arg()) + .arg(num_accounts_arg()), + ) + .get_matches_from(args) +} + +fn parse_new_args(matches: &ArgMatches<'_>) -> NewArgs { + NewArgs { + fee_payer: value_t_or_exit!(matches, "fee_payer", String), + funding_keypair: value_t_or_exit!(matches, "funding_keypair", String), + lamports: sol_to_lamports(value_t_or_exit!(matches, "amount", f64)), + base_keypair: value_t_or_exit!(matches, "base_keypair", String), + stake_authority: value_t_or_exit!(matches, "stake_authority", String), + withdraw_authority: value_t_or_exit!(matches, "withdraw_authority", String), + index: value_t_or_exit!(matches, "index", usize), + } +} + +fn parse_count_args(matches: &ArgMatches<'_>) -> CountArgs { + CountArgs { + base_pubkey: value_t_or_exit!(matches, "base_pubkey", String), + } +} + +fn parse_query_args(matches: &ArgMatches<'_>) -> QueryArgs { + QueryArgs { + base_pubkey: value_t_or_exit!(matches, "base_pubkey", String), + num_accounts: value_t_or_exit!(matches, "num_accounts", usize), + } +} + +fn parse_authorize_args(matches: &ArgMatches<'_>) -> AuthorizeArgs { + AuthorizeArgs { + fee_payer: value_t_or_exit!(matches, "fee_payer", String), + base_pubkey: value_t_or_exit!(matches, "base_pubkey", String), + stake_authority: value_t_or_exit!(matches, "stake_authority", String), + withdraw_authority: value_t_or_exit!(matches, "withdraw_authority", String), + new_stake_authority: value_t_or_exit!(matches, "new_stake_authority", String), + new_withdraw_authority: value_t_or_exit!(matches, "new_withdraw_authority", String), + num_accounts: value_t_or_exit!(matches, "num_accounts", usize), + } +} + +fn parse_rebase_args(matches: &ArgMatches<'_>) -> RebaseArgs { + RebaseArgs { + fee_payer: value_t_or_exit!(matches, "fee_payer", String), + base_pubkey: value_t_or_exit!(matches, "base_pubkey", String), + new_base_keypair: value_t_or_exit!(matches, "new_base_keypair", String), + stake_authority: value_t_or_exit!(matches, "stake_authority", String), + num_accounts: value_t_or_exit!(matches, "num_accounts", usize), + } +} + +fn parse_move_args(matches: &ArgMatches<'_>) -> MoveArgs { + MoveArgs { + rebase_args: parse_rebase_args(matches), + authorize_args: parse_authorize_args(matches), + } +} + +pub(crate) fn parse_args(args: I) -> Args +where + I: IntoIterator, + T: Into + Clone, +{ + let matches = get_matches(args); + let config_file = matches.value_of("config_file").unwrap().to_string(); + let url = matches.value_of("url").map(|x| x.to_string()); + + let command = match matches.subcommand() { + ("new", Some(matches)) => Command::New(parse_new_args(matches)), + ("count", Some(matches)) => Command::Count(parse_count_args(matches)), + ("addresses", Some(matches)) => Command::Addresses(parse_query_args(matches)), + ("balance", Some(matches)) => Command::Balance(parse_query_args(matches)), + ("authorize", Some(matches)) => Command::Authorize(parse_authorize_args(matches)), + ("rebase", Some(matches)) => Command::Rebase(parse_rebase_args(matches)), + ("move", Some(matches)) => Command::Move(Box::new(parse_move_args(matches))), + _ => { + eprintln!("{}", matches.usage()); + exit(1); + } + }; + Args { + config_file, + url, + command, + } +} diff --git a/stake-accounts/src/args.rs b/stake-accounts/src/args.rs index 3d2932e4a..5483c9364 100644 --- a/stake-accounts/src/args.rs +++ b/stake-accounts/src/args.rs @@ -1,382 +1,233 @@ -use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand}; -use solana_clap_utils::input_validators::{is_amount, is_valid_pubkey, is_valid_signer}; -use solana_cli_config::CONFIG_FILE; -use solana_sdk::native_token::sol_to_lamports; -use std::ffi::OsString; -use std::process::exit; +use clap::ArgMatches; +use solana_clap_utils::keypair::{pubkey_from_path, signer_from_path}; +use solana_remote_wallet::remote_wallet::{maybe_wallet_manager, RemoteWalletManager}; +use solana_sdk::{pubkey::Pubkey, signature::Signer}; +use std::error::Error; +use std::sync::Arc; -pub(crate) struct NewCommandConfig { - pub fee_payer: String, - pub funding_keypair: String, - pub base_keypair: String, +pub(crate) struct NewArgs { + pub fee_payer: K, + pub funding_keypair: K, + pub base_keypair: K, pub lamports: u64, - pub stake_authority: String, - pub withdraw_authority: String, + pub stake_authority: P, + pub withdraw_authority: P, pub index: usize, } -pub(crate) struct CountCommandConfig { - pub base_pubkey: String, +pub(crate) struct CountArgs

{ + pub base_pubkey: P, } -pub(crate) struct QueryCommandConfig { - pub base_pubkey: String, +pub(crate) struct QueryArgs

{ + pub base_pubkey: P, pub num_accounts: usize, } -pub(crate) struct AuthorizeCommandConfig { - pub fee_payer: String, - pub base_pubkey: String, - pub stake_authority: String, - pub withdraw_authority: String, - pub new_stake_authority: String, - pub new_withdraw_authority: String, +pub(crate) struct AuthorizeArgs { + pub fee_payer: K, + pub base_pubkey: P, + pub stake_authority: K, + pub withdraw_authority: K, + pub new_stake_authority: P, + pub new_withdraw_authority: P, pub num_accounts: usize, } -pub(crate) struct RebaseCommandConfig { - pub fee_payer: String, - pub base_pubkey: String, - pub new_base_keypair: String, - pub stake_authority: String, +pub(crate) struct RebaseArgs { + pub fee_payer: K, + pub base_pubkey: P, + pub new_base_keypair: K, + pub stake_authority: K, pub num_accounts: usize, } -pub(crate) struct MoveCommandConfig { - pub rebase_config: RebaseCommandConfig, - pub authorize_config: AuthorizeCommandConfig, +pub(crate) struct MoveArgs { + pub rebase_args: RebaseArgs, + pub authorize_args: AuthorizeArgs, } -pub(crate) enum Command { - New(NewCommandConfig), - Count(CountCommandConfig), - Addresses(QueryCommandConfig), - Balance(QueryCommandConfig), - Authorize(AuthorizeCommandConfig), - Rebase(RebaseCommandConfig), - Move(Box), +pub(crate) enum Command { + New(NewArgs), + Count(CountArgs

), + Addresses(QueryArgs

), + Balance(QueryArgs

), + Authorize(AuthorizeArgs), + Rebase(RebaseArgs), + Move(Box>), } -pub(crate) struct CommandConfig { +pub(crate) struct Args { pub config_file: String, pub url: Option, - pub command: Command, + pub command: Command, } -fn fee_payer_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("fee_payer") - .long("fee-payer") - .required(true) - .takes_value(true) - .value_name("KEYPAIR") - .validator(is_valid_signer) - .help("Fee payer") +fn resolve_stake_authority( + wallet_manager: Option<&Arc>, + key_url: &str, +) -> Result, Box> { + let matches = ArgMatches::default(); + signer_from_path(&matches, key_url, "stake authority", wallet_manager) } -fn funding_keypair_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("funding_keypair") - .required(true) - .takes_value(true) - .value_name("FUNDING_KEYPAIR") - .validator(is_valid_signer) - .help("Keypair to fund accounts") +fn resolve_withdraw_authority( + wallet_manager: Option<&Arc>, + key_url: &str, +) -> Result, Box> { + let matches = ArgMatches::default(); + signer_from_path(&matches, key_url, "withdraw authority", wallet_manager) } -fn base_pubkey_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("base_pubkey") - .required(true) - .takes_value(true) - .value_name("BASE_PUBKEY") - .validator(is_valid_pubkey) - .help("Public key which stake account addresses are derived from") +fn resolve_new_stake_authority( + wallet_manager: Option<&Arc>, + key_url: &str, +) -> Result> { + let matches = ArgMatches::default(); + pubkey_from_path(&matches, key_url, "new stake authority", wallet_manager) } -fn new_base_keypair_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("new_base_keypair") - .required(true) - .takes_value(true) - .value_name("NEW_BASE_KEYPAIR") - .validator(is_valid_signer) - .help("New keypair which stake account addresses are derived from") +fn resolve_new_withdraw_authority( + wallet_manager: Option<&Arc>, + key_url: &str, +) -> Result> { + let matches = ArgMatches::default(); + pubkey_from_path(&matches, key_url, "new withdraw authority", wallet_manager) } -fn stake_authority_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("stake_authority") - .long("stake-authority") - .required(true) - .takes_value(true) - .value_name("KEYPAIR") - .validator(is_valid_signer) - .help("Stake authority") +fn resolve_fee_payer( + wallet_manager: Option<&Arc>, + key_url: &str, +) -> Result, Box> { + let matches = ArgMatches::default(); + signer_from_path(&matches, key_url, "fee-payer", wallet_manager) } -fn withdraw_authority_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("withdraw_authority") - .long("withdraw-authority") - .required(true) - .takes_value(true) - .value_name("KEYPAIR") - .validator(is_valid_signer) - .help("Withdraw authority") +fn resolve_base_pubkey( + wallet_manager: Option<&Arc>, + key_url: &str, +) -> Result> { + let matches = ArgMatches::default(); + pubkey_from_path(&matches, key_url, "base pubkey", wallet_manager) } -fn new_stake_authority_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("new_stake_authority") - .long("new-stake-authority") - .required(true) - .takes_value(true) - .value_name("PUBKEY") - .validator(is_valid_pubkey) - .help("New stake authority") +fn resolve_new_base_keypair( + wallet_manager: Option<&Arc>, + key_url: &str, +) -> Result, Box> { + let matches = ArgMatches::default(); + signer_from_path(&matches, key_url, "new base pubkey", wallet_manager) } -fn new_withdraw_authority_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("new_withdraw_authority") - .long("new-withdraw-authority") - .required(true) - .takes_value(true) - .value_name("PUBKEY") - .validator(is_valid_pubkey) - .help("New withdraw authority") -} - -fn num_accounts_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("num_accounts") - .long("num-accounts") - .required(true) - .takes_value(true) - .value_name("NUMBER") - .help("Number of derived stake accounts") -} - -pub(crate) fn get_matches<'a, I, T>(args: I) -> ArgMatches<'a> -where - I: IntoIterator, - T: Into + Clone, -{ - let default_config_file = CONFIG_FILE.as_ref().unwrap(); - App::new("solana-stake-accounts") - .about("about") - .version("version") - .arg( - Arg::with_name("config_file") - .long("config") - .takes_value(true) - .value_name("FILEPATH") - .default_value(default_config_file) - .help("Config file"), - ) - .arg( - Arg::with_name("url") - .long("url") - .global(true) - .takes_value(true) - .value_name("URL") - .help("RPC entrypoint address. i.e. http://devnet.solana.com"), - ) - .subcommand( - SubCommand::with_name("new") - .about("Create derived stake accounts") - .arg(fee_payer_arg()) - .arg(funding_keypair_arg().index(1)) - .arg( - Arg::with_name("base_keypair") - .required(true) - .index(2) - .takes_value(true) - .value_name("BASE_KEYPAIR") - .validator(is_valid_signer) - .help("Keypair which stake account addresses are derived from"), - ) - .arg( - Arg::with_name("amount") - .required(true) - .index(3) - .takes_value(true) - .value_name("AMOUNT") - .validator(is_amount) - .help("Amount to move into the new stake accounts, in SOL"), - ) - .arg( - Arg::with_name("stake_authority") - .long("stake-authority") - .required(true) - .takes_value(true) - .value_name("PUBKEY") - .validator(is_valid_pubkey) - .help("Stake authority"), - ) - .arg( - Arg::with_name("withdraw_authority") - .long("withdraw-authority") - .required(true) - .takes_value(true) - .value_name("PUBKEY") - .validator(is_valid_pubkey) - .help("Withdraw authority"), - ) - .arg( - Arg::with_name("index") - .long("index") - .takes_value(true) - .default_value("0") - .value_name("NUMBER") - .help("Index of the derived account to create"), - ), - ) - .subcommand( - SubCommand::with_name("count") - .about("Count derived stake accounts") - .arg(base_pubkey_arg().index(1)), - ) - .subcommand( - SubCommand::with_name("addresses") - .about("Show public keys of all derived stake accounts") - .arg(base_pubkey_arg().index(1)) - .arg(num_accounts_arg()), - ) - .subcommand( - SubCommand::with_name("balance") - .about("Sum balances of all derived stake accounts") - .arg(base_pubkey_arg().index(1)) - .arg(num_accounts_arg()), - ) - .subcommand( - SubCommand::with_name("authorize") - .about("Set new authorities in all derived stake accounts") - .arg(fee_payer_arg()) - .arg(base_pubkey_arg().index(1)) - .arg(stake_authority_arg()) - .arg(withdraw_authority_arg()) - .arg(new_stake_authority_arg()) - .arg(new_withdraw_authority_arg()) - .arg(num_accounts_arg()), - ) - .subcommand( - SubCommand::with_name("rebase") - .about("Relocate derived stake accounts") - .arg(fee_payer_arg()) - .arg(base_pubkey_arg().index(1)) - .arg(new_base_keypair_arg().index(2)) - .arg(stake_authority_arg()) - .arg(num_accounts_arg()), - ) - .subcommand( - SubCommand::with_name("move") - .about("Rebase and set new authorities in all derived stake accounts") - .arg(fee_payer_arg()) - .arg(base_pubkey_arg().index(1)) - .arg(new_base_keypair_arg().index(2)) - .arg(stake_authority_arg()) - .arg(withdraw_authority_arg()) - .arg(new_stake_authority_arg()) - .arg(new_withdraw_authority_arg()) - .arg(num_accounts_arg()), - ) - .get_matches_from(args) -} - -fn parse_new_args(matches: &ArgMatches<'_>) -> NewCommandConfig { - let fee_payer = value_t_or_exit!(matches, "fee_payer", String); - let funding_keypair = value_t_or_exit!(matches, "funding_keypair", String); - let lamports = sol_to_lamports(value_t_or_exit!(matches, "amount", f64)); - let base_keypair = value_t_or_exit!(matches, "base_keypair", String); - let stake_authority = value_t_or_exit!(matches, "stake_authority", String); - let withdraw_authority = value_t_or_exit!(matches, "withdraw_authority", String); - let index = value_t_or_exit!(matches, "index", usize); - NewCommandConfig { - fee_payer, - funding_keypair, - lamports, - base_keypair, - stake_authority, - withdraw_authority, - index, - } -} - -fn parse_count_args(matches: &ArgMatches<'_>) -> CountCommandConfig { - let base_pubkey = value_t_or_exit!(matches, "base_pubkey", String); - CountCommandConfig { base_pubkey } -} - -fn parse_query_args(matches: &ArgMatches<'_>) -> QueryCommandConfig { - let base_pubkey = value_t_or_exit!(matches, "base_pubkey", String); - let num_accounts = value_t_or_exit!(matches, "num_accounts", usize); - QueryCommandConfig { - base_pubkey, - num_accounts, - } -} - -fn parse_authorize_args(matches: &ArgMatches<'_>) -> AuthorizeCommandConfig { - let fee_payer = value_t_or_exit!(matches, "fee_payer", String); - let base_pubkey = value_t_or_exit!(matches, "base_pubkey", String); - let stake_authority = value_t_or_exit!(matches, "stake_authority", String); - let withdraw_authority = value_t_or_exit!(matches, "withdraw_authority", String); - let new_stake_authority = value_t_or_exit!(matches, "new_stake_authority", String); - let new_withdraw_authority = value_t_or_exit!(matches, "new_withdraw_authority", String); - let num_accounts = value_t_or_exit!(matches, "num_accounts", usize); - AuthorizeCommandConfig { - fee_payer, - base_pubkey, - stake_authority, - withdraw_authority, - new_stake_authority, - new_withdraw_authority, - num_accounts, - } -} - -fn parse_rebase_args(matches: &ArgMatches<'_>) -> RebaseCommandConfig { - let fee_payer = value_t_or_exit!(matches, "fee_payer", String); - let base_pubkey = value_t_or_exit!(matches, "base_pubkey", String); - let new_base_keypair = value_t_or_exit!(matches, "new_base_keypair", String); - let stake_authority = value_t_or_exit!(matches, "stake_authority", String); - let num_accounts = value_t_or_exit!(matches, "num_accounts", usize); - RebaseCommandConfig { - fee_payer, - base_pubkey, - new_base_keypair, - stake_authority, - num_accounts, - } -} - -fn parse_move_args(matches: &ArgMatches<'_>) -> MoveCommandConfig { - let rebase_config = parse_rebase_args(matches); - let authorize_config = parse_authorize_args(matches); - MoveCommandConfig { - rebase_config, - authorize_config, - } -} - -pub(crate) fn parse_args(args: I) -> CommandConfig -where - I: IntoIterator, - T: Into + Clone, -{ - let matches = get_matches(args); - let config_file = matches.value_of("config_file").unwrap().to_string(); - let url = matches.value_of("url").map(|x| x.to_string()); - - let command = match matches.subcommand() { - ("new", Some(matches)) => Command::New(parse_new_args(matches)), - ("count", Some(matches)) => Command::Count(parse_count_args(matches)), - ("addresses", Some(matches)) => Command::Addresses(parse_query_args(matches)), - ("balance", Some(matches)) => Command::Balance(parse_query_args(matches)), - ("authorize", Some(matches)) => Command::Authorize(parse_authorize_args(matches)), - ("rebase", Some(matches)) => Command::Rebase(parse_rebase_args(matches)), - ("move", Some(matches)) => Command::Move(Box::new(parse_move_args(matches))), - _ => { - eprintln!("{}", matches.usage()); - exit(1); - } +fn resolve_authorize_args( + wallet_manager: Option<&Arc>, + args: &AuthorizeArgs, +) -> Result>, Box> { + let resolved_args = AuthorizeArgs { + fee_payer: resolve_fee_payer(wallet_manager, &args.fee_payer)?, + base_pubkey: resolve_base_pubkey(wallet_manager, &args.base_pubkey)?, + stake_authority: resolve_stake_authority(wallet_manager, &args.stake_authority)?, + withdraw_authority: resolve_withdraw_authority(wallet_manager, &args.withdraw_authority)?, + new_stake_authority: resolve_new_stake_authority( + wallet_manager, + &args.new_stake_authority, + )?, + new_withdraw_authority: resolve_new_withdraw_authority( + wallet_manager, + &args.new_withdraw_authority, + )?, + num_accounts: args.num_accounts, }; - CommandConfig { - config_file, - url, - command, + Ok(resolved_args) +} + +fn resolve_rebase_args( + wallet_manager: Option<&Arc>, + args: &RebaseArgs, +) -> Result>, Box> { + let resolved_args = RebaseArgs { + fee_payer: resolve_fee_payer(wallet_manager, &args.fee_payer)?, + base_pubkey: resolve_base_pubkey(wallet_manager, &args.base_pubkey)?, + new_base_keypair: resolve_new_base_keypair(wallet_manager, &args.new_base_keypair)?, + stake_authority: resolve_stake_authority(wallet_manager, &args.stake_authority)?, + num_accounts: args.num_accounts, + }; + Ok(resolved_args) +} + +pub(crate) fn resolve_command( + command: &Command, +) -> Result>, Box> { + let wallet_manager = maybe_wallet_manager()?; + let wallet_manager = wallet_manager.as_ref(); + let matches = ArgMatches::default(); + match command { + Command::New(args) => { + let resolved_args = NewArgs { + fee_payer: resolve_fee_payer(wallet_manager, &args.fee_payer)?, + funding_keypair: signer_from_path( + &matches, + &args.funding_keypair, + "funding keypair", + wallet_manager, + )?, + base_keypair: signer_from_path( + &matches, + &args.base_keypair, + "base keypair", + wallet_manager, + )?, + stake_authority: pubkey_from_path( + &matches, + &args.stake_authority, + "stake authority", + wallet_manager, + )?, + withdraw_authority: pubkey_from_path( + &matches, + &args.withdraw_authority, + "withdraw authority", + wallet_manager, + )?, + lamports: args.lamports, + index: args.index, + }; + Ok(Command::New(resolved_args)) + } + Command::Count(args) => { + let resolved_args = CountArgs { + base_pubkey: resolve_base_pubkey(wallet_manager, &args.base_pubkey)?, + }; + Ok(Command::Count(resolved_args)) + } + Command::Addresses(args) => { + let resolved_args = QueryArgs { + base_pubkey: resolve_base_pubkey(wallet_manager, &args.base_pubkey)?, + num_accounts: args.num_accounts, + }; + Ok(Command::Addresses(resolved_args)) + } + Command::Balance(args) => { + let resolved_args = QueryArgs { + base_pubkey: resolve_base_pubkey(wallet_manager, &args.base_pubkey)?, + num_accounts: args.num_accounts, + }; + Ok(Command::Balance(resolved_args)) + } + Command::Authorize(args) => { + let resolved_args = resolve_authorize_args(wallet_manager, &args)?; + Ok(Command::Authorize(resolved_args)) + } + Command::Rebase(args) => { + let resolved_args = resolve_rebase_args(wallet_manager, &args)?; + Ok(Command::Rebase(resolved_args)) + } + Command::Move(args) => { + let resolved_args = MoveArgs { + authorize_args: resolve_authorize_args(wallet_manager, &args.authorize_args)?, + rebase_args: resolve_rebase_args(wallet_manager, &args.rebase_args)?, + }; + Ok(Command::Move(Box::new(resolved_args))) + } } } diff --git a/stake-accounts/src/main.rs b/stake-accounts/src/main.rs index 5432d9f46..fc2ac18d5 100644 --- a/stake-accounts/src/main.rs +++ b/stake-accounts/src/main.rs @@ -1,16 +1,12 @@ +mod arg_parser; mod args; mod stake_accounts; -use crate::args::{ - parse_args, AuthorizeCommandConfig, Command, MoveCommandConfig, NewCommandConfig, - RebaseCommandConfig, -}; -use clap::ArgMatches; -use solana_clap_utils::keypair::{pubkey_from_path, signer_from_path}; +use crate::arg_parser::parse_args; +use crate::args::{resolve_command, AuthorizeArgs, Command, MoveArgs, NewArgs, RebaseArgs}; use solana_cli_config::Config; use solana_client::client_error::ClientError; use solana_client::rpc_client::RpcClient; -use solana_remote_wallet::remote_wallet::{maybe_wallet_manager, RemoteWalletManager}; use solana_sdk::{ message::Message, native_token::lamports_to_sol, @@ -21,63 +17,6 @@ use solana_sdk::{ }; use std::env; use std::error::Error; -use std::sync::Arc; - -fn resolve_stake_authority( - wallet_manager: Option<&Arc>, - key_url: &str, -) -> Result, Box> { - let matches = ArgMatches::default(); - signer_from_path(&matches, key_url, "stake authority", wallet_manager) -} - -fn resolve_withdraw_authority( - wallet_manager: Option<&Arc>, - key_url: &str, -) -> Result, Box> { - let matches = ArgMatches::default(); - signer_from_path(&matches, key_url, "withdraw authority", wallet_manager) -} - -fn resolve_new_stake_authority( - wallet_manager: Option<&Arc>, - key_url: &str, -) -> Result> { - let matches = ArgMatches::default(); - pubkey_from_path(&matches, key_url, "new stake authority", wallet_manager) -} - -fn resolve_new_withdraw_authority( - wallet_manager: Option<&Arc>, - key_url: &str, -) -> Result> { - let matches = ArgMatches::default(); - pubkey_from_path(&matches, key_url, "new withdraw authority", wallet_manager) -} - -fn resolve_fee_payer( - wallet_manager: Option<&Arc>, - key_url: &str, -) -> Result, Box> { - let matches = ArgMatches::default(); - signer_from_path(&matches, key_url, "fee-payer", wallet_manager) -} - -fn resolve_base_pubkey( - wallet_manager: Option<&Arc>, - key_url: &str, -) -> Result> { - let matches = ArgMatches::default(); - pubkey_from_path(&matches, key_url, "base pubkey", wallet_manager) -} - -fn resolve_new_base_keypair( - wallet_manager: Option<&Arc>, - key_url: &str, -) -> Result, Box> { - let matches = ArgMatches::default(); - signer_from_path(&matches, key_url, "new base pubkey", wallet_manager) -} fn get_balance_at(client: &RpcClient, pubkey: &Pubkey, i: usize) -> Result { let address = stake_accounts::derive_stake_account_address(pubkey, i); @@ -105,77 +44,43 @@ fn get_balances( fn process_new_stake_account( client: &RpcClient, - wallet_manager: Option<&Arc>, - new_config: &NewCommandConfig, -) -> Result> { - let matches = ArgMatches::default(); - let fee_payer_keypair = resolve_fee_payer(wallet_manager, &new_config.fee_payer)?; - let funding_keypair = signer_from_path( - &matches, - &new_config.funding_keypair, - "funding keypair", - wallet_manager, - )?; - let base_keypair = signer_from_path( - &matches, - &new_config.base_keypair, - "base keypair", - wallet_manager, - )?; - let stake_authority_pubkey = pubkey_from_path( - &matches, - &new_config.stake_authority, - "stake authority", - wallet_manager, - )?; - let withdraw_authority_pubkey = pubkey_from_path( - &matches, - &new_config.withdraw_authority, - "withdraw authority", - wallet_manager, - )?; + args: &NewArgs>, +) -> Result { let message = stake_accounts::new_stake_account( - &fee_payer_keypair.pubkey(), - &funding_keypair.pubkey(), - &base_keypair.pubkey(), - new_config.lamports, - &stake_authority_pubkey, - &withdraw_authority_pubkey, - new_config.index, + &args.fee_payer.pubkey(), + &args.funding_keypair.pubkey(), + &args.base_keypair.pubkey(), + args.lamports, + &args.stake_authority, + &args.withdraw_authority, + args.index, ); - let signers = vec![&*fee_payer_keypair, &*funding_keypair, &*base_keypair]; + let signers = vec![ + &*args.fee_payer, + &*args.funding_keypair, + &*args.base_keypair, + ]; let signature = send_message(client, message, &signers)?; Ok(signature) } fn process_authorize_stake_accounts( client: &RpcClient, - wallet_manager: Option<&Arc>, - authorize_config: &AuthorizeCommandConfig, -) -> Result<(), Box> { - let fee_payer_keypair = resolve_fee_payer(wallet_manager, &authorize_config.fee_payer)?; - let base_pubkey = resolve_base_pubkey(wallet_manager, &authorize_config.base_pubkey)?; - let stake_authority_keypair = - resolve_stake_authority(wallet_manager, &authorize_config.stake_authority)?; - let withdraw_authority_keypair = - resolve_withdraw_authority(wallet_manager, &authorize_config.withdraw_authority)?; - let new_stake_authority_pubkey = - resolve_new_stake_authority(wallet_manager, &authorize_config.new_stake_authority)?; - let new_withdraw_authority_pubkey = - resolve_new_withdraw_authority(wallet_manager, &authorize_config.new_withdraw_authority)?; + args: &AuthorizeArgs>, +) -> Result<(), ClientError> { let messages = stake_accounts::authorize_stake_accounts( - &fee_payer_keypair.pubkey(), - &base_pubkey, - &stake_authority_keypair.pubkey(), - &withdraw_authority_keypair.pubkey(), - &new_stake_authority_pubkey, - &new_withdraw_authority_pubkey, - authorize_config.num_accounts, + &args.fee_payer.pubkey(), + &args.base_pubkey, + &args.stake_authority.pubkey(), + &args.withdraw_authority.pubkey(), + &args.new_stake_authority, + &args.new_withdraw_authority, + args.num_accounts, ); let signers = vec![ - &*fee_payer_keypair, - &*stake_authority_keypair, - &*withdraw_authority_keypair, + &*args.fee_payer, + &*args.stake_authority, + &*args.withdraw_authority, ]; for message in messages { let signature = send_message(client, message, &signers)?; @@ -186,29 +91,22 @@ fn process_authorize_stake_accounts( fn process_rebase_stake_accounts( client: &RpcClient, - wallet_manager: Option<&Arc>, - rebase_config: &RebaseCommandConfig, -) -> Result<(), Box> { - let fee_payer_keypair = resolve_fee_payer(wallet_manager, &rebase_config.fee_payer)?; - let base_pubkey = resolve_base_pubkey(wallet_manager, &rebase_config.base_pubkey)?; - let new_base_keypair = - resolve_new_base_keypair(wallet_manager, &rebase_config.new_base_keypair)?; - let stake_authority_keypair = - resolve_stake_authority(wallet_manager, &rebase_config.stake_authority)?; + args: &RebaseArgs>, +) -> Result<(), ClientError> { let addresses = - stake_accounts::derive_stake_account_addresses(&base_pubkey, rebase_config.num_accounts); + stake_accounts::derive_stake_account_addresses(&args.base_pubkey, args.num_accounts); let balances = get_balances(&client, addresses)?; let messages = stake_accounts::rebase_stake_accounts( - &fee_payer_keypair.pubkey(), - &new_base_keypair.pubkey(), - &stake_authority_keypair.pubkey(), + &args.fee_payer.pubkey(), + &args.new_base_keypair.pubkey(), + &args.stake_authority.pubkey(), &balances, ); let signers = vec![ - &*fee_payer_keypair, - &*new_base_keypair, - &*stake_authority_keypair, + &*args.fee_payer, + &*args.new_base_keypair, + &*args.stake_authority, ]; for message in messages { let signature = send_message(client, message, &signers)?; @@ -219,41 +117,28 @@ fn process_rebase_stake_accounts( fn process_move_stake_accounts( client: &RpcClient, - wallet_manager: Option<&Arc>, - move_config: &MoveCommandConfig, -) -> Result<(), Box> { - let authorize_config = &move_config.authorize_config; - let rebase_config = &move_config.rebase_config; - let fee_payer_keypair = resolve_fee_payer(wallet_manager, &authorize_config.fee_payer)?; - let base_pubkey = resolve_base_pubkey(wallet_manager, &authorize_config.base_pubkey)?; - let new_base_keypair = - resolve_new_base_keypair(wallet_manager, &rebase_config.new_base_keypair)?; - let stake_authority_keypair = - resolve_stake_authority(wallet_manager, &authorize_config.stake_authority)?; - let withdraw_authority_keypair = - resolve_withdraw_authority(wallet_manager, &authorize_config.withdraw_authority)?; - let new_stake_authority_pubkey = - resolve_new_stake_authority(wallet_manager, &authorize_config.new_stake_authority)?; - let new_withdraw_authority_pubkey = - resolve_new_withdraw_authority(wallet_manager, &authorize_config.new_withdraw_authority)?; + move_args: &MoveArgs>, +) -> Result<(), ClientError> { + let authorize_args = &move_args.authorize_args; + let args = &move_args.rebase_args; let addresses = - stake_accounts::derive_stake_account_addresses(&base_pubkey, authorize_config.num_accounts); + stake_accounts::derive_stake_account_addresses(&args.base_pubkey, args.num_accounts); let balances = get_balances(&client, addresses)?; let messages = stake_accounts::move_stake_accounts( - &fee_payer_keypair.pubkey(), - &new_base_keypair.pubkey(), - &stake_authority_keypair.pubkey(), - &withdraw_authority_keypair.pubkey(), - &new_stake_authority_pubkey, - &new_withdraw_authority_pubkey, + &args.fee_payer.pubkey(), + &args.new_base_keypair.pubkey(), + &args.stake_authority.pubkey(), + &authorize_args.withdraw_authority.pubkey(), + &authorize_args.new_stake_authority, + &authorize_args.new_withdraw_authority, &balances, ); let signers = vec![ - &*fee_payer_keypair, - &*new_base_keypair, - &*stake_authority_keypair, - &*withdraw_authority_keypair, + &*args.fee_payer, + &*args.new_base_keypair, + &*args.stake_authority, + &*authorize_args.withdraw_authority, ]; for message in messages { let signature = send_message(client, message, &signers)?; @@ -273,51 +158,46 @@ fn send_message( } fn main() -> Result<(), Box> { - let command_config = parse_args(env::args_os()); - let config = Config::load(&command_config.config_file)?; - let json_rpc_url = command_config.url.unwrap_or(config.json_rpc_url); + let command_args = parse_args(env::args_os()); + let config = Config::load(&command_args.config_file)?; + let json_rpc_url = command_args.url.unwrap_or(config.json_rpc_url); let client = RpcClient::new(json_rpc_url); - let wallet_manager = maybe_wallet_manager()?; - let wallet_manager = wallet_manager.as_ref(); - match command_config.command { - Command::New(new_config) => { - process_new_stake_account(&client, wallet_manager, &new_config)?; + match resolve_command(&command_args.command)? { + Command::New(args) => { + process_new_stake_account(&client, &args)?; } - Command::Count(count_config) => { - let base_pubkey = resolve_base_pubkey(wallet_manager, &count_config.base_pubkey)?; - let num_accounts = count_stake_accounts(&client, &base_pubkey)?; + Command::Count(args) => { + let num_accounts = count_stake_accounts(&client, &args.base_pubkey)?; println!("{}", num_accounts); } - Command::Addresses(query_config) => { - let base_pubkey = resolve_base_pubkey(wallet_manager, &query_config.base_pubkey)?; + Command::Addresses(args) => { let addresses = stake_accounts::derive_stake_account_addresses( - &base_pubkey, - query_config.num_accounts, + &args.base_pubkey, + args.num_accounts, ); for address in addresses { println!("{:?}", address); } } - Command::Balance(query_config) => { - let base_pubkey = resolve_base_pubkey(wallet_manager, &query_config.base_pubkey)?; + Command::Balance(args) => { let addresses = stake_accounts::derive_stake_account_addresses( - &base_pubkey, - query_config.num_accounts, + &args.base_pubkey, + args.num_accounts, ); let balances = get_balances(&client, addresses)?; let lamports: u64 = balances.into_iter().map(|(_, bal)| bal).sum(); let sol = lamports_to_sol(lamports); println!("{} SOL", sol); } - Command::Authorize(authorize_config) => { - process_authorize_stake_accounts(&client, wallet_manager, &authorize_config)?; + Command::Authorize(args) => { + process_authorize_stake_accounts(&client, &args)?; } - Command::Rebase(rebase_config) => { - process_rebase_stake_accounts(&client, wallet_manager, &rebase_config)?; + Command::Rebase(args) => { + process_rebase_stake_accounts(&client, &args)?; } - Command::Move(move_config) => { - process_move_stake_accounts(&client, wallet_manager, &move_config)?; + Command::Move(args) => { + process_move_stake_accounts(&client, &args)?; } } Ok(())