diff --git a/tokens/src/arg_parser.rs b/tokens/src/arg_parser.rs index e61bf8047f..a37a630f24 100644 --- a/tokens/src/arg_parser.rs +++ b/tokens/src/arg_parser.rs @@ -2,8 +2,13 @@ use crate::args::{ Args, BalancesArgs, Command, DistributeTokensArgs, StakeArgs, TransactionLogArgs, }; use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand}; -use solana_clap_utils::input_validators::{is_valid_pubkey, is_valid_signer}; +use solana_clap_utils::{ + input_validators::{is_valid_pubkey, is_valid_signer}, + keypair::{pubkey_from_path, signer_from_path}, +}; use solana_cli_config::CONFIG_FILE; +use solana_remote_wallet::remote_wallet::maybe_wallet_manager; +use std::error::Error; use std::ffi::OsString; use std::process::exit; @@ -225,36 +230,102 @@ fn create_db_path(campaign_name: Option) -> String { .to_string() } -fn parse_distribute_tokens_args(matches: &ArgMatches<'_>) -> DistributeTokensArgs { - DistributeTokensArgs { +fn parse_distribute_tokens_args( + matches: &ArgMatches<'_>, +) -> Result> { + let mut wallet_manager = maybe_wallet_manager()?; + let signer_matches = ArgMatches::default(); // No default signer + + let sender_keypair_str = value_t_or_exit!(matches, "sender_keypair", String); + let sender_keypair = signer_from_path( + &signer_matches, + &sender_keypair_str, + "sender", + &mut wallet_manager, + )?; + + let fee_payer_str = value_t_or_exit!(matches, "fee_payer", String); + let fee_payer = signer_from_path( + &signer_matches, + &fee_payer_str, + "fee-payer", + &mut wallet_manager, + )?; + + Ok(DistributeTokensArgs { input_csv: value_t_or_exit!(matches, "input_csv", String), from_bids: matches.is_present("from_bids"), transaction_db: create_db_path(value_t!(matches, "campaign_name", String).ok()), dollars_per_sol: value_t!(matches, "dollars_per_sol", f64).ok(), dry_run: matches.is_present("dry_run"), - sender_keypair: value_t_or_exit!(matches, "sender_keypair", String), - fee_payer: value_t_or_exit!(matches, "fee_payer", String), + sender_keypair, + fee_payer, stake_args: None, - } + }) } -fn parse_distribute_stake_args(matches: &ArgMatches<'_>) -> DistributeTokensArgs { +fn parse_distribute_stake_args( + matches: &ArgMatches<'_>, +) -> Result> { + let mut wallet_manager = maybe_wallet_manager()?; + let signer_matches = ArgMatches::default(); // No default signer + + let sender_keypair_str = value_t_or_exit!(matches, "sender_keypair", String); + let sender_keypair = signer_from_path( + &signer_matches, + &sender_keypair_str, + "sender", + &mut wallet_manager, + )?; + + let fee_payer_str = value_t_or_exit!(matches, "fee_payer", String); + let fee_payer = signer_from_path( + &signer_matches, + &fee_payer_str, + "fee-payer", + &mut wallet_manager, + )?; + + let stake_account_address_str = value_t_or_exit!(matches, "stake_account_address", String); + let stake_account_address = pubkey_from_path( + &signer_matches, + &stake_account_address_str, + "stake account address", + &mut wallet_manager, + )?; + + let stake_authority_str = value_t_or_exit!(matches, "stake_authority", String); + let stake_authority = signer_from_path( + &signer_matches, + &stake_authority_str, + "stake authority", + &mut wallet_manager, + )?; + + let withdraw_authority_str = value_t_or_exit!(matches, "withdraw_authority", String); + let withdraw_authority = signer_from_path( + &signer_matches, + &withdraw_authority_str, + "withdraw authority", + &mut wallet_manager, + )?; + let stake_args = StakeArgs { - stake_account_address: value_t_or_exit!(matches, "stake_account_address", String), + stake_account_address, sol_for_fees: value_t_or_exit!(matches, "sol_for_fees", f64), - stake_authority: value_t_or_exit!(matches, "stake_authority", String), - withdraw_authority: value_t_or_exit!(matches, "withdraw_authority", String), + stake_authority, + withdraw_authority, }; - DistributeTokensArgs { + Ok(DistributeTokensArgs { input_csv: value_t_or_exit!(matches, "input_csv", String), from_bids: false, transaction_db: create_db_path(value_t!(matches, "campaign_name", String).ok()), dollars_per_sol: None, dry_run: matches.is_present("dry_run"), - sender_keypair: value_t_or_exit!(matches, "sender_keypair", String), - fee_payer: value_t_or_exit!(matches, "fee_payer", String), + sender_keypair, + fee_payer, stake_args: Some(stake_args), - } + }) } fn parse_balances_args(matches: &ArgMatches<'_>) -> BalancesArgs { @@ -272,7 +343,7 @@ fn parse_transaction_log_args(matches: &ArgMatches<'_>) -> TransactionLogArgs { } } -pub fn parse_args(args: I) -> Args +pub fn parse_args(args: I) -> Result> where I: IntoIterator, T: Into + Clone, @@ -283,10 +354,10 @@ where let command = match matches.subcommand() { ("distribute-tokens", Some(matches)) => { - Command::DistributeTokens(parse_distribute_tokens_args(matches)) + Command::DistributeTokens(parse_distribute_tokens_args(matches)?) } ("distribute-stake", Some(matches)) => { - Command::DistributeTokens(parse_distribute_stake_args(matches)) + Command::DistributeTokens(parse_distribute_stake_args(matches)?) } ("balances", Some(matches)) => Command::Balances(parse_balances_args(matches)), ("transaction-log", Some(matches)) => { @@ -297,9 +368,10 @@ where exit(1); } }; - Args { + let args = Args { config_file, url, command, - } + }; + Ok(args) } diff --git a/tokens/src/args.rs b/tokens/src/args.rs index 0eed694638..0052e8dc38 100644 --- a/tokens/src/args.rs +++ b/tokens/src/args.rs @@ -1,25 +1,21 @@ -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, sync::Arc}; -pub struct DistributeTokensArgs { +pub struct DistributeTokensArgs { pub input_csv: String, pub from_bids: bool, pub transaction_db: String, pub dollars_per_sol: Option, pub dry_run: bool, - pub sender_keypair: K, - pub fee_payer: K, - pub stake_args: Option>, + pub sender_keypair: Box, + pub fee_payer: Box, + pub stake_args: Option, } -pub struct StakeArgs { +pub struct StakeArgs { pub sol_for_fees: f64, - pub stake_account_address: P, - pub stake_authority: K, - pub withdraw_authority: K, + pub stake_account_address: Pubkey, + pub stake_authority: Box, + pub withdraw_authority: Box, } pub struct BalancesArgs { @@ -33,85 +29,14 @@ pub struct TransactionLogArgs { pub output_path: String, } -pub enum Command { - DistributeTokens(DistributeTokensArgs), +pub enum Command { + DistributeTokens(DistributeTokensArgs), Balances(BalancesArgs), TransactionLog(TransactionLogArgs), } -pub struct Args { +pub struct Args { pub config_file: String, pub url: Option, - pub command: Command, -} - -pub fn resolve_stake_args( - wallet_manager: &mut Option>, - args: StakeArgs, -) -> Result>, Box> { - let matches = ArgMatches::default(); - let resolved_args = StakeArgs { - stake_account_address: pubkey_from_path( - &matches, - &args.stake_account_address, - "stake account address", - wallet_manager, - ) - .unwrap(), - sol_for_fees: args.sol_for_fees, - stake_authority: signer_from_path( - &matches, - &args.stake_authority, - "stake authority", - wallet_manager, - ) - .unwrap(), - withdraw_authority: signer_from_path( - &matches, - &args.withdraw_authority, - "withdraw authority", - wallet_manager, - ) - .unwrap(), - }; - Ok(resolved_args) -} - -pub fn resolve_command( - command: Command, -) -> Result>, Box> { - match command { - Command::DistributeTokens(args) => { - let mut wallet_manager = maybe_wallet_manager()?; - let matches = ArgMatches::default(); - let resolved_stake_args = args - .stake_args - .map(|args| resolve_stake_args(&mut wallet_manager, args)); - let resolved_args = DistributeTokensArgs { - input_csv: args.input_csv, - from_bids: args.from_bids, - transaction_db: args.transaction_db, - dollars_per_sol: args.dollars_per_sol, - dry_run: args.dry_run, - sender_keypair: signer_from_path( - &matches, - &args.sender_keypair, - "sender", - &mut wallet_manager, - ) - .unwrap(), - fee_payer: signer_from_path( - &matches, - &args.fee_payer, - "fee-payer", - &mut wallet_manager, - ) - .unwrap(), - stake_args: resolved_stake_args.map_or(Ok(None), |r| r.map(Some))?, - }; - Ok(Command::DistributeTokens(resolved_args)) - } - Command::Balances(args) => Ok(Command::Balances(args)), - Command::TransactionLog(args) => Ok(Command::TransactionLog(args)), - } + pub command: Command, } diff --git a/tokens/src/commands.rs b/tokens/src/commands.rs index 3cc4c975f2..4d5646ff67 100644 --- a/tokens/src/commands.rs +++ b/tokens/src/commands.rs @@ -92,11 +92,11 @@ fn create_allocation(bid: &Bid, dollars_per_sol: f64) -> Allocation { } } -fn distribute_tokens( - client: &ThinClient, +fn distribute_tokens( + client: &ThinClient, db: &mut PickleDb, allocations: &[Allocation], - args: &DistributeTokensArgs>, + args: &DistributeTokensArgs, ) -> Result<(), Error> { for allocation in allocations { let new_stake_account_keypair = Keypair::new(); @@ -206,9 +206,9 @@ fn new_spinner_progress_bar() -> ProgressBar { progress_bar } -pub fn process_distribute_tokens( - client: &ThinClient, - args: &DistributeTokensArgs>, +pub fn process_distribute_tokens( + client: &ThinClient, + args: &DistributeTokensArgs, ) -> Result, Error> { let mut allocations: Vec = read_allocations(&args.input_csv, args.from_bids, args.dollars_per_sol); @@ -290,8 +290,8 @@ pub fn process_distribute_tokens( Ok(opt_confirmations) } -fn finalize_transactions( - client: &ThinClient, +fn finalize_transactions( + client: &ThinClient, db: &mut PickleDb, dry_run: bool, ) -> Result, Error> { @@ -322,8 +322,8 @@ fn finalize_transactions( // Update the finalized bit on any transactions that are now rooted // Return the lowest number of confirmations on the unfinalized transactions or None if all are finalized. -fn update_finalized_transactions( - client: &ThinClient, +fn update_finalized_transactions( + client: &ThinClient, db: &mut PickleDb, ) -> Result, Error> { let transaction_infos = db::read_transaction_infos(db); @@ -368,10 +368,7 @@ fn update_finalized_transactions( Ok(confirmations) } -pub fn process_balances( - client: &ThinClient, - args: &BalancesArgs, -) -> Result<(), csv::Error> { +pub fn process_balances(client: &ThinClient, args: &BalancesArgs) -> Result<(), csv::Error> { let allocations: Vec = read_allocations(&args.input_csv, args.from_bids, args.dollars_per_sol); let allocations = merge_allocations(&allocations); @@ -438,7 +435,7 @@ pub fn test_process_distribute_tokens_with_client(client: C, sender_k .unwrap() .to_string(); - let args: DistributeTokensArgs> = DistributeTokensArgs { + let args = DistributeTokensArgs { sender_keypair: Box::new(sender_keypair), fee_payer: Box::new(fee_payer), dry_run: false, @@ -534,13 +531,13 @@ pub fn test_process_distribute_stake_with_client(client: C, sender_ke .unwrap() .to_string(); - let stake_args: StakeArgs> = StakeArgs { + let stake_args = StakeArgs { stake_account_address, stake_authority: Box::new(stake_authority), withdraw_authority: Box::new(withdraw_authority), sol_for_fees: 1.0, }; - let args: DistributeTokensArgs> = DistributeTokensArgs { + let args = DistributeTokensArgs { fee_payer: Box::new(fee_payer), dry_run: false, input_csv, diff --git a/tokens/src/main.rs b/tokens/src/main.rs index 3ea9db57dd..080793ba02 100644 --- a/tokens/src/main.rs +++ b/tokens/src/main.rs @@ -1,19 +1,14 @@ use solana_cli_config::Config; use solana_cli_config::CONFIG_FILE; use solana_client::rpc_client::RpcClient; -use solana_tokens::{ - arg_parser::parse_args, - args::{resolve_command, Command}, - commands, - thin_client::ThinClient, -}; +use solana_tokens::{arg_parser::parse_args, args::Command, commands, thin_client::ThinClient}; use std::env; use std::error::Error; use std::path::Path; use std::process; fn main() -> Result<(), Box> { - let command_args = parse_args(env::args_os()); + let command_args = parse_args(env::args_os())?; let config = if Path::new(&command_args.config_file).exists() { Config::load(&command_args.config_file)? } else { @@ -27,7 +22,7 @@ fn main() -> Result<(), Box> { let json_rpc_url = command_args.url.unwrap_or(config.json_rpc_url); let client = RpcClient::new(json_rpc_url); - match resolve_command(command_args.command)? { + match command_args.command { Command::DistributeTokens(args) => { let thin_client = ThinClient::new(client, args.dry_run); commands::process_distribute_tokens(&thin_client, &args)?; diff --git a/tokens/src/thin_client.rs b/tokens/src/thin_client.rs index 769c549b59..1bbe02ee0a 100644 --- a/tokens/src/thin_client.rs +++ b/tokens/src/thin_client.rs @@ -114,14 +114,17 @@ impl Client for BankClient { } } -pub struct ThinClient { - client: C, +pub struct ThinClient<'a> { + client: Box, dry_run: bool, } -impl ThinClient { - pub fn new(client: C, dry_run: bool) -> Self { - Self { client, dry_run } +impl<'a> ThinClient<'a> { + pub fn new(client: C, dry_run: bool) -> Self { + Self { + client: Box::new(client), + dry_run, + } } pub fn send_transaction(&self, transaction: Transaction) -> Result {