2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
crate::{
|
|
|
|
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
|
|
|
|
cli::{
|
|
|
|
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
|
|
|
ProcessResult,
|
|
|
|
},
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price::WithComputeUnitPrice,
|
2021-12-03 09:00:31 -08:00
|
|
|
memo::WithMemo,
|
2021-12-06 14:54:50 -08:00
|
|
|
nonce::check_nonce_account,
|
|
|
|
spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount},
|
2021-12-03 09:00:31 -08:00
|
|
|
stake::check_current_authority,
|
2020-04-14 12:10:25 -07:00
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand},
|
|
|
|
solana_clap_utils::{
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price::{compute_unit_price_arg, COMPUTE_UNIT_PRICE_ARG},
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer::{fee_payer_arg, FEE_PAYER_ARG},
|
2021-12-03 09:00:31 -08:00
|
|
|
input_parsers::*,
|
|
|
|
input_validators::*,
|
|
|
|
keypair::{DefaultSigner, SignerIndex},
|
|
|
|
memo::{memo_arg, MEMO_ARG},
|
2021-12-06 14:54:50 -08:00
|
|
|
nonce::*,
|
|
|
|
offline::*,
|
|
|
|
},
|
|
|
|
solana_cli_output::{
|
|
|
|
return_signers_with_config, CliEpochVotingHistory, CliLockout, CliVoteAccount,
|
|
|
|
ReturnSignersConfig,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_remote_wallet::remote_wallet::RemoteWalletManager,
|
2022-08-24 09:47:02 -07:00
|
|
|
solana_rpc_client::rpc_client::RpcClient,
|
|
|
|
solana_rpc_client_api::config::RpcGetVoteAccountsConfig,
|
|
|
|
solana_rpc_client_nonce_utils::blockhash_query::BlockhashQuery,
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_sdk::{
|
|
|
|
account::Account, commitment_config::CommitmentConfig, message::Message,
|
|
|
|
native_token::lamports_to_sol, pubkey::Pubkey, system_instruction::SystemError,
|
|
|
|
transaction::Transaction,
|
|
|
|
},
|
|
|
|
solana_vote_program::{
|
2022-01-14 01:25:15 -08:00
|
|
|
vote_error::VoteError,
|
|
|
|
vote_instruction::{self, withdraw},
|
2021-12-03 09:00:31 -08:00
|
|
|
vote_state::{VoteAuthorize, VoteInit, VoteState},
|
|
|
|
},
|
|
|
|
std::sync::Arc,
|
2019-09-18 09:29:57 -07:00
|
|
|
};
|
|
|
|
|
2019-10-04 14:18:19 -07:00
|
|
|
pub trait VoteSubCommands {
|
|
|
|
fn vote_subcommands(self) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VoteSubCommands for App<'_, '_> {
|
|
|
|
fn vote_subcommands(self) -> Self {
|
|
|
|
self.subcommand(
|
|
|
|
SubCommand::with_name("create-vote-account")
|
|
|
|
.about("Create a vote account")
|
|
|
|
.arg(
|
2019-11-06 06:47:34 -08:00
|
|
|
Arg::with_name("vote_account")
|
2019-10-04 14:18:19 -07:00
|
|
|
.index(1)
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("ACCOUNT_KEYPAIR")
|
2019-10-04 14:18:19 -07:00
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
2020-03-13 16:06:33 -07:00
|
|
|
.validator(is_valid_signer)
|
2020-03-19 20:43:11 -07:00
|
|
|
.help("Vote account keypair to create"),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-03-19 01:58:52 -07:00
|
|
|
Arg::with_name("identity_account")
|
2019-10-04 14:18:19 -07:00
|
|
|
.index(2)
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("IDENTITY_KEYPAIR")
|
2019-10-04 14:18:19 -07:00
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
2020-03-19 01:58:52 -07:00
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Keypair of validator that will vote with this account"),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
2021-09-02 17:22:33 -07:00
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("authorized_withdrawer")
|
|
|
|
.index(3)
|
|
|
|
.value_name("WITHDRAWER_PUBKEY")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.long("authorized-withdrawer"),
|
|
|
|
"Public key of the authorized withdrawer")
|
|
|
|
)
|
2019-10-04 14:18:19 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("commission")
|
|
|
|
.long("commission")
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("PERCENTAGE")
|
2019-10-04 14:18:19 -07:00
|
|
|
.takes_value(true)
|
2020-01-04 08:20:44 -08:00
|
|
|
.default_value("100")
|
|
|
|
.help("The commission taken on reward redemption (0-100)"),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-04-01 19:45:37 -07:00
|
|
|
pubkey!(Arg::with_name("authorized_voter")
|
2019-10-04 14:18:19 -07:00
|
|
|
.long("authorized-voter")
|
2020-04-01 19:45:37 -07:00
|
|
|
.value_name("VOTER_PUBKEY"),
|
|
|
|
"Public key of the authorized voter [default: validator identity pubkey]. "),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2021-09-02 17:22:33 -07:00
|
|
|
Arg::with_name("allow_unsafe_authorized_withdrawer")
|
|
|
|
.long("allow-unsafe-authorized-withdrawer")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Allow an authorized withdrawer pubkey to be identical to the validator identity \
|
|
|
|
account pubkey or vote account pubkey, which is normally an unsafe \
|
|
|
|
configuration and should be avoided."),
|
2020-01-09 15:22:48 -08:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("seed")
|
|
|
|
.long("seed")
|
2020-03-16 08:24:59 -07:00
|
|
|
.value_name("STRING")
|
2020-01-09 15:22:48 -08:00
|
|
|
.takes_value(true)
|
|
|
|
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the VOTE ACCOUNT pubkey")
|
2021-04-05 13:53:50 -07:00
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2021-07-03 10:46:52 -07:00
|
|
|
.arg(memo_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(compute_unit_price_arg())
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
2019-12-12 15:04:03 -08:00
|
|
|
.subcommand(
|
2020-03-16 15:17:13 -07:00
|
|
|
SubCommand::with_name("vote-authorize-voter")
|
|
|
|
.about("Authorize a new vote signing keypair for the given vote account")
|
2019-12-12 15:04:03 -08:00
|
|
|
.arg(
|
2020-04-01 19:45:37 -07:00
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
2019-12-12 15:04:03 -08:00
|
|
|
.index(1)
|
2020-03-21 12:30:01 -07:00
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
2020-04-03 09:58:11 -07:00
|
|
|
"Vote account in which to set the authorized voter. "),
|
2019-12-12 15:04:03 -08:00
|
|
|
)
|
|
|
|
.arg(
|
2020-04-02 20:47:31 -07:00
|
|
|
Arg::with_name("authorized")
|
2019-12-12 15:04:03 -08:00
|
|
|
.index(2)
|
2020-04-02 20:47:31 -07:00
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Current authorized vote signer."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("new_authorized_pubkey")
|
|
|
|
.index(3)
|
|
|
|
.value_name("NEW_AUTHORIZED_PUBKEY")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
2020-04-03 09:58:11 -07:00
|
|
|
"New authorized vote signer. "),
|
2021-04-05 13:53:50 -07:00
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2021-07-03 10:46:52 -07:00
|
|
|
.arg(memo_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(compute_unit_price_arg())
|
2019-12-12 15:04:03 -08:00
|
|
|
)
|
2019-10-04 14:18:19 -07:00
|
|
|
.subcommand(
|
2020-03-16 15:17:13 -07:00
|
|
|
SubCommand::with_name("vote-authorize-withdrawer")
|
|
|
|
.about("Authorize a new withdraw signing keypair for the given vote account")
|
2019-10-04 14:18:19 -07:00
|
|
|
.arg(
|
2020-04-01 19:45:37 -07:00
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
2019-10-04 14:18:19 -07:00
|
|
|
.index(1)
|
2020-03-21 12:30:01 -07:00
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
2020-04-03 09:58:11 -07:00
|
|
|
"Vote account in which to set the authorized withdrawer. "),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-04-02 20:47:31 -07:00
|
|
|
Arg::with_name("authorized")
|
2019-10-04 14:18:19 -07:00
|
|
|
.index(2)
|
2020-04-02 20:47:31 -07:00
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Current authorized withdrawer."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("new_authorized_pubkey")
|
|
|
|
.index(3)
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("AUTHORIZED_PUBKEY")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
2020-04-03 09:58:11 -07:00
|
|
|
"New authorized withdrawer. "),
|
2021-04-05 13:53:50 -07:00
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2021-07-03 10:46:52 -07:00
|
|
|
.arg(memo_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(compute_unit_price_arg())
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
2021-07-15 15:45:03 -07:00
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("vote-authorize-voter-checked")
|
|
|
|
.about("Authorize a new vote signing keypair for the given vote account, \
|
|
|
|
checking the new authority as a signer")
|
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
|
|
|
.required(true),
|
|
|
|
"Vote account in which to set the authorized voter. "),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("authorized")
|
|
|
|
.index(2)
|
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Current authorized vote signer."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("new_authorized")
|
|
|
|
.index(3)
|
|
|
|
.value_name("NEW_AUTHORIZED_KEYPAIR")
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("New authorized vote signer."),
|
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2021-07-15 15:45:03 -07:00
|
|
|
.arg(memo_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(compute_unit_price_arg())
|
2021-07-15 15:45:03 -07:00
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("vote-authorize-withdrawer-checked")
|
|
|
|
.about("Authorize a new withdraw signing keypair for the given vote account, \
|
|
|
|
checking the new authority as a signer")
|
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
|
|
|
.required(true),
|
|
|
|
"Vote account in which to set the authorized withdrawer. "),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("authorized")
|
|
|
|
.index(2)
|
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Current authorized withdrawer."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("new_authorized")
|
|
|
|
.index(3)
|
|
|
|
.value_name("NEW_AUTHORIZED_KEYPAIR")
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("New authorized withdrawer."),
|
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2021-07-15 15:45:03 -07:00
|
|
|
.arg(memo_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(compute_unit_price_arg())
|
2021-07-15 15:45:03 -07:00
|
|
|
)
|
2019-10-04 14:18:19 -07:00
|
|
|
.subcommand(
|
2020-03-16 15:17:13 -07:00
|
|
|
SubCommand::with_name("vote-update-validator")
|
|
|
|
.about("Update the vote account's validator identity")
|
2019-10-04 14:18:19 -07:00
|
|
|
.arg(
|
2020-04-01 19:45:37 -07:00
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
2019-10-04 14:18:19 -07:00
|
|
|
.index(1)
|
2020-03-21 12:30:01 -07:00
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
|
|
|
"Vote account to update. "),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-03-19 01:58:52 -07:00
|
|
|
Arg::with_name("new_identity_account")
|
2019-10-04 14:18:19 -07:00
|
|
|
.index(2)
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("IDENTITY_KEYPAIR")
|
2019-10-04 14:18:19 -07:00
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
2020-03-19 01:58:52 -07:00
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Keypair of new validator that will vote with this account"),
|
2020-03-16 15:17:13 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-03-19 01:58:52 -07:00
|
|
|
Arg::with_name("authorized_withdrawer")
|
2020-03-16 15:17:13 -07:00
|
|
|
.index(3)
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
2020-03-16 15:17:13 -07:00
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
2020-03-19 01:58:52 -07:00
|
|
|
.help("Authorized withdrawer keypair"),
|
2020-03-16 15:17:13 -07:00
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2021-07-03 10:46:52 -07:00
|
|
|
.arg(memo_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(compute_unit_price_arg())
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
2020-06-09 21:15:46 -07:00
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("vote-update-commission")
|
|
|
|
.about("Update the vote account's commission")
|
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
|
|
|
.required(true),
|
|
|
|
"Vote account to update. "),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("commission")
|
|
|
|
.index(2)
|
|
|
|
.value_name("PERCENTAGE")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_percentage)
|
|
|
|
.help("The new commission")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("authorized_withdrawer")
|
|
|
|
.index(3)
|
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Authorized withdrawer keypair"),
|
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2021-07-03 10:46:52 -07:00
|
|
|
.arg(memo_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(compute_unit_price_arg())
|
2020-06-09 21:15:46 -07:00
|
|
|
)
|
2019-10-04 14:18:19 -07:00
|
|
|
.subcommand(
|
2020-01-20 22:06:47 -08:00
|
|
|
SubCommand::with_name("vote-account")
|
2019-10-04 14:18:19 -07:00
|
|
|
.about("Show the contents of a vote account")
|
2020-01-20 22:06:47 -08:00
|
|
|
.alias("show-vote-account")
|
2019-10-04 14:18:19 -07:00
|
|
|
.arg(
|
2020-04-01 19:45:37 -07:00
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
2019-10-04 14:18:19 -07:00
|
|
|
.index(1)
|
2020-03-21 12:30:01 -07:00
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
|
|
|
"Vote account pubkey. "),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("lamports")
|
|
|
|
.long("lamports")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Display balance in lamports instead of SOL"),
|
2021-04-08 09:57:33 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("with_rewards")
|
|
|
|
.long("with-rewards")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Display inflation rewards"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("num_rewards_epochs")
|
|
|
|
.long("num-rewards-epochs")
|
|
|
|
.takes_value(true)
|
|
|
|
.value_name("NUM")
|
2023-02-01 09:17:12 -08:00
|
|
|
.validator(|s| is_within_range(s, 1..=10))
|
2021-04-08 09:57:33 -07:00
|
|
|
.default_value_if("with_rewards", None, "1")
|
|
|
|
.requires("with_rewards")
|
|
|
|
.help("Display rewards for NUM recent epochs, max 10 [default: latest epoch only]"),
|
2021-01-20 08:48:10 -08:00
|
|
|
),
|
2019-10-04 14:18:19 -07:00
|
|
|
)
|
2020-03-13 13:30:04 -07:00
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("withdraw-from-vote-account")
|
|
|
|
.about("Withdraw lamports from a vote account into a specified account")
|
|
|
|
.arg(
|
2020-04-01 19:45:37 -07:00
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
2020-03-13 13:30:04 -07:00
|
|
|
.index(1)
|
2020-03-21 12:30:01 -07:00
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
|
|
|
"Vote account from which to withdraw. "),
|
2020-03-13 13:30:04 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-04-01 19:45:37 -07:00
|
|
|
pubkey!(Arg::with_name("destination_account_pubkey")
|
2020-03-13 13:30:04 -07:00
|
|
|
.index(2)
|
2020-03-21 12:30:01 -07:00
|
|
|
.value_name("RECIPIENT_ADDRESS")
|
2020-04-01 19:45:37 -07:00
|
|
|
.required(true),
|
|
|
|
"The recipient of withdrawn SOL. "),
|
2020-03-13 13:30:04 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("amount")
|
|
|
|
.index(3)
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("AMOUNT")
|
2020-03-13 13:30:04 -07:00
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
2020-06-15 14:36:47 -07:00
|
|
|
.validator(is_amount_or_all)
|
2021-12-13 18:00:29 -08:00
|
|
|
.help("The amount to withdraw, in SOL; accepts keyword ALL, which for this command means account balance minus rent-exempt minimum"),
|
2020-03-13 13:30:04 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("authorized_withdrawer")
|
|
|
|
.long("authorized-withdrawer")
|
2020-03-19 20:43:11 -07:00
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
2020-03-13 13:30:04 -07:00
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Authorized withdrawer [default: cli config keypair]"),
|
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.offline_args()
|
|
|
|
.nonce_args(false)
|
|
|
|
.arg(fee_payer_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(memo_arg())
|
|
|
|
.arg(compute_unit_price_arg()
|
2021-09-13 08:13:59 -07:00
|
|
|
)
|
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("close-vote-account")
|
|
|
|
.about("Close a vote account and withdraw all funds remaining")
|
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("vote_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("VOTE_ACCOUNT_ADDRESS")
|
|
|
|
.required(true),
|
|
|
|
"Vote account to be closed. "),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
pubkey!(Arg::with_name("destination_account_pubkey")
|
|
|
|
.index(2)
|
|
|
|
.value_name("RECIPIENT_ADDRESS")
|
|
|
|
.required(true),
|
|
|
|
"The recipient of all withdrawn SOL. "),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("authorized_withdrawer")
|
|
|
|
.long("authorized-withdrawer")
|
|
|
|
.value_name("AUTHORIZED_KEYPAIR")
|
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_valid_signer)
|
|
|
|
.help("Authorized withdrawer [default: cli config keypair]"),
|
|
|
|
)
|
2021-12-06 14:54:50 -08:00
|
|
|
.arg(fee_payer_arg())
|
2022-08-02 20:23:05 -07:00
|
|
|
.arg(memo_arg())
|
|
|
|
.arg(compute_unit_price_arg()
|
2021-09-13 08:13:59 -07:00
|
|
|
)
|
2020-03-13 13:30:04 -07:00
|
|
|
)
|
2019-10-04 14:18:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-13 11:41:18 -07:00
|
|
|
pub fn parse_create_vote_account(
|
2020-02-24 16:03:30 -08:00
|
|
|
matches: &ArgMatches<'_>,
|
2020-09-21 20:53:15 -07:00
|
|
|
default_signer: &DefaultSigner,
|
2020-04-18 11:54:21 -07:00
|
|
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
2020-02-24 16:03:30 -08:00
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-07-13 20:27:41 -07:00
|
|
|
let (vote_account, vote_account_pubkey) = signer_of(matches, "vote_account", wallet_manager)?;
|
2020-01-09 15:22:48 -08:00
|
|
|
let seed = matches.value_of("seed").map(|s| s.to_string());
|
2020-03-19 01:58:52 -07:00
|
|
|
let (identity_account, identity_pubkey) =
|
|
|
|
signer_of(matches, "identity_account", wallet_manager)?;
|
2020-01-04 08:20:44 -08:00
|
|
|
let commission = value_t_or_exit!(matches, "commission", u8);
|
2020-03-16 15:17:13 -07:00
|
|
|
let authorized_voter = pubkey_of_signer(matches, "authorized_voter", wallet_manager)?;
|
2021-09-02 17:22:33 -07:00
|
|
|
let authorized_withdrawer =
|
|
|
|
pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?.unwrap();
|
|
|
|
let allow_unsafe = matches.is_present("allow_unsafe_authorized_withdrawer");
|
2021-12-06 14:54:50 -08:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
|
|
|
let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?;
|
2021-04-05 13:53:50 -07:00
|
|
|
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
2021-12-06 14:54:50 -08:00
|
|
|
let (nonce_authority, nonce_authority_pubkey) =
|
|
|
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
2022-08-02 20:23:05 -07:00
|
|
|
let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name);
|
2019-09-26 10:26:47 -07:00
|
|
|
|
2021-09-02 17:22:33 -07:00
|
|
|
if !allow_unsafe {
|
|
|
|
if authorized_withdrawer == vote_account_pubkey.unwrap() {
|
|
|
|
return Err(CliError::BadParameter(
|
|
|
|
"Authorized withdrawer pubkey is identical to vote \
|
|
|
|
account pubkey, an unsafe configuration"
|
|
|
|
.to_owned(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
if authorized_withdrawer == identity_pubkey.unwrap() {
|
|
|
|
return Err(CliError::BadParameter(
|
|
|
|
"Authorized withdrawer pubkey is identical to identity \
|
|
|
|
account pubkey, an unsafe configuration"
|
|
|
|
.to_owned(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let mut bulk_signers = vec![fee_payer, vote_account, identity_account];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
2020-02-24 16:03:30 -08:00
|
|
|
|
2019-10-21 16:08:09 -07:00
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::CreateVoteAccount {
|
2020-07-13 20:27:41 -07:00
|
|
|
vote_account: signer_info.index_of(vote_account_pubkey).unwrap(),
|
2020-01-09 15:22:48 -08:00
|
|
|
seed,
|
2020-03-19 01:58:52 -07:00
|
|
|
identity_account: signer_info.index_of(identity_pubkey).unwrap(),
|
2019-09-25 13:53:49 -07:00
|
|
|
authorized_voter,
|
|
|
|
authorized_withdrawer,
|
|
|
|
commission,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only,
|
|
|
|
dump_transaction_message,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
2021-04-05 13:53:50 -07:00
|
|
|
memo,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price,
|
2019-09-25 13:53:49 -07:00
|
|
|
},
|
2020-03-19 01:58:52 -07:00
|
|
|
signers: signer_info.signers,
|
2019-10-21 16:08:09 -07:00
|
|
|
})
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
|
2019-09-25 13:53:49 -07:00
|
|
|
pub fn parse_vote_authorize(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-09-21 20:53:15 -07:00
|
|
|
default_signer: &DefaultSigner,
|
2020-04-18 11:54:21 -07:00
|
|
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
2019-09-25 13:53:49 -07:00
|
|
|
vote_authorize: VoteAuthorize,
|
2021-07-15 15:45:03 -07:00
|
|
|
checked: bool,
|
2019-10-21 16:08:09 -07:00
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-03-16 15:17:13 -07:00
|
|
|
let vote_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
2021-07-15 15:45:03 -07:00
|
|
|
let (authorized, authorized_pubkey) = signer_of(matches, "authorized", wallet_manager)?;
|
2019-09-18 09:29:57 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
|
|
|
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
|
|
|
let (nonce_authority, nonce_authority_pubkey) =
|
|
|
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
2022-08-02 20:23:05 -07:00
|
|
|
let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name);
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
let mut bulk_signers = vec![fee_payer, authorized];
|
2021-07-15 15:45:03 -07:00
|
|
|
|
|
|
|
let new_authorized_pubkey = if checked {
|
|
|
|
let (new_authorized_signer, new_authorized_pubkey) =
|
|
|
|
signer_of(matches, "new_authorized", wallet_manager)?;
|
2021-12-06 14:54:50 -08:00
|
|
|
bulk_signers.push(new_authorized_signer);
|
2021-07-15 15:45:03 -07:00
|
|
|
new_authorized_pubkey.unwrap()
|
|
|
|
} else {
|
|
|
|
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap()
|
|
|
|
};
|
2021-12-06 14:54:50 -08:00
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
2020-02-24 16:03:30 -08:00
|
|
|
|
2019-10-21 16:08:09 -07:00
|
|
|
Ok(CliCommandInfo {
|
2019-12-12 15:04:03 -08:00
|
|
|
command: CliCommand::VoteAuthorize {
|
2019-10-21 16:08:09 -07:00
|
|
|
vote_account_pubkey,
|
|
|
|
new_authorized_pubkey,
|
|
|
|
vote_authorize,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only,
|
|
|
|
dump_transaction_message,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
2021-04-05 13:53:50 -07:00
|
|
|
memo,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2021-07-15 15:45:03 -07:00
|
|
|
authorized: signer_info.index_of(authorized_pubkey).unwrap(),
|
|
|
|
new_authorized: if checked {
|
|
|
|
signer_info.index_of(Some(new_authorized_pubkey))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price,
|
2019-12-12 15:04:03 -08:00
|
|
|
},
|
2020-04-02 20:47:31 -07:00
|
|
|
signers: signer_info.signers,
|
2019-12-12 15:04:03 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
pub fn parse_vote_update_validator(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-09-21 20:53:15 -07:00
|
|
|
default_signer: &DefaultSigner,
|
2020-04-18 11:54:21 -07:00
|
|
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
2020-02-24 16:03:30 -08:00
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-03-16 15:17:13 -07:00
|
|
|
let vote_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
2020-03-19 01:58:52 -07:00
|
|
|
let (new_identity_account, new_identity_pubkey) =
|
|
|
|
signer_of(matches, "new_identity_account", wallet_manager)?;
|
2020-07-13 20:49:59 -07:00
|
|
|
let (authorized_withdrawer, authorized_withdrawer_pubkey) =
|
|
|
|
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
2020-02-24 16:03:30 -08:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
2021-04-05 13:53:50 -07:00
|
|
|
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
2021-12-06 14:54:50 -08:00
|
|
|
let (nonce_authority, nonce_authority_pubkey) =
|
|
|
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
2022-08-02 20:23:05 -07:00
|
|
|
let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name);
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
let mut bulk_signers = vec![fee_payer, authorized_withdrawer, new_identity_account];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
2019-12-12 15:04:03 -08:00
|
|
|
|
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::VoteUpdateValidator {
|
|
|
|
vote_account_pubkey,
|
2020-03-19 01:58:52 -07:00
|
|
|
new_identity_account: signer_info.index_of(new_identity_pubkey).unwrap(),
|
2020-07-13 20:49:59 -07:00
|
|
|
withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(),
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only,
|
|
|
|
dump_transaction_message,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
2021-04-05 13:53:50 -07:00
|
|
|
memo,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price,
|
2019-12-12 15:04:03 -08:00
|
|
|
},
|
2020-03-19 01:58:52 -07:00
|
|
|
signers: signer_info.signers,
|
2019-10-21 16:08:09 -07:00
|
|
|
})
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
|
2020-06-09 21:15:46 -07:00
|
|
|
pub fn parse_vote_update_commission(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-09-21 20:53:15 -07:00
|
|
|
default_signer: &DefaultSigner,
|
2020-06-09 21:15:46 -07:00
|
|
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
|
|
|
let vote_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
2020-07-13 19:30:49 -07:00
|
|
|
let (authorized_withdrawer, authorized_withdrawer_pubkey) =
|
|
|
|
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
2020-06-09 21:15:46 -07:00
|
|
|
let commission = value_t_or_exit!(matches, "commission", u8);
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
2021-04-05 13:53:50 -07:00
|
|
|
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
2021-12-06 14:54:50 -08:00
|
|
|
let (nonce_authority, nonce_authority_pubkey) =
|
|
|
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
2022-08-02 20:23:05 -07:00
|
|
|
let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name);
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
let mut bulk_signers = vec![fee_payer, authorized_withdrawer];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
2020-06-09 21:15:46 -07:00
|
|
|
|
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::VoteUpdateCommission {
|
|
|
|
vote_account_pubkey,
|
|
|
|
commission,
|
2020-07-13 19:30:49 -07:00
|
|
|
withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(),
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only,
|
|
|
|
dump_transaction_message,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
2021-04-05 13:53:50 -07:00
|
|
|
memo,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price,
|
2020-06-09 21:15:46 -07:00
|
|
|
},
|
|
|
|
signers: signer_info.signers,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-10-21 16:08:09 -07:00
|
|
|
pub fn parse_vote_get_account_command(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-04-18 11:54:21 -07:00
|
|
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
2019-10-21 16:08:09 -07:00
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-03-16 15:17:13 -07:00
|
|
|
let vote_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
2019-09-26 10:26:47 -07:00
|
|
|
let use_lamports_unit = matches.is_present("lamports");
|
2021-04-08 09:57:33 -07:00
|
|
|
let with_rewards = if matches.is_present("with_rewards") {
|
|
|
|
Some(value_of(matches, "num_rewards_epochs").unwrap())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2019-10-21 16:08:09 -07:00
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::ShowVoteAccount {
|
|
|
|
pubkey: vote_account_pubkey,
|
|
|
|
use_lamports_unit,
|
2021-04-08 09:57:33 -07:00
|
|
|
with_rewards,
|
2019-10-21 16:08:09 -07:00
|
|
|
},
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![],
|
2019-09-26 10:26:47 -07:00
|
|
|
})
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
|
2020-03-13 13:30:04 -07:00
|
|
|
pub fn parse_withdraw_from_vote_account(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-09-21 20:53:15 -07:00
|
|
|
default_signer: &DefaultSigner,
|
2020-04-18 11:54:21 -07:00
|
|
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
2020-03-13 13:30:04 -07:00
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-03-16 15:17:13 -07:00
|
|
|
let vote_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
|
|
|
let destination_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "destination_account_pubkey", wallet_manager)?.unwrap();
|
2021-12-13 18:00:29 -08:00
|
|
|
let mut withdraw_amount = SpendAmount::new_from_matches(matches, "amount");
|
|
|
|
// As a safeguard for vote accounts for running validators, `ALL` withdraws only the amount in
|
|
|
|
// excess of the rent-exempt minimum. In order to close the account with this subcommand, a
|
|
|
|
// validator must specify the withdrawal amount precisely.
|
|
|
|
if withdraw_amount == SpendAmount::All {
|
|
|
|
withdraw_amount = SpendAmount::RentExempt;
|
|
|
|
}
|
2020-06-15 14:36:47 -07:00
|
|
|
|
2020-03-13 13:30:04 -07:00
|
|
|
let (withdraw_authority, withdraw_authority_pubkey) =
|
|
|
|
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
2021-04-05 13:53:50 -07:00
|
|
|
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
2021-12-06 14:54:50 -08:00
|
|
|
let (nonce_authority, nonce_authority_pubkey) =
|
|
|
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
2022-08-02 20:23:05 -07:00
|
|
|
let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name);
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
let mut bulk_signers = vec![fee_payer, withdraw_authority];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
2020-03-13 13:30:04 -07:00
|
|
|
|
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawFromVoteAccount {
|
|
|
|
vote_account_pubkey,
|
|
|
|
destination_account_pubkey,
|
|
|
|
withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(),
|
2020-06-15 14:36:47 -07:00
|
|
|
withdraw_amount,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only,
|
|
|
|
dump_transaction_message,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
2021-04-05 13:53:50 -07:00
|
|
|
memo,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price,
|
2020-03-13 13:30:04 -07:00
|
|
|
},
|
|
|
|
signers: signer_info.signers,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-13 08:13:59 -07:00
|
|
|
pub fn parse_close_vote_account(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
default_signer: &DefaultSigner,
|
|
|
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
|
|
|
let vote_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
|
|
|
let destination_account_pubkey =
|
|
|
|
pubkey_of_signer(matches, "destination_account_pubkey", wallet_manager)?.unwrap();
|
|
|
|
|
|
|
|
let (withdraw_authority, withdraw_authority_pubkey) =
|
|
|
|
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
2021-12-06 14:54:50 -08:00
|
|
|
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
2021-09-13 08:13:59 -07:00
|
|
|
|
|
|
|
let signer_info = default_signer.generate_unique_signers(
|
2021-12-06 14:54:50 -08:00
|
|
|
vec![fee_payer, withdraw_authority],
|
2021-09-13 08:13:59 -07:00
|
|
|
matches,
|
|
|
|
wallet_manager,
|
|
|
|
)?;
|
|
|
|
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
2022-08-02 20:23:05 -07:00
|
|
|
let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name);
|
2021-09-13 08:13:59 -07:00
|
|
|
|
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::CloseVoteAccount {
|
|
|
|
vote_account_pubkey,
|
|
|
|
destination_account_pubkey,
|
|
|
|
withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(),
|
|
|
|
memo,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price,
|
2021-09-13 08:13:59 -07:00
|
|
|
},
|
|
|
|
signers: signer_info.signers,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-09-18 09:29:57 -07:00
|
|
|
pub fn process_create_vote_account(
|
|
|
|
rpc_client: &RpcClient,
|
2019-10-04 15:13:21 -07:00
|
|
|
config: &CliConfig,
|
2020-07-13 20:27:41 -07:00
|
|
|
vote_account: SignerIndex,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: &Option<String>,
|
2020-03-19 01:58:52 -07:00
|
|
|
identity_account: SignerIndex,
|
2019-10-21 16:08:09 -07:00
|
|
|
authorized_voter: &Option<Pubkey>,
|
2021-09-02 17:22:33 -07:00
|
|
|
authorized_withdrawer: Pubkey,
|
2019-10-21 16:08:09 -07:00
|
|
|
commission: u8,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: bool,
|
|
|
|
dump_transaction_message: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<&Pubkey>,
|
|
|
|
nonce_authority: SignerIndex,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: Option<&String>,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: SignerIndex,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: Option<&u64>,
|
2019-09-18 09:29:57 -07:00
|
|
|
) -> ProcessResult {
|
2020-07-13 20:27:41 -07:00
|
|
|
let vote_account = config.signers[vote_account];
|
2019-11-06 06:47:34 -08:00
|
|
|
let vote_account_pubkey = vote_account.pubkey();
|
2020-01-09 15:22:48 -08:00
|
|
|
let vote_account_address = if let Some(seed) = seed {
|
2021-06-18 06:34:46 -07:00
|
|
|
Pubkey::create_with_seed(&vote_account_pubkey, seed, &solana_vote_program::id())?
|
2020-01-09 15:22:48 -08:00
|
|
|
} else {
|
|
|
|
vote_account_pubkey
|
|
|
|
};
|
2019-09-18 09:29:57 -07:00
|
|
|
check_unique_pubkeys(
|
2020-02-24 16:03:30 -08:00
|
|
|
(&config.signers[0].pubkey(), "cli keypair".to_string()),
|
2020-01-09 15:22:48 -08:00
|
|
|
(&vote_account_address, "vote_account".to_string()),
|
2019-09-18 09:29:57 -07:00
|
|
|
)?;
|
2020-01-09 15:22:48 -08:00
|
|
|
|
2020-03-19 01:58:52 -07:00
|
|
|
let identity_account = config.signers[identity_account];
|
|
|
|
let identity_pubkey = identity_account.pubkey();
|
2019-09-18 09:29:57 -07:00
|
|
|
check_unique_pubkeys(
|
2020-01-09 15:22:48 -08:00
|
|
|
(&vote_account_address, "vote_account".to_string()),
|
|
|
|
(&identity_pubkey, "identity_pubkey".to_string()),
|
2019-09-18 09:29:57 -07:00
|
|
|
)?;
|
2019-12-09 21:56:43 -08:00
|
|
|
|
2020-05-14 11:24:14 -07:00
|
|
|
let required_balance = rpc_client
|
|
|
|
.get_minimum_balance_for_rent_exemption(VoteState::size_of())?
|
|
|
|
.max(1);
|
|
|
|
let amount = SpendAmount::Some(required_balance);
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let fee_payer = config.signers[fee_payer];
|
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
|
|
|
|
2020-05-14 11:24:14 -07:00
|
|
|
let build_message = |lamports| {
|
|
|
|
let vote_init = VoteInit {
|
|
|
|
node_pubkey: identity_pubkey,
|
|
|
|
authorized_voter: authorized_voter.unwrap_or(identity_pubkey),
|
2021-09-02 17:22:33 -07:00
|
|
|
authorized_withdrawer,
|
2020-05-14 11:24:14 -07:00
|
|
|
commission,
|
|
|
|
};
|
|
|
|
|
|
|
|
let ixs = if let Some(seed) = seed {
|
|
|
|
vote_instruction::create_account_with_seed(
|
|
|
|
&config.signers[0].pubkey(), // from
|
|
|
|
&vote_account_address, // to
|
|
|
|
&vote_account_pubkey, // base
|
|
|
|
seed, // seed
|
|
|
|
&vote_init,
|
|
|
|
lamports,
|
|
|
|
)
|
2021-04-05 13:53:50 -07:00
|
|
|
.with_memo(memo)
|
2022-08-02 20:23:05 -07:00
|
|
|
.with_compute_unit_price(compute_unit_price)
|
2020-05-14 11:24:14 -07:00
|
|
|
} else {
|
|
|
|
vote_instruction::create_account(
|
|
|
|
&config.signers[0].pubkey(),
|
|
|
|
&vote_account_pubkey,
|
|
|
|
&vote_init,
|
|
|
|
lamports,
|
|
|
|
)
|
2021-04-05 13:53:50 -07:00
|
|
|
.with_memo(memo)
|
2022-08-02 20:23:05 -07:00
|
|
|
.with_compute_unit_price(compute_unit_price)
|
2020-05-14 11:24:14 -07:00
|
|
|
};
|
2021-12-06 14:54:50 -08:00
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Message::new(&ixs, Some(&fee_payer.pubkey()))
|
2020-06-17 11:18:48 -07:00
|
|
|
}
|
2021-12-06 14:54:50 -08:00
|
|
|
};
|
2020-01-09 15:22:48 -08:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let recent_blockhash = blockhash_query.get_blockhash(rpc_client, config.commitment)?;
|
2020-01-09 15:22:48 -08:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let (message, _) = resolve_spend_tx_and_check_account_balances(
|
2019-12-09 23:11:04 -08:00
|
|
|
rpc_client,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only,
|
2020-05-14 11:24:14 -07:00
|
|
|
amount,
|
2021-12-06 14:54:50 -08:00
|
|
|
&recent_blockhash,
|
2020-05-14 11:24:14 -07:00
|
|
|
&config.signers[0].pubkey(),
|
2021-12-06 14:54:50 -08:00
|
|
|
&fee_payer.pubkey(),
|
2020-05-14 11:24:14 -07:00
|
|
|
build_message,
|
2020-06-17 11:18:48 -07:00
|
|
|
config.commitment,
|
2019-12-09 23:11:04 -08:00
|
|
|
)?;
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
if !sign_only {
|
|
|
|
if let Ok(response) =
|
|
|
|
rpc_client.get_account_with_commitment(&vote_account_address, config.commitment)
|
|
|
|
{
|
|
|
|
if let Some(vote_account) = response.value {
|
|
|
|
let err_msg = if vote_account.owner == solana_vote_program::id() {
|
2022-12-06 06:30:06 -08:00
|
|
|
format!("Vote account {vote_account_address} already exists")
|
2021-12-06 14:54:50 -08:00
|
|
|
} else {
|
|
|
|
format!(
|
2022-12-06 06:30:06 -08:00
|
|
|
"Account {vote_account_address} already exists and is not a vote account"
|
2021-12-06 14:54:50 -08:00
|
|
|
)
|
|
|
|
};
|
|
|
|
return Err(CliError::BadParameter(err_msg).into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
2022-08-24 09:47:02 -07:00
|
|
|
let nonce_account = solana_rpc_client_nonce_utils::get_account_with_commitment(
|
2021-12-06 14:54:50 -08:00
|
|
|
rpc_client,
|
|
|
|
nonce_account,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 11:24:14 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
2021-12-06 14:54:50 -08:00
|
|
|
if sign_only {
|
|
|
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
|
|
|
return_signers_with_config(
|
|
|
|
&tx,
|
|
|
|
&config.output_format,
|
|
|
|
&ReturnSignersConfig {
|
|
|
|
dump_transaction_message,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
|
|
|
log_instruction_custom_error::<SystemError>(result, config)
|
|
|
|
}
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-09-25 13:53:49 -07:00
|
|
|
pub fn process_vote_authorize(
|
2019-09-18 09:29:57 -07:00
|
|
|
rpc_client: &RpcClient,
|
2019-10-04 15:13:21 -07:00
|
|
|
config: &CliConfig,
|
2019-09-18 09:29:57 -07:00
|
|
|
vote_account_pubkey: &Pubkey,
|
2019-09-25 13:53:49 -07:00
|
|
|
new_authorized_pubkey: &Pubkey,
|
|
|
|
vote_authorize: VoteAuthorize,
|
2021-07-15 15:45:03 -07:00
|
|
|
authorized: SignerIndex,
|
|
|
|
new_authorized: Option<SignerIndex>,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: bool,
|
|
|
|
dump_transaction_message: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<Pubkey>,
|
|
|
|
nonce_authority: SignerIndex,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: Option<&String>,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: SignerIndex,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: Option<&u64>,
|
2019-09-18 09:29:57 -07:00
|
|
|
) -> ProcessResult {
|
2021-07-15 15:45:03 -07:00
|
|
|
let authorized = config.signers[authorized];
|
|
|
|
let new_authorized_signer = new_authorized.map(|index| config.signers[index]);
|
2020-04-02 20:47:31 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let vote_state = if !sign_only {
|
|
|
|
Some(get_vote_account(rpc_client, vote_account_pubkey, config.commitment)?.1)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2021-09-15 12:59:05 -07:00
|
|
|
match vote_authorize {
|
|
|
|
VoteAuthorize::Voter => {
|
2021-12-06 14:54:50 -08:00
|
|
|
if let Some(vote_state) = vote_state {
|
|
|
|
let current_epoch = rpc_client.get_epoch_info()?.epoch;
|
|
|
|
let current_authorized_voter = vote_state
|
|
|
|
.authorized_voters()
|
|
|
|
.get_authorized_voter(current_epoch)
|
|
|
|
.ok_or_else(|| {
|
|
|
|
CliError::RpcRequestError(
|
|
|
|
"Invalid vote account state; no authorized voters found".to_string(),
|
|
|
|
)
|
|
|
|
})?;
|
2022-03-24 11:51:40 -07:00
|
|
|
check_current_authority(
|
|
|
|
&[current_authorized_voter, vote_state.authorized_withdrawer],
|
|
|
|
&authorized.pubkey(),
|
|
|
|
)?;
|
2021-12-06 14:54:50 -08:00
|
|
|
if let Some(signer) = new_authorized_signer {
|
|
|
|
if signer.is_interactive() {
|
|
|
|
return Err(CliError::BadParameter(format!(
|
2022-12-06 06:30:06 -08:00
|
|
|
"invalid new authorized vote signer {new_authorized_pubkey:?}. Interactive vote signers not supported"
|
2021-12-06 14:54:50 -08:00
|
|
|
)).into());
|
|
|
|
}
|
2021-10-28 13:48:16 -07:00
|
|
|
}
|
|
|
|
}
|
2021-09-15 12:59:05 -07:00
|
|
|
}
|
|
|
|
VoteAuthorize::Withdrawer => {
|
2021-11-29 07:46:29 -08:00
|
|
|
check_unique_pubkeys(
|
|
|
|
(&authorized.pubkey(), "authorized_account".to_string()),
|
|
|
|
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
|
|
|
|
)?;
|
2021-12-06 14:54:50 -08:00
|
|
|
if let Some(vote_state) = vote_state {
|
2022-03-24 11:51:40 -07:00
|
|
|
check_current_authority(&[vote_state.authorized_withdrawer], &authorized.pubkey())?
|
2021-12-06 14:54:50 -08:00
|
|
|
}
|
2021-09-15 12:59:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-15 15:45:03 -07:00
|
|
|
let vote_ix = if new_authorized_signer.is_some() {
|
|
|
|
vote_instruction::authorize_checked(
|
|
|
|
vote_account_pubkey, // vote account to update
|
|
|
|
&authorized.pubkey(), // current authorized
|
|
|
|
new_authorized_pubkey, // new vote signer/withdrawer
|
|
|
|
vote_authorize, // vote or withdraw
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
vote_instruction::authorize(
|
|
|
|
vote_account_pubkey, // vote account to update
|
|
|
|
&authorized.pubkey(), // current authorized
|
|
|
|
new_authorized_pubkey, // new vote signer/withdrawer
|
|
|
|
vote_authorize, // vote or withdraw
|
|
|
|
)
|
|
|
|
};
|
2022-08-02 20:23:05 -07:00
|
|
|
let ixs = vec![vote_ix]
|
|
|
|
.with_memo(memo)
|
|
|
|
.with_compute_unit_price(compute_unit_price);
|
2019-09-18 09:29:57 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let recent_blockhash = blockhash_query.get_blockhash(rpc_client, config.commitment)?;
|
|
|
|
|
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
|
|
|
let fee_payer = config.signers[fee_payer];
|
|
|
|
|
|
|
|
let message = if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Message::new(&ixs, Some(&fee_payer.pubkey()))
|
|
|
|
};
|
2020-02-21 13:55:53 -08:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
if sign_only {
|
|
|
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
|
|
|
return_signers_with_config(
|
|
|
|
&tx,
|
|
|
|
&config.output_format,
|
|
|
|
&ReturnSignersConfig {
|
|
|
|
dump_transaction_message,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
2022-08-24 09:47:02 -07:00
|
|
|
let nonce_account = solana_rpc_client_nonce_utils::get_account_with_commitment(
|
2021-12-06 14:54:50 -08:00
|
|
|
rpc_client,
|
|
|
|
nonce_account,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
|
|
|
}
|
|
|
|
check_account_for_fee_with_commitment(
|
|
|
|
rpc_client,
|
|
|
|
&config.signers[0].pubkey(),
|
|
|
|
&tx.message,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
|
|
|
log_instruction_custom_error::<VoteError>(result, config)
|
|
|
|
}
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-12-12 15:04:03 -08:00
|
|
|
pub fn process_vote_update_validator(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
config: &CliConfig,
|
|
|
|
vote_account_pubkey: &Pubkey,
|
2020-03-19 01:58:52 -07:00
|
|
|
new_identity_account: SignerIndex,
|
2020-07-13 20:49:59 -07:00
|
|
|
withdraw_authority: SignerIndex,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: bool,
|
|
|
|
dump_transaction_message: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<Pubkey>,
|
|
|
|
nonce_authority: SignerIndex,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: Option<&String>,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: SignerIndex,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: Option<&u64>,
|
2019-12-12 15:04:03 -08:00
|
|
|
) -> ProcessResult {
|
2020-07-13 20:49:59 -07:00
|
|
|
let authorized_withdrawer = config.signers[withdraw_authority];
|
2020-03-19 01:58:52 -07:00
|
|
|
let new_identity_account = config.signers[new_identity_account];
|
|
|
|
let new_identity_pubkey = new_identity_account.pubkey();
|
2019-12-12 15:04:03 -08:00
|
|
|
check_unique_pubkeys(
|
|
|
|
(vote_account_pubkey, "vote_account_pubkey".to_string()),
|
2020-03-19 01:58:52 -07:00
|
|
|
(&new_identity_pubkey, "new_identity_account".to_string()),
|
2019-12-12 15:04:03 -08:00
|
|
|
)?;
|
2021-12-06 14:54:50 -08:00
|
|
|
let recent_blockhash = blockhash_query.get_blockhash(rpc_client, config.commitment)?;
|
2020-04-10 14:09:56 -07:00
|
|
|
let ixs = vec![vote_instruction::update_validator_identity(
|
2019-12-12 15:04:03 -08:00
|
|
|
vote_account_pubkey,
|
2020-03-19 01:58:52 -07:00
|
|
|
&authorized_withdrawer.pubkey(),
|
|
|
|
&new_identity_pubkey,
|
2021-04-05 13:53:50 -07:00
|
|
|
)]
|
2022-08-02 20:23:05 -07:00
|
|
|
.with_memo(memo)
|
|
|
|
.with_compute_unit_price(compute_unit_price);
|
2021-12-06 14:54:50 -08:00
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
|
|
|
let fee_payer = config.signers[fee_payer];
|
|
|
|
|
|
|
|
let message = if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Message::new(&ixs, Some(&fee_payer.pubkey()))
|
|
|
|
};
|
2020-02-21 13:55:53 -08:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
if sign_only {
|
|
|
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
|
|
|
return_signers_with_config(
|
|
|
|
&tx,
|
|
|
|
&config.output_format,
|
|
|
|
&ReturnSignersConfig {
|
|
|
|
dump_transaction_message,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
2022-08-24 09:47:02 -07:00
|
|
|
let nonce_account = solana_rpc_client_nonce_utils::get_account_with_commitment(
|
2021-12-06 14:54:50 -08:00
|
|
|
rpc_client,
|
|
|
|
nonce_account,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
|
|
|
}
|
|
|
|
check_account_for_fee_with_commitment(
|
|
|
|
rpc_client,
|
|
|
|
&config.signers[0].pubkey(),
|
|
|
|
&tx.message,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
|
|
|
log_instruction_custom_error::<VoteError>(result, config)
|
|
|
|
}
|
2019-12-12 15:04:03 -08:00
|
|
|
}
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-06-09 21:15:46 -07:00
|
|
|
pub fn process_vote_update_commission(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
config: &CliConfig,
|
|
|
|
vote_account_pubkey: &Pubkey,
|
|
|
|
commission: u8,
|
2020-07-13 19:30:49 -07:00
|
|
|
withdraw_authority: SignerIndex,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: bool,
|
|
|
|
dump_transaction_message: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<Pubkey>,
|
|
|
|
nonce_authority: SignerIndex,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: Option<&String>,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: SignerIndex,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: Option<&u64>,
|
2020-06-09 21:15:46 -07:00
|
|
|
) -> ProcessResult {
|
2020-07-13 19:30:49 -07:00
|
|
|
let authorized_withdrawer = config.signers[withdraw_authority];
|
2021-12-06 14:54:50 -08:00
|
|
|
let recent_blockhash = blockhash_query.get_blockhash(rpc_client, config.commitment)?;
|
2020-06-09 21:15:46 -07:00
|
|
|
let ixs = vec![vote_instruction::update_commission(
|
|
|
|
vote_account_pubkey,
|
|
|
|
&authorized_withdrawer.pubkey(),
|
|
|
|
commission,
|
2021-04-05 13:53:50 -07:00
|
|
|
)]
|
2022-08-02 20:23:05 -07:00
|
|
|
.with_memo(memo)
|
|
|
|
.with_compute_unit_price(compute_unit_price);
|
2021-12-06 14:54:50 -08:00
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
|
|
|
let fee_payer = config.signers[fee_payer];
|
|
|
|
|
|
|
|
let message = if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Message::new(&ixs, Some(&fee_payer.pubkey()))
|
|
|
|
};
|
2020-06-09 21:15:46 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
2021-12-06 14:54:50 -08:00
|
|
|
if sign_only {
|
|
|
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
|
|
|
return_signers_with_config(
|
|
|
|
&tx,
|
|
|
|
&config.output_format,
|
|
|
|
&ReturnSignersConfig {
|
|
|
|
dump_transaction_message,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
2022-08-24 09:47:02 -07:00
|
|
|
let nonce_account = solana_rpc_client_nonce_utils::get_account_with_commitment(
|
2021-12-06 14:54:50 -08:00
|
|
|
rpc_client,
|
|
|
|
nonce_account,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
|
|
|
}
|
|
|
|
check_account_for_fee_with_commitment(
|
|
|
|
rpc_client,
|
|
|
|
&config.signers[0].pubkey(),
|
|
|
|
&tx.message,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
|
|
|
log_instruction_custom_error::<VoteError>(result, config)
|
|
|
|
}
|
2020-06-09 21:15:46 -07:00
|
|
|
}
|
|
|
|
|
2022-03-25 09:11:51 -07:00
|
|
|
pub(crate) fn get_vote_account(
|
2019-09-18 09:29:57 -07:00
|
|
|
rpc_client: &RpcClient,
|
|
|
|
vote_account_pubkey: &Pubkey,
|
2020-03-03 16:53:30 -08:00
|
|
|
commitment_config: CommitmentConfig,
|
2019-10-08 22:34:26 -07:00
|
|
|
) -> Result<(Account, VoteState), Box<dyn std::error::Error>> {
|
2020-03-03 16:53:30 -08:00
|
|
|
let vote_account = rpc_client
|
|
|
|
.get_account_with_commitment(vote_account_pubkey, commitment_config)?
|
|
|
|
.value
|
|
|
|
.ok_or_else(|| {
|
2022-12-06 06:30:06 -08:00
|
|
|
CliError::RpcRequestError(format!("{vote_account_pubkey:?} account does not exist"))
|
2020-03-03 16:53:30 -08:00
|
|
|
})?;
|
2019-09-18 09:29:57 -07:00
|
|
|
|
2019-11-20 10:12:43 -08:00
|
|
|
if vote_account.owner != solana_vote_program::id() {
|
2019-12-19 23:27:54 -08:00
|
|
|
return Err(CliError::RpcRequestError(format!(
|
2022-12-06 06:30:06 -08:00
|
|
|
"{vote_account_pubkey:?} is not a vote account"
|
2019-12-19 23:27:54 -08:00
|
|
|
))
|
2019-10-02 18:33:01 -07:00
|
|
|
.into());
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
let vote_state = VoteState::deserialize(&vote_account.data).map_err(|_| {
|
2019-10-04 15:13:21 -07:00
|
|
|
CliError::RpcRequestError(
|
2019-09-18 09:29:57 -07:00
|
|
|
"Account data could not be deserialized to vote state".to_string(),
|
|
|
|
)
|
|
|
|
})?;
|
|
|
|
|
2019-10-08 22:34:26 -07:00
|
|
|
Ok((vote_account, vote_state))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_show_vote_account(
|
|
|
|
rpc_client: &RpcClient,
|
2020-04-14 12:10:25 -07:00
|
|
|
config: &CliConfig,
|
2020-10-07 14:38:17 -07:00
|
|
|
vote_account_address: &Pubkey,
|
2019-10-08 22:34:26 -07:00
|
|
|
use_lamports_unit: bool,
|
2021-04-08 09:57:33 -07:00
|
|
|
with_rewards: Option<usize>,
|
2019-10-08 22:34:26 -07:00
|
|
|
) -> ProcessResult {
|
2020-03-03 16:53:30 -08:00
|
|
|
let (vote_account, vote_state) =
|
2020-10-07 14:38:17 -07:00
|
|
|
get_vote_account(rpc_client, vote_account_address, config.commitment)?;
|
2019-10-08 22:34:26 -07:00
|
|
|
|
2019-10-22 13:41:18 -07:00
|
|
|
let epoch_schedule = rpc_client.get_epoch_schedule()?;
|
2019-10-08 22:34:26 -07:00
|
|
|
|
2020-04-14 12:10:25 -07:00
|
|
|
let mut votes: Vec<CliLockout> = vec![];
|
|
|
|
let mut epoch_voting_history: Vec<CliEpochVotingHistory> = vec![];
|
2019-09-18 09:29:57 -07:00
|
|
|
if !vote_state.votes.is_empty() {
|
|
|
|
for vote in &vote_state.votes {
|
2020-04-14 12:10:25 -07:00
|
|
|
votes.push(vote.into());
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
2020-11-06 07:07:40 -08:00
|
|
|
for (epoch, credits, prev_credits) in vote_state.epoch_credits().iter().copied() {
|
2019-09-18 09:29:57 -07:00
|
|
|
let credits_earned = credits - prev_credits;
|
2020-11-06 07:07:40 -08:00
|
|
|
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(epoch);
|
2020-04-14 12:10:25 -07:00
|
|
|
epoch_voting_history.push(CliEpochVotingHistory {
|
2020-11-06 07:07:40 -08:00
|
|
|
epoch,
|
2020-04-14 12:10:25 -07:00
|
|
|
slots_in_epoch,
|
|
|
|
credits_earned,
|
2020-11-06 07:07:40 -08:00
|
|
|
credits,
|
|
|
|
prev_credits,
|
2020-04-14 12:10:25 -07:00
|
|
|
});
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
}
|
2020-04-14 12:10:25 -07:00
|
|
|
|
2021-04-08 09:57:33 -07:00
|
|
|
let epoch_rewards =
|
|
|
|
with_rewards.and_then(|num_epochs| {
|
|
|
|
match crate::stake::fetch_epoch_rewards(rpc_client, vote_account_address, num_epochs) {
|
|
|
|
Ok(rewards) => Some(rewards),
|
|
|
|
Err(error) => {
|
2022-12-06 06:30:06 -08:00
|
|
|
eprintln!("Failed to fetch epoch rewards: {error:?}");
|
2021-04-08 09:57:33 -07:00
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2020-10-07 14:38:17 -07:00
|
|
|
|
2020-04-14 12:10:25 -07:00
|
|
|
let vote_account_data = CliVoteAccount {
|
|
|
|
account_balance: vote_account.lamports,
|
|
|
|
validator_identity: vote_state.node_pubkey.to_string(),
|
|
|
|
authorized_voters: vote_state.authorized_voters().into(),
|
|
|
|
authorized_withdrawer: vote_state.authorized_withdrawer.to_string(),
|
|
|
|
credits: vote_state.credits(),
|
|
|
|
commission: vote_state.commission,
|
|
|
|
root_slot: vote_state.root_slot,
|
|
|
|
recent_timestamp: vote_state.last_timestamp.clone(),
|
|
|
|
votes,
|
|
|
|
epoch_voting_history,
|
|
|
|
use_lamports_unit,
|
2020-10-07 14:38:17 -07:00
|
|
|
epoch_rewards,
|
2020-04-14 12:10:25 -07:00
|
|
|
};
|
|
|
|
|
2020-05-06 19:27:15 -07:00
|
|
|
Ok(config.output_format.formatted_string(&vote_account_data))
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-03-13 13:30:04 -07:00
|
|
|
pub fn process_withdraw_from_vote_account(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
config: &CliConfig,
|
|
|
|
vote_account_pubkey: &Pubkey,
|
|
|
|
withdraw_authority: SignerIndex,
|
2020-06-15 14:36:47 -07:00
|
|
|
withdraw_amount: SpendAmount,
|
2020-03-13 13:30:04 -07:00
|
|
|
destination_account_pubkey: &Pubkey,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: bool,
|
|
|
|
dump_transaction_message: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<&Pubkey>,
|
|
|
|
nonce_authority: SignerIndex,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: Option<&String>,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: SignerIndex,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: Option<&u64>,
|
2020-03-13 13:30:04 -07:00
|
|
|
) -> ProcessResult {
|
|
|
|
let withdraw_authority = config.signers[withdraw_authority];
|
2021-12-06 14:54:50 -08:00
|
|
|
let recent_blockhash = blockhash_query.get_blockhash(rpc_client, config.commitment)?;
|
2020-03-13 13:30:04 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let fee_payer = config.signers[fee_payer];
|
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
|
|
|
|
|
|
|
let build_message = |lamports| {
|
|
|
|
let ixs = vec![withdraw(
|
|
|
|
vote_account_pubkey,
|
|
|
|
&withdraw_authority.pubkey(),
|
|
|
|
lamports,
|
|
|
|
destination_account_pubkey,
|
|
|
|
)]
|
2022-08-02 20:23:05 -07:00
|
|
|
.with_memo(memo)
|
|
|
|
.with_compute_unit_price(compute_unit_price);
|
2021-12-06 14:54:50 -08:00
|
|
|
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Message::new(&ixs, Some(&fee_payer.pubkey()))
|
|
|
|
}
|
|
|
|
};
|
2020-06-15 14:36:47 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let (message, _) = resolve_spend_tx_and_check_account_balances(
|
|
|
|
rpc_client,
|
|
|
|
sign_only,
|
|
|
|
withdraw_amount,
|
|
|
|
&recent_blockhash,
|
|
|
|
vote_account_pubkey,
|
|
|
|
&fee_payer.pubkey(),
|
|
|
|
build_message,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
if !sign_only {
|
|
|
|
let current_balance = rpc_client.get_balance(vote_account_pubkey)?;
|
|
|
|
let minimum_balance =
|
|
|
|
rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?;
|
|
|
|
if let SpendAmount::Some(withdraw_amount) = withdraw_amount {
|
|
|
|
let balance_remaining = current_balance.saturating_sub(withdraw_amount);
|
|
|
|
if balance_remaining < minimum_balance && balance_remaining != 0 {
|
2020-06-15 14:36:47 -07:00
|
|
|
return Err(CliError::BadParameter(format!(
|
|
|
|
"Withdraw amount too large. The vote account balance must be at least {} SOL to remain rent exempt", lamports_to_sol(minimum_balance)
|
|
|
|
))
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
}
|
2021-12-06 14:54:50 -08:00
|
|
|
}
|
2020-06-15 14:36:47 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
2020-03-13 13:30:04 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
if sign_only {
|
|
|
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
|
|
|
return_signers_with_config(
|
|
|
|
&tx,
|
|
|
|
&config.output_format,
|
|
|
|
&ReturnSignersConfig {
|
|
|
|
dump_transaction_message,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
2022-08-24 09:47:02 -07:00
|
|
|
let nonce_account = solana_rpc_client_nonce_utils::get_account_with_commitment(
|
2021-12-06 14:54:50 -08:00
|
|
|
rpc_client,
|
|
|
|
nonce_account,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
|
|
|
}
|
|
|
|
check_account_for_fee_with_commitment(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&tx.message,
|
|
|
|
config.commitment,
|
|
|
|
)?;
|
|
|
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
|
|
|
log_instruction_custom_error::<VoteError>(result, config)
|
|
|
|
}
|
2020-03-13 13:30:04 -07:00
|
|
|
}
|
|
|
|
|
2021-09-13 08:13:59 -07:00
|
|
|
pub fn process_close_vote_account(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
config: &CliConfig,
|
|
|
|
vote_account_pubkey: &Pubkey,
|
|
|
|
withdraw_authority: SignerIndex,
|
|
|
|
destination_account_pubkey: &Pubkey,
|
|
|
|
memo: Option<&String>,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: SignerIndex,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: Option<&u64>,
|
2021-09-13 08:13:59 -07:00
|
|
|
) -> ProcessResult {
|
|
|
|
let vote_account_status =
|
|
|
|
rpc_client.get_vote_accounts_with_config(RpcGetVoteAccountsConfig {
|
|
|
|
vote_pubkey: Some(vote_account_pubkey.to_string()),
|
|
|
|
..RpcGetVoteAccountsConfig::default()
|
|
|
|
})?;
|
|
|
|
|
|
|
|
if let Some(vote_account) = vote_account_status
|
|
|
|
.current
|
|
|
|
.into_iter()
|
|
|
|
.chain(vote_account_status.delinquent.into_iter())
|
|
|
|
.next()
|
|
|
|
{
|
|
|
|
if vote_account.activated_stake != 0 {
|
|
|
|
return Err(format!(
|
2022-12-06 06:30:06 -08:00
|
|
|
"Cannot close a vote account with active stake: {vote_account_pubkey}"
|
2021-09-13 08:13:59 -07:00
|
|
|
)
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let latest_blockhash = rpc_client.get_latest_blockhash()?;
|
|
|
|
let withdraw_authority = config.signers[withdraw_authority];
|
2021-12-06 14:54:50 -08:00
|
|
|
let fee_payer = config.signers[fee_payer];
|
2021-09-13 08:13:59 -07:00
|
|
|
|
|
|
|
let current_balance = rpc_client.get_balance(vote_account_pubkey)?;
|
|
|
|
|
|
|
|
let ixs = vec![withdraw(
|
|
|
|
vote_account_pubkey,
|
|
|
|
&withdraw_authority.pubkey(),
|
|
|
|
current_balance,
|
|
|
|
destination_account_pubkey,
|
|
|
|
)]
|
2022-08-02 20:23:05 -07:00
|
|
|
.with_memo(memo)
|
|
|
|
.with_compute_unit_price(compute_unit_price);
|
2021-09-13 08:13:59 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let message = Message::new(&ixs, Some(&fee_payer.pubkey()));
|
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, latest_blockhash)?;
|
2021-09-13 08:13:59 -07:00
|
|
|
check_account_for_fee_with_commitment(
|
|
|
|
rpc_client,
|
2021-12-06 14:54:50 -08:00
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&tx.message,
|
2021-09-13 08:13:59 -07:00
|
|
|
config.commitment,
|
|
|
|
)?;
|
2021-12-06 14:54:50 -08:00
|
|
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
2021-09-13 08:13:59 -07:00
|
|
|
log_instruction_custom_error::<VoteError>(result, config)
|
|
|
|
}
|
|
|
|
|
2019-09-18 09:29:57 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
crate::{clap_app::get_clap_app, cli::parse_command},
|
2022-08-24 09:47:02 -07:00
|
|
|
solana_rpc_client_nonce_utils::blockhash_query,
|
2021-12-06 14:54:50 -08:00
|
|
|
solana_sdk::{
|
|
|
|
hash::Hash,
|
|
|
|
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
|
|
|
signer::presigner::Presigner,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
tempfile::NamedTempFile,
|
|
|
|
};
|
2019-11-06 06:47:34 -08:00
|
|
|
|
|
|
|
fn make_tmp_file() -> (String, NamedTempFile) {
|
|
|
|
let tmp_file = NamedTempFile::new().unwrap();
|
|
|
|
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
|
|
|
}
|
2019-09-18 09:29:57 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse_command() {
|
2021-07-28 08:43:32 -07:00
|
|
|
let test_commands = get_clap_app("test", "desc", "version");
|
2019-11-06 06:47:34 -08:00
|
|
|
let keypair = Keypair::new();
|
|
|
|
let pubkey = keypair.pubkey();
|
2019-09-29 21:18:15 -07:00
|
|
|
let pubkey_string = pubkey.to_string();
|
2019-12-12 15:04:03 -08:00
|
|
|
let keypair2 = Keypair::new();
|
|
|
|
let pubkey2 = keypair2.pubkey();
|
|
|
|
let pubkey2_string = pubkey2.to_string();
|
2021-12-06 14:54:50 -08:00
|
|
|
let sig2 = keypair2.sign_message(&[0u8]);
|
|
|
|
let signer2 = format!("{}={}", keypair2.pubkey(), sig2);
|
2019-09-18 09:29:57 -07:00
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
let default_keypair = Keypair::new();
|
|
|
|
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
2021-05-28 00:42:55 -07:00
|
|
|
let default_signer = DefaultSigner::new("", &default_keypair_file);
|
2020-02-24 16:03:30 -08:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let blockhash = Hash::default();
|
2022-12-06 06:30:06 -08:00
|
|
|
let blockhash_string = format!("{blockhash}");
|
2021-12-06 14:54:50 -08:00
|
|
|
let nonce_account = Pubkey::new_unique();
|
|
|
|
|
|
|
|
// Test VoteAuthorize SubCommand
|
2019-09-18 09:29:57 -07:00
|
|
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
2019-09-25 13:53:49 -07:00
|
|
|
"vote-authorize-voter",
|
2019-09-18 09:29:57 -07:00
|
|
|
&pubkey_string,
|
2020-04-02 20:47:31 -07:00
|
|
|
&default_keypair_file,
|
2019-12-12 15:04:03 -08:00
|
|
|
&pubkey2_string,
|
2019-09-18 09:29:57 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
2019-10-21 16:08:09 -07:00
|
|
|
CliCommandInfo {
|
2019-12-12 15:04:03 -08:00
|
|
|
command: CliCommand::VoteAuthorize {
|
|
|
|
vote_account_pubkey: pubkey,
|
|
|
|
new_authorized_pubkey: pubkey2,
|
2021-04-05 13:53:50 -07:00
|
|
|
vote_authorize: VoteAuthorize::Voter,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2021-07-15 15:45:03 -07:00
|
|
|
authorized: 0,
|
|
|
|
new_authorized: None,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2019-12-12 15:04:03 -08:00
|
|
|
},
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2019-10-21 16:08:09 -07:00
|
|
|
}
|
2019-09-18 09:29:57 -07:00
|
|
|
);
|
|
|
|
|
2020-04-02 20:47:31 -07:00
|
|
|
let authorized_keypair = Keypair::new();
|
|
|
|
let (authorized_keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
write_keypair(&authorized_keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
|
|
|
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-authorize-voter",
|
|
|
|
&pubkey_string,
|
|
|
|
&authorized_keypair_file,
|
|
|
|
&pubkey2_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
2020-04-02 20:47:31 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::VoteAuthorize {
|
|
|
|
vote_account_pubkey: pubkey,
|
|
|
|
new_authorized_pubkey: pubkey2,
|
2021-04-05 13:53:50 -07:00
|
|
|
vote_authorize: VoteAuthorize::Voter,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2021-07-15 15:45:03 -07:00
|
|
|
authorized: 1,
|
|
|
|
new_authorized: None,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2020-04-02 20:47:31 -07:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&authorized_keypair_file).unwrap().into(),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-authorize-voter",
|
|
|
|
&pubkey_string,
|
|
|
|
&authorized_keypair_file,
|
|
|
|
&pubkey2_string,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--sign-only",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::VoteAuthorize {
|
|
|
|
vote_account_pubkey: pubkey,
|
|
|
|
new_authorized_pubkey: pubkey2,
|
|
|
|
vote_authorize: VoteAuthorize::Voter,
|
|
|
|
sign_only: true,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::None(blockhash),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
|
|
|
memo: None,
|
|
|
|
fee_payer: 0,
|
|
|
|
authorized: 1,
|
|
|
|
new_authorized: None,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&authorized_keypair_file).unwrap().into(),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let authorized_sig = authorized_keypair.sign_message(&[0u8]);
|
|
|
|
let authorized_signer = format!("{}={}", authorized_keypair.pubkey(), authorized_sig);
|
|
|
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-authorize-voter",
|
|
|
|
&pubkey_string,
|
|
|
|
&authorized_keypair.pubkey().to_string(),
|
|
|
|
&pubkey2_string,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--signer",
|
|
|
|
&authorized_signer,
|
|
|
|
"--signer",
|
|
|
|
&signer2,
|
|
|
|
"--fee-payer",
|
|
|
|
&pubkey2_string,
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account.to_string(),
|
|
|
|
"--nonce-authority",
|
|
|
|
&pubkey2_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::VoteAuthorize {
|
|
|
|
vote_account_pubkey: pubkey,
|
|
|
|
new_authorized_pubkey: pubkey2,
|
|
|
|
vote_authorize: VoteAuthorize::Voter,
|
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
blockhash
|
|
|
|
),
|
|
|
|
nonce_account: Some(nonce_account),
|
|
|
|
nonce_authority: 0,
|
|
|
|
memo: None,
|
|
|
|
fee_payer: 0,
|
|
|
|
authorized: 1,
|
|
|
|
new_authorized: None,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
Presigner::new(&pubkey2, &sig2).into(),
|
|
|
|
Presigner::new(&authorized_keypair.pubkey(), &authorized_sig).into(),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test checked VoteAuthorize SubCommand
|
2021-07-15 15:45:03 -07:00
|
|
|
let (voter_keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let voter_keypair = Keypair::new();
|
|
|
|
write_keypair(&voter_keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
|
|
|
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-authorize-voter-checked",
|
|
|
|
&pubkey_string,
|
|
|
|
&default_keypair_file,
|
|
|
|
&voter_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::VoteAuthorize {
|
|
|
|
vote_account_pubkey: pubkey,
|
|
|
|
new_authorized_pubkey: voter_keypair.pubkey(),
|
|
|
|
vote_authorize: VoteAuthorize::Voter,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-07-15 15:45:03 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2021-07-15 15:45:03 -07:00
|
|
|
authorized: 0,
|
|
|
|
new_authorized: Some(1),
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-07-15 15:45:03 -07:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&voter_keypair_file).unwrap().into()
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-authorize-voter-checked",
|
|
|
|
&pubkey_string,
|
|
|
|
&authorized_keypair_file,
|
|
|
|
&voter_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::VoteAuthorize {
|
|
|
|
vote_account_pubkey: pubkey,
|
|
|
|
new_authorized_pubkey: voter_keypair.pubkey(),
|
|
|
|
vote_authorize: VoteAuthorize::Voter,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-07-15 15:45:03 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2021-07-15 15:45:03 -07:00
|
|
|
authorized: 1,
|
|
|
|
new_authorized: Some(2),
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-07-15 15:45:03 -07:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&authorized_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&voter_keypair_file).unwrap().into(),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-authorize-voter-checked",
|
|
|
|
&pubkey_string,
|
|
|
|
&authorized_keypair_file,
|
|
|
|
&pubkey2_string,
|
|
|
|
]);
|
|
|
|
assert!(parse_command(&test_authorize_voter, &default_signer, &mut None).is_err());
|
|
|
|
|
2019-09-18 09:29:57 -07:00
|
|
|
// Test CreateVoteAccount SubCommand
|
2020-03-19 01:58:52 -07:00
|
|
|
let (identity_keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let identity_keypair = Keypair::new();
|
2021-09-02 17:22:33 -07:00
|
|
|
let authorized_withdrawer = Keypair::new().pubkey();
|
2020-03-19 01:58:52 -07:00
|
|
|
write_keypair(&identity_keypair, tmp_file.as_file_mut()).unwrap();
|
2021-12-06 14:54:50 -08:00
|
|
|
let (keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
|
2019-09-18 09:29:57 -07:00
|
|
|
let test_create_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-vote-account",
|
2019-11-06 06:47:34 -08:00
|
|
|
&keypair_file,
|
2020-03-19 01:58:52 -07:00
|
|
|
&identity_keypair_file,
|
2021-09-02 17:22:33 -07:00
|
|
|
&authorized_withdrawer.to_string(),
|
2019-09-18 09:29:57 -07:00
|
|
|
"--commission",
|
|
|
|
"10",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_create_vote_account, &default_signer, &mut None).unwrap(),
|
2019-10-21 16:08:09 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateVoteAccount {
|
2020-07-13 20:27:41 -07:00
|
|
|
vote_account: 1,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: None,
|
2020-03-19 01:58:52 -07:00
|
|
|
identity_account: 2,
|
2019-10-21 16:08:09 -07:00
|
|
|
authorized_voter: None,
|
2021-09-02 17:22:33 -07:00
|
|
|
authorized_withdrawer,
|
2019-10-21 16:08:09 -07:00
|
|
|
commission: 10,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2019-10-21 16:08:09 -07:00
|
|
|
},
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
2021-12-06 14:54:50 -08:00
|
|
|
read_keypair_file(&keypair_file).unwrap().into(),
|
2020-03-19 01:58:52 -07:00
|
|
|
read_keypair_file(&identity_keypair_file).unwrap().into(),
|
2020-02-24 16:03:30 -08:00
|
|
|
],
|
2019-10-21 16:08:09 -07:00
|
|
|
}
|
2019-09-18 09:29:57 -07:00
|
|
|
);
|
2019-11-06 06:47:34 -08:00
|
|
|
|
2019-09-18 09:29:57 -07:00
|
|
|
let test_create_vote_account2 = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-vote-account",
|
2019-11-06 06:47:34 -08:00
|
|
|
&keypair_file,
|
2020-03-19 01:58:52 -07:00
|
|
|
&identity_keypair_file,
|
2021-09-02 17:22:33 -07:00
|
|
|
&authorized_withdrawer.to_string(),
|
2019-09-18 09:29:57 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_create_vote_account2, &default_signer, &mut None).unwrap(),
|
2019-10-21 16:08:09 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateVoteAccount {
|
2020-07-13 20:27:41 -07:00
|
|
|
vote_account: 1,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: None,
|
2020-03-19 01:58:52 -07:00
|
|
|
identity_account: 2,
|
2019-10-21 16:08:09 -07:00
|
|
|
authorized_voter: None,
|
2021-09-02 17:22:33 -07:00
|
|
|
authorized_withdrawer,
|
2020-01-04 08:20:44 -08:00
|
|
|
commission: 100,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2019-10-21 16:08:09 -07:00
|
|
|
},
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
2021-12-06 14:54:50 -08:00
|
|
|
read_keypair_file(&keypair_file).unwrap().into(),
|
2020-03-19 01:58:52 -07:00
|
|
|
read_keypair_file(&identity_keypair_file).unwrap().into(),
|
2020-02-24 16:03:30 -08:00
|
|
|
],
|
2019-10-21 16:08:09 -07:00
|
|
|
}
|
2019-09-25 13:53:49 -07:00
|
|
|
);
|
2019-11-06 06:47:34 -08:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
let test_create_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&identity_keypair_file,
|
|
|
|
&authorized_withdrawer.to_string(),
|
|
|
|
"--commission",
|
|
|
|
"10",
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--sign-only",
|
|
|
|
"--fee-payer",
|
|
|
|
&default_keypair.pubkey().to_string(),
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_create_vote_account, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateVoteAccount {
|
|
|
|
vote_account: 1,
|
|
|
|
seed: None,
|
|
|
|
identity_account: 2,
|
|
|
|
authorized_voter: None,
|
|
|
|
authorized_withdrawer,
|
|
|
|
commission: 10,
|
|
|
|
sign_only: true,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::None(blockhash),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
|
|
|
memo: None,
|
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&identity_keypair_file).unwrap().into(),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let identity_sig = identity_keypair.sign_message(&[0u8]);
|
|
|
|
let identity_signer = format!("{}={}", identity_keypair.pubkey(), identity_sig);
|
|
|
|
let test_create_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&identity_keypair.pubkey().to_string(),
|
|
|
|
&authorized_withdrawer.to_string(),
|
|
|
|
"--commission",
|
|
|
|
"10",
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--signer",
|
|
|
|
&identity_signer,
|
|
|
|
"--signer",
|
|
|
|
&signer2,
|
|
|
|
"--fee-payer",
|
|
|
|
&default_keypair_file,
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account.to_string(),
|
|
|
|
"--nonce-authority",
|
|
|
|
&pubkey2_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_create_vote_account, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateVoteAccount {
|
|
|
|
vote_account: 1,
|
|
|
|
seed: None,
|
|
|
|
identity_account: 2,
|
|
|
|
authorized_voter: None,
|
|
|
|
authorized_withdrawer,
|
|
|
|
commission: 10,
|
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
blockhash
|
|
|
|
),
|
|
|
|
nonce_account: Some(nonce_account),
|
|
|
|
nonce_authority: 3,
|
|
|
|
memo: None,
|
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&identity_keypair.pubkey(), &identity_sig).into(),
|
|
|
|
Presigner::new(&pubkey2, &sig2).into(),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-09-25 13:53:49 -07:00
|
|
|
// test init with an authed voter
|
2020-10-19 12:12:08 -07:00
|
|
|
let authed = solana_sdk::pubkey::new_rand();
|
2019-11-06 06:47:34 -08:00
|
|
|
let (keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
|
2019-09-25 13:53:49 -07:00
|
|
|
let test_create_vote_account3 = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-vote-account",
|
2019-11-06 06:47:34 -08:00
|
|
|
&keypair_file,
|
2020-03-19 01:58:52 -07:00
|
|
|
&identity_keypair_file,
|
2021-09-02 17:22:33 -07:00
|
|
|
&authorized_withdrawer.to_string(),
|
2019-09-25 13:53:49 -07:00
|
|
|
"--authorized-voter",
|
|
|
|
&authed.to_string(),
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_create_vote_account3, &default_signer, &mut None).unwrap(),
|
2019-10-21 16:08:09 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateVoteAccount {
|
2020-07-13 20:27:41 -07:00
|
|
|
vote_account: 1,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: None,
|
2020-03-19 01:58:52 -07:00
|
|
|
identity_account: 2,
|
2019-10-21 16:08:09 -07:00
|
|
|
authorized_voter: Some(authed),
|
2021-09-02 17:22:33 -07:00
|
|
|
authorized_withdrawer,
|
2021-04-05 13:53:50 -07:00
|
|
|
commission: 100,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2019-10-21 16:08:09 -07:00
|
|
|
},
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
2020-03-19 01:58:52 -07:00
|
|
|
Box::new(keypair),
|
|
|
|
read_keypair_file(&identity_keypair_file).unwrap().into(),
|
2020-02-24 16:03:30 -08:00
|
|
|
],
|
2019-10-21 16:08:09 -07:00
|
|
|
}
|
2019-09-25 13:53:49 -07:00
|
|
|
);
|
2019-11-06 06:47:34 -08:00
|
|
|
|
|
|
|
let (keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
2021-09-02 17:22:33 -07:00
|
|
|
// succeed even though withdrawer unsafe (because forcefully allowed)
|
2019-09-25 13:53:49 -07:00
|
|
|
let test_create_vote_account4 = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-vote-account",
|
2019-11-06 06:47:34 -08:00
|
|
|
&keypair_file,
|
2020-03-19 01:58:52 -07:00
|
|
|
&identity_keypair_file,
|
2021-09-02 17:22:33 -07:00
|
|
|
&identity_keypair_file,
|
|
|
|
"--allow-unsafe-authorized-withdrawer",
|
2019-09-25 13:53:49 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_create_vote_account4, &default_signer, &mut None).unwrap(),
|
2019-10-21 16:08:09 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateVoteAccount {
|
2020-07-13 20:27:41 -07:00
|
|
|
vote_account: 1,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: None,
|
2020-03-19 01:58:52 -07:00
|
|
|
identity_account: 2,
|
2019-10-21 16:08:09 -07:00
|
|
|
authorized_voter: None,
|
2021-09-02 17:22:33 -07:00
|
|
|
authorized_withdrawer: identity_keypair.pubkey(),
|
2021-04-05 13:53:50 -07:00
|
|
|
commission: 100,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2019-10-21 16:08:09 -07:00
|
|
|
},
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
2021-12-06 14:54:50 -08:00
|
|
|
read_keypair_file(&keypair_file).unwrap().into(),
|
2020-03-19 01:58:52 -07:00
|
|
|
read_keypair_file(&identity_keypair_file).unwrap().into(),
|
2020-02-24 16:03:30 -08:00
|
|
|
],
|
2019-10-21 16:08:09 -07:00
|
|
|
}
|
2019-09-18 09:29:57 -07:00
|
|
|
);
|
|
|
|
|
2019-12-12 15:04:03 -08:00
|
|
|
let test_update_validator = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-update-validator",
|
|
|
|
&pubkey_string,
|
2020-03-19 01:58:52 -07:00
|
|
|
&identity_keypair_file,
|
2019-12-12 15:04:03 -08:00
|
|
|
&keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_update_validator, &default_signer, &mut None).unwrap(),
|
2019-12-12 15:04:03 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::VoteUpdateValidator {
|
|
|
|
vote_account_pubkey: pubkey,
|
2020-03-19 01:58:52 -07:00
|
|
|
new_identity_account: 2,
|
2020-07-13 20:49:59 -07:00
|
|
|
withdraw_authority: 1,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2019-12-12 15:04:03 -08:00
|
|
|
},
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
2020-03-19 01:58:52 -07:00
|
|
|
Box::new(read_keypair_file(&keypair_file).unwrap()),
|
|
|
|
read_keypair_file(&identity_keypair_file).unwrap().into(),
|
2020-02-24 16:03:30 -08:00
|
|
|
],
|
2019-12-12 15:04:03 -08:00
|
|
|
}
|
|
|
|
);
|
2020-03-13 13:30:04 -07:00
|
|
|
|
2020-06-09 21:15:46 -07:00
|
|
|
let test_update_commission = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"vote-update-commission",
|
|
|
|
&pubkey_string,
|
|
|
|
"42",
|
|
|
|
&keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_update_commission, &default_signer, &mut None).unwrap(),
|
2020-06-09 21:15:46 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::VoteUpdateCommission {
|
|
|
|
vote_account_pubkey: pubkey,
|
|
|
|
commission: 42,
|
2020-07-13 19:30:49 -07:00
|
|
|
withdraw_authority: 1,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2020-06-09 21:15:46 -07:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Box::new(read_keypair_file(&keypair_file).unwrap()),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-03-13 13:30:04 -07:00
|
|
|
// Test WithdrawFromVoteAccount subcommand
|
|
|
|
let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-from-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&pubkey_string,
|
|
|
|
"42",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
2020-03-13 13:30:04 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawFromVoteAccount {
|
|
|
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 0,
|
2020-06-15 14:36:47 -07:00
|
|
|
withdraw_amount: SpendAmount::Some(42_000_000_000),
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2020-06-15 14:36:47 -07:00
|
|
|
},
|
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test WithdrawFromVoteAccount subcommand
|
|
|
|
let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-from-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&pubkey_string,
|
|
|
|
"ALL",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
2020-06-15 14:36:47 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawFromVoteAccount {
|
|
|
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 0,
|
2021-12-13 18:00:29 -08:00
|
|
|
withdraw_amount: SpendAmount::RentExempt,
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2020-03-13 13:30:04 -07:00
|
|
|
},
|
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test WithdrawFromVoteAccount subcommand with authority
|
|
|
|
let withdraw_authority = Keypair::new();
|
|
|
|
let (withdraw_authority_file, mut tmp_file) = make_tmp_file();
|
|
|
|
write_keypair(&withdraw_authority, tmp_file.as_file_mut()).unwrap();
|
|
|
|
let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-from-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&pubkey_string,
|
|
|
|
"42",
|
|
|
|
"--authorized-withdrawer",
|
|
|
|
&withdraw_authority_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-09-21 20:53:15 -07:00
|
|
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
2020-03-13 13:30:04 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawFromVoteAccount {
|
|
|
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 1,
|
2020-06-15 14:36:47 -07:00
|
|
|
withdraw_amount: SpendAmount::Some(42_000_000_000),
|
2021-12-06 14:54:50 -08:00
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
2021-04-05 13:53:50 -07:00
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2020-03-13 13:30:04 -07:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&withdraw_authority_file).unwrap().into()
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
2021-09-13 08:13:59 -07:00
|
|
|
|
2021-12-06 14:54:50 -08:00
|
|
|
// Test WithdrawFromVoteAccount subcommand with offline authority
|
|
|
|
let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-from-vote-account",
|
|
|
|
&keypair.pubkey().to_string(),
|
|
|
|
&pubkey_string,
|
|
|
|
"42",
|
|
|
|
"--authorized-withdrawer",
|
|
|
|
&withdraw_authority_file,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--sign-only",
|
|
|
|
"--fee-payer",
|
|
|
|
&withdraw_authority_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawFromVoteAccount {
|
|
|
|
vote_account_pubkey: keypair.pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 0,
|
|
|
|
withdraw_amount: SpendAmount::Some(42_000_000_000),
|
|
|
|
sign_only: true,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::None(blockhash),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
|
|
|
memo: None,
|
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
},
|
|
|
|
signers: vec![read_keypair_file(&withdraw_authority_file).unwrap().into()],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let authorized_sig = withdraw_authority.sign_message(&[0u8]);
|
|
|
|
let authorized_signer = format!("{}={}", withdraw_authority.pubkey(), authorized_sig);
|
|
|
|
let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-from-vote-account",
|
|
|
|
&keypair.pubkey().to_string(),
|
|
|
|
&pubkey_string,
|
|
|
|
"42",
|
|
|
|
"--authorized-withdrawer",
|
|
|
|
&withdraw_authority.pubkey().to_string(),
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--signer",
|
|
|
|
&authorized_signer,
|
|
|
|
"--fee-payer",
|
|
|
|
&withdraw_authority.pubkey().to_string(),
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawFromVoteAccount {
|
|
|
|
vote_account_pubkey: keypair.pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 0,
|
|
|
|
withdraw_amount: SpendAmount::Some(42_000_000_000),
|
|
|
|
sign_only: false,
|
|
|
|
dump_transaction_message: false,
|
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
|
|
|
nonce_account: None,
|
|
|
|
nonce_authority: 0,
|
|
|
|
memo: None,
|
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
},
|
|
|
|
signers: vec![Presigner::new(&withdraw_authority.pubkey(), &authorized_sig).into(),],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2021-09-13 08:13:59 -07:00
|
|
|
// Test CloseVoteAccount subcommand
|
|
|
|
let test_close_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"close-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&pubkey_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_close_vote_account, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CloseVoteAccount {
|
|
|
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 0,
|
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
2021-09-13 08:13:59 -07:00
|
|
|
},
|
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test CloseVoteAccount subcommand with authority
|
|
|
|
let withdraw_authority = Keypair::new();
|
|
|
|
let (withdraw_authority_file, mut tmp_file) = make_tmp_file();
|
|
|
|
write_keypair(&withdraw_authority, tmp_file.as_file_mut()).unwrap();
|
|
|
|
let test_close_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"close-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&pubkey_string,
|
|
|
|
"--authorized-withdrawer",
|
|
|
|
&withdraw_authority_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_close_vote_account, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CloseVoteAccount {
|
|
|
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 1,
|
|
|
|
memo: None,
|
2021-12-06 14:54:50 -08:00
|
|
|
fee_payer: 0,
|
2022-08-02 20:23:05 -07:00
|
|
|
compute_unit_price: None,
|
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&withdraw_authority_file).unwrap().into()
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test CloseVoteAccount subcommand with authority w/ ComputeUnitPrice
|
|
|
|
let withdraw_authority = Keypair::new();
|
|
|
|
let (withdraw_authority_file, mut tmp_file) = make_tmp_file();
|
|
|
|
write_keypair(&withdraw_authority, tmp_file.as_file_mut()).unwrap();
|
|
|
|
let test_close_vote_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"close-vote-account",
|
|
|
|
&keypair_file,
|
|
|
|
&pubkey_string,
|
|
|
|
"--authorized-withdrawer",
|
|
|
|
&withdraw_authority_file,
|
|
|
|
"--with-compute-unit-price",
|
|
|
|
"99",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_command(&test_close_vote_account, &default_signer, &mut None).unwrap(),
|
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CloseVoteAccount {
|
|
|
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
|
|
|
destination_account_pubkey: pubkey,
|
|
|
|
withdraw_authority: 1,
|
|
|
|
memo: None,
|
|
|
|
fee_payer: 0,
|
|
|
|
compute_unit_price: Some(99),
|
2021-09-13 08:13:59 -07:00
|
|
|
},
|
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&withdraw_authority_file).unwrap().into()
|
|
|
|
],
|
|
|
|
}
|
|
|
|
);
|
2019-09-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
}
|