Code cleanup v1
This commit is contained in:
parent
eb1bf2eb44
commit
2cd7adbf87
|
@ -0,0 +1,115 @@
|
|||
use {
|
||||
bincode::deserialize,
|
||||
borsh::BorshDeserialize,
|
||||
solana_account_decoder::UiAccountEncoding,
|
||||
solana_client::{
|
||||
client_error::ClientError,
|
||||
rpc_client::RpcClient,
|
||||
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
|
||||
rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
|
||||
},
|
||||
solana_program::{program_pack::Pack, pubkey::Pubkey},
|
||||
spl_stake_pool::{
|
||||
borsh::try_from_slice_unchecked,
|
||||
stake_program,
|
||||
state::{StakePool, ValidatorList},
|
||||
},
|
||||
};
|
||||
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
|
||||
pub(crate) fn get_stake_pool(
|
||||
rpc_client: &RpcClient,
|
||||
pool_address: &Pubkey,
|
||||
) -> Result<StakePool, Error> {
|
||||
let account_data = rpc_client.get_account_data(pool_address)?;
|
||||
let stake_pool = StakePool::try_from_slice(account_data.as_slice())
|
||||
.map_err(|err| format!("Invalid stake pool {}: {}", pool_address, err))?;
|
||||
Ok(stake_pool)
|
||||
}
|
||||
|
||||
pub(crate) fn get_validator_list(
|
||||
rpc_client: &RpcClient,
|
||||
validator_list_address: &Pubkey,
|
||||
) -> Result<ValidatorList, Error> {
|
||||
let account_data = rpc_client.get_account_data(validator_list_address)?;
|
||||
let validator_list = try_from_slice_unchecked::<ValidatorList>(&account_data.as_slice())
|
||||
.map_err(|err| format!("Invalid validator list {}: {}", validator_list_address, err))?;
|
||||
Ok(validator_list)
|
||||
}
|
||||
|
||||
pub(crate) fn get_token_account(
|
||||
rpc_client: &RpcClient,
|
||||
token_account_address: &Pubkey,
|
||||
expected_token_mint: &Pubkey,
|
||||
) -> Result<spl_token::state::Account, Error> {
|
||||
let account_data = rpc_client.get_account_data(token_account_address)?;
|
||||
let token_account = spl_token::state::Account::unpack_from_slice(account_data.as_slice())
|
||||
.map_err(|err| format!("Invalid token account {}: {}", token_account_address, err))?;
|
||||
|
||||
if token_account.mint != *expected_token_mint {
|
||||
Err(format!(
|
||||
"Invalid token mint for {}, expected mint is {}",
|
||||
token_account_address, expected_token_mint
|
||||
)
|
||||
.into())
|
||||
} else {
|
||||
Ok(token_account)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_token_mint(
|
||||
rpc_client: &RpcClient,
|
||||
token_mint_address: &Pubkey,
|
||||
) -> Result<spl_token::state::Mint, Error> {
|
||||
let account_data = rpc_client.get_account_data(token_mint_address)?;
|
||||
let token_mint = spl_token::state::Mint::unpack_from_slice(account_data.as_slice())
|
||||
.map_err(|err| format!("Invalid token mint {}: {}", token_mint_address, err))?;
|
||||
|
||||
Ok(token_mint)
|
||||
}
|
||||
|
||||
pub(crate) fn get_stake_state(
|
||||
rpc_client: &RpcClient,
|
||||
stake_address: &Pubkey,
|
||||
) -> Result<stake_program::StakeState, Error> {
|
||||
let account_data = rpc_client.get_account_data(stake_address)?;
|
||||
let stake_state = deserialize(account_data.as_slice())
|
||||
.map_err(|err| format!("Invalid stake account {}: {}", stake_address, err))?;
|
||||
Ok(stake_state)
|
||||
}
|
||||
|
||||
pub(crate) fn get_stake_accounts_by_withdrawer(
|
||||
rpc_client: &RpcClient,
|
||||
withdrawer: &Pubkey,
|
||||
) -> Result<Vec<(Pubkey, u64, stake_program::StakeState)>, ClientError> {
|
||||
rpc_client
|
||||
.get_program_accounts_with_config(
|
||||
&stake_program::id(),
|
||||
RpcProgramAccountsConfig {
|
||||
filters: Some(vec![RpcFilterType::Memcmp(Memcmp {
|
||||
offset: 44, // 44 is Withdrawer authority offset in stake account stake
|
||||
bytes: MemcmpEncodedBytes::Binary(format!("{}", withdrawer)),
|
||||
encoding: None,
|
||||
})]),
|
||||
account_config: RpcAccountInfoConfig {
|
||||
encoding: Some(UiAccountEncoding::Base64),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
},
|
||||
)
|
||||
.map(|accounts| {
|
||||
accounts
|
||||
.into_iter()
|
||||
.filter_map(
|
||||
|(address, account)| match deserialize(account.data.as_slice()) {
|
||||
Ok(stake_state) => Some((address, account.lamports, stake_state)),
|
||||
Err(err) => {
|
||||
eprintln!("Invalid stake account data for {}: {}", address, err);
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
})
|
||||
}
|
|
@ -1,26 +1,20 @@
|
|||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
mod client;
|
||||
|
||||
use {
|
||||
bincode::deserialize,
|
||||
borsh::BorshDeserialize,
|
||||
crate::client::*,
|
||||
clap::{
|
||||
crate_description, crate_name, crate_version, value_t, value_t_or_exit, App, AppSettings,
|
||||
Arg, ArgGroup, SubCommand,
|
||||
},
|
||||
solana_account_decoder::UiAccountEncoding,
|
||||
solana_clap_utils::{
|
||||
input_parsers::pubkey_of,
|
||||
input_validators::{is_amount, is_keypair, is_parsable, is_pubkey, is_url},
|
||||
keypair::signer_from_path,
|
||||
},
|
||||
solana_client::{
|
||||
client_error::ClientError,
|
||||
rpc_client::RpcClient,
|
||||
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
|
||||
rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
|
||||
rpc_response::StakeActivationState,
|
||||
},
|
||||
solana_client::{rpc_client::RpcClient, rpc_response::StakeActivationState},
|
||||
solana_program::{
|
||||
borsh::get_packed_len, instruction::Instruction, program_pack::Pack, pubkey::Pubkey,
|
||||
},
|
||||
|
@ -32,22 +26,13 @@ use {
|
|||
transaction::Transaction,
|
||||
},
|
||||
spl_stake_pool::{
|
||||
borsh::{get_instance_packed_len, try_from_slice_unchecked},
|
||||
self,
|
||||
borsh::get_instance_packed_len,
|
||||
create_pool_authority_address, find_authority_bump_seed, find_stake_address_for_validator,
|
||||
instruction::{
|
||||
add_validator_to_pool, create_validator_stake_account, deposit,
|
||||
initialize as initialize_pool, remove_validator_from_pool, set_owner,
|
||||
update_stake_pool_balance, update_validator_list_balance, withdraw, Fee as PoolFee,
|
||||
},
|
||||
stake_program::{self, StakeAuthorize, StakeState},
|
||||
state::{StakePool, ValidatorList},
|
||||
AUTHORITY_DEPOSIT, AUTHORITY_WITHDRAW,
|
||||
},
|
||||
spl_token::{
|
||||
self, instruction::approve as approve_token, instruction::initialize_account,
|
||||
instruction::initialize_mint, native_mint, state::Account as TokenAccount,
|
||||
state::Mint as TokenMint,
|
||||
},
|
||||
std::process::exit,
|
||||
};
|
||||
|
||||
|
@ -91,41 +76,6 @@ fn check_fee_payer_balance(config: &Config, required_balance: u64) -> Result<(),
|
|||
}
|
||||
}
|
||||
|
||||
fn get_stake_accounts_by_withdrawer(
|
||||
rpc_client: &RpcClient,
|
||||
withdrawer: &Pubkey,
|
||||
) -> Result<Vec<(Pubkey, u64, StakeState)>, ClientError> {
|
||||
rpc_client
|
||||
.get_program_accounts_with_config(
|
||||
&stake_program::id(),
|
||||
RpcProgramAccountsConfig {
|
||||
filters: Some(vec![RpcFilterType::Memcmp(Memcmp {
|
||||
offset: 44, // 44 is Withdrawer authority offset in stake account stake
|
||||
bytes: MemcmpEncodedBytes::Binary(format!("{}", withdrawer)),
|
||||
encoding: None,
|
||||
})]),
|
||||
account_config: RpcAccountInfoConfig {
|
||||
encoding: Some(UiAccountEncoding::Base64),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
},
|
||||
)
|
||||
.map(|accounts| {
|
||||
accounts
|
||||
.into_iter()
|
||||
.filter_map(
|
||||
|(address, account)| match deserialize(account.data.as_slice()) {
|
||||
Ok(stake_state) => Some((address, account.lamports, stake_state)),
|
||||
Err(err) => {
|
||||
eprintln!("Invalid stake account data for {}: {}", address, err);
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn send_transaction(
|
||||
config: &Config,
|
||||
transaction: Transaction,
|
||||
|
@ -142,7 +92,11 @@ fn send_transaction(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn command_create_pool(config: &Config, fee: PoolFee, max_validators: u32) -> CommandResult {
|
||||
fn command_create_pool(
|
||||
config: &Config,
|
||||
fee: spl_stake_pool::instruction::Fee,
|
||||
max_validators: u32,
|
||||
) -> CommandResult {
|
||||
let mint_account = Keypair::new();
|
||||
println!("Creating mint {}", mint_account.pubkey());
|
||||
|
||||
|
@ -159,10 +113,10 @@ fn command_create_pool(config: &Config, fee: PoolFee, max_validators: u32) -> Co
|
|||
|
||||
let mint_account_balance = config
|
||||
.rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(TokenMint::LEN)?;
|
||||
.get_minimum_balance_for_rent_exemption(spl_token::state::Mint::LEN)?;
|
||||
let pool_fee_account_balance = config
|
||||
.rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(TokenAccount::LEN)?;
|
||||
.get_minimum_balance_for_rent_exemption(spl_token::state::Account::LEN)?;
|
||||
let pool_account_balance = config
|
||||
.rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(get_packed_len::<StakePool>())?;
|
||||
|
@ -176,7 +130,7 @@ fn command_create_pool(config: &Config, fee: PoolFee, max_validators: u32) -> Co
|
|||
+ pool_account_balance
|
||||
+ validator_list_balance;
|
||||
|
||||
let default_decimals = native_mint::DECIMALS;
|
||||
let default_decimals = spl_token::native_mint::DECIMALS;
|
||||
|
||||
// Calculate withdraw authority used for minting pool tokens
|
||||
let (withdraw_authority, _) = find_authority_bump_seed(
|
||||
|
@ -196,7 +150,7 @@ fn command_create_pool(config: &Config, fee: PoolFee, max_validators: u32) -> Co
|
|||
&config.fee_payer.pubkey(),
|
||||
&mint_account.pubkey(),
|
||||
mint_account_balance,
|
||||
TokenMint::LEN as u64,
|
||||
spl_token::state::Mint::LEN as u64,
|
||||
&spl_token::id(),
|
||||
),
|
||||
// Account for the pool fee accumulation
|
||||
|
@ -204,7 +158,7 @@ fn command_create_pool(config: &Config, fee: PoolFee, max_validators: u32) -> Co
|
|||
&config.fee_payer.pubkey(),
|
||||
&pool_fee_account.pubkey(),
|
||||
pool_fee_account_balance,
|
||||
TokenAccount::LEN as u64,
|
||||
spl_token::state::Account::LEN as u64,
|
||||
&spl_token::id(),
|
||||
),
|
||||
// Account for the stake pool
|
||||
|
@ -224,7 +178,7 @@ fn command_create_pool(config: &Config, fee: PoolFee, max_validators: u32) -> Co
|
|||
&spl_stake_pool::id(),
|
||||
),
|
||||
// Initialize pool token mint account
|
||||
initialize_mint(
|
||||
spl_token::instruction::initialize_mint(
|
||||
&spl_token::id(),
|
||||
&mint_account.pubkey(),
|
||||
&withdraw_authority,
|
||||
|
@ -232,14 +186,14 @@ fn command_create_pool(config: &Config, fee: PoolFee, max_validators: u32) -> Co
|
|||
default_decimals,
|
||||
)?,
|
||||
// Initialize fee receiver account
|
||||
initialize_account(
|
||||
spl_token::instruction::initialize_account(
|
||||
&spl_token::id(),
|
||||
&pool_fee_account.pubkey(),
|
||||
&mint_account.pubkey(),
|
||||
&config.owner.pubkey(),
|
||||
)?,
|
||||
// Initialize stake pool account
|
||||
initialize_pool(
|
||||
spl_stake_pool::instruction::initialize(
|
||||
&spl_stake_pool::id(),
|
||||
&pool_account.pubkey(),
|
||||
&config.owner.pubkey(),
|
||||
|
@ -282,7 +236,7 @@ fn command_vsa_create(config: &Config, pool: &Pubkey, vote_account: &Pubkey) ->
|
|||
let mut transaction = Transaction::new_with_payer(
|
||||
&[
|
||||
// Create new validator stake account address
|
||||
create_validator_stake_account(
|
||||
spl_stake_pool::instruction::create_validator_stake_account(
|
||||
&spl_stake_pool::id(),
|
||||
&pool,
|
||||
&config.owner.pubkey(),
|
||||
|
@ -318,9 +272,7 @@ fn command_vsa_add(
|
|||
command_update(config, pool)?;
|
||||
}
|
||||
|
||||
// Get stake pool state
|
||||
let pool_data = config.rpc_client.get_account_data(&pool)?;
|
||||
let pool_data = StakePool::try_from_slice(pool_data.as_slice()).unwrap();
|
||||
let pool_data = get_stake_pool(&config.rpc_client, pool)?;
|
||||
|
||||
let mut total_rent_free_balances: u64 = 0;
|
||||
|
||||
|
@ -374,7 +326,7 @@ fn command_vsa_add(
|
|||
StakeAuthorize::Staker,
|
||||
),
|
||||
// Add validator stake account to the pool
|
||||
add_validator_to_pool(
|
||||
spl_stake_pool::instruction::add_validator_to_pool(
|
||||
&spl_stake_pool::id(),
|
||||
&pool,
|
||||
&config.owner.pubkey(),
|
||||
|
@ -413,10 +365,7 @@ fn command_vsa_remove(
|
|||
command_update(config, pool)?;
|
||||
}
|
||||
|
||||
// Get stake pool state
|
||||
let pool_data = config.rpc_client.get_account_data(&pool)?;
|
||||
let pool_data: StakePool = StakePool::try_from_slice(pool_data.as_slice()).unwrap();
|
||||
|
||||
let pool_data = get_stake_pool(&config.rpc_client, pool)?;
|
||||
let pool_withdraw_authority: Pubkey = create_pool_authority_address(
|
||||
&spl_stake_pool::id(),
|
||||
pool,
|
||||
|
@ -435,17 +384,11 @@ fn command_vsa_remove(
|
|||
.unwrap();
|
||||
|
||||
// Check balance and mint
|
||||
let account_data = config.rpc_client.get_account_data(&withdraw_from)?;
|
||||
let account_data: TokenAccount =
|
||||
TokenAccount::unpack_from_slice(account_data.as_slice()).unwrap();
|
||||
let token_account =
|
||||
get_token_account(&config.rpc_client, &withdraw_from, &pool_data.pool_mint)?;
|
||||
|
||||
if account_data.mint != pool_data.pool_mint {
|
||||
return Err("Wrong token account.".into());
|
||||
}
|
||||
|
||||
if account_data.amount < tokens_to_withdraw {
|
||||
let pool_mint_data = config.rpc_client.get_account_data(&pool_data.pool_mint)?;
|
||||
let pool_mint = TokenMint::unpack_from_slice(pool_mint_data.as_slice()).unwrap();
|
||||
if token_account.amount < tokens_to_withdraw {
|
||||
let pool_mint = get_token_mint(&config.rpc_client, &pool_data.pool_mint)?;
|
||||
return Err(format!(
|
||||
"Not enough balance to burn to remove validator stake account from the pool. {} pool tokens needed.",
|
||||
spl_token::amount_to_ui_amount(tokens_to_withdraw, pool_mint.decimals)
|
||||
|
@ -455,7 +398,7 @@ fn command_vsa_remove(
|
|||
let mut transaction = Transaction::new_with_payer(
|
||||
&[
|
||||
// Approve spending token
|
||||
approve_token(
|
||||
spl_token::instruction::approve(
|
||||
&spl_token::id(),
|
||||
&withdraw_from,
|
||||
&pool_withdraw_authority,
|
||||
|
@ -464,7 +407,7 @@ fn command_vsa_remove(
|
|||
tokens_to_withdraw,
|
||||
)?,
|
||||
// Create new validator stake account address
|
||||
remove_validator_from_pool(
|
||||
spl_stake_pool::instruction::remove_validator_from_pool(
|
||||
&spl_stake_pool::id(),
|
||||
&pool,
|
||||
&config.owner.pubkey(),
|
||||
|
@ -509,7 +452,7 @@ where
|
|||
|
||||
let min_account_balance = config
|
||||
.rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(TokenAccount::LEN)?;
|
||||
.get_minimum_balance_for_rent_exemption(spl_token::state::Account::LEN)?;
|
||||
|
||||
instructions.extend(vec![
|
||||
// Creating new account
|
||||
|
@ -517,11 +460,11 @@ where
|
|||
&config.fee_payer.pubkey(),
|
||||
&keypair.pubkey(),
|
||||
min_account_balance,
|
||||
TokenAccount::LEN as u64,
|
||||
spl_token::state::Account::LEN as u64,
|
||||
&spl_token::id(),
|
||||
),
|
||||
// Initialize token receiver account
|
||||
initialize_account(
|
||||
spl_token::instruction::initialize_account(
|
||||
&spl_token::id(),
|
||||
&keypair.pubkey(),
|
||||
mint,
|
||||
|
@ -547,44 +490,31 @@ fn command_deposit(
|
|||
command_update(config, pool)?;
|
||||
}
|
||||
|
||||
// Get stake pool state
|
||||
let pool_data = config.rpc_client.get_account_data(&pool)?;
|
||||
let pool_data: StakePool = StakePool::try_from_slice(pool_data.as_slice()).unwrap();
|
||||
let pool_data = get_stake_pool(&config.rpc_client, pool)?;
|
||||
let stake_state = get_stake_state(&config.rpc_client, &stake)?;
|
||||
|
||||
// Get stake account data
|
||||
let stake_data = config.rpc_client.get_account_data(&stake)?;
|
||||
let stake_data: StakeState =
|
||||
deserialize(stake_data.as_slice()).or(Err("Invalid stake account data"))?;
|
||||
if config.verbose {
|
||||
println!("Depositing stake account {:?}", stake_data);
|
||||
println!("Depositing stake account {:?}", stake_state);
|
||||
}
|
||||
let vote_account: Pubkey = match stake_data {
|
||||
let vote_account: Pubkey = match stake_state {
|
||||
StakeState::Stake(_, stake) => Ok(stake.delegation.voter_pubkey),
|
||||
_ => Err("Wrong stake account state, must be delegated to validator"),
|
||||
}?;
|
||||
|
||||
// Check if this vote account has staking account in the pool
|
||||
let validator_list_data = config
|
||||
.rpc_client
|
||||
.get_account_data(&pool_data.validator_list)?;
|
||||
let validator_list_data =
|
||||
try_from_slice_unchecked::<ValidatorList>(&validator_list_data.as_slice())?;
|
||||
if !validator_list_data.contains(&vote_account) {
|
||||
let validator_list = get_validator_list(&config.rpc_client, &pool_data.validator_list)?;
|
||||
if !validator_list.contains(&vote_account) {
|
||||
return Err("Stake account for this validator does not exist in the pool.".into());
|
||||
}
|
||||
|
||||
// Calculate validator stake account address linked to the pool
|
||||
let (validator_stake_account, _) =
|
||||
find_stake_address_for_validator(&spl_stake_pool::id(), &vote_account, pool);
|
||||
let validator_stake_data = config
|
||||
.rpc_client
|
||||
.get_account_data(&validator_stake_account)?;
|
||||
let validator_stake_data: StakeState =
|
||||
deserialize(validator_stake_data.as_slice()).or(Err("Invalid stake account data"))?;
|
||||
|
||||
let validator_stake_state = get_stake_state(&config.rpc_client, &validator_stake_account)?;
|
||||
println!("Depositing into stake account {}", validator_stake_account);
|
||||
if config.verbose {
|
||||
println!("Depositing into stake account {:?}", validator_stake_data);
|
||||
} else {
|
||||
println!("Depositing into stake account {}", validator_stake_account);
|
||||
println!("{:?}", validator_stake_state);
|
||||
}
|
||||
|
||||
let mut instructions: Vec<Instruction> = vec![];
|
||||
|
@ -639,7 +569,7 @@ fn command_deposit(
|
|||
StakeAuthorize::Staker,
|
||||
),
|
||||
// Add stake account to the pool
|
||||
deposit(
|
||||
spl_stake_pool::instruction::deposit(
|
||||
&spl_stake_pool::id(),
|
||||
&pool,
|
||||
&pool_data.validator_list,
|
||||
|
@ -669,26 +599,12 @@ fn command_deposit(
|
|||
}
|
||||
|
||||
fn command_list(config: &Config, pool: &Pubkey) -> CommandResult {
|
||||
// Get stake pool state
|
||||
let pool_data = config.rpc_client.get_account_data(&pool)?;
|
||||
let pool_data = StakePool::try_from_slice(pool_data.as_slice())
|
||||
.map_err(|err| format!("Invalid pool {}: {}", pool, err))?;
|
||||
let pool_data = get_stake_pool(&config.rpc_client, pool)?;
|
||||
|
||||
if config.verbose {
|
||||
let validator_list = config
|
||||
.rpc_client
|
||||
.get_account_data(&pool_data.validator_list)?;
|
||||
let validator_list_data = try_from_slice_unchecked::<ValidatorList>(
|
||||
&validator_list.as_slice(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"Invalid validator list{}: {}",
|
||||
pool_data.validator_list, err
|
||||
)
|
||||
})?;
|
||||
println!("Current validator list");
|
||||
for validator in validator_list_data.validators {
|
||||
let validator_list = get_validator_list(&config.rpc_client, &pool_data.validator_list)?;
|
||||
for validator in validator_list.validators {
|
||||
println!(
|
||||
"Vote Account: {}\tBalance: {}\tEpoch: {}",
|
||||
validator.validator_account, validator.balance, validator.last_update_epoch
|
||||
|
@ -725,18 +641,11 @@ fn command_list(config: &Config, pool: &Pubkey) -> CommandResult {
|
|||
}
|
||||
|
||||
fn command_update(config: &Config, pool: &Pubkey) -> CommandResult {
|
||||
// Get stake pool state
|
||||
let pool_data = config.rpc_client.get_account_data(&pool)?;
|
||||
let pool_data = StakePool::try_from_slice(pool_data.as_slice()).unwrap();
|
||||
let validator_list_data = config
|
||||
.rpc_client
|
||||
.get_account_data(&pool_data.validator_list)?;
|
||||
let validator_list_data =
|
||||
try_from_slice_unchecked::<ValidatorList>(&validator_list_data.as_slice())?;
|
||||
|
||||
let pool_data = get_stake_pool(&config.rpc_client, pool)?;
|
||||
let validator_list = get_validator_list(&config.rpc_client, &pool_data.validator_list)?;
|
||||
let epoch_info = config.rpc_client.get_epoch_info()?;
|
||||
|
||||
let accounts_to_update: Vec<Pubkey> = validator_list_data
|
||||
let accounts_to_update: Vec<Pubkey> = validator_list
|
||||
.validators
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
|
@ -756,7 +665,7 @@ fn command_update(config: &Config, pool: &Pubkey) -> CommandResult {
|
|||
let mut instructions: Vec<Instruction> = vec![];
|
||||
|
||||
for chunk in accounts_to_update.chunks(MAX_ACCOUNTS_TO_UPDATE) {
|
||||
instructions.push(update_validator_list_balance(
|
||||
instructions.push(spl_stake_pool::instruction::update_validator_list_balance(
|
||||
&spl_stake_pool::id(),
|
||||
&pool_data.validator_list,
|
||||
&chunk,
|
||||
|
@ -768,7 +677,7 @@ fn command_update(config: &Config, pool: &Pubkey) -> CommandResult {
|
|||
Ok(())
|
||||
} else {
|
||||
println!("Updating stake pool...");
|
||||
instructions.push(update_stake_pool_balance(
|
||||
instructions.push(spl_stake_pool::instruction::update_stake_pool_balance(
|
||||
&spl_stake_pool::id(),
|
||||
pool,
|
||||
&pool_data.validator_list,
|
||||
|
@ -802,8 +711,7 @@ fn prepare_withdraw_accounts(
|
|||
return Err("No accounts found.".to_string().into());
|
||||
}
|
||||
let min_balance = rpc_client.get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)? + 1;
|
||||
let pool_mint_data = rpc_client.get_account_data(&stake_pool.pool_mint)?;
|
||||
let pool_mint = TokenMint::unpack_from_slice(pool_mint_data.as_slice()).unwrap();
|
||||
let pool_mint = get_token_mint(rpc_client, &stake_pool.pool_mint)?;
|
||||
|
||||
// Sort from highest to lowest balance
|
||||
accounts.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
|
@ -857,12 +765,8 @@ fn command_withdraw(
|
|||
command_update(config, pool)?;
|
||||
}
|
||||
|
||||
// Get stake pool state
|
||||
let pool_data = config.rpc_client.get_account_data(&pool)?;
|
||||
let pool_data = StakePool::try_from_slice(pool_data.as_slice()).unwrap();
|
||||
|
||||
let pool_mint_data = config.rpc_client.get_account_data(&pool_data.pool_mint)?;
|
||||
let pool_mint = TokenMint::unpack_from_slice(pool_mint_data.as_slice()).unwrap();
|
||||
let pool_data = get_stake_pool(&config.rpc_client, pool)?;
|
||||
let pool_mint = get_token_mint(&config.rpc_client, &pool_data.pool_mint)?;
|
||||
let pool_amount = spl_token::ui_amount_to_amount(pool_amount, pool_mint.decimals);
|
||||
|
||||
let pool_withdraw_authority: Pubkey = create_pool_authority_address(
|
||||
|
@ -874,20 +778,15 @@ fn command_withdraw(
|
|||
.unwrap();
|
||||
|
||||
// Check withdraw_from account type
|
||||
let account_data = config.rpc_client.get_account_data(&withdraw_from)?;
|
||||
let account_data: TokenAccount =
|
||||
TokenAccount::unpack_from_slice(account_data.as_slice()).unwrap();
|
||||
|
||||
if account_data.mint != pool_data.pool_mint {
|
||||
return Err("Wrong token account.".into());
|
||||
}
|
||||
let token_account =
|
||||
get_token_account(&config.rpc_client, &withdraw_from, &pool_data.pool_mint)?;
|
||||
|
||||
// Check withdraw_from balance
|
||||
if account_data.amount < pool_amount {
|
||||
if token_account.amount < pool_amount {
|
||||
return Err(format!(
|
||||
"Not enough token balance to withdraw {} pool tokens.\nMaximum withdraw amount is {} pool tokens.",
|
||||
spl_token::amount_to_ui_amount(pool_amount, pool_mint.decimals),
|
||||
spl_token::amount_to_ui_amount(account_data.amount, pool_mint.decimals)
|
||||
spl_token::amount_to_ui_amount(token_account.amount, pool_mint.decimals)
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
@ -907,7 +806,7 @@ fn command_withdraw(
|
|||
|
||||
instructions.push(
|
||||
// Approve spending token
|
||||
approve_token(
|
||||
spl_token::instruction::approve(
|
||||
&spl_token::id(),
|
||||
&withdraw_from,
|
||||
&pool_withdraw_authority,
|
||||
|
@ -965,7 +864,7 @@ fn command_withdraw(
|
|||
stake_receiver = Some(stake_receiver_account.pubkey());
|
||||
}
|
||||
|
||||
instructions.push(withdraw(
|
||||
instructions.push(spl_stake_pool::instruction::withdraw(
|
||||
&spl_stake_pool::id(),
|
||||
&pool,
|
||||
&pool_data.validator_list,
|
||||
|
@ -1000,27 +899,19 @@ fn command_set_owner(
|
|||
new_owner: &Option<Pubkey>,
|
||||
new_fee_receiver: &Option<Pubkey>,
|
||||
) -> CommandResult {
|
||||
let pool_data = config.rpc_client.get_account_data(&pool)?;
|
||||
let pool_data: StakePool = StakePool::try_from_slice(pool_data.as_slice()).unwrap();
|
||||
let pool_data = get_stake_pool(&config.rpc_client, pool)?;
|
||||
|
||||
// If new accounts are missing in the arguments use the old ones
|
||||
let new_owner: Pubkey = match new_owner {
|
||||
let new_owner = match new_owner {
|
||||
None => pool_data.owner,
|
||||
Some(value) => *value,
|
||||
};
|
||||
let new_fee_receiver: Pubkey = match new_fee_receiver {
|
||||
let new_fee_receiver = match new_fee_receiver {
|
||||
None => pool_data.owner_fee_account,
|
||||
Some(value) => {
|
||||
// Check for fee receiver being a valid token account and have to same mint as the stake pool
|
||||
let account_data = config.rpc_client.get_account_data(value)?;
|
||||
let account_data: TokenAccount =
|
||||
match TokenAccount::unpack_from_slice(account_data.as_slice()) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
return Err(format!("{} is not a token account", value).into());
|
||||
}
|
||||
};
|
||||
if account_data.mint != pool_data.pool_mint {
|
||||
let token_account = get_token_account(&config.rpc_client, value, &pool_data.pool_mint)?;
|
||||
if token_account.mint != pool_data.pool_mint {
|
||||
return Err("Fee receiver account belongs to a different mint"
|
||||
.to_string()
|
||||
.into());
|
||||
|
@ -1030,7 +921,7 @@ fn command_set_owner(
|
|||
};
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[set_owner(
|
||||
&[spl_stake_pool::instruction::set_owner(
|
||||
&spl_stake_pool::id(),
|
||||
&pool,
|
||||
&config.owner.pubkey(),
|
||||
|
@ -1122,7 +1013,8 @@ fn main() {
|
|||
Defaults to the client keypair.",
|
||||
),
|
||||
)
|
||||
.subcommand(SubCommand::with_name("create-pool").about("Create a new stake pool")
|
||||
.subcommand(SubCommand::with_name("create-pool")
|
||||
.about("Create a new stake pool")
|
||||
.arg(
|
||||
Arg::with_name("fee_numerator")
|
||||
.long("fee-numerator")
|
||||
|
@ -1154,7 +1046,8 @@ fn main() {
|
|||
.help("Max number of validators included in the stake pool"),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("create-validator-stake").about("Create a new stake account to use with the pool. Must be signed by the pool owner.")
|
||||
.subcommand(SubCommand::with_name("create-validator-stake")
|
||||
.about("Create a new stake account to use with the pool. Must be signed by the pool owner.")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1174,7 +1067,8 @@ fn main() {
|
|||
.help("The validator vote account that this stake will be delegated to"),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("add-validator").about("Add validator account to the stake pool. Must be signed by the pool owner.")
|
||||
.subcommand(SubCommand::with_name("add-validator")
|
||||
.about("Add validator account to the stake pool. Must be signed by the pool owner.")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1199,10 +1093,12 @@ fn main() {
|
|||
.validator(is_pubkey)
|
||||
.value_name("ADDRESS")
|
||||
.takes_value(true)
|
||||
.help("Account to receive pool token. Must be initialized account of the stake pool token. Defaults to the new pool token account."),
|
||||
.help("Account to receive pool token. Must be initialized account of the stake pool token. \
|
||||
Defaults to the new pool token account."),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("remove-validator").about("Remove validator account from the stake pool. Must be signed by the pool owner.")
|
||||
.subcommand(SubCommand::with_name("remove-validator")
|
||||
.about("Remove validator account from the stake pool. Must be signed by the pool owner.")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1228,7 +1124,8 @@ fn main() {
|
|||
.value_name("ADDRESS")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("Token account to withdraw pool token from. Must have enough tokens for the full stake address balance."),
|
||||
.help("Token account to withdraw pool token from. \
|
||||
Must have enough tokens for the full stake address balance."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("new_authority")
|
||||
|
@ -1236,10 +1133,12 @@ fn main() {
|
|||
.validator(is_pubkey)
|
||||
.value_name("ADDRESS")
|
||||
.takes_value(true)
|
||||
.help("New authority to set as Staker and Withdrawer in the stake account removed from the pool. Defaults to the wallet owner pubkey."),
|
||||
.help("New authority to set as Staker and Withdrawer in the stake account removed from the pool.
|
||||
Defaults to the wallet owner pubkey."),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("deposit").about("Add stake account to the stake pool")
|
||||
.subcommand(SubCommand::with_name("deposit")
|
||||
.about("Add stake account to the stake pool")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1264,10 +1163,12 @@ fn main() {
|
|||
.validator(is_pubkey)
|
||||
.value_name("ADDRESS")
|
||||
.takes_value(true)
|
||||
.help("Account to receive pool token. Must be initialized account of the stake pool token. Defaults to the new pool token account."),
|
||||
.help("Account to receive pool token. Must be initialized account of the stake pool token. \
|
||||
Defaults to the new pool token account."),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("list").about("List stake accounts managed by this pool")
|
||||
.subcommand(SubCommand::with_name("list")
|
||||
.about("List stake accounts managed by this pool")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1278,7 +1179,8 @@ fn main() {
|
|||
.help("Stake pool address."),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("update").about("Updates all balances in the pool after validator stake accounts receive rewards.")
|
||||
.subcommand(SubCommand::with_name("update")
|
||||
.about("Updates all balances in the pool after validator stake accounts receive rewards.")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1289,7 +1191,8 @@ fn main() {
|
|||
.help("Stake pool address."),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("withdraw").about("Withdraw amount from the stake pool")
|
||||
.subcommand(SubCommand::with_name("withdraw")
|
||||
.about("Withdraw amount from the stake pool")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1326,7 +1229,8 @@ fn main() {
|
|||
.help("Stake account to receive SOL from the stake pool. Defaults to a new stake account."),
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("set-owner").about("Changes owner or fee receiver account for the stake pool.")
|
||||
.subcommand(SubCommand::with_name("set-owner")
|
||||
.about("Changes owner or fee receiver account for the stake pool.")
|
||||
.arg(
|
||||
Arg::with_name("pool")
|
||||
.index(1)
|
||||
|
@ -1414,7 +1318,7 @@ fn main() {
|
|||
let max_validators = value_t_or_exit!(arg_matches, "max_validators", u32);
|
||||
command_create_pool(
|
||||
&config,
|
||||
PoolFee {
|
||||
spl_stake_pool::instruction::Fee {
|
||||
denominator,
|
||||
numerator,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue