@ -411,11 +411,11 @@ impl LocalCluster {
|
|||||||
let stake_account_pubkey = stake_account_keypair.pubkey();
|
let stake_account_pubkey = stake_account_keypair.pubkey();
|
||||||
let mut transaction = Transaction::new_signed_instructions(
|
let mut transaction = Transaction::new_signed_instructions(
|
||||||
&[from_account.as_ref()],
|
&[from_account.as_ref()],
|
||||||
vec![stake_instruction::create_account(
|
stake_instruction::create_delegate_account(
|
||||||
&from_account.pubkey(),
|
&from_account.pubkey(),
|
||||||
&stake_account_pubkey,
|
&stake_account_pubkey,
|
||||||
amount,
|
amount,
|
||||||
)],
|
),
|
||||||
client.get_recent_blockhash().unwrap().0,
|
client.get_recent_blockhash().unwrap().0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -183,11 +183,11 @@ pub(crate) mod tests {
|
|||||||
process_instructions(
|
process_instructions(
|
||||||
bank,
|
bank,
|
||||||
&[from_account],
|
&[from_account],
|
||||||
vec![stake_instruction::create_account(
|
stake_instruction::create_delegate_account(
|
||||||
&from_account.pubkey(),
|
&from_account.pubkey(),
|
||||||
&stake_account_pubkey,
|
&stake_account_pubkey,
|
||||||
amount,
|
amount,
|
||||||
)],
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
process_instructions(
|
process_instructions(
|
||||||
|
@ -10,26 +10,84 @@ use solana_sdk::system_instruction;
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum StakeInstruction {
|
pub enum StakeInstruction {
|
||||||
|
/// Initialize the stake account as a Delegate account.
|
||||||
|
///
|
||||||
|
/// Expects 2 Accounts:
|
||||||
|
/// 0 - payer (TODO unused/remove)
|
||||||
|
/// 1 - Delegate StakeAccount to be initialized
|
||||||
|
InitializeDelegate,
|
||||||
|
|
||||||
|
// Initialize the stake account as a MiningPool account
|
||||||
|
///
|
||||||
|
/// Expects 2 Accounts:
|
||||||
|
/// 0 - payer (TODO unused/remove)
|
||||||
|
/// 1 - MiningPool StakeAccount to be initialized
|
||||||
|
InitializeMiningPool,
|
||||||
|
|
||||||
/// `Delegate` or `Assign` a stake account to a particular node
|
/// `Delegate` or `Assign` a stake account to a particular node
|
||||||
/// expects 2 KeyedAccounts:
|
///
|
||||||
/// StakeAccount to be updated
|
/// Expects 3 Accounts:
|
||||||
/// VoteAccount to which this Stake will be delegated
|
/// 0 - payer (TODO unused/remove)
|
||||||
|
/// 1 - Delegate StakeAccount to be updated
|
||||||
|
/// 2 - VoteAccount to which this Stake will be delegated
|
||||||
DelegateStake,
|
DelegateStake,
|
||||||
|
|
||||||
/// Redeem credits in the stake account
|
/// Redeem credits in the stake account
|
||||||
/// expects 3 KeyedAccounts: the StakeAccount to be updated
|
///
|
||||||
/// and the VoteAccount to which this Stake will be delegated
|
/// Expects 4 Accounts:
|
||||||
|
/// 0 - payer (TODO unused/remove)
|
||||||
|
/// 1 - MiningPool Stake Account to redeem credits from
|
||||||
|
/// 2 - Delegate StakeAccount to be updated
|
||||||
|
/// 3 - VoteAccount to which the Stake is delegated
|
||||||
RedeemVoteCredits,
|
RedeemVoteCredits,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_account(from_id: &Pubkey, staker_id: &Pubkey, lamports: u64) -> Instruction {
|
pub fn create_delegate_account(
|
||||||
|
from_id: &Pubkey,
|
||||||
|
staker_id: &Pubkey,
|
||||||
|
lamports: u64,
|
||||||
|
) -> Vec<Instruction> {
|
||||||
|
vec![
|
||||||
system_instruction::create_account(
|
system_instruction::create_account(
|
||||||
from_id,
|
from_id,
|
||||||
staker_id,
|
staker_id,
|
||||||
lamports,
|
lamports,
|
||||||
std::mem::size_of::<StakeState>() as u64,
|
std::mem::size_of::<StakeState>() as u64,
|
||||||
&id(),
|
&id(),
|
||||||
)
|
),
|
||||||
|
Instruction::new(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::InitializeDelegate,
|
||||||
|
vec![
|
||||||
|
AccountMeta::new(*from_id, true),
|
||||||
|
AccountMeta::new(*staker_id, false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_mining_pool_account(
|
||||||
|
from_id: &Pubkey,
|
||||||
|
staker_id: &Pubkey,
|
||||||
|
lamports: u64,
|
||||||
|
) -> Vec<Instruction> {
|
||||||
|
vec![
|
||||||
|
system_instruction::create_account(
|
||||||
|
from_id,
|
||||||
|
staker_id,
|
||||||
|
lamports,
|
||||||
|
std::mem::size_of::<StakeState>() as u64,
|
||||||
|
&id(),
|
||||||
|
),
|
||||||
|
Instruction::new(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::InitializeMiningPool,
|
||||||
|
vec![
|
||||||
|
AccountMeta::new(*from_id, true),
|
||||||
|
AccountMeta::new(*staker_id, false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redeem_vote_credits(
|
pub fn redeem_vote_credits(
|
||||||
@ -67,17 +125,29 @@ pub fn process_instruction(
|
|||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
trace!("keyed_accounts: {:?}", keyed_accounts);
|
trace!("keyed_accounts: {:?}", keyed_accounts);
|
||||||
|
|
||||||
if keyed_accounts.len() < 3 {
|
if keyed_accounts.len() < 2 {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0th index is the guy who paid for the transaction
|
// 0th index is the account who paid for the transaction
|
||||||
|
// TODO: Remove the 0th index from the instruction. The stake program doesn't care who paid.
|
||||||
let (me, rest) = &mut keyed_accounts.split_at_mut(2);
|
let (me, rest) = &mut keyed_accounts.split_at_mut(2);
|
||||||
|
|
||||||
let me = &mut me[1];
|
let me = &mut me[1];
|
||||||
|
|
||||||
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
||||||
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
||||||
|
StakeInstruction::InitializeMiningPool => {
|
||||||
|
if !rest.is_empty() {
|
||||||
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
|
}
|
||||||
|
me.initialize_mining_pool()
|
||||||
|
}
|
||||||
|
StakeInstruction::InitializeDelegate => {
|
||||||
|
if !rest.is_empty() {
|
||||||
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
|
}
|
||||||
|
me.initialize_delegate()
|
||||||
|
}
|
||||||
StakeInstruction::DelegateStake => {
|
StakeInstruction::DelegateStake => {
|
||||||
if rest.len() != 1 {
|
if rest.len() != 1 {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
@ -127,10 +197,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stake_process_instruction() {
|
fn test_stake_process_instruction() {
|
||||||
assert_eq!(
|
|
||||||
process_instruction(&create_account(&Pubkey::default(), &Pubkey::default(), 0)),
|
|
||||||
Err(InstructionError::InvalidInstructionData) // won't even decode ;)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&redeem_vote_credits(
|
process_instruction(&redeem_vote_credits(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
|
@ -13,6 +13,7 @@ use solana_vote_api::vote_state::VoteState;
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
pub enum StakeState {
|
pub enum StakeState {
|
||||||
|
Uninitialized,
|
||||||
Delegate {
|
Delegate {
|
||||||
voter_id: Pubkey,
|
voter_id: Pubkey,
|
||||||
credits_observed: u64,
|
credits_observed: u64,
|
||||||
@ -22,10 +23,7 @@ pub enum StakeState {
|
|||||||
|
|
||||||
impl Default for StakeState {
|
impl Default for StakeState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
StakeState::Delegate {
|
StakeState::Uninitialized
|
||||||
voter_id: Pubkey::default(),
|
|
||||||
credits_observed: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: trusted values of network parameters come from where?
|
// TODO: trusted values of network parameters come from where?
|
||||||
@ -90,6 +88,8 @@ impl StakeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait StakeAccount {
|
pub trait StakeAccount {
|
||||||
|
fn initialize_mining_pool(&mut self) -> Result<(), InstructionError>;
|
||||||
|
fn initialize_delegate(&mut self) -> Result<(), InstructionError>;
|
||||||
fn delegate_stake(&mut self, vote_account: &KeyedAccount) -> Result<(), InstructionError>;
|
fn delegate_stake(&mut self, vote_account: &KeyedAccount) -> Result<(), InstructionError>;
|
||||||
fn redeem_vote_credits(
|
fn redeem_vote_credits(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -99,6 +99,23 @@ pub trait StakeAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StakeAccount for KeyedAccount<'a> {
|
impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
|
fn initialize_mining_pool(&mut self) -> Result<(), InstructionError> {
|
||||||
|
if let StakeState::Uninitialized = self.state()? {
|
||||||
|
self.set_state(&StakeState::MiningPool)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn initialize_delegate(&mut self) -> Result<(), InstructionError> {
|
||||||
|
if let StakeState::Uninitialized = self.state()? {
|
||||||
|
self.set_state(&StakeState::Delegate {
|
||||||
|
voter_id: Pubkey::default(),
|
||||||
|
credits_observed: 0,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
}
|
||||||
|
}
|
||||||
fn delegate_stake(&mut self, vote_account: &KeyedAccount) -> Result<(), InstructionError> {
|
fn delegate_stake(&mut self, vote_account: &KeyedAccount) -> Result<(), InstructionError> {
|
||||||
if self.signer_key().is_none() {
|
if self.signer_key().is_none() {
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
@ -156,7 +173,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// not worth collecting
|
// not worth collecting
|
||||||
Ok(())
|
Err(InstructionError::CustomError(1))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
@ -215,6 +232,7 @@ mod tests {
|
|||||||
assert_eq!(stake_state, StakeState::default());
|
assert_eq!(stake_state, StakeState::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stake_keyed_account.initialize_delegate().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(&vote_keyed_account),
|
stake_keyed_account.delegate_stake(&vote_keyed_account),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
@ -316,6 +334,7 @@ mod tests {
|
|||||||
&id(),
|
&id(),
|
||||||
);
|
);
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
||||||
|
stake_keyed_account.initialize_delegate().unwrap();
|
||||||
|
|
||||||
// delegate the stake
|
// delegate the stake
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
@ -338,9 +357,11 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// no movement in vote account, so no redemption needed
|
// no movement in vote account, so no redemption needed
|
||||||
assert!(mining_pool_keyed_account
|
assert_eq!(
|
||||||
.redeem_vote_credits(&mut stake_keyed_account, &mut vote_keyed_account)
|
mining_pool_keyed_account
|
||||||
.is_ok());
|
.redeem_vote_credits(&mut stake_keyed_account, &mut vote_keyed_account),
|
||||||
|
Err(InstructionError::CustomError(1))
|
||||||
|
);
|
||||||
|
|
||||||
// move the vote account forward
|
// move the vote account forward
|
||||||
vote_state.process_vote(&Vote::new(1000));
|
vote_state.process_vote(&Vote::new(1000));
|
||||||
@ -383,6 +404,7 @@ mod tests {
|
|||||||
let pubkey = Pubkey::default();
|
let pubkey = Pubkey::default();
|
||||||
let mut stake_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
let mut stake_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
||||||
|
stake_keyed_account.initialize_delegate().unwrap();
|
||||||
|
|
||||||
// delegate the stake
|
// delegate the stake
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
|
@ -48,7 +48,9 @@ pub enum WalletCommand {
|
|||||||
CreateVoteAccount(Pubkey, Pubkey, u32, u64),
|
CreateVoteAccount(Pubkey, Pubkey, u32, u64),
|
||||||
ShowVoteAccount(Pubkey),
|
ShowVoteAccount(Pubkey),
|
||||||
CreateStakeAccount(Pubkey, u64),
|
CreateStakeAccount(Pubkey, u64),
|
||||||
|
CreateMiningPoolAccount(Pubkey, u64),
|
||||||
DelegateStake(Keypair, Pubkey),
|
DelegateStake(Keypair, Pubkey),
|
||||||
|
RedeemVoteCredits(Pubkey, Pubkey, Pubkey),
|
||||||
ShowStakeAccount(Pubkey),
|
ShowStakeAccount(Pubkey),
|
||||||
Deploy(String),
|
Deploy(String),
|
||||||
GetTransactionCount,
|
GetTransactionCount,
|
||||||
@ -216,6 +218,14 @@ pub fn parse_command(
|
|||||||
lamports,
|
lamports,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
("create-mining-pool-account", Some(matches)) => {
|
||||||
|
let mining_pool_account_id = pubkey_of(matches, "mining_pool_account_id").unwrap();
|
||||||
|
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
||||||
|
Ok(WalletCommand::CreateMiningPoolAccount(
|
||||||
|
mining_pool_account_id,
|
||||||
|
lamports,
|
||||||
|
))
|
||||||
|
}
|
||||||
("delegate-stake", Some(matches)) => {
|
("delegate-stake", Some(matches)) => {
|
||||||
let staking_account_keypair =
|
let staking_account_keypair =
|
||||||
keypair_of(matches, "staking_account_keypair_file").unwrap();
|
keypair_of(matches, "staking_account_keypair_file").unwrap();
|
||||||
@ -225,6 +235,16 @@ pub fn parse_command(
|
|||||||
voting_account_id,
|
voting_account_id,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
("redeem-vote-credits", Some(matches)) => {
|
||||||
|
let mining_pool_account_id = pubkey_of(matches, "mining_pool_account_id").unwrap();
|
||||||
|
let staking_account_id = pubkey_of(matches, "staking_account_id").unwrap();
|
||||||
|
let voting_account_id = pubkey_of(matches, "voting_account_id").unwrap();
|
||||||
|
Ok(WalletCommand::RedeemVoteCredits(
|
||||||
|
mining_pool_account_id,
|
||||||
|
staking_account_id,
|
||||||
|
voting_account_id,
|
||||||
|
))
|
||||||
|
}
|
||||||
("show-stake-account", Some(matches)) => {
|
("show-stake-account", Some(matches)) => {
|
||||||
let staking_account_id = pubkey_of(matches, "staking_account_id").unwrap();
|
let staking_account_id = pubkey_of(matches, "staking_account_id").unwrap();
|
||||||
Ok(WalletCommand::ShowStakeAccount(staking_account_id))
|
Ok(WalletCommand::ShowStakeAccount(staking_account_id))
|
||||||
@ -469,11 +489,28 @@ fn process_create_stake_account(
|
|||||||
lamports: u64,
|
lamports: u64,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
let ixs = vec![stake_instruction::create_account(
|
let ixs = stake_instruction::create_delegate_account(
|
||||||
&config.keypair.pubkey(),
|
&config.keypair.pubkey(),
|
||||||
staking_account_id,
|
staking_account_id,
|
||||||
lamports,
|
lamports,
|
||||||
)];
|
);
|
||||||
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
|
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||||
|
Ok(signature_str.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_create_mining_pool_account(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
mining_pool_account_id: &Pubkey,
|
||||||
|
lamports: u64,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
let ixs = stake_instruction::create_mining_pool_account(
|
||||||
|
&config.keypair.pubkey(),
|
||||||
|
mining_pool_account_id,
|
||||||
|
lamports,
|
||||||
|
);
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
@ -501,6 +538,25 @@ fn process_delegate_stake(
|
|||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_redeem_vote_credits(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
mining_pool_account_id: &Pubkey,
|
||||||
|
staking_account_id: &Pubkey,
|
||||||
|
voting_account_id: &Pubkey,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
let ixs = vec![stake_instruction::redeem_vote_credits(
|
||||||
|
&config.keypair.pubkey(),
|
||||||
|
mining_pool_account_id,
|
||||||
|
staking_account_id,
|
||||||
|
voting_account_id,
|
||||||
|
)];
|
||||||
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
|
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||||
|
Ok(signature_str.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
fn process_show_stake_account(
|
fn process_show_stake_account(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
_config: &WalletConfig,
|
_config: &WalletConfig,
|
||||||
@ -518,6 +574,10 @@ fn process_show_stake_account(
|
|||||||
println!("credits observed: {}", credits_observed);
|
println!("credits observed: {}", credits_observed);
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
|
Ok(StakeState::MiningPool) => {
|
||||||
|
println!("account lamports: {}", stake_account.lamports);
|
||||||
|
Ok("".to_string())
|
||||||
|
}
|
||||||
_ => Err(WalletError::RpcRequestError(
|
_ => Err(WalletError::RpcRequestError(
|
||||||
"Account data could not be deserialized to stake state".to_string(),
|
"Account data could not be deserialized to stake state".to_string(),
|
||||||
))?,
|
))?,
|
||||||
@ -813,7 +873,15 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
|||||||
process_create_stake_account(&rpc_client, config, &staking_account_id, *lamports)
|
process_create_stake_account(&rpc_client, config, &staking_account_id, *lamports)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create stake account
|
WalletCommand::CreateMiningPoolAccount(mining_pool_account_id, lamports) => {
|
||||||
|
process_create_mining_pool_account(
|
||||||
|
&rpc_client,
|
||||||
|
config,
|
||||||
|
&mining_pool_account_id,
|
||||||
|
*lamports,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
WalletCommand::DelegateStake(staking_account_keypair, voting_account_id) => {
|
WalletCommand::DelegateStake(staking_account_keypair, voting_account_id) => {
|
||||||
process_delegate_stake(
|
process_delegate_stake(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
@ -822,6 +890,19 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
|||||||
&voting_account_id,
|
&voting_account_id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WalletCommand::RedeemVoteCredits(
|
||||||
|
mining_pool_account_id,
|
||||||
|
staking_account_id,
|
||||||
|
voting_account_id,
|
||||||
|
) => process_redeem_vote_credits(
|
||||||
|
&rpc_client,
|
||||||
|
config,
|
||||||
|
&mining_pool_account_id,
|
||||||
|
&staking_account_id,
|
||||||
|
&voting_account_id,
|
||||||
|
),
|
||||||
|
|
||||||
// Show a vote account
|
// Show a vote account
|
||||||
WalletCommand::ShowStakeAccount(staking_account_id) => {
|
WalletCommand::ShowStakeAccount(staking_account_id) => {
|
||||||
process_show_stake_account(&rpc_client, config, &staking_account_id)
|
process_show_stake_account(&rpc_client, config, &staking_account_id)
|
||||||
@ -1098,6 +1179,27 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.help("Vote account pubkey"),
|
.help("Vote account pubkey"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("create-mining-pool-account")
|
||||||
|
.about("Create mining pool account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("mining_pool_account_id")
|
||||||
|
.index(1)
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey)
|
||||||
|
.help("Staking account address to fund"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("lamports")
|
||||||
|
.index(2)
|
||||||
|
.value_name("NUM")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("The number of lamports to assign to the mining pool account"),
|
||||||
|
),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("create-stake-account")
|
SubCommand::with_name("create-stake-account")
|
||||||
.about("Create staking account")
|
.about("Create staking account")
|
||||||
@ -1140,6 +1242,37 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.help("The voting account to which to delegate the stake."),
|
.help("The voting account to which to delegate the stake."),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("redeem-vote-credits")
|
||||||
|
.about("Redeem credits in the staking account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("mining_pool_account_id")
|
||||||
|
.index(1)
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey)
|
||||||
|
.help("Mining pool account to redeem credits from"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("staking_account_id")
|
||||||
|
.index(2)
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey)
|
||||||
|
.help("Staking account address to redeem credits for"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("voting_account_id")
|
||||||
|
.index(3)
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey)
|
||||||
|
.help("The voting account to which the stake was previously delegated."),
|
||||||
|
),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("show-stake-account")
|
SubCommand::with_name("show-stake-account")
|
||||||
.about("Show the contents of a stake account")
|
.about("Show the contents of a stake account")
|
||||||
|
Reference in New Issue
Block a user