2019-12-27 14:35:49 -06:00
|
|
|
use crate::{
|
|
|
|
cli::{
|
2020-02-07 09:14:27 -07:00
|
|
|
build_balance_message, check_account_for_fee, check_unique_pubkeys, fee_payer_arg,
|
2020-02-24 17:03:30 -07:00
|
|
|
generate_unique_signers, log_instruction_custom_error, nonce_authority_arg, return_signers,
|
|
|
|
CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult, SignerIndex, FEE_PAYER_ARG,
|
2019-12-27 14:35:49 -06:00
|
|
|
},
|
2020-01-22 12:19:07 -07:00
|
|
|
nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG},
|
2020-03-11 12:14:15 -06:00
|
|
|
offline::{blockhash_query::BlockhashQuery, *},
|
2019-09-29 21:18:15 -07:00
|
|
|
};
|
2020-03-02 12:28:43 -08:00
|
|
|
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
|
|
|
|
use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand};
|
2019-10-25 12:20:08 -04:00
|
|
|
use console::style;
|
2020-02-21 14:55:53 -07:00
|
|
|
use solana_clap_utils::{input_parsers::*, input_validators::*, offline::*, ArgConstant};
|
2019-09-29 21:18:15 -07:00
|
|
|
use solana_client::rpc_client::RpcClient;
|
2020-02-24 17:03:30 -07:00
|
|
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
2019-09-29 21:18:15 -07:00
|
|
|
use solana_sdk::{
|
2020-01-22 17:54:06 -08:00
|
|
|
account_utils::StateMut,
|
2020-02-21 14:55:53 -07:00
|
|
|
message::Message,
|
2019-10-25 12:20:08 -04:00
|
|
|
pubkey::Pubkey,
|
2020-01-09 15:22:48 -08:00
|
|
|
system_instruction::{create_address_with_seed, SystemError},
|
2019-11-04 12:31:24 -08:00
|
|
|
sysvar::{
|
|
|
|
stake_history::{self, StakeHistory},
|
|
|
|
Sysvar,
|
|
|
|
},
|
2019-09-29 21:18:15 -07:00
|
|
|
transaction::Transaction,
|
|
|
|
};
|
2019-11-20 10:12:43 -08:00
|
|
|
use solana_stake_program::{
|
2020-03-02 12:28:43 -08:00
|
|
|
stake_instruction::{self, LockupArgs, StakeError},
|
2020-01-17 12:10:52 -07:00
|
|
|
stake_state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState},
|
2019-09-29 21:18:15 -07:00
|
|
|
};
|
2019-11-20 10:12:43 -08:00
|
|
|
use solana_vote_program::vote_state::VoteState;
|
2020-02-24 17:03:30 -07:00
|
|
|
use std::{ops::Deref, sync::Arc};
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2020-01-15 14:32:06 -07:00
|
|
|
pub const STAKE_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant {
|
|
|
|
name: "stake_authority",
|
|
|
|
long: "stake-authority",
|
2020-03-13 16:30:04 -04:00
|
|
|
help: "Authorized staker [default: cli config keypair]",
|
2020-01-15 14:32:06 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
pub const WITHDRAW_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant {
|
|
|
|
name: "withdraw_authority",
|
|
|
|
long: "withdraw-authority",
|
2020-03-13 16:30:04 -04:00
|
|
|
help: "Authorized withdrawer [default: cli config keypair]",
|
2020-01-15 14:32:06 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
fn stake_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
|
|
|
|
Arg::with_name(STAKE_AUTHORITY_ARG.name)
|
|
|
|
.long(STAKE_AUTHORITY_ARG.long)
|
|
|
|
.takes_value(true)
|
2020-02-21 14:55:53 -07:00
|
|
|
.value_name("KEYPAIR or PUBKEY or REMOTE WALLET PATH")
|
|
|
|
.validator(is_valid_signer)
|
2020-01-15 14:32:06 -07:00
|
|
|
.help(STAKE_AUTHORITY_ARG.help)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn withdraw_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
|
|
|
|
Arg::with_name(WITHDRAW_AUTHORITY_ARG.name)
|
|
|
|
.long(WITHDRAW_AUTHORITY_ARG.long)
|
|
|
|
.takes_value(true)
|
2020-02-21 14:55:53 -07:00
|
|
|
.value_name("KEYPAIR or PUBKEY or REMOTE WALLET PATH")
|
|
|
|
.validator(is_valid_signer)
|
2020-01-15 14:32:06 -07:00
|
|
|
.help(WITHDRAW_AUTHORITY_ARG.help)
|
|
|
|
}
|
|
|
|
|
2019-09-29 21:18:15 -07:00
|
|
|
pub trait StakeSubCommands {
|
|
|
|
fn stake_subcommands(self) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StakeSubCommands for App<'_, '_> {
|
|
|
|
fn stake_subcommands(self) -> Self {
|
|
|
|
self.subcommand(
|
|
|
|
SubCommand::with_name("create-stake-account")
|
|
|
|
.about("Create a stake account")
|
|
|
|
.arg(
|
2019-11-06 20:17:34 +05:30
|
|
|
Arg::with_name("stake_account")
|
2019-09-29 21:18:15 -07:00
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
2020-02-21 14:55:53 -07:00
|
|
|
.validator(is_valid_signer)
|
2020-02-12 23:00:28 -07:00
|
|
|
.help("Signing authority of the stake address to fund")
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("amount")
|
|
|
|
.index(2)
|
|
|
|
.value_name("AMOUNT")
|
|
|
|
.takes_value(true)
|
2019-12-10 11:29:17 -07:00
|
|
|
.validator(is_amount)
|
2019-09-29 21:18:15 -07:00
|
|
|
.required(true)
|
2020-03-09 11:12:42 -06:00
|
|
|
.help("The amount to send to the stake account, in SOL")
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("custodian")
|
|
|
|
.long("custodian")
|
2020-02-12 16:36:29 -07:00
|
|
|
.value_name("KEYPAIR or PUBKEY")
|
2019-09-29 21:18:15 -07:00
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Identity of the custodian (can withdraw before lockup expires)")
|
|
|
|
)
|
2020-01-09 15:22:48 -08:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("seed")
|
|
|
|
.long("seed")
|
|
|
|
.value_name("SEED STRING")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the STAKE ACCOUNT pubkey")
|
|
|
|
)
|
2019-09-29 21:18:15 -07:00
|
|
|
.arg(
|
2019-12-19 14:37:47 -08:00
|
|
|
Arg::with_name("lockup_epoch")
|
|
|
|
.long("lockup-epoch")
|
|
|
|
.value_name("EPOCH")
|
2019-09-29 21:18:15 -07:00
|
|
|
.takes_value(true)
|
2019-12-19 14:37:47 -08:00
|
|
|
.help("The epoch height at which this account will be available for withdrawal")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("lockup_date")
|
|
|
|
.long("lockup-date")
|
|
|
|
.value_name("RFC3339 DATE TIME")
|
2019-12-30 22:57:47 -07:00
|
|
|
.validator(is_rfc3339_datetime)
|
2019-12-19 14:37:47 -08:00
|
|
|
.takes_value(true)
|
|
|
|
.help("The date and time at which this account will be available for withdrawal")
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-01-15 14:32:06 -07:00
|
|
|
Arg::with_name(STAKE_AUTHORITY_ARG.name)
|
|
|
|
.long(STAKE_AUTHORITY_ARG.long)
|
2019-09-29 21:18:15 -07:00
|
|
|
.value_name("PUBKEY")
|
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
2020-01-15 14:32:06 -07:00
|
|
|
.help(STAKE_AUTHORITY_ARG.help)
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.arg(
|
2020-01-15 14:32:06 -07:00
|
|
|
Arg::with_name(WITHDRAW_AUTHORITY_ARG.name)
|
|
|
|
.long(WITHDRAW_AUTHORITY_ARG.long)
|
2019-09-29 21:18:15 -07:00
|
|
|
.value_name("PUBKEY")
|
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
2020-01-15 14:32:06 -07:00
|
|
|
.help(WITHDRAW_AUTHORITY_ARG.help)
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
2020-02-12 23:00:28 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("from")
|
|
|
|
.long("from")
|
|
|
|
.takes_value(true)
|
2020-02-21 14:55:53 -07:00
|
|
|
.value_name("KEYPAIR or PUBKEY or REMOTE WALLET PATH")
|
|
|
|
.validator(is_valid_signer)
|
2020-02-12 23:00:28 -07:00
|
|
|
.help("Source account of funds (if different from client local account)"),
|
|
|
|
)
|
|
|
|
.offline_args()
|
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
|
|
|
.arg(fee_payer_arg())
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("delegate-stake")
|
|
|
|
.about("Delegate stake to a vote account")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("force")
|
|
|
|
.long("force")
|
|
|
|
.takes_value(false)
|
|
|
|
.hidden(true) // Don't document this argument to discourage its use
|
|
|
|
.help("Override vote account sanity checks (use carefully!)")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Stake account to delegate")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("vote_account_pubkey")
|
|
|
|
.index(2)
|
|
|
|
.value_name("VOTE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("The vote account to which the stake will be delegated")
|
|
|
|
)
|
2020-01-15 14:32:06 -07:00
|
|
|
.arg(stake_authority_arg())
|
2020-01-26 01:27:24 -07:00
|
|
|
.offline_args()
|
2020-01-22 12:19:07 -07:00
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
2020-02-07 09:14:27 -07:00
|
|
|
.arg(fee_payer_arg())
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("stake-authorize-staker")
|
|
|
|
.about("Authorize a new stake signing keypair for the given stake account")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Stake account in which to set the authorized staker")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("authorized_pubkey")
|
|
|
|
.index(2)
|
|
|
|
.value_name("AUTHORIZE PUBKEY")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("New authorized staker")
|
|
|
|
)
|
2020-01-15 14:32:06 -07:00
|
|
|
.arg(stake_authority_arg())
|
2020-01-26 01:27:24 -07:00
|
|
|
.offline_args()
|
2020-01-22 12:19:07 -07:00
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
2020-02-07 09:14:27 -07:00
|
|
|
.arg(fee_payer_arg())
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("stake-authorize-withdrawer")
|
|
|
|
.about("Authorize a new withdraw signing keypair for the given stake account")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Stake account in which to set the authorized withdrawer")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("authorized_pubkey")
|
|
|
|
.index(2)
|
|
|
|
.value_name("AUTHORIZE PUBKEY")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("New authorized withdrawer")
|
|
|
|
)
|
2020-01-15 14:32:06 -07:00
|
|
|
.arg(withdraw_authority_arg())
|
2020-01-26 01:27:24 -07:00
|
|
|
.offline_args()
|
2020-01-22 12:19:07 -07:00
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
2020-02-07 09:14:27 -07:00
|
|
|
.arg(fee_payer_arg())
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("deactivate-stake")
|
|
|
|
.about("Deactivate the delegated stake from the stake account")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.help("Stake account to be deactivated.")
|
|
|
|
)
|
2020-01-15 14:32:06 -07:00
|
|
|
.arg(stake_authority_arg())
|
2020-01-26 01:27:24 -07:00
|
|
|
.offline_args()
|
2020-01-22 12:19:07 -07:00
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
2020-02-07 09:14:27 -07:00
|
|
|
.arg(fee_payer_arg())
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
2020-02-02 22:20:28 -07:00
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("split-stake")
|
|
|
|
.about("Split a stake account")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.help("Stake account to be split")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("split_stake_account")
|
|
|
|
.index(2)
|
|
|
|
.value_name("SPLIT STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
2020-03-13 17:06:33 -06:00
|
|
|
.validator(is_valid_signer)
|
2020-02-02 22:20:28 -07:00
|
|
|
.help("Keypair of the new stake account to split funds into")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("amount")
|
|
|
|
.index(3)
|
|
|
|
.value_name("AMOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_amount)
|
|
|
|
.required(true)
|
2020-03-13 16:30:04 -04:00
|
|
|
.help("The amount to move into the new stake account, in SOL")
|
2020-02-02 22:20:28 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("seed")
|
|
|
|
.long("seed")
|
|
|
|
.value_name("SEED STRING")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the SPLIT STAKE ACCOUNT pubkey")
|
|
|
|
)
|
|
|
|
.arg(stake_authority_arg())
|
|
|
|
.offline_args()
|
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
2020-02-11 00:23:54 -07:00
|
|
|
.arg(fee_payer_arg())
|
2020-02-02 22:20:28 -07:00
|
|
|
)
|
2019-09-29 21:18:15 -07:00
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("withdraw-stake")
|
2020-03-13 16:30:04 -04:00
|
|
|
.about("Withdraw the unstaked SOL from the stake account")
|
2019-09-29 21:18:15 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Stake account from which to withdraw")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("destination_account_pubkey")
|
|
|
|
.index(2)
|
|
|
|
.value_name("DESTINATION ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
2020-03-13 16:30:04 -04:00
|
|
|
.help("The account to which the SOL should be transferred")
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("amount")
|
|
|
|
.index(3)
|
|
|
|
.value_name("AMOUNT")
|
|
|
|
.takes_value(true)
|
2019-12-10 11:29:17 -07:00
|
|
|
.validator(is_amount)
|
2019-09-29 21:18:15 -07:00
|
|
|
.required(true)
|
2020-02-15 12:53:52 -07:00
|
|
|
.help("The amount to withdraw from the stake account, in SOL")
|
2019-09-29 21:18:15 -07:00
|
|
|
)
|
2020-01-15 14:32:06 -07:00
|
|
|
.arg(withdraw_authority_arg())
|
2020-02-12 23:00:28 -07:00
|
|
|
.offline_args()
|
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
|
|
|
.arg(fee_payer_arg())
|
2020-02-12 16:36:29 -07:00
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("stake-set-lockup")
|
|
|
|
.about("Set Lockup for the stake account")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Stake account for which to set Lockup")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("lockup_epoch")
|
|
|
|
.long("lockup-epoch")
|
|
|
|
.value_name("EPOCH")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("The epoch height at which this account will be available for withdrawal")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("lockup_date")
|
|
|
|
.long("lockup-date")
|
|
|
|
.value_name("RFC3339 DATE TIME")
|
|
|
|
.validator(is_rfc3339_datetime)
|
|
|
|
.takes_value(true)
|
|
|
|
.help("The date and time at which this account will be available for withdrawal")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("new_custodian")
|
|
|
|
.long("new-custodian")
|
|
|
|
.value_name("KEYPAIR or PUBKEY")
|
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Identity of the new lockup custodian (can withdraw before lockup expires)")
|
|
|
|
)
|
2020-03-02 12:28:43 -08:00
|
|
|
.group(ArgGroup::with_name("lockup_details")
|
|
|
|
.args(&["lockup_epoch", "lockup_date", "new_custodian"])
|
|
|
|
.required(true))
|
2020-02-12 16:36:29 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("custodian")
|
|
|
|
.long("custodian")
|
|
|
|
.takes_value(true)
|
2020-02-21 14:55:53 -07:00
|
|
|
.value_name("KEYPAIR or PUBKEY or REMOTE WALLET PATH")
|
|
|
|
.validator(is_valid_signer)
|
2020-03-13 16:30:04 -04:00
|
|
|
.help("Public key of signing custodian [default: cli config pubkey]")
|
2020-02-12 16:36:29 -07:00
|
|
|
)
|
|
|
|
.offline_args()
|
|
|
|
.arg(nonce_arg())
|
|
|
|
.arg(nonce_authority_arg())
|
|
|
|
.arg(fee_payer_arg())
|
|
|
|
)
|
2019-09-29 21:18:15 -07:00
|
|
|
.subcommand(
|
2020-01-31 09:52:36 -07:00
|
|
|
SubCommand::with_name("stake-account")
|
2019-09-29 21:18:15 -07:00
|
|
|
.about("Show the contents of a stake account")
|
2020-01-20 23:06:47 -07:00
|
|
|
.alias("show-stake-account")
|
2019-09-29 21:18:15 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("stake_account_pubkey")
|
|
|
|
.index(1)
|
|
|
|
.value_name("STAKE ACCOUNT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(true)
|
|
|
|
.validator(is_pubkey_or_keypair)
|
|
|
|
.help("Address of the stake account to display")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("lamports")
|
|
|
|
.long("lamports")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Display balance in lamports instead of SOL")
|
|
|
|
)
|
|
|
|
)
|
2019-10-25 12:20:08 -04:00
|
|
|
.subcommand(
|
2020-01-20 23:06:47 -07:00
|
|
|
SubCommand::with_name("stake-history")
|
2019-10-25 12:20:08 -04:00
|
|
|
.about("Show the stake history")
|
2020-01-20 23:06:47 -07:00
|
|
|
.alias("show-stake-history")
|
2019-10-25 12:20:08 -04:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("lamports")
|
|
|
|
.long("lamports")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Display balance in lamports instead of SOL")
|
|
|
|
)
|
|
|
|
)
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
pub fn parse_stake_create_account(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
default_signer_path: &str,
|
|
|
|
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-01-09 15:22:48 -08:00
|
|
|
let seed = matches.value_of("seed").map(|s| s.to_string());
|
2020-02-24 17:03:30 -07:00
|
|
|
let epoch = value_of(matches, "lockup_epoch").unwrap_or(0);
|
|
|
|
let unix_timestamp = unix_timestamp_from_rfc3339_datetime(matches, "lockup_date").unwrap_or(0);
|
2019-09-29 21:18:15 -07:00
|
|
|
let custodian = pubkey_of(matches, "custodian").unwrap_or_default();
|
2020-01-15 14:32:06 -07:00
|
|
|
let staker = pubkey_of(matches, STAKE_AUTHORITY_ARG.name);
|
|
|
|
let withdrawer = pubkey_of(matches, WITHDRAW_AUTHORITY_ARG.name);
|
2020-02-15 12:53:52 -07:00
|
|
|
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
2020-02-12 23:00:28 -07:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
|
|
|
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)?;
|
|
|
|
let (from, from_pubkey) = signer_of(matches, "from", wallet_manager)?;
|
|
|
|
let (stake_account, stake_account_pubkey) =
|
|
|
|
signer_of(matches, "stake_account", wallet_manager)?;
|
|
|
|
|
|
|
|
let mut bulk_signers = vec![fee_payer, from, stake_account];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2019-10-21 17:08:09 -06:00
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::CreateStakeAccount {
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_account: signer_info.index_of(stake_account_pubkey).unwrap(),
|
2020-01-09 15:22:48 -08:00
|
|
|
seed,
|
2019-10-21 17:08:09 -06:00
|
|
|
staker,
|
|
|
|
withdrawer,
|
2019-12-19 14:37:47 -08:00
|
|
|
lockup: Lockup {
|
|
|
|
custodian,
|
|
|
|
epoch,
|
|
|
|
unix_timestamp,
|
|
|
|
},
|
2019-10-21 17:08:09 -06:00
|
|
|
lamports,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
|
|
|
from: signer_info.index_of(from_pubkey).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: signer_info.signers,
|
2019-10-21 17:08:09 -06:00
|
|
|
})
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
pub fn parse_stake_delegate_stake(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
default_signer_path: &str,
|
|
|
|
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2019-09-29 21:18:15 -07:00
|
|
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
|
|
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
|
|
|
let force = matches.is_present("force");
|
2020-01-26 01:27:24 -07:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
2020-01-30 09:21:32 -07:00
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
|
|
|
let (stake_authority, stake_authority_pubkey) =
|
|
|
|
signer_of(matches, STAKE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
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)?;
|
|
|
|
|
|
|
|
let mut bulk_signers = vec![stake_authority, fee_payer];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2019-10-21 17:08:09 -06:00
|
|
|
Ok(CliCommandInfo {
|
2019-11-25 21:09:57 -08:00
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: signer_info.index_of(stake_authority_pubkey).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
force,
|
|
|
|
sign_only,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query,
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: signer_info.signers,
|
2019-10-21 17:08:09 -06:00
|
|
|
})
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parse_stake_authorize(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-02-24 17:03:30 -07:00
|
|
|
default_signer_path: &str,
|
|
|
|
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
2019-09-29 21:18:15 -07:00
|
|
|
stake_authorize: StakeAuthorize,
|
2019-10-21 17:08:09 -06:00
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2019-09-29 21:18:15 -07:00
|
|
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
2020-01-15 14:32:06 -07:00
|
|
|
let new_authorized_pubkey = pubkey_of(matches, "authorized_pubkey").unwrap();
|
|
|
|
let authority_flag = match stake_authorize {
|
|
|
|
StakeAuthorize::Staker => STAKE_AUTHORITY_ARG.name,
|
|
|
|
StakeAuthorize::Withdrawer => WITHDRAW_AUTHORITY_ARG.name,
|
|
|
|
};
|
2020-01-26 01:27:24 -07:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
2020-02-24 17:03:30 -07:00
|
|
|
let (authority, authority_pubkey) = signer_of(matches, authority_flag, wallet_manager)?;
|
2020-01-30 09:21:32 -07:00
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
|
|
|
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)?;
|
|
|
|
|
|
|
|
let mut bulk_signers = vec![authority, fee_payer];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2019-10-21 17:08:09 -06:00
|
|
|
Ok(CliCommandInfo {
|
2020-01-15 14:32:06 -07:00
|
|
|
command: CliCommand::StakeAuthorize {
|
2019-10-21 17:08:09 -06:00
|
|
|
stake_account_pubkey,
|
2020-01-15 14:32:06 -07:00
|
|
|
new_authorized_pubkey,
|
2019-10-21 17:08:09 -06:00
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: signer_info.index_of(authority_pubkey).unwrap(),
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query,
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: signer_info.signers,
|
2019-10-21 17:08:09 -06:00
|
|
|
})
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
pub fn parse_split_stake(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
default_signer_path: &str,
|
|
|
|
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-02-02 22:20:28 -07:00
|
|
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
2020-02-24 17:03:30 -07:00
|
|
|
let (split_stake_account, split_stake_account_pubkey) =
|
|
|
|
signer_of(matches, "split_stake_account", wallet_manager)?;
|
2020-02-15 12:53:52 -07:00
|
|
|
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
2020-02-02 22:20:28 -07:00
|
|
|
let seed = matches.value_of("seed").map(|s| s.to_string());
|
|
|
|
|
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
|
|
|
let (stake_authority, stake_authority_pubkey) =
|
|
|
|
signer_of(matches, STAKE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
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)?;
|
|
|
|
|
|
|
|
let mut bulk_signers = vec![stake_authority, fee_payer, split_stake_account];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
|
2020-02-02 22:20:28 -07:00
|
|
|
|
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::SplitStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: signer_info.index_of(stake_authority_pubkey).unwrap(),
|
2020-02-02 22:20:28 -07:00
|
|
|
sign_only,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
|
|
|
split_stake_account: signer_info.index_of(split_stake_account_pubkey).unwrap(),
|
2020-02-02 22:20:28 -07:00
|
|
|
seed,
|
|
|
|
lamports,
|
2020-02-24 17:03:30 -07:00
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2020-02-02 22:20:28 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: signer_info.signers,
|
2020-02-02 22:20:28 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
pub fn parse_stake_deactivate_stake(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
default_signer_path: &str,
|
|
|
|
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2019-09-29 21:18:15 -07:00
|
|
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
2020-01-26 01:27:24 -07:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
2020-01-30 09:21:32 -07:00
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
|
|
|
let (stake_authority, stake_authority_pubkey) =
|
|
|
|
signer_of(matches, STAKE_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
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)?;
|
|
|
|
|
|
|
|
let mut bulk_signers = vec![stake_authority, fee_payer];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
|
2019-12-09 23:11:04 -08:00
|
|
|
|
2019-10-21 17:08:09 -06:00
|
|
|
Ok(CliCommandInfo {
|
2019-11-25 21:09:57 -08:00
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: signer_info.index_of(stake_authority_pubkey).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query,
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: signer_info.signers,
|
2019-10-21 17:08:09 -06:00
|
|
|
})
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
pub fn parse_stake_withdraw_stake(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
default_signer_path: &str,
|
|
|
|
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2019-09-29 21:18:15 -07:00
|
|
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
|
|
|
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
|
2020-02-15 12:53:52 -07:00
|
|
|
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
2020-02-12 23:00:28 -07:00
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
|
|
|
let (withdraw_authority, withdraw_authority_pubkey) =
|
|
|
|
signer_of(matches, WITHDRAW_AUTHORITY_ARG.name, wallet_manager)?;
|
|
|
|
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)?;
|
|
|
|
|
|
|
|
let mut bulk_signers = vec![withdraw_authority, fee_payer];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2019-10-21 17:08:09 -06:00
|
|
|
Ok(CliCommandInfo {
|
2020-01-15 14:32:06 -07:00
|
|
|
command: CliCommand::WithdrawStake {
|
2019-10-21 17:08:09 -06:00
|
|
|
stake_account_pubkey,
|
|
|
|
destination_account_pubkey,
|
|
|
|
lamports,
|
2020-02-24 17:03:30 -07:00
|
|
|
withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(),
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: signer_info.signers,
|
2019-10-21 17:08:09 -06:00
|
|
|
})
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
pub fn parse_stake_set_lockup(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
default_signer_path: &str,
|
|
|
|
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<CliCommandInfo, CliError> {
|
2020-02-12 16:36:29 -07:00
|
|
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
2020-03-02 12:28:43 -08:00
|
|
|
let epoch = value_of(matches, "lockup_epoch");
|
|
|
|
let unix_timestamp = unix_timestamp_from_rfc3339_datetime(matches, "lockup_date");
|
|
|
|
let new_custodian = pubkey_of(matches, "new_custodian");
|
2020-02-12 16:36:29 -07:00
|
|
|
|
|
|
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
|
|
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
|
2020-02-12 16:36:29 -07:00
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
let (custodian, custodian_pubkey) = signer_of(matches, "custodian", wallet_manager)?;
|
|
|
|
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)?;
|
|
|
|
|
|
|
|
let mut bulk_signers = vec![custodian, fee_payer];
|
|
|
|
if nonce_account.is_some() {
|
|
|
|
bulk_signers.push(nonce_authority);
|
|
|
|
}
|
|
|
|
let signer_info =
|
|
|
|
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
|
2020-02-12 16:36:29 -07:00
|
|
|
|
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::StakeSetLockup {
|
|
|
|
stake_account_pubkey,
|
2020-03-02 12:28:43 -08:00
|
|
|
lockup: LockupArgs {
|
2020-02-12 16:36:29 -07:00
|
|
|
custodian: new_custodian,
|
|
|
|
epoch,
|
|
|
|
unix_timestamp,
|
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
custodian: signer_info.index_of(custodian_pubkey).unwrap(),
|
2020-02-12 16:36:29 -07:00
|
|
|
sign_only,
|
|
|
|
blockhash_query,
|
|
|
|
nonce_account,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
|
|
|
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
2020-02-12 16:36:29 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: signer_info.signers,
|
2020-02-12 16:36:29 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-10-21 17:08:09 -06:00
|
|
|
pub fn parse_show_stake_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
2019-09-29 21:18:15 -07:00
|
|
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
|
|
|
let use_lamports_unit = matches.is_present("lamports");
|
2019-10-21 17:08:09 -06:00
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::ShowStakeAccount {
|
|
|
|
pubkey: stake_account_pubkey,
|
|
|
|
use_lamports_unit,
|
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![],
|
2019-09-29 21:18:15 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-10-25 12:20:08 -04:00
|
|
|
pub fn parse_show_stake_history(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
|
|
|
let use_lamports_unit = matches.is_present("lamports");
|
|
|
|
Ok(CliCommandInfo {
|
|
|
|
command: CliCommand::ShowStakeHistory { use_lamports_unit },
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![],
|
2019-10-25 12:20:08 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-09-29 21:18:15 -07:00
|
|
|
pub fn process_create_stake_account(
|
|
|
|
rpc_client: &RpcClient,
|
2019-10-04 16:13:21 -06:00
|
|
|
config: &CliConfig,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_account: SignerIndex,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: &Option<String>,
|
2019-10-21 17:08:09 -06:00
|
|
|
staker: &Option<Pubkey>,
|
|
|
|
withdrawer: &Option<Pubkey>,
|
2019-09-29 21:18:15 -07:00
|
|
|
lockup: &Lockup,
|
|
|
|
lamports: u64,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<&Pubkey>,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: SignerIndex,
|
|
|
|
fee_payer: SignerIndex,
|
|
|
|
from: SignerIndex,
|
2019-09-29 21:18:15 -07:00
|
|
|
) -> ProcessResult {
|
2020-02-24 17:03:30 -07:00
|
|
|
let stake_account = config.signers[stake_account];
|
2020-01-09 15:22:48 -08:00
|
|
|
let stake_account_address = if let Some(seed) = seed {
|
2020-02-21 14:55:53 -07:00
|
|
|
create_address_with_seed(&stake_account.pubkey(), &seed, &solana_stake_program::id())?
|
2020-01-09 15:22:48 -08:00
|
|
|
} else {
|
2020-02-21 14:55:53 -07:00
|
|
|
stake_account.pubkey()
|
2020-01-09 15:22:48 -08:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let from = config.signers[from];
|
2019-09-29 21:18:15 -07:00
|
|
|
check_unique_pubkeys(
|
2020-02-21 14:55:53 -07:00
|
|
|
(&from.pubkey(), "from keypair".to_string()),
|
2020-01-09 15:22:48 -08:00
|
|
|
(&stake_account_address, "stake_account".to_string()),
|
2019-09-29 21:18:15 -07:00
|
|
|
)?;
|
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
if !sign_only {
|
|
|
|
if let Ok(stake_account) = rpc_client.get_account(&stake_account_address) {
|
|
|
|
let err_msg = if stake_account.owner == solana_stake_program::id() {
|
|
|
|
format!("Stake account {} already exists", stake_account_address)
|
|
|
|
} else {
|
|
|
|
format!(
|
|
|
|
"Account {} already exists and is not a stake account",
|
|
|
|
stake_account_address
|
|
|
|
)
|
|
|
|
};
|
|
|
|
return Err(CliError::BadParameter(err_msg).into());
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
let minimum_balance =
|
|
|
|
rpc_client.get_minimum_balance_for_rent_exemption(std::mem::size_of::<StakeState>())?;
|
2019-10-01 01:14:49 +05:30
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
if lamports < minimum_balance {
|
|
|
|
return Err(CliError::BadParameter(format!(
|
|
|
|
"need at least {} lamports for stake account to be rent exempt, provided lamports: {}",
|
|
|
|
minimum_balance, lamports
|
|
|
|
))
|
|
|
|
.into());
|
|
|
|
}
|
2019-10-01 01:14:49 +05:30
|
|
|
}
|
|
|
|
|
2019-10-21 17:08:09 -06:00
|
|
|
let authorized = Authorized {
|
2020-02-21 14:55:53 -07:00
|
|
|
staker: staker.unwrap_or(from.pubkey()),
|
|
|
|
withdrawer: withdrawer.unwrap_or(from.pubkey()),
|
2019-10-21 17:08:09 -06:00
|
|
|
};
|
|
|
|
|
2020-01-09 15:22:48 -08:00
|
|
|
let ixs = if let Some(seed) = seed {
|
|
|
|
stake_instruction::create_account_with_seed(
|
2020-02-12 23:00:28 -07:00
|
|
|
&from.pubkey(), // from
|
|
|
|
&stake_account_address, // to
|
|
|
|
&stake_account.pubkey(), // base
|
|
|
|
seed, // seed
|
2020-01-09 15:22:48 -08:00
|
|
|
&authorized,
|
|
|
|
lockup,
|
|
|
|
lamports,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
stake_instruction::create_account(
|
2020-02-12 23:00:28 -07:00
|
|
|
&from.pubkey(),
|
|
|
|
&stake_account.pubkey(),
|
2020-01-09 15:22:48 -08:00
|
|
|
&authorized,
|
|
|
|
lockup,
|
|
|
|
lamports,
|
|
|
|
)
|
|
|
|
};
|
2020-02-12 23:00:28 -07:00
|
|
|
let (recent_blockhash, fee_calculator) =
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?;
|
2020-01-09 15:22:48 -08:00
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
let fee_payer = config.signers[fee_payer];
|
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
2020-01-09 15:22:48 -08:00
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
let message = if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
2020-02-12 23:00:28 -07:00
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
)
|
2020-02-12 23:00:28 -07:00
|
|
|
} else {
|
2020-03-11 14:37:23 -07:00
|
|
|
Message::new_with_payer(&ixs, Some(&fee_payer.pubkey()))
|
2020-02-12 23:00:28 -07:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
if sign_only {
|
|
|
|
return_signers(&tx)
|
|
|
|
} else {
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
2020-02-21 14:55:53 -07:00
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
2020-02-12 23:00:28 -07:00
|
|
|
}
|
|
|
|
check_account_for_fee(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&fee_calculator,
|
|
|
|
&tx.message,
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
2020-02-12 23:00:28 -07:00
|
|
|
log_instruction_custom_error::<SystemError>(result)
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-01-17 10:30:56 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-09-29 21:18:15 -07:00
|
|
|
pub fn process_stake_authorize(
|
|
|
|
rpc_client: &RpcClient,
|
2019-10-04 16:13:21 -06:00
|
|
|
config: &CliConfig,
|
2019-09-29 21:18:15 -07:00
|
|
|
stake_account_pubkey: &Pubkey,
|
|
|
|
authorized_pubkey: &Pubkey,
|
|
|
|
stake_authorize: StakeAuthorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: SignerIndex,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: bool,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: &BlockhashQuery,
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account: Option<Pubkey>,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: SignerIndex,
|
|
|
|
fee_payer: SignerIndex,
|
2019-09-29 21:18:15 -07:00
|
|
|
) -> ProcessResult {
|
|
|
|
check_unique_pubkeys(
|
|
|
|
(stake_account_pubkey, "stake_account_pubkey".to_string()),
|
|
|
|
(authorized_pubkey, "new_authorized_pubkey".to_string()),
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let authority = config.signers[authority];
|
2020-01-17 10:30:56 -07:00
|
|
|
let (recent_blockhash, fee_calculator) =
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?;
|
2019-09-29 21:18:15 -07:00
|
|
|
let ixs = vec![stake_instruction::authorize(
|
2020-01-15 14:32:06 -07:00
|
|
|
stake_account_pubkey, // stake account to update
|
|
|
|
&authority.pubkey(), // currently authorized
|
|
|
|
authorized_pubkey, // new stake signer
|
|
|
|
stake_authorize, // stake or withdraw
|
2019-09-29 21:18:15 -07:00
|
|
|
)];
|
|
|
|
|
2020-02-24 17:03:30 -07: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(
|
2020-01-17 10:30:56 -07:00
|
|
|
ixs,
|
2020-02-07 09:14:27 -07:00
|
|
|
Some(&fee_payer.pubkey()),
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
)
|
2020-01-17 10:30:56 -07:00
|
|
|
} else {
|
2020-03-11 14:37:23 -07:00
|
|
|
Message::new_with_payer(&ixs, Some(&fee_payer.pubkey()))
|
2020-01-17 10:30:56 -07:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
|
2020-01-17 10:30:56 -07:00
|
|
|
if sign_only {
|
|
|
|
return_signers(&tx)
|
|
|
|
} else {
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
2020-02-21 14:55:53 -07:00
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
2020-01-17 10:30:56 -07:00
|
|
|
}
|
|
|
|
check_account_for_fee(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&fee_calculator,
|
|
|
|
&tx.message,
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
2020-01-17 10:30:56 -07:00
|
|
|
log_instruction_custom_error::<StakeError>(result)
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-02-07 09:14:27 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-09-29 21:18:15 -07:00
|
|
|
pub fn process_deactivate_stake_account(
|
|
|
|
rpc_client: &RpcClient,
|
2019-10-04 16:13:21 -06:00
|
|
|
config: &CliConfig,
|
2019-09-29 21:18:15 -07:00
|
|
|
stake_account_pubkey: &Pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: SignerIndex,
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only: bool,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: &BlockhashQuery,
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: Option<Pubkey>,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: SignerIndex,
|
|
|
|
fee_payer: SignerIndex,
|
2019-09-29 21:18:15 -07:00
|
|
|
) -> ProcessResult {
|
2019-11-25 21:09:57 -08:00
|
|
|
let (recent_blockhash, fee_calculator) =
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let stake_authority = config.signers[stake_authority];
|
2019-09-29 21:18:15 -07:00
|
|
|
let ixs = vec![stake_instruction::deactivate_stake(
|
|
|
|
stake_account_pubkey,
|
2020-01-15 14:32:06 -07:00
|
|
|
&stake_authority.pubkey(),
|
2019-09-29 21:18:15 -07:00
|
|
|
)];
|
2020-02-24 17:03:30 -07: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(
|
2019-12-27 14:35:49 -06:00
|
|
|
ixs,
|
2020-02-07 09:14:27 -07:00
|
|
|
Some(&fee_payer.pubkey()),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
)
|
2019-12-27 14:35:49 -06:00
|
|
|
} else {
|
2020-03-11 14:37:23 -07:00
|
|
|
Message::new_with_payer(&ixs, Some(&fee_payer.pubkey()))
|
2019-12-27 14:35:49 -06:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
|
2019-11-25 21:09:57 -08:00
|
|
|
if sign_only {
|
|
|
|
return_signers(&tx)
|
|
|
|
} else {
|
2019-12-27 14:35:49 -06:00
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
2020-02-21 14:55:53 -07:00
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
2019-12-27 14:35:49 -06:00
|
|
|
}
|
2019-12-09 23:11:04 -08:00
|
|
|
check_account_for_fee(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&fee_calculator,
|
|
|
|
&tx.message,
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
2019-11-25 21:09:57 -08:00
|
|
|
log_instruction_custom_error::<StakeError>(result)
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-09-29 21:18:15 -07:00
|
|
|
pub fn process_withdraw_stake(
|
|
|
|
rpc_client: &RpcClient,
|
2019-10-04 16:13:21 -06:00
|
|
|
config: &CliConfig,
|
2019-09-29 21:18:15 -07:00
|
|
|
stake_account_pubkey: &Pubkey,
|
|
|
|
destination_account_pubkey: &Pubkey,
|
|
|
|
lamports: u64,
|
2020-02-24 17:03:30 -07:00
|
|
|
withdraw_authority: SignerIndex,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<&Pubkey>,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: SignerIndex,
|
|
|
|
fee_payer: SignerIndex,
|
2019-09-29 21:18:15 -07:00
|
|
|
) -> ProcessResult {
|
2020-02-12 23:00:28 -07:00
|
|
|
let (recent_blockhash, fee_calculator) =
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let withdraw_authority = config.signers[withdraw_authority];
|
2019-09-29 21:18:15 -07:00
|
|
|
|
|
|
|
let ixs = vec![stake_instruction::withdraw(
|
|
|
|
stake_account_pubkey,
|
2020-01-15 14:32:06 -07:00
|
|
|
&withdraw_authority.pubkey(),
|
2019-09-29 21:18:15 -07:00
|
|
|
destination_account_pubkey,
|
|
|
|
lamports,
|
|
|
|
)];
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
let fee_payer = config.signers[fee_payer];
|
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
|
|
|
|
|
|
|
let message = if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
2020-02-12 23:00:28 -07:00
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
)
|
2020-02-12 23:00:28 -07:00
|
|
|
} else {
|
2020-03-11 14:37:23 -07:00
|
|
|
Message::new_with_payer(&ixs, Some(&fee_payer.pubkey()))
|
2020-02-12 23:00:28 -07:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
if sign_only {
|
|
|
|
return_signers(&tx)
|
|
|
|
} else {
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
2020-02-21 14:55:53 -07:00
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
2020-02-12 23:00:28 -07:00
|
|
|
}
|
|
|
|
check_account_for_fee(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&fee_calculator,
|
|
|
|
&tx.message,
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
2020-02-12 23:00:28 -07:00
|
|
|
log_instruction_custom_error::<SystemError>(result)
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
2020-02-02 22:20:28 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
pub fn process_split_stake(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
config: &CliConfig,
|
|
|
|
stake_account_pubkey: &Pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: SignerIndex,
|
2020-02-02 22:20:28 -07:00
|
|
|
sign_only: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<Pubkey>,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: SignerIndex,
|
|
|
|
split_stake_account: SignerIndex,
|
2020-02-02 22:20:28 -07:00
|
|
|
split_stake_account_seed: &Option<String>,
|
|
|
|
lamports: u64,
|
2020-02-24 17:03:30 -07:00
|
|
|
fee_payer: SignerIndex,
|
2020-02-02 22:20:28 -07:00
|
|
|
) -> ProcessResult {
|
2020-02-24 17:03:30 -07:00
|
|
|
let split_stake_account = config.signers[split_stake_account];
|
|
|
|
let fee_payer = config.signers[fee_payer];
|
2020-03-10 14:30:30 -07:00
|
|
|
|
|
|
|
if split_stake_account_seed.is_none() {
|
|
|
|
check_unique_pubkeys(
|
|
|
|
(&fee_payer.pubkey(), "fee-payer keypair".to_string()),
|
|
|
|
(
|
|
|
|
&split_stake_account.pubkey(),
|
|
|
|
"split_stake_account".to_string(),
|
|
|
|
),
|
|
|
|
)?;
|
|
|
|
}
|
2020-02-02 22:20:28 -07:00
|
|
|
check_unique_pubkeys(
|
2020-02-21 14:55:53 -07:00
|
|
|
(&fee_payer.pubkey(), "fee-payer keypair".to_string()),
|
2020-02-02 22:20:28 -07:00
|
|
|
(&stake_account_pubkey, "stake_account".to_string()),
|
|
|
|
)?;
|
|
|
|
check_unique_pubkeys(
|
|
|
|
(&stake_account_pubkey, "stake_account".to_string()),
|
|
|
|
(
|
|
|
|
&split_stake_account.pubkey(),
|
|
|
|
"split_stake_account".to_string(),
|
|
|
|
),
|
|
|
|
)?;
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
let stake_authority = config.signers[stake_authority];
|
2020-02-02 22:20:28 -07:00
|
|
|
|
|
|
|
let split_stake_account_address = if let Some(seed) = split_stake_account_seed {
|
|
|
|
create_address_with_seed(
|
|
|
|
&split_stake_account.pubkey(),
|
|
|
|
&seed,
|
|
|
|
&solana_stake_program::id(),
|
|
|
|
)?
|
|
|
|
} else {
|
|
|
|
split_stake_account.pubkey()
|
|
|
|
};
|
|
|
|
|
2020-02-11 00:23:54 -07:00
|
|
|
if !sign_only {
|
|
|
|
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
|
|
|
|
let err_msg = if stake_account.owner == solana_stake_program::id() {
|
|
|
|
format!(
|
|
|
|
"Stake account {} already exists",
|
|
|
|
split_stake_account_address
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!(
|
|
|
|
"Account {} already exists and is not a stake account",
|
|
|
|
split_stake_account_address
|
|
|
|
)
|
|
|
|
};
|
|
|
|
return Err(CliError::BadParameter(err_msg).into());
|
|
|
|
}
|
2020-02-02 22:20:28 -07:00
|
|
|
|
2020-02-11 00:23:54 -07:00
|
|
|
let minimum_balance =
|
|
|
|
rpc_client.get_minimum_balance_for_rent_exemption(std::mem::size_of::<StakeState>())?;
|
2020-02-02 22:20:28 -07:00
|
|
|
|
2020-02-11 00:23:54 -07:00
|
|
|
if lamports < minimum_balance {
|
|
|
|
return Err(CliError::BadParameter(format!(
|
|
|
|
"need at least {} lamports for stake account to be rent exempt, provided lamports: {}",
|
|
|
|
minimum_balance, lamports
|
|
|
|
))
|
|
|
|
.into());
|
|
|
|
}
|
2020-02-02 22:20:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
let (recent_blockhash, fee_calculator) =
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?;
|
2020-02-02 22:20:28 -07:00
|
|
|
|
|
|
|
let ixs = if let Some(seed) = split_stake_account_seed {
|
|
|
|
stake_instruction::split_with_seed(
|
|
|
|
&stake_account_pubkey,
|
|
|
|
&stake_authority.pubkey(),
|
|
|
|
lamports,
|
|
|
|
&split_stake_account_address,
|
|
|
|
&split_stake_account.pubkey(),
|
|
|
|
seed,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
stake_instruction::split(
|
|
|
|
&stake_account_pubkey,
|
|
|
|
&stake_authority.pubkey(),
|
|
|
|
lamports,
|
|
|
|
&split_stake_account_address,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
let nonce_authority = config.signers[nonce_authority];
|
2020-02-02 22:20:28 -07:00
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
let message = if let Some(nonce_account) = &nonce_account {
|
|
|
|
Message::new_with_nonce(
|
2020-02-02 22:20:28 -07:00
|
|
|
ixs,
|
2020-02-11 00:23:54 -07:00
|
|
|
Some(&fee_payer.pubkey()),
|
2020-02-21 14:55:53 -07:00
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
)
|
2020-02-02 22:20:28 -07:00
|
|
|
} else {
|
2020-03-11 14:37:23 -07:00
|
|
|
Message::new_with_payer(&ixs, Some(&fee_payer.pubkey()))
|
2020-02-02 22:20:28 -07:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
|
2020-02-02 22:20:28 -07:00
|
|
|
if sign_only {
|
|
|
|
return_signers(&tx)
|
|
|
|
} else {
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
2020-02-21 14:55:53 -07:00
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
2020-02-02 22:20:28 -07:00
|
|
|
}
|
|
|
|
check_account_for_fee(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&fee_calculator,
|
|
|
|
&tx.message,
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
2020-02-02 22:20:28 -07:00
|
|
|
log_instruction_custom_error::<StakeError>(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 16:36:29 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
pub fn process_stake_set_lockup(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
config: &CliConfig,
|
|
|
|
stake_account_pubkey: &Pubkey,
|
2020-03-02 12:28:43 -08:00
|
|
|
lockup: &mut LockupArgs,
|
2020-02-24 17:03:30 -07:00
|
|
|
custodian: SignerIndex,
|
2020-02-12 16:36:29 -07:00
|
|
|
sign_only: bool,
|
|
|
|
blockhash_query: &BlockhashQuery,
|
|
|
|
nonce_account: Option<Pubkey>,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: SignerIndex,
|
|
|
|
fee_payer: SignerIndex,
|
2020-02-12 16:36:29 -07:00
|
|
|
) -> ProcessResult {
|
|
|
|
let (recent_blockhash, fee_calculator) =
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let custodian = config.signers[custodian];
|
2020-03-02 12:28:43 -08:00
|
|
|
|
2020-02-12 16:36:29 -07:00
|
|
|
let ixs = vec![stake_instruction::set_lockup(
|
|
|
|
stake_account_pubkey,
|
|
|
|
lockup,
|
|
|
|
&custodian.pubkey(),
|
|
|
|
)];
|
2020-02-24 17:03:30 -07: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(
|
2020-02-12 16:36:29 -07:00
|
|
|
ixs,
|
|
|
|
Some(&fee_payer.pubkey()),
|
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
)
|
2020-02-12 16:36:29 -07:00
|
|
|
} else {
|
2020-03-11 14:37:23 -07:00
|
|
|
Message::new_with_payer(&ixs, Some(&fee_payer.pubkey()))
|
2020-02-12 16:36:29 -07:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
|
2020-02-12 16:36:29 -07:00
|
|
|
if sign_only {
|
|
|
|
return_signers(&tx)
|
|
|
|
} else {
|
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
2020-02-21 14:55:53 -07:00
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
2020-02-12 16:36:29 -07:00
|
|
|
}
|
|
|
|
check_account_for_fee(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&fee_calculator,
|
|
|
|
&tx.message,
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
2020-02-12 16:36:29 -07:00
|
|
|
log_instruction_custom_error::<StakeError>(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-17 12:10:52 -07:00
|
|
|
pub fn print_stake_state(stake_lamports: u64, stake_state: &StakeState, use_lamports_unit: bool) {
|
2019-09-29 21:18:15 -07:00
|
|
|
fn show_authorized(authorized: &Authorized) {
|
2020-02-05 11:14:44 -07:00
|
|
|
println!("Authorized Staker: {}", authorized.staker);
|
|
|
|
println!("Authorized Withdrawer: {}", authorized.withdrawer);
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
fn show_lockup(lockup: &Lockup) {
|
2020-03-02 12:28:43 -08:00
|
|
|
println!(
|
|
|
|
"Lockup Timestamp: {} (UnixTimestamp: {})",
|
|
|
|
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(lockup.unix_timestamp, 0), Utc)
|
|
|
|
.to_rfc3339_opts(SecondsFormat::Secs, true),
|
|
|
|
lockup.unix_timestamp
|
|
|
|
);
|
2020-02-05 11:14:44 -07:00
|
|
|
println!("Lockup Epoch: {}", lockup.epoch);
|
|
|
|
println!("Lockup Custodian: {}", lockup.custodian);
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
2020-01-17 12:10:52 -07:00
|
|
|
match stake_state {
|
|
|
|
StakeState::Stake(
|
2019-10-31 11:07:27 -07:00
|
|
|
Meta {
|
|
|
|
authorized, lockup, ..
|
|
|
|
},
|
|
|
|
stake,
|
2020-01-17 12:10:52 -07:00
|
|
|
) => {
|
2019-09-29 21:18:15 -07:00
|
|
|
println!(
|
2020-02-05 11:14:44 -07:00
|
|
|
"Total Stake: {}",
|
2020-01-17 12:10:52 -07:00
|
|
|
build_balance_message(stake_lamports, use_lamports_unit, true)
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
2020-02-05 11:14:44 -07:00
|
|
|
println!("Credits Observed: {}", stake.credits_observed);
|
2019-09-29 21:18:15 -07:00
|
|
|
println!(
|
2020-02-05 11:14:44 -07:00
|
|
|
"Delegated Stake: {}",
|
2019-11-25 13:14:32 -08:00
|
|
|
build_balance_message(stake.delegation.stake, use_lamports_unit, true)
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
2019-11-25 13:14:32 -08:00
|
|
|
if stake.delegation.voter_pubkey != Pubkey::default() {
|
2020-02-05 11:14:44 -07:00
|
|
|
println!("Delegated Voter Pubkey: {}", stake.delegation.voter_pubkey);
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
println!(
|
2020-02-05 11:14:44 -07:00
|
|
|
"Stake activates starting from epoch: {}",
|
2019-11-25 13:14:32 -08:00
|
|
|
if stake.delegation.activation_epoch < std::u64::MAX {
|
|
|
|
stake.delegation.activation_epoch
|
2019-11-22 15:35:02 +09:00
|
|
|
} else {
|
|
|
|
0
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
2019-11-25 13:14:32 -08:00
|
|
|
if stake.delegation.deactivation_epoch < std::u64::MAX {
|
2019-09-29 21:18:15 -07:00
|
|
|
println!(
|
2020-02-05 11:14:44 -07:00
|
|
|
"Stake deactivates starting from epoch: {}",
|
2019-11-25 13:14:32 -08:00
|
|
|
stake.delegation.deactivation_epoch
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
show_authorized(&authorized);
|
|
|
|
show_lockup(&lockup);
|
|
|
|
}
|
2020-02-05 11:14:44 -07:00
|
|
|
StakeState::RewardsPool => println!("Stake account is a rewards pool"),
|
|
|
|
StakeState::Uninitialized => println!("Stake account is uninitialized"),
|
2020-01-17 12:10:52 -07:00
|
|
|
StakeState::Initialized(Meta {
|
2019-10-31 11:07:27 -07:00
|
|
|
authorized, lockup, ..
|
2020-01-17 12:10:52 -07:00
|
|
|
}) => {
|
|
|
|
println!(
|
2020-02-05 11:14:44 -07:00
|
|
|
"Total Stake: {}",
|
2020-01-17 12:10:52 -07:00
|
|
|
build_balance_message(stake_lamports, use_lamports_unit, true)
|
|
|
|
);
|
2020-02-05 11:14:44 -07:00
|
|
|
println!("Stake account is undelegated");
|
2019-09-29 21:18:15 -07:00
|
|
|
show_authorized(&authorized);
|
|
|
|
show_lockup(&lockup);
|
2020-01-17 12:10:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_show_stake_account(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
_config: &CliConfig,
|
|
|
|
stake_account_pubkey: &Pubkey,
|
|
|
|
use_lamports_unit: bool,
|
|
|
|
) -> ProcessResult {
|
|
|
|
let stake_account = rpc_client.get_account(stake_account_pubkey)?;
|
|
|
|
if stake_account.owner != solana_stake_program::id() {
|
|
|
|
return Err(CliError::RpcRequestError(format!(
|
|
|
|
"{:?} is not a stake account",
|
2020-02-21 14:55:53 -07:00
|
|
|
stake_account_pubkey,
|
2020-01-17 12:10:52 -07:00
|
|
|
))
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
match stake_account.state() {
|
|
|
|
Ok(stake_state) => {
|
|
|
|
print_stake_state(stake_account.lamports, &stake_state, use_lamports_unit);
|
2019-09-29 21:18:15 -07:00
|
|
|
Ok("".to_string())
|
|
|
|
}
|
2019-10-04 16:13:21 -06:00
|
|
|
Err(err) => Err(CliError::RpcRequestError(format!(
|
2020-03-13 00:20:49 -06:00
|
|
|
"Account data could not be deserialized to stake state: {}",
|
2019-09-29 21:18:15 -07:00
|
|
|
err
|
2019-10-02 18:33:01 -07:00
|
|
|
))
|
|
|
|
.into()),
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-25 12:20:08 -04:00
|
|
|
pub fn process_show_stake_history(
|
|
|
|
rpc_client: &RpcClient,
|
|
|
|
_config: &CliConfig,
|
|
|
|
use_lamports_unit: bool,
|
|
|
|
) -> ProcessResult {
|
|
|
|
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
2019-10-25 16:44:09 -05:00
|
|
|
let stake_history = StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
|
|
|
|
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
|
|
|
})?;
|
2019-10-25 12:20:08 -04:00
|
|
|
|
|
|
|
println!();
|
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
style(format!(
|
2019-12-10 08:29:54 -07:00
|
|
|
" {:<5} {:>20} {:>20} {:>20}",
|
2019-10-25 12:20:08 -04:00
|
|
|
"Epoch", "Effective Stake", "Activating Stake", "Deactivating Stake",
|
|
|
|
))
|
|
|
|
.bold()
|
|
|
|
);
|
|
|
|
|
|
|
|
for (epoch, entry) in stake_history.deref() {
|
|
|
|
println!(
|
2019-12-10 08:29:54 -07:00
|
|
|
" {:>5} {:>20} {:>20} {:>20} {}",
|
2019-10-25 12:20:08 -04:00
|
|
|
epoch,
|
|
|
|
build_balance_message(entry.effective, use_lamports_unit, false),
|
|
|
|
build_balance_message(entry.activating, use_lamports_unit, false),
|
|
|
|
build_balance_message(entry.deactivating, use_lamports_unit, false),
|
|
|
|
if use_lamports_unit { "lamports" } else { "SOL" }
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Ok("".to_string())
|
|
|
|
}
|
|
|
|
|
2019-12-27 14:35:49 -06:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-09-29 21:18:15 -07:00
|
|
|
pub fn process_delegate_stake(
|
|
|
|
rpc_client: &RpcClient,
|
2019-10-04 16:13:21 -06:00
|
|
|
config: &CliConfig,
|
2019-09-29 21:18:15 -07:00
|
|
|
stake_account_pubkey: &Pubkey,
|
|
|
|
vote_account_pubkey: &Pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: SignerIndex,
|
2019-09-29 21:18:15 -07:00
|
|
|
force: bool,
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only: bool,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: &BlockhashQuery,
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: Option<Pubkey>,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: SignerIndex,
|
|
|
|
fee_payer: SignerIndex,
|
2019-09-29 21:18:15 -07:00
|
|
|
) -> ProcessResult {
|
|
|
|
check_unique_pubkeys(
|
2020-02-24 17:03:30 -07:00
|
|
|
(&config.signers[0].pubkey(), "cli keypair".to_string()),
|
2019-09-29 21:18:15 -07:00
|
|
|
(stake_account_pubkey, "stake_account_pubkey".to_string()),
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let stake_authority = config.signers[stake_authority];
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2020-02-10 18:59:05 -07:00
|
|
|
if !sign_only {
|
|
|
|
// Sanity check the vote account to ensure it is attached to a validator that has recently
|
|
|
|
// voted at the tip of the ledger
|
|
|
|
let vote_account_data = rpc_client
|
|
|
|
.get_account_data(vote_account_pubkey)
|
|
|
|
.map_err(|_| {
|
|
|
|
CliError::RpcRequestError(format!(
|
|
|
|
"Vote account not found: {}",
|
|
|
|
vote_account_pubkey
|
|
|
|
))
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let vote_state = VoteState::deserialize(&vote_account_data).map_err(|_| {
|
|
|
|
CliError::RpcRequestError(
|
|
|
|
"Account data could not be deserialized to vote state".to_string(),
|
|
|
|
)
|
2019-09-29 21:18:15 -07:00
|
|
|
})?;
|
|
|
|
|
2020-02-10 18:59:05 -07:00
|
|
|
let sanity_check_result = match vote_state.root_slot {
|
|
|
|
None => Err(CliError::BadParameter(
|
|
|
|
"Unable to delegate. Vote account has no root slot".to_string(),
|
|
|
|
)),
|
|
|
|
Some(root_slot) => {
|
|
|
|
let slot = rpc_client.get_slot()?;
|
|
|
|
if root_slot + solana_sdk::clock::DEFAULT_SLOTS_PER_TURN < slot {
|
|
|
|
Err(CliError::BadParameter(
|
|
|
|
format!(
|
|
|
|
"Unable to delegate. Vote account root slot ({}) is too old, the current slot is {}", root_slot, slot
|
|
|
|
)
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2020-03-13 00:20:49 -06:00
|
|
|
if let Err(err) = &sanity_check_result {
|
2020-02-10 18:59:05 -07:00
|
|
|
if !force {
|
|
|
|
sanity_check_result?;
|
2019-09-29 21:18:15 -07:00
|
|
|
} else {
|
2020-03-13 00:20:49 -06:00
|
|
|
println!("--force supplied, ignoring: {}", err);
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-25 21:09:57 -08:00
|
|
|
let (recent_blockhash, fee_calculator) =
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?;
|
2019-09-29 21:18:15 -07:00
|
|
|
|
|
|
|
let ixs = vec![stake_instruction::delegate_stake(
|
|
|
|
stake_account_pubkey,
|
2020-01-15 14:32:06 -07:00
|
|
|
&stake_authority.pubkey(),
|
2019-09-29 21:18:15 -07:00
|
|
|
vote_account_pubkey,
|
|
|
|
)];
|
2020-02-24 17:03:30 -07: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(
|
2019-12-27 14:35:49 -06:00
|
|
|
ixs,
|
2020-02-07 09:14:27 -07:00
|
|
|
Some(&fee_payer.pubkey()),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account,
|
|
|
|
&nonce_authority.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
)
|
2019-12-27 14:35:49 -06:00
|
|
|
} else {
|
2020-03-11 14:37:23 -07:00
|
|
|
Message::new_with_payer(&ixs, Some(&fee_payer.pubkey()))
|
2019-12-27 14:35:49 -06:00
|
|
|
};
|
2020-02-24 17:03:30 -07:00
|
|
|
let mut tx = Transaction::new_unsigned(message);
|
|
|
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
|
|
|
|
2019-11-25 21:09:57 -08:00
|
|
|
if sign_only {
|
|
|
|
return_signers(&tx)
|
|
|
|
} else {
|
2019-12-27 14:35:49 -06:00
|
|
|
if let Some(nonce_account) = &nonce_account {
|
|
|
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
2020-02-21 14:55:53 -07:00
|
|
|
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
2019-12-27 14:35:49 -06:00
|
|
|
}
|
2019-12-09 23:11:04 -08:00
|
|
|
check_account_for_fee(
|
|
|
|
rpc_client,
|
|
|
|
&tx.message.account_keys[0],
|
|
|
|
&fee_calculator,
|
|
|
|
&tx.message,
|
|
|
|
)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
2019-11-25 21:09:57 -08:00
|
|
|
log_instruction_custom_error::<StakeError>(result)
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2019-10-04 16:13:21 -06:00
|
|
|
use crate::cli::{app, parse_command};
|
2020-01-30 09:21:32 -07:00
|
|
|
use solana_sdk::{
|
|
|
|
hash::Hash,
|
2020-02-21 14:55:53 -07:00
|
|
|
signature::{
|
|
|
|
keypair_from_seed, read_keypair_file, write_keypair, Keypair, Presigner, Signer,
|
|
|
|
},
|
2020-01-30 09:21:32 -07:00
|
|
|
};
|
2019-11-06 20:17:34 +05:30
|
|
|
use tempfile::NamedTempFile;
|
|
|
|
|
|
|
|
fn make_tmp_file() -> (String, NamedTempFile) {
|
|
|
|
let tmp_file = NamedTempFile::new().unwrap();
|
|
|
|
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2020-01-15 14:32:06 -07:00
|
|
|
fn parse_authorize_tests(
|
|
|
|
test_commands: &App,
|
|
|
|
stake_account_pubkey: Pubkey,
|
|
|
|
authority_keypair_file: &str,
|
|
|
|
stake_authorize: StakeAuthorize,
|
|
|
|
) {
|
2020-02-24 17:03:30 -07: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();
|
|
|
|
|
2019-11-06 20:17:34 +05:30
|
|
|
let stake_account_string = stake_account_pubkey.to_string();
|
2019-09-29 21:18:15 -07:00
|
|
|
|
2020-01-15 14:32:06 -07:00
|
|
|
let (subcommand, authority_flag) = match stake_authorize {
|
|
|
|
StakeAuthorize::Staker => ("stake-authorize-staker", "--stake-authority"),
|
|
|
|
StakeAuthorize::Withdrawer => ("stake-authorize-withdrawer", "--withdraw-authority"),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Test Staker Subcommand
|
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
2019-10-01 10:34:45 -07:00
|
|
|
"test",
|
2020-01-15 14:32:06 -07:00
|
|
|
&subcommand,
|
2019-11-06 20:17:34 +05:30
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
2019-10-01 10:34:45 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
2020-01-15 14:32:06 -07:00
|
|
|
command: CliCommand::StakeAuthorize {
|
2019-11-06 20:17:34 +05:30
|
|
|
stake_account_pubkey,
|
2020-01-15 14:32:06 -07:00
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: false,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: BlockhashQuery::default(),
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2019-10-21 17:08:09 -06:00
|
|
|
}
|
2019-10-01 10:34:45 -07:00
|
|
|
);
|
2020-01-15 14:32:06 -07:00
|
|
|
// Test Staker Subcommand w/ authority
|
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
2019-10-01 10:34:45 -07:00
|
|
|
"test",
|
2020-01-15 14:32:06 -07:00
|
|
|
&subcommand,
|
2019-11-06 20:17:34 +05:30
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
2020-01-15 14:32:06 -07:00
|
|
|
&authority_flag,
|
|
|
|
&authority_keypair_file,
|
2019-10-01 10:34:45 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
2020-01-15 14:32:06 -07:00
|
|
|
command: CliCommand::StakeAuthorize {
|
2019-11-06 20:17:34 +05:30
|
|
|
stake_account_pubkey,
|
2020-01-15 14:32:06 -07:00
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 1,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: false,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: BlockhashQuery::default(),
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&authority_keypair_file).unwrap().into()
|
|
|
|
],
|
2020-01-17 10:30:56 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
// Test Authorize Subcommand w/ sign-only
|
2020-01-26 10:06:21 -07:00
|
|
|
let blockhash = Hash::default();
|
|
|
|
let blockhash_string = format!("{}", blockhash);
|
2020-01-17 10:30:56 -07:00
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
&subcommand,
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2020-01-17 10:30:56 -07:00
|
|
|
"--sign-only",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2020-01-17 10:30:56 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::StakeAuthorize {
|
|
|
|
stake_account_pubkey,
|
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: true,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::None(blockhash),
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2020-01-17 10:30:56 -07:00
|
|
|
}
|
|
|
|
);
|
2020-02-21 14:55:53 -07:00
|
|
|
// Test Authorize Subcommand w/ offline feepayer
|
2020-01-17 10:30:56 -07:00
|
|
|
let keypair = Keypair::new();
|
2020-02-21 14:55:53 -07:00
|
|
|
let pubkey = keypair.pubkey();
|
2020-01-17 10:30:56 -07:00
|
|
|
let sig = keypair.sign_message(&[0u8]);
|
|
|
|
let signer = format!("{}={}", keypair.pubkey(), sig);
|
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
&subcommand,
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2020-01-17 10:30:56 -07:00
|
|
|
"--signer",
|
|
|
|
&signer,
|
2020-02-21 14:55:53 -07:00
|
|
|
"--fee-payer",
|
|
|
|
&pubkey.to_string(),
|
2020-01-17 10:30:56 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2020-01-17 10:30:56 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::StakeAuthorize {
|
|
|
|
stake_account_pubkey,
|
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 1,
|
2020-01-17 10:30:56 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&pubkey, &sig).into()
|
|
|
|
],
|
2020-01-17 10:30:56 -07:00
|
|
|
}
|
|
|
|
);
|
2020-02-21 14:55:53 -07:00
|
|
|
// Test Authorize Subcommand w/ offline fee payer and nonce authority
|
2020-01-17 10:30:56 -07:00
|
|
|
let keypair2 = Keypair::new();
|
2020-02-21 14:55:53 -07:00
|
|
|
let pubkey2 = keypair2.pubkey();
|
2020-01-17 10:30:56 -07:00
|
|
|
let sig2 = keypair.sign_message(&[0u8]);
|
|
|
|
let signer2 = format!("{}={}", keypair2.pubkey(), sig2);
|
2020-02-21 14:55:53 -07:00
|
|
|
let nonce_account = Pubkey::new(&[1u8; 32]);
|
2020-01-17 10:30:56 -07:00
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
&subcommand,
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2020-01-17 10:30:56 -07:00
|
|
|
"--signer",
|
|
|
|
&signer,
|
|
|
|
"--signer",
|
|
|
|
&signer2,
|
2020-02-21 14:55:53 -07:00
|
|
|
"--fee-payer",
|
|
|
|
&pubkey.to_string(),
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account.to_string(),
|
|
|
|
"--nonce-authority",
|
|
|
|
&pubkey2.to_string(),
|
2020-01-17 10:30:56 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2020-01-17 10:30:56 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::StakeAuthorize {
|
|
|
|
stake_account_pubkey,
|
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
blockhash
|
|
|
|
),
|
2020-02-21 14:55:53 -07:00
|
|
|
nonce_account: Some(nonce_account),
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 2,
|
|
|
|
fee_payer: 1,
|
2020-01-17 10:30:56 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&pubkey, &sig).into(),
|
|
|
|
Presigner::new(&pubkey2, &sig2).into(),
|
|
|
|
],
|
2020-01-17 10:30:56 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
// Test Authorize Subcommand w/ blockhash
|
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
&subcommand,
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2020-01-17 10:30:56 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::StakeAuthorize {
|
|
|
|
stake_account_pubkey,
|
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2020-01-17 10:30:56 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
// Test Authorize Subcommand w/ nonce
|
|
|
|
let (nonce_keypair_file, mut nonce_tmp_file) = make_tmp_file();
|
|
|
|
let nonce_authority_keypair = Keypair::new();
|
|
|
|
write_keypair(&nonce_authority_keypair, nonce_tmp_file.as_file_mut()).unwrap();
|
|
|
|
let nonce_account_pubkey = nonce_authority_keypair.pubkey();
|
|
|
|
let nonce_account_string = nonce_account_pubkey.to_string();
|
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
&subcommand,
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account_string,
|
|
|
|
"--nonce-authority",
|
|
|
|
&nonce_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2020-01-17 10:30:56 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::StakeAuthorize {
|
|
|
|
stake_account_pubkey,
|
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-01-17 10:30:56 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account_pubkey),
|
|
|
|
blockhash
|
|
|
|
),
|
2020-01-17 10:30:56 -07:00
|
|
|
nonce_account: Some(nonce_account_pubkey),
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 1,
|
|
|
|
fee_payer: 0,
|
2020-02-07 09:14:27 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
nonce_authority_keypair.into()
|
|
|
|
],
|
2020-02-07 09:14:27 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
// Test Authorize Subcommand w/ fee-payer
|
|
|
|
let (fee_payer_keypair_file, mut fee_payer_tmp_file) = make_tmp_file();
|
|
|
|
let fee_payer_keypair = Keypair::new();
|
|
|
|
write_keypair(&fee_payer_keypair, fee_payer_tmp_file.as_file_mut()).unwrap();
|
|
|
|
let fee_payer_pubkey = fee_payer_keypair.pubkey();
|
|
|
|
let fee_payer_string = fee_payer_pubkey.to_string();
|
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
&subcommand,
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
|
|
|
"--fee-payer",
|
|
|
|
&fee_payer_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2020-02-07 09:14:27 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::StakeAuthorize {
|
|
|
|
stake_account_pubkey,
|
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-02-07 09:14:27 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
2020-02-07 09:14:27 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 1,
|
2020-02-07 09:14:27 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&fee_payer_keypair_file).unwrap().into(),
|
|
|
|
],
|
2020-02-07 09:14:27 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
// Test Authorize Subcommand w/ absentee fee-payer
|
|
|
|
let sig = fee_payer_keypair.sign_message(&[0u8]);
|
|
|
|
let signer = format!("{}={}", fee_payer_string, sig);
|
|
|
|
let test_authorize = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
&subcommand,
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
|
|
|
"--fee-payer",
|
|
|
|
&fee_payer_string,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
"--signer",
|
|
|
|
&signer,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_authorize, &default_keypair_file, None).unwrap(),
|
2020-02-07 09:14:27 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::StakeAuthorize {
|
|
|
|
stake_account_pubkey,
|
|
|
|
new_authorized_pubkey: stake_account_pubkey,
|
|
|
|
stake_authorize,
|
2020-02-24 17:03:30 -07:00
|
|
|
authority: 0,
|
2020-02-07 09:14:27 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
2020-02-07 09:14:27 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 1,
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&fee_payer_pubkey, &sig).into()
|
|
|
|
],
|
2019-10-21 17:08:09 -06:00
|
|
|
}
|
2019-10-01 10:34:45 -07:00
|
|
|
);
|
2020-01-15 14:32:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse_command() {
|
|
|
|
let test_commands = app("test", "desc", "version");
|
2020-02-24 17:03:30 -07: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();
|
2020-01-15 14:32:06 -07:00
|
|
|
let (keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let stake_account_keypair = Keypair::new();
|
|
|
|
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
let stake_account_pubkey = stake_account_keypair.pubkey();
|
|
|
|
let (stake_authority_keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let stake_authority_keypair = Keypair::new();
|
|
|
|
write_keypair(&stake_authority_keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
|
|
|
|
parse_authorize_tests(
|
|
|
|
&test_commands,
|
|
|
|
stake_account_pubkey,
|
|
|
|
&stake_authority_keypair_file,
|
|
|
|
StakeAuthorize::Staker,
|
|
|
|
);
|
|
|
|
parse_authorize_tests(
|
|
|
|
&test_commands,
|
|
|
|
stake_account_pubkey,
|
|
|
|
&stake_authority_keypair_file,
|
|
|
|
StakeAuthorize::Withdrawer,
|
|
|
|
);
|
2019-10-01 10:34:45 -07:00
|
|
|
|
|
|
|
// Test CreateStakeAccount SubCommand
|
2019-09-29 21:18:15 -07:00
|
|
|
let custodian = Pubkey::new_rand();
|
|
|
|
let custodian_string = format!("{}", custodian);
|
|
|
|
let authorized = Pubkey::new_rand();
|
|
|
|
let authorized_string = format!("{}", authorized);
|
|
|
|
let test_create_stake_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-stake-account",
|
2019-11-06 20:17:34 +05:30
|
|
|
&keypair_file,
|
2019-09-29 21:18:15 -07:00
|
|
|
"50",
|
2020-01-15 14:32:06 -07:00
|
|
|
"--stake-authority",
|
2019-09-29 21:18:15 -07:00
|
|
|
&authorized_string,
|
2020-01-15 14:32:06 -07:00
|
|
|
"--withdraw-authority",
|
2019-09-29 21:18:15 -07:00
|
|
|
&authorized_string,
|
|
|
|
"--custodian",
|
|
|
|
&custodian_string,
|
2019-12-19 14:37:47 -08:00
|
|
|
"--lockup-epoch",
|
2019-09-29 21:18:15 -07:00
|
|
|
"43",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_create_stake_account, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateStakeAccount {
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_account: 1,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: None,
|
2019-10-21 17:08:09 -06:00
|
|
|
staker: Some(authorized),
|
|
|
|
withdrawer: Some(authorized),
|
|
|
|
lockup: Lockup {
|
2019-11-25 15:11:55 -08:00
|
|
|
epoch: 43,
|
2019-12-19 14:37:47 -08:00
|
|
|
unix_timestamp: 0,
|
2019-10-21 17:08:09 -06:00
|
|
|
custodian,
|
|
|
|
},
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 50_000_000_000,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
2020-02-12 23:00:28 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
|
|
|
from: 0,
|
2019-09-29 21:18:15 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
stake_account_keypair.into()
|
|
|
|
],
|
2019-10-21 17:08:09 -06:00
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
2019-11-06 20:17:34 +05:30
|
|
|
|
|
|
|
let (keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let stake_account_keypair = Keypair::new();
|
|
|
|
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
let stake_account_pubkey = stake_account_keypair.pubkey();
|
|
|
|
let stake_account_string = stake_account_pubkey.to_string();
|
|
|
|
|
2019-09-29 21:18:15 -07:00
|
|
|
let test_create_stake_account2 = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-stake-account",
|
2019-11-06 20:17:34 +05:30
|
|
|
&keypair_file,
|
2019-09-29 21:18:15 -07:00
|
|
|
"50",
|
|
|
|
]);
|
2019-11-06 20:17:34 +05:30
|
|
|
|
2019-09-29 21:18:15 -07:00
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_create_stake_account2, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateStakeAccount {
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_account: 1,
|
2020-01-09 15:22:48 -08:00
|
|
|
seed: None,
|
2019-10-21 17:08:09 -06:00
|
|
|
staker: None,
|
|
|
|
withdrawer: None,
|
2019-11-25 15:11:55 -08:00
|
|
|
lockup: Lockup::default(),
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 50_000_000_000,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
2020-02-12 23:00:28 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
|
|
|
from: 0,
|
2019-09-29 21:18:15 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&keypair_file).unwrap().into()
|
|
|
|
],
|
2019-10-21 17:08:09 -06:00
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
// CreateStakeAccount offline and nonce
|
|
|
|
let nonce_account = Pubkey::new(&[1u8; 32]);
|
|
|
|
let nonce_account_string = nonce_account.to_string();
|
|
|
|
let offline = keypair_from_seed(&[2u8; 32]).unwrap();
|
|
|
|
let offline_pubkey = offline.pubkey();
|
|
|
|
let offline_string = offline_pubkey.to_string();
|
|
|
|
let offline_sig = offline.sign_message(&[3u8]);
|
|
|
|
let offline_signer = format!("{}={}", offline_pubkey, offline_sig);
|
|
|
|
let nonce_hash = Hash::new(&[4u8; 32]);
|
|
|
|
let nonce_hash_string = nonce_hash.to_string();
|
|
|
|
let test_create_stake_account2 = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"create-stake-account",
|
|
|
|
&keypair_file,
|
|
|
|
"50",
|
|
|
|
"--blockhash",
|
|
|
|
&nonce_hash_string,
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account_string,
|
|
|
|
"--nonce-authority",
|
|
|
|
&offline_string,
|
|
|
|
"--fee-payer",
|
|
|
|
&offline_string,
|
|
|
|
"--from",
|
|
|
|
&offline_string,
|
|
|
|
"--signer",
|
|
|
|
&offline_signer,
|
|
|
|
]);
|
|
|
|
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_create_stake_account2, &default_keypair_file, None).unwrap(),
|
2020-02-12 23:00:28 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::CreateStakeAccount {
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_account: 1,
|
2020-02-12 23:00:28 -07:00
|
|
|
seed: None,
|
|
|
|
staker: None,
|
|
|
|
withdrawer: None,
|
|
|
|
lockup: Lockup::default(),
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 50_000_000_000,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
nonce_hash
|
|
|
|
),
|
2020-02-12 23:00:28 -07:00
|
|
|
nonce_account: Some(nonce_account),
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
|
|
|
from: 0,
|
2020-02-12 23:00:28 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
Presigner::new(&offline_pubkey, &offline_sig).into(),
|
|
|
|
read_keypair_file(&keypair_file).unwrap().into()
|
|
|
|
],
|
2020-02-12 23:00:28 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-09-29 21:18:15 -07:00
|
|
|
// Test DelegateStake Subcommand
|
2019-11-25 21:09:57 -08:00
|
|
|
let vote_account_pubkey = Pubkey::new_rand();
|
|
|
|
let vote_account_string = vote_account_pubkey.to_string();
|
2019-09-29 21:18:15 -07:00
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
2019-11-06 20:17:34 +05:30
|
|
|
&stake_account_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
&vote_account_string,
|
2019-09-29 21:18:15 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
2019-11-25 21:09:57 -08:00
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2020-01-15 14:32:06 -07:00
|
|
|
force: false,
|
|
|
|
sign_only: false,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: BlockhashQuery::default(),
|
2020-01-15 14:32:06 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2020-01-15 14:32:06 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test DelegateStake Subcommand w/ authority
|
|
|
|
let vote_account_pubkey = Pubkey::new_rand();
|
|
|
|
let vote_account_string = vote_account_pubkey.to_string();
|
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&vote_account_string,
|
|
|
|
"--stake-authority",
|
|
|
|
&stake_authority_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2020-01-15 14:32:06 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 1,
|
2019-11-25 21:09:57 -08:00
|
|
|
force: false,
|
|
|
|
sign_only: false,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: BlockhashQuery::default(),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&stake_authority_keypair_file)
|
|
|
|
.unwrap()
|
|
|
|
.into()
|
|
|
|
],
|
2019-10-21 17:08:09 -06:00
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
|
|
|
|
2020-01-15 14:32:06 -07:00
|
|
|
// Test DelegateStake Subcommand w/ force
|
2019-09-29 21:18:15 -07:00
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
|
|
|
"--force",
|
2019-11-06 20:17:34 +05:30
|
|
|
&stake_account_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
&vote_account_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
force: true,
|
|
|
|
sign_only: false,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: BlockhashQuery::default(),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test Delegate Subcommand w/ Blockhash
|
|
|
|
let blockhash = Hash::default();
|
|
|
|
let blockhash_string = format!("{}", blockhash);
|
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&vote_account_string,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
force: false,
|
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&vote_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
"--sign-only",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
force: false,
|
|
|
|
sign_only: true,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::None(blockhash),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-02-21 14:55:53 -07:00
|
|
|
// Test Delegate Subcommand w/ absent fee payer
|
2019-11-25 21:09:57 -08:00
|
|
|
let key1 = Pubkey::new_rand();
|
|
|
|
let sig1 = Keypair::new().sign_message(&[0u8]);
|
|
|
|
let signer1 = format!("{}={}", key1, sig1);
|
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&vote_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
"--signer",
|
|
|
|
&signer1,
|
2020-02-21 14:55:53 -07:00
|
|
|
"--fee-payer",
|
|
|
|
&key1.to_string(),
|
2019-11-25 21:09:57 -08:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
force: false,
|
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 1,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&key1, &sig1).into()
|
|
|
|
],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-02-21 14:55:53 -07:00
|
|
|
// Test Delegate Subcommand w/ absent fee payer and absent nonce authority
|
2019-11-25 21:09:57 -08:00
|
|
|
let key2 = Pubkey::new_rand();
|
|
|
|
let sig2 = Keypair::new().sign_message(&[0u8]);
|
|
|
|
let signer2 = format!("{}={}", key2, sig2);
|
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&vote_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
"--signer",
|
|
|
|
&signer1,
|
|
|
|
"--signer",
|
|
|
|
&signer2,
|
2020-02-21 14:55:53 -07:00
|
|
|
"--fee-payer",
|
|
|
|
&key1.to_string(),
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account.to_string(),
|
|
|
|
"--nonce-authority",
|
|
|
|
&key2.to_string(),
|
2019-09-29 21:18:15 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
2019-11-25 21:09:57 -08:00
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
force: false,
|
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
blockhash
|
|
|
|
),
|
2020-02-21 14:55:53 -07:00
|
|
|
nonce_account: Some(nonce_account),
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 2,
|
|
|
|
fee_payer: 1,
|
2020-02-07 09:14:27 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&key1, &sig1).into(),
|
|
|
|
Presigner::new(&key2, &sig2).into(),
|
|
|
|
],
|
2020-02-07 09:14:27 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-02-21 14:55:53 -07:00
|
|
|
// Test Delegate Subcommand w/ present fee-payer
|
2020-02-07 09:14:27 -07:00
|
|
|
let (fee_payer_keypair_file, mut fee_payer_tmp_file) = make_tmp_file();
|
|
|
|
let fee_payer_keypair = Keypair::new();
|
|
|
|
write_keypair(&fee_payer_keypair, fee_payer_tmp_file.as_file_mut()).unwrap();
|
|
|
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"delegate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&vote_account_string,
|
|
|
|
"--fee-payer",
|
|
|
|
&fee_payer_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_delegate_stake, &default_keypair_file, None).unwrap(),
|
2020-02-07 09:14:27 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DelegateStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
vote_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2020-02-07 09:14:27 -07:00
|
|
|
force: false,
|
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
2020-02-07 09:14:27 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 1,
|
2020-02-07 09:14:27 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&fee_payer_keypair_file).unwrap().into()
|
|
|
|
],
|
2020-02-07 09:14:27 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-09-29 21:18:15 -07:00
|
|
|
// Test WithdrawStake Subcommand
|
|
|
|
let test_withdraw_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-stake",
|
2019-11-25 21:09:57 -08:00
|
|
|
&stake_account_string,
|
2019-11-06 20:17:34 +05:30
|
|
|
&stake_account_string,
|
2019-09-29 21:18:15 -07:00
|
|
|
"42",
|
|
|
|
]);
|
|
|
|
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_withdraw_stake, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
2020-01-15 14:32:06 -07:00
|
|
|
command: CliCommand::WithdrawStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
destination_account_pubkey: stake_account_pubkey,
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 42_000_000_000,
|
2020-02-24 17:03:30 -07:00
|
|
|
withdraw_authority: 0,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
2020-02-12 23:00:28 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2020-01-15 14:32:06 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test WithdrawStake Subcommand w/ authority
|
|
|
|
let test_withdraw_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
|
|
|
"42",
|
|
|
|
"--withdraw-authority",
|
|
|
|
&stake_authority_keypair_file,
|
|
|
|
]);
|
|
|
|
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_withdraw_stake, &default_keypair_file, None).unwrap(),
|
2020-01-15 14:32:06 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
destination_account_pubkey: stake_account_pubkey,
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 42_000_000_000,
|
2020-02-24 17:03:30 -07:00
|
|
|
withdraw_authority: 1,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
2020-02-12 23:00:28 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&stake_authority_keypair_file)
|
|
|
|
.unwrap()
|
|
|
|
.into()
|
|
|
|
],
|
2019-10-21 17:08:09 -06:00
|
|
|
}
|
2019-09-29 21:18:15 -07:00
|
|
|
);
|
|
|
|
|
2020-02-12 23:00:28 -07:00
|
|
|
// Test WithdrawStake Subcommand w/ authority and offline nonce
|
|
|
|
let test_withdraw_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"withdraw-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
&stake_account_string,
|
|
|
|
"42",
|
|
|
|
"--withdraw-authority",
|
|
|
|
&stake_authority_keypair_file,
|
|
|
|
"--blockhash",
|
|
|
|
&nonce_hash_string,
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account_string,
|
|
|
|
"--nonce-authority",
|
|
|
|
&offline_string,
|
|
|
|
"--fee-payer",
|
|
|
|
&offline_string,
|
|
|
|
"--signer",
|
|
|
|
&offline_signer,
|
|
|
|
]);
|
|
|
|
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_withdraw_stake, &default_keypair_file, None).unwrap(),
|
2020-02-12 23:00:28 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::WithdrawStake {
|
|
|
|
stake_account_pubkey,
|
|
|
|
destination_account_pubkey: stake_account_pubkey,
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 42_000_000_000,
|
2020-02-24 17:03:30 -07:00
|
|
|
withdraw_authority: 0,
|
2020-02-12 23:00:28 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
nonce_hash
|
|
|
|
),
|
2020-02-12 23:00:28 -07:00
|
|
|
nonce_account: Some(nonce_account),
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 1,
|
|
|
|
fee_payer: 1,
|
2020-02-12 23:00:28 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&stake_authority_keypair_file)
|
|
|
|
.unwrap()
|
|
|
|
.into(),
|
|
|
|
Presigner::new(&offline_pubkey, &offline_sig).into()
|
|
|
|
],
|
2020-02-12 23:00:28 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-09-29 21:18:15 -07:00
|
|
|
// Test DeactivateStake Subcommand
|
|
|
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"deactivate-stake",
|
2019-11-25 21:09:57 -08:00
|
|
|
&stake_account_string,
|
2019-09-29 21:18:15 -07:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_deactivate_stake, &default_keypair_file, None).unwrap(),
|
2019-10-21 17:08:09 -06:00
|
|
|
CliCommandInfo {
|
2019-11-25 21:09:57 -08:00
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2020-01-15 14:32:06 -07:00
|
|
|
sign_only: false,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: BlockhashQuery::default(),
|
2020-01-15 14:32:06 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2020-01-15 14:32:06 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2020-01-15 14:32:06 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test DeactivateStake Subcommand w/ authority
|
|
|
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"deactivate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
"--stake-authority",
|
|
|
|
&stake_authority_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_deactivate_stake, &default_keypair_file, None).unwrap(),
|
2020-01-15 14:32:06 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 1,
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only: false,
|
2020-01-30 09:21:32 -07:00
|
|
|
blockhash_query: BlockhashQuery::default(),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&stake_authority_keypair_file)
|
|
|
|
.unwrap()
|
|
|
|
.into()
|
|
|
|
],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test Deactivate Subcommand w/ Blockhash
|
|
|
|
let blockhash = Hash::default();
|
|
|
|
let blockhash_string = format!("{}", blockhash);
|
|
|
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"deactivate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_deactivate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"deactivate-stake",
|
|
|
|
&stake_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
"--sign-only",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_deactivate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only: true,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::None(blockhash),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-02-21 14:55:53 -07:00
|
|
|
// Test Deactivate Subcommand w/ absent fee payer
|
2019-11-25 21:09:57 -08:00
|
|
|
let key1 = Pubkey::new_rand();
|
|
|
|
let sig1 = Keypair::new().sign_message(&[0u8]);
|
|
|
|
let signer1 = format!("{}={}", key1, sig1);
|
|
|
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"deactivate-stake",
|
|
|
|
&stake_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
"--signer",
|
|
|
|
&signer1,
|
2020-02-21 14:55:53 -07:00
|
|
|
"--fee-payer",
|
|
|
|
&key1.to_string(),
|
2019-11-25 21:09:57 -08:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_deactivate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::Cluster,
|
|
|
|
blockhash
|
|
|
|
),
|
2019-12-27 14:35:49 -06:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 1,
|
2019-11-25 21:09:57 -08:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&key1, &sig1).into()
|
|
|
|
],
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-02-21 14:55:53 -07:00
|
|
|
// Test Deactivate Subcommand w/ absent fee payer and nonce authority
|
2019-11-25 21:09:57 -08:00
|
|
|
let key2 = Pubkey::new_rand();
|
|
|
|
let sig2 = Keypair::new().sign_message(&[0u8]);
|
|
|
|
let signer2 = format!("{}={}", key2, sig2);
|
|
|
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"deactivate-stake",
|
|
|
|
&stake_account_string,
|
2020-01-26 10:06:21 -07:00
|
|
|
"--blockhash",
|
|
|
|
&blockhash_string,
|
2019-11-25 21:09:57 -08:00
|
|
|
"--signer",
|
|
|
|
&signer1,
|
|
|
|
"--signer",
|
|
|
|
&signer2,
|
2020-02-21 14:55:53 -07:00
|
|
|
"--fee-payer",
|
|
|
|
&key1.to_string(),
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account.to_string(),
|
|
|
|
"--nonce-authority",
|
|
|
|
&key2.to_string(),
|
2019-11-25 21:09:57 -08:00
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_deactivate_stake, &default_keypair_file, None).unwrap(),
|
2019-11-25 21:09:57 -08:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2019-11-25 21:09:57 -08:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
blockhash
|
|
|
|
),
|
2020-02-21 14:55:53 -07:00
|
|
|
nonce_account: Some(nonce_account),
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 2,
|
|
|
|
fee_payer: 1,
|
2020-02-07 09:14:27 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
Presigner::new(&key1, &sig1).into(),
|
|
|
|
Presigner::new(&key2, &sig2).into(),
|
|
|
|
],
|
2020-02-07 09:14:27 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test Deactivate Subcommand w/ fee-payer
|
|
|
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"deactivate-stake",
|
|
|
|
&stake_account_string,
|
|
|
|
"--fee-payer",
|
|
|
|
&fee_payer_keypair_file,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_deactivate_stake, &default_keypair_file, None).unwrap(),
|
2020-02-07 09:14:27 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::DeactivateStake {
|
|
|
|
stake_account_pubkey,
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2020-02-07 09:14:27 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
2020-02-07 09:14:27 -07:00
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
fee_payer: 1,
|
2020-02-07 09:14:27 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&fee_payer_keypair_file).unwrap().into()
|
|
|
|
],
|
2020-02-07 09:14:27 -07:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-02-02 22:20:28 -07:00
|
|
|
// Test SplitStake SubCommand
|
|
|
|
let (keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let stake_account_keypair = Keypair::new();
|
|
|
|
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
let (split_stake_account_keypair_file, mut tmp_file) = make_tmp_file();
|
|
|
|
let split_stake_account_keypair = Keypair::new();
|
|
|
|
write_keypair(&split_stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
|
|
|
|
|
|
|
let test_split_stake_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"split-stake",
|
|
|
|
&keypair_file,
|
|
|
|
&split_stake_account_keypair_file,
|
|
|
|
"50",
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_split_stake_account, &default_keypair_file, None).unwrap(),
|
2020-02-02 22:20:28 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::SplitStake {
|
|
|
|
stake_account_pubkey: stake_account_keypair.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2020-02-02 22:20:28 -07:00
|
|
|
sign_only: false,
|
|
|
|
blockhash_query: BlockhashQuery::default(),
|
|
|
|
nonce_account: None,
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 0,
|
|
|
|
split_stake_account: 1,
|
2020-02-02 22:20:28 -07:00
|
|
|
seed: None,
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 50_000_000_000,
|
2020-02-24 17:03:30 -07:00
|
|
|
fee_payer: 0,
|
2020-02-02 22:20:28 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
|
|
|
read_keypair_file(&split_stake_account_keypair_file)
|
|
|
|
.unwrap()
|
|
|
|
.into()
|
|
|
|
],
|
2020-02-02 22:20:28 -07:00
|
|
|
}
|
|
|
|
);
|
2020-02-11 00:23:54 -07:00
|
|
|
|
|
|
|
// Split stake offline nonced submission
|
|
|
|
let nonce_account = Pubkey::new(&[1u8; 32]);
|
|
|
|
let nonce_account_string = nonce_account.to_string();
|
|
|
|
let nonce_auth = keypair_from_seed(&[2u8; 32]).unwrap();
|
|
|
|
let nonce_auth_pubkey = nonce_auth.pubkey();
|
|
|
|
let nonce_auth_string = nonce_auth_pubkey.to_string();
|
|
|
|
let nonce_sig = nonce_auth.sign_message(&[0u8]);
|
|
|
|
let nonce_signer = format!("{}={}", nonce_auth_pubkey, nonce_sig);
|
|
|
|
let stake_auth = keypair_from_seed(&[3u8; 32]).unwrap();
|
|
|
|
let stake_auth_pubkey = stake_auth.pubkey();
|
|
|
|
let stake_auth_string = stake_auth_pubkey.to_string();
|
|
|
|
let stake_sig = stake_auth.sign_message(&[0u8]);
|
|
|
|
let stake_signer = format!("{}={}", stake_auth_pubkey, stake_sig);
|
|
|
|
let nonce_hash = Hash::new(&[4u8; 32]);
|
|
|
|
let nonce_hash_string = nonce_hash.to_string();
|
|
|
|
|
|
|
|
let test_split_stake_account = test_commands.clone().get_matches_from(vec![
|
|
|
|
"test",
|
|
|
|
"split-stake",
|
|
|
|
&keypair_file,
|
|
|
|
&split_stake_account_keypair_file,
|
|
|
|
"50",
|
|
|
|
"--stake-authority",
|
|
|
|
&stake_auth_string,
|
|
|
|
"--blockhash",
|
|
|
|
&nonce_hash_string,
|
|
|
|
"--nonce",
|
|
|
|
&nonce_account_string,
|
|
|
|
"--nonce-authority",
|
|
|
|
&nonce_auth_string,
|
|
|
|
"--fee-payer",
|
|
|
|
&nonce_auth_string, // Arbitrary choice of fee-payer
|
|
|
|
"--signer",
|
|
|
|
&nonce_signer,
|
|
|
|
"--signer",
|
|
|
|
&stake_signer,
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
2020-02-24 17:03:30 -07:00
|
|
|
parse_command(&test_split_stake_account, &default_keypair_file, None).unwrap(),
|
2020-02-11 00:23:54 -07:00
|
|
|
CliCommandInfo {
|
|
|
|
command: CliCommand::SplitStake {
|
|
|
|
stake_account_pubkey: stake_account_keypair.pubkey(),
|
2020-02-24 17:03:30 -07:00
|
|
|
stake_authority: 0,
|
2020-02-11 00:23:54 -07:00
|
|
|
sign_only: false,
|
2020-03-11 12:14:15 -06:00
|
|
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
|
|
|
blockhash_query::Source::NonceAccount(nonce_account),
|
|
|
|
nonce_hash
|
|
|
|
),
|
2020-02-11 00:23:54 -07:00
|
|
|
nonce_account: Some(nonce_account.into()),
|
2020-02-24 17:03:30 -07:00
|
|
|
nonce_authority: 1,
|
|
|
|
split_stake_account: 2,
|
2020-02-11 00:23:54 -07:00
|
|
|
seed: None,
|
2020-02-15 12:53:52 -07:00
|
|
|
lamports: 50_000_000_000,
|
2020-02-24 17:03:30 -07:00
|
|
|
fee_payer: 1,
|
2020-02-11 00:23:54 -07:00
|
|
|
},
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![
|
|
|
|
Presigner::new(&stake_auth_pubkey, &stake_sig).into(),
|
|
|
|
Presigner::new(&nonce_auth_pubkey, &nonce_sig).into(),
|
|
|
|
read_keypair_file(&split_stake_account_keypair_file)
|
|
|
|
.unwrap()
|
|
|
|
.into(),
|
|
|
|
],
|
2020-02-11 00:23:54 -07:00
|
|
|
}
|
|
|
|
);
|
2019-09-29 21:18:15 -07:00
|
|
|
}
|
|
|
|
}
|