stake-pool: Add depositor key on init, required on deposit (#1616)
* stake-pool: Add depositor key on init, required on deposit Some stake pools need to be private, and not allow outside depositors. Enhance the existing deposit authority in the stake pool be configurable on initialization, and then require its signature on deposit. The existing deposit authority is a program address, making deposits permissionless. This allows a pool creator to set their own deposit_authority on initialization. In a great turn of events, almost everything else works the same way! Here's the current workflow for deposit, where the user calls stake_program::authorize and stake_pool::deposit in the same transaction: * stake_program::authorize assigns staker and withdraw authority to the stake pool deposit authority * stake_pool::deposit - uses the deposit authority to assign authority on the deposited stake account to the stake pool withdraw authority - uses the withdraw authority to merge the deposited stake into the validator stake The deposit authority must "sign" the transaction in order to reassign authority to the withdraw authority. Currently, as a program address, it can just do that. With this change, if the deposit authority is set during initialization, then that deposit authority must sign the instruction. There's also a little update for ease-of-use to always do the stake_program::authorize in the same transaction as stake_pool::deposit. This way, in case someone tries to deposit into a forbidden stake pool, the whole transaction will bail and their stake will stay as theirs. * Address review feedback * Fix rebase issues
This commit is contained in:
parent
804a61e558
commit
c149b0a46e
|
@ -14,7 +14,7 @@ use {
|
|||
input_validators::{is_amount, is_keypair, is_parsable, is_pubkey, is_url},
|
||||
keypair::signer_from_path,
|
||||
},
|
||||
solana_client::{rpc_client::RpcClient, rpc_response::StakeActivationState},
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_program::{
|
||||
borsh::get_packed_len, instruction::Instruction, program_pack::Pack, pubkey::Pubkey,
|
||||
},
|
||||
|
@ -28,9 +28,9 @@ use {
|
|||
spl_stake_pool::{
|
||||
self,
|
||||
borsh::get_instance_packed_len,
|
||||
find_deposit_authority_program_address, find_stake_program_address,
|
||||
find_transient_stake_program_address, find_withdraw_authority_program_address,
|
||||
stake_program::{self, StakeAuthorize, StakeState},
|
||||
find_stake_program_address, find_transient_stake_program_address,
|
||||
find_withdraw_authority_program_address,
|
||||
stake_program::{self, StakeState},
|
||||
state::{Fee, StakePool, ValidatorList},
|
||||
MAX_VALIDATORS_TO_UPDATE,
|
||||
},
|
||||
|
@ -42,6 +42,7 @@ struct Config {
|
|||
verbose: bool,
|
||||
manager: Box<dyn Signer>,
|
||||
staker: Box<dyn Signer>,
|
||||
depositor: Option<Box<dyn Signer>>,
|
||||
token_owner: Box<dyn Signer>,
|
||||
fee_payer: Box<dyn Signer>,
|
||||
dry_run: bool,
|
||||
|
@ -94,7 +95,12 @@ fn send_transaction(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn command_create_pool(config: &Config, fee: Fee, max_validators: u32) -> CommandResult {
|
||||
fn command_create_pool(
|
||||
config: &Config,
|
||||
deposit_authority: Option<Pubkey>,
|
||||
fee: Fee,
|
||||
max_validators: u32,
|
||||
) -> CommandResult {
|
||||
let reserve_stake = Keypair::new();
|
||||
println!("Creating reserve stake {}", reserve_stake.pubkey());
|
||||
|
||||
|
@ -224,6 +230,7 @@ fn command_create_pool(config: &Config, fee: Fee, max_validators: u32) -> Comman
|
|||
&mint_account.pubkey(),
|
||||
&pool_fee_account.pubkey(),
|
||||
&spl_token::id(),
|
||||
deposit_authority,
|
||||
fee,
|
||||
max_validators,
|
||||
)?,
|
||||
|
@ -286,7 +293,17 @@ fn command_vsa_create(
|
|||
}
|
||||
|
||||
fn command_vsa_add(config: &Config, stake_pool_address: &Pubkey, stake: &Pubkey) -> CommandResult {
|
||||
if config.rpc_client.get_stake_activation(*stake, None)?.state != StakeActivationState::Active {
|
||||
let stake_state = get_stake_state(&config.rpc_client, &stake)?;
|
||||
if let stake_program::StakeState::Stake(meta, _stake) = stake_state {
|
||||
if meta.authorized.withdrawer != config.staker.pubkey() {
|
||||
let error = format!(
|
||||
"Stake account withdraw authority must be the staker {}, actual {}",
|
||||
config.staker.pubkey(),
|
||||
meta.authorized.withdrawer
|
||||
);
|
||||
return Err(error.into());
|
||||
}
|
||||
} else {
|
||||
return Err("Stake account is not active.".into());
|
||||
}
|
||||
|
||||
|
@ -299,34 +316,16 @@ fn command_vsa_add(config: &Config, stake_pool_address: &Pubkey, stake: &Pubkey)
|
|||
let mut instructions: Vec<Instruction> = vec![];
|
||||
let mut signers = vec![config.fee_payer.as_ref(), config.staker.as_ref()];
|
||||
|
||||
// Calculate Deposit and Withdraw stake pool authorities
|
||||
let pool_deposit_authority =
|
||||
find_deposit_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0;
|
||||
|
||||
// Calculate Withdraw stake pool authorities
|
||||
let pool_withdraw_authority =
|
||||
find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0;
|
||||
|
||||
instructions.extend(vec![
|
||||
// Set Withdrawer on stake account to Deposit authority of the stake pool
|
||||
stake_program::authorize(
|
||||
&stake,
|
||||
&config.staker.pubkey(),
|
||||
&pool_deposit_authority,
|
||||
StakeAuthorize::Withdrawer,
|
||||
),
|
||||
// Set Staker on stake account to Deposit authority of the stake pool
|
||||
stake_program::authorize(
|
||||
&stake,
|
||||
&config.staker.pubkey(),
|
||||
&pool_deposit_authority,
|
||||
StakeAuthorize::Staker,
|
||||
),
|
||||
// Add validator stake account to the pool
|
||||
spl_stake_pool::instruction::add_validator_to_pool(
|
||||
&spl_stake_pool::id(),
|
||||
&stake_pool_address,
|
||||
&config.staker.pubkey(),
|
||||
&pool_deposit_authority,
|
||||
&pool_withdraw_authority,
|
||||
&stake_pool.validator_list,
|
||||
&stake,
|
||||
|
@ -588,42 +587,49 @@ fn command_deposit(
|
|||
},
|
||||
)?;
|
||||
|
||||
// Calculate Deposit and Withdraw stake pool authorities
|
||||
let pool_deposit_authority =
|
||||
find_deposit_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0;
|
||||
|
||||
let pool_withdraw_authority =
|
||||
find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0;
|
||||
|
||||
instructions.extend(vec![
|
||||
// Set Withdrawer on stake account to Deposit authority of the stake pool
|
||||
stake_program::authorize(
|
||||
&stake,
|
||||
&config.staker.pubkey(),
|
||||
&pool_deposit_authority,
|
||||
StakeAuthorize::Withdrawer,
|
||||
),
|
||||
// Set Staker on stake account to Deposit authority of the stake pool
|
||||
stake_program::authorize(
|
||||
&stake,
|
||||
&config.staker.pubkey(),
|
||||
&pool_deposit_authority,
|
||||
StakeAuthorize::Staker,
|
||||
),
|
||||
// Add stake account to the pool
|
||||
spl_stake_pool::instruction::deposit(
|
||||
let mut deposit_instructions = if let Some(deposit_authority) = config.depositor.as_ref() {
|
||||
signers.push(deposit_authority.as_ref());
|
||||
if deposit_authority.pubkey() != stake_pool.deposit_authority {
|
||||
let error = format!(
|
||||
"Invalid deposit authority specified, expected {}, received {}",
|
||||
stake_pool.deposit_authority,
|
||||
deposit_authority.pubkey()
|
||||
);
|
||||
return Err(error.into());
|
||||
}
|
||||
|
||||
spl_stake_pool::instruction::deposit_with_authority(
|
||||
&spl_stake_pool::id(),
|
||||
&stake_pool_address,
|
||||
&stake_pool.validator_list,
|
||||
&pool_deposit_authority,
|
||||
&deposit_authority.pubkey(),
|
||||
&pool_withdraw_authority,
|
||||
&stake,
|
||||
&config.staker.pubkey(),
|
||||
&validator_stake_account,
|
||||
&token_receiver,
|
||||
&stake_pool.pool_mint,
|
||||
&spl_token::id(),
|
||||
)?,
|
||||
]);
|
||||
)
|
||||
} else {
|
||||
spl_stake_pool::instruction::deposit(
|
||||
&spl_stake_pool::id(),
|
||||
&stake_pool_address,
|
||||
&stake_pool.validator_list,
|
||||
&pool_withdraw_authority,
|
||||
&stake,
|
||||
&config.staker.pubkey(),
|
||||
&validator_stake_account,
|
||||
&token_receiver,
|
||||
&stake_pool.pool_mint,
|
||||
&spl_token::id(),
|
||||
)
|
||||
};
|
||||
|
||||
instructions.append(&mut deposit_instructions);
|
||||
|
||||
let mut transaction =
|
||||
Transaction::new_with_payer(&instructions, Some(&config.fee_payer.pubkey()));
|
||||
|
@ -1130,6 +1136,17 @@ fn main() {
|
|||
Defaults to the client keypair.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("depositor")
|
||||
.long("depositor")
|
||||
.value_name("KEYPAIR")
|
||||
.validator(is_keypair)
|
||||
.takes_value(true)
|
||||
.help(
|
||||
"Specify the stake pool depositor. \
|
||||
This may be a keypair file, the ASK keyword.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("token_owner")
|
||||
.long("token-owner")
|
||||
|
@ -1186,6 +1203,15 @@ fn main() {
|
|||
.required(true)
|
||||
.help("Max number of validators included in the stake pool"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("deposit_authority")
|
||||
.long("deposit-authority")
|
||||
.short("a")
|
||||
.validator(is_pubkey)
|
||||
.value_name("DEPOSIT_AUTHORITY_ADDRESS")
|
||||
.takes_value(true)
|
||||
.help("Deposit authority required to sign all deposits into 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 staker.")
|
||||
|
@ -1515,6 +1541,22 @@ fn main() {
|
|||
eprintln!("error: {}", e);
|
||||
exit(1);
|
||||
});
|
||||
let depositor = if matches.is_present("depositor") {
|
||||
Some(
|
||||
signer_from_path(
|
||||
&matches,
|
||||
&cli_config.keypair_path,
|
||||
"depositor",
|
||||
&mut wallet_manager,
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("error: {}", e);
|
||||
exit(1);
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let manager = signer_from_path(
|
||||
&matches,
|
||||
&cli_config.keypair_path,
|
||||
|
@ -1554,6 +1596,7 @@ fn main() {
|
|||
verbose,
|
||||
manager,
|
||||
staker,
|
||||
depositor,
|
||||
token_owner,
|
||||
fee_payer,
|
||||
dry_run,
|
||||
|
@ -1563,11 +1606,13 @@ fn main() {
|
|||
|
||||
let _ = match matches.subcommand() {
|
||||
("create-pool", Some(arg_matches)) => {
|
||||
let deposit_authority = pubkey_of(arg_matches, "deposit_authority");
|
||||
let numerator = value_t_or_exit!(arg_matches, "fee_numerator", u64);
|
||||
let denominator = value_t_or_exit!(arg_matches, "fee_denominator", u64);
|
||||
let max_validators = value_t_or_exit!(arg_matches, "max_validators", u32);
|
||||
command_create_pool(
|
||||
&config,
|
||||
deposit_authority,
|
||||
Fee {
|
||||
denominator,
|
||||
numerator,
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
use {
|
||||
crate::{
|
||||
find_stake_program_address, find_transient_stake_program_address, stake_program, state::Fee,
|
||||
find_deposit_authority_program_address, find_stake_program_address,
|
||||
find_transient_stake_program_address, stake_program, state::Fee,
|
||||
},
|
||||
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
|
||||
solana_program::{
|
||||
|
@ -32,6 +33,9 @@ pub enum StakePoolInstruction {
|
|||
/// 7. `[]` Clock sysvar
|
||||
/// 8. `[]` Rent sysvar
|
||||
/// 9. `[]` Token program id
|
||||
/// 10. `[]` (Optional) Deposit authority that must sign all deposits.
|
||||
/// Defaults to the program address generated using
|
||||
/// `find_deposit_authority_program_address`, making deposits permissionless.
|
||||
Initialize {
|
||||
/// Fee assessed as percentage of perceived rewards
|
||||
#[allow(dead_code)] // but it's not
|
||||
|
@ -70,13 +74,13 @@ pub enum StakePoolInstruction {
|
|||
///
|
||||
/// 0. `[w]` Stake pool
|
||||
/// 1. `[s]` Staker
|
||||
/// 2. `[]` Stake pool deposit authority
|
||||
/// 3. `[]` Stake pool withdraw authority
|
||||
/// 4. `[w]` Validator stake list storage account
|
||||
/// 5. `[w]` Stake account to add to the pool, its withdraw authority should be set to stake pool deposit
|
||||
/// 6. `[]` Clock sysvar
|
||||
/// 7. '[]' Sysvar stake history account
|
||||
/// 8. `[]` Stake program
|
||||
/// 2. `[]` Stake pool withdraw authority
|
||||
/// 3. `[w]` Validator stake list storage account
|
||||
/// 4. `[w]` Stake account to add to the pool, its withdraw authority must
|
||||
/// be set to the staker
|
||||
/// 5. `[]` Clock sysvar
|
||||
/// 6. '[]' Sysvar stake history account
|
||||
/// 7. `[]` Stake program
|
||||
AddValidatorToPool,
|
||||
|
||||
/// (Staker only) Removes validator from the pool
|
||||
|
@ -195,7 +199,7 @@ pub enum StakePoolInstruction {
|
|||
/// 1. `[w]` Validator stake list storage account
|
||||
/// 2. `[]` Stake pool deposit authority
|
||||
/// 3. `[]` Stake pool withdraw authority
|
||||
/// 4. `[w]` Stake account to join the pool (withdraw should be set to stake pool deposit)
|
||||
/// 4. `[w]` Stake account to join the pool (withdraw authority for the stake account should be first set to the stake pool deposit authority)
|
||||
/// 5. `[w]` Validator stake account for the stake account to be merged with
|
||||
/// 6. `[w]` User account to receive pool tokens
|
||||
/// 8. `[w]` Pool token mint account
|
||||
|
@ -267,6 +271,7 @@ pub fn initialize(
|
|||
pool_mint: &Pubkey,
|
||||
manager_pool_account: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
deposit_authority: Option<Pubkey>,
|
||||
fee: Fee,
|
||||
max_validators: u32,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
|
@ -275,7 +280,7 @@ pub fn initialize(
|
|||
max_validators,
|
||||
};
|
||||
let data = init_data.try_to_vec()?;
|
||||
let accounts = vec![
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new(*stake_pool, true),
|
||||
AccountMeta::new_readonly(*manager, true),
|
||||
AccountMeta::new_readonly(*staker, false),
|
||||
|
@ -287,6 +292,9 @@ pub fn initialize(
|
|||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(*token_program_id, false),
|
||||
];
|
||||
if let Some(deposit_authority) = deposit_authority {
|
||||
accounts.push(AccountMeta::new_readonly(deposit_authority, true));
|
||||
}
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
|
@ -328,7 +336,6 @@ pub fn add_validator_to_pool(
|
|||
program_id: &Pubkey,
|
||||
stake_pool: &Pubkey,
|
||||
staker: &Pubkey,
|
||||
stake_pool_deposit: &Pubkey,
|
||||
stake_pool_withdraw: &Pubkey,
|
||||
validator_list: &Pubkey,
|
||||
stake_account: &Pubkey,
|
||||
|
@ -336,7 +343,6 @@ pub fn add_validator_to_pool(
|
|||
let accounts = vec![
|
||||
AccountMeta::new(*stake_pool, false),
|
||||
AccountMeta::new_readonly(*staker, true),
|
||||
AccountMeta::new_readonly(*stake_pool_deposit, false),
|
||||
AccountMeta::new_readonly(*stake_pool_withdraw, false),
|
||||
AccountMeta::new(*validator_list, false),
|
||||
AccountMeta::new(*stake_account, false),
|
||||
|
@ -529,25 +535,28 @@ pub fn update_stake_pool_balance(
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a 'Deposit' instruction.
|
||||
/// Creates instructions required to deposit into a stake pool, given a stake
|
||||
/// account owned by the user.
|
||||
pub fn deposit(
|
||||
program_id: &Pubkey,
|
||||
stake_pool: &Pubkey,
|
||||
validator_list_storage: &Pubkey,
|
||||
stake_pool_deposit: &Pubkey,
|
||||
stake_pool_withdraw: &Pubkey,
|
||||
stake_to_join: &Pubkey,
|
||||
stake_pool_withdraw_authority: &Pubkey,
|
||||
deposit_stake_address: &Pubkey,
|
||||
deposit_stake_withdraw_authority: &Pubkey,
|
||||
validator_stake_accont: &Pubkey,
|
||||
pool_tokens_to: &Pubkey,
|
||||
pool_mint: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
) -> Vec<Instruction> {
|
||||
let stake_pool_deposit_authority =
|
||||
find_deposit_authority_program_address(program_id, stake_pool).0;
|
||||
let accounts = vec![
|
||||
AccountMeta::new(*stake_pool, false),
|
||||
AccountMeta::new(*validator_list_storage, false),
|
||||
AccountMeta::new_readonly(*stake_pool_deposit, false),
|
||||
AccountMeta::new_readonly(*stake_pool_withdraw, false),
|
||||
AccountMeta::new(*stake_to_join, false),
|
||||
AccountMeta::new_readonly(stake_pool_deposit_authority, false),
|
||||
AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
|
||||
AccountMeta::new(*deposit_stake_address, false),
|
||||
AccountMeta::new(*validator_stake_accont, false),
|
||||
AccountMeta::new(*pool_tokens_to, false),
|
||||
AccountMeta::new(*pool_mint, false),
|
||||
|
@ -556,11 +565,76 @@ pub fn deposit(
|
|||
AccountMeta::new_readonly(*token_program_id, false),
|
||||
AccountMeta::new_readonly(stake_program::id(), false),
|
||||
];
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data: StakePoolInstruction::Deposit.try_to_vec()?,
|
||||
})
|
||||
vec![
|
||||
stake_program::authorize(
|
||||
deposit_stake_address,
|
||||
deposit_stake_withdraw_authority,
|
||||
&stake_pool_deposit_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
),
|
||||
stake_program::authorize(
|
||||
deposit_stake_address,
|
||||
deposit_stake_withdraw_authority,
|
||||
&stake_pool_deposit_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
),
|
||||
Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data: StakePoolInstruction::Deposit.try_to_vec().unwrap(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/// Creates instructions required to deposit into a stake pool, given a stake
|
||||
/// account owned by the user. The difference with `deposit()` is that a deposit
|
||||
/// authority must sign this instruction, which is required for private pools.
|
||||
pub fn deposit_with_authority(
|
||||
program_id: &Pubkey,
|
||||
stake_pool: &Pubkey,
|
||||
validator_list_storage: &Pubkey,
|
||||
stake_pool_deposit_authority: &Pubkey,
|
||||
stake_pool_withdraw_authority: &Pubkey,
|
||||
deposit_stake_address: &Pubkey,
|
||||
deposit_stake_withdraw_authority: &Pubkey,
|
||||
validator_stake_accont: &Pubkey,
|
||||
pool_tokens_to: &Pubkey,
|
||||
pool_mint: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
) -> Vec<Instruction> {
|
||||
let accounts = vec![
|
||||
AccountMeta::new(*stake_pool, false),
|
||||
AccountMeta::new(*validator_list_storage, false),
|
||||
AccountMeta::new_readonly(*stake_pool_deposit_authority, true),
|
||||
AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
|
||||
AccountMeta::new(*deposit_stake_address, false),
|
||||
AccountMeta::new(*validator_stake_accont, false),
|
||||
AccountMeta::new(*pool_tokens_to, false),
|
||||
AccountMeta::new(*pool_mint, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
AccountMeta::new_readonly(*token_program_id, false),
|
||||
AccountMeta::new_readonly(stake_program::id(), false),
|
||||
];
|
||||
vec![
|
||||
stake_program::authorize(
|
||||
deposit_stake_address,
|
||||
deposit_stake_withdraw_authority,
|
||||
stake_pool_deposit_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
),
|
||||
stake_program::authorize(
|
||||
deposit_stake_address,
|
||||
deposit_stake_withdraw_authority,
|
||||
stake_pool_deposit_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
),
|
||||
Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data: StakePoolInstruction::Deposit.try_to_vec().unwrap(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/// Creates a 'withdraw' instruction.
|
||||
|
|
|
@ -4,6 +4,7 @@ use {
|
|||
crate::{
|
||||
borsh::try_from_slice_unchecked,
|
||||
error::StakePoolError,
|
||||
find_deposit_authority_program_address,
|
||||
instruction::StakePoolInstruction,
|
||||
minimum_reserve_lamports, minimum_stake_lamports, stake_program,
|
||||
state::{AccountType, Fee, StakePool, ValidatorList, ValidatorStakeInfo},
|
||||
|
@ -203,10 +204,14 @@ impl Processor {
|
|||
let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]];
|
||||
let signers = &[&authority_signature_seeds[..]];
|
||||
|
||||
let ix =
|
||||
let split_instruction =
|
||||
stake_program::split_only(stake_account.key, authority.key, amount, split_stake.key);
|
||||
|
||||
invoke_signed(&ix, &[stake_account, split_stake, authority], signers)
|
||||
invoke_signed(
|
||||
&split_instruction,
|
||||
&[stake_account, split_stake, authority],
|
||||
signers,
|
||||
)
|
||||
}
|
||||
|
||||
/// Issue a stake_merge instruction.
|
||||
|
@ -226,10 +231,11 @@ impl Processor {
|
|||
let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]];
|
||||
let signers = &[&authority_signature_seeds[..]];
|
||||
|
||||
let ix = stake_program::merge(destination_account.key, source_account.key, authority.key);
|
||||
let merge_instruction =
|
||||
stake_program::merge(destination_account.key, source_account.key, authority.key);
|
||||
|
||||
invoke_signed(
|
||||
&ix,
|
||||
&merge_instruction,
|
||||
&[
|
||||
destination_account,
|
||||
source_account,
|
||||
|
@ -242,16 +248,53 @@ impl Processor {
|
|||
)
|
||||
}
|
||||
|
||||
/// Issue a stake_set_manager instruction.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
/// Issue stake_program::authorize instructions to update both authorities
|
||||
fn stake_authorize<'a>(
|
||||
stake_account: AccountInfo<'a>,
|
||||
stake_authority: AccountInfo<'a>,
|
||||
new_stake_authority: &Pubkey,
|
||||
clock: AccountInfo<'a>,
|
||||
stake_program_info: AccountInfo<'a>,
|
||||
) -> Result<(), ProgramError> {
|
||||
let authorize_instruction = stake_program::authorize(
|
||||
stake_account.key,
|
||||
stake_authority.key,
|
||||
new_stake_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
);
|
||||
|
||||
invoke(
|
||||
&authorize_instruction,
|
||||
&[
|
||||
stake_account.clone(),
|
||||
clock.clone(),
|
||||
stake_authority.clone(),
|
||||
stake_program_info.clone(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let authorize_instruction = stake_program::authorize(
|
||||
stake_account.key,
|
||||
stake_authority.key,
|
||||
new_stake_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
);
|
||||
|
||||
invoke(
|
||||
&authorize_instruction,
|
||||
&[stake_account, clock, stake_authority, stake_program_info],
|
||||
)
|
||||
}
|
||||
|
||||
/// Issue stake_program::authorize instructions to update both authorities
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn stake_authorize_signed<'a>(
|
||||
stake_pool: &Pubkey,
|
||||
stake_account: AccountInfo<'a>,
|
||||
authority: AccountInfo<'a>,
|
||||
stake_authority: AccountInfo<'a>,
|
||||
authority_type: &[u8],
|
||||
bump_seed: u8,
|
||||
new_staker: &Pubkey,
|
||||
staker_auth: stake_program::StakeAuthorize,
|
||||
new_stake_authority: &Pubkey,
|
||||
clock: AccountInfo<'a>,
|
||||
stake_program_info: AccountInfo<'a>,
|
||||
) -> Result<(), ProgramError> {
|
||||
|
@ -259,12 +302,33 @@ impl Processor {
|
|||
let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]];
|
||||
let signers = &[&authority_signature_seeds[..]];
|
||||
|
||||
let ix =
|
||||
stake_program::authorize(stake_account.key, authority.key, new_staker, staker_auth);
|
||||
let authorize_instruction = stake_program::authorize(
|
||||
stake_account.key,
|
||||
stake_authority.key,
|
||||
new_stake_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
);
|
||||
|
||||
invoke_signed(
|
||||
&ix,
|
||||
&[stake_account, clock, authority, stake_program_info],
|
||||
&authorize_instruction,
|
||||
&[
|
||||
stake_account.clone(),
|
||||
clock.clone(),
|
||||
stake_authority.clone(),
|
||||
stake_program_info.clone(),
|
||||
],
|
||||
signers,
|
||||
)?;
|
||||
|
||||
let authorize_instruction = stake_program::authorize(
|
||||
stake_account.key,
|
||||
stake_authority.key,
|
||||
new_stake_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
);
|
||||
invoke_signed(
|
||||
&authorize_instruction,
|
||||
&[stake_account, clock, stake_authority, stake_program_info],
|
||||
signers,
|
||||
)
|
||||
}
|
||||
|
@ -414,8 +478,10 @@ impl Processor {
|
|||
return Err(StakePoolError::WrongAccountMint.into());
|
||||
}
|
||||
|
||||
let (_, deposit_bump_seed) =
|
||||
crate::find_deposit_authority_program_address(program_id, stake_pool_info.key);
|
||||
let deposit_authority = match next_account_info(account_info_iter) {
|
||||
Ok(deposit_authority_info) => *deposit_authority_info.key,
|
||||
Err(_) => find_deposit_authority_program_address(program_id, stake_pool_info.key).0,
|
||||
};
|
||||
let (withdraw_authority_key, withdraw_bump_seed) =
|
||||
crate::find_withdraw_authority_program_address(program_id, stake_pool_info.key);
|
||||
|
||||
|
@ -475,7 +541,7 @@ impl Processor {
|
|||
stake_pool.manager = *manager_info.key;
|
||||
stake_pool.staker = *staker_info.key;
|
||||
stake_pool.reserve_stake = *reserve_stake_info.key;
|
||||
stake_pool.deposit_bump_seed = deposit_bump_seed;
|
||||
stake_pool.deposit_authority = deposit_authority;
|
||||
stake_pool.withdraw_bump_seed = withdraw_bump_seed;
|
||||
stake_pool.validator_list = *validator_list_info.key;
|
||||
stake_pool.pool_mint = *pool_mint_info.key;
|
||||
|
@ -594,8 +660,7 @@ impl Processor {
|
|||
let account_info_iter = &mut accounts.iter();
|
||||
let stake_pool_info = next_account_info(account_info_iter)?;
|
||||
let staker_info = next_account_info(account_info_iter)?;
|
||||
let deposit_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_authority_info = next_account_info(account_info_iter)?;
|
||||
let validator_list_info = next_account_info(account_info_iter)?;
|
||||
let stake_account_info = next_account_info(account_info_iter)?;
|
||||
let clock_info = next_account_info(account_info_iter)?;
|
||||
|
@ -614,8 +679,11 @@ impl Processor {
|
|||
return Err(StakePoolError::InvalidState.into());
|
||||
}
|
||||
|
||||
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
|
||||
stake_pool.check_authority_deposit(deposit_info.key, program_id, stake_pool_info.key)?;
|
||||
stake_pool.check_authority_withdraw(
|
||||
withdraw_authority_info.key,
|
||||
program_id,
|
||||
stake_pool_info.key,
|
||||
)?;
|
||||
|
||||
stake_pool.check_staker(staker_info)?;
|
||||
|
||||
|
@ -645,6 +713,11 @@ impl Processor {
|
|||
&vote_account_address,
|
||||
)?;
|
||||
|
||||
if meta.lockup != stake_program::Lockup::default() {
|
||||
msg!("Validator stake account has a lockup");
|
||||
return Err(StakePoolError::WrongStakeState.into());
|
||||
}
|
||||
|
||||
if validator_list.contains(&vote_account_address) {
|
||||
return Err(StakePoolError::ValidatorAlreadyAdded.into());
|
||||
}
|
||||
|
@ -665,22 +738,13 @@ impl Processor {
|
|||
//Self::check_stake_activation(stake_account_info, clock, stake_history)?;
|
||||
|
||||
// Update Withdrawer and Staker authority to the program withdraw authority
|
||||
for authority in &[
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
] {
|
||||
Self::stake_authorize(
|
||||
stake_pool_info.key,
|
||||
stake_account_info.clone(),
|
||||
deposit_info.clone(),
|
||||
AUTHORITY_DEPOSIT,
|
||||
stake_pool.deposit_bump_seed,
|
||||
withdraw_info.key,
|
||||
*authority,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
}
|
||||
Self::stake_authorize(
|
||||
stake_account_info.clone(),
|
||||
staker_info.clone(),
|
||||
withdraw_authority_info.key,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
|
||||
validator_list.validators.push(ValidatorStakeInfo {
|
||||
vote_account_address,
|
||||
|
@ -700,7 +764,7 @@ impl Processor {
|
|||
let account_info_iter = &mut accounts.iter();
|
||||
let stake_pool_info = next_account_info(account_info_iter)?;
|
||||
let staker_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_authority_info = next_account_info(account_info_iter)?;
|
||||
let new_stake_authority_info = next_account_info(account_info_iter)?;
|
||||
let validator_list_info = next_account_info(account_info_iter)?;
|
||||
let stake_account_info = next_account_info(account_info_iter)?;
|
||||
|
@ -717,7 +781,11 @@ impl Processor {
|
|||
return Err(StakePoolError::InvalidState.into());
|
||||
}
|
||||
|
||||
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
|
||||
stake_pool.check_authority_withdraw(
|
||||
withdraw_authority_info.key,
|
||||
program_id,
|
||||
stake_pool_info.key,
|
||||
)?;
|
||||
stake_pool.check_staker(staker_info)?;
|
||||
|
||||
if stake_pool.last_update_epoch < clock.epoch {
|
||||
|
@ -772,22 +840,16 @@ impl Processor {
|
|||
return Err(StakePoolError::StakeLamportsNotEqualToMinimum.into());
|
||||
}
|
||||
|
||||
for authority in &[
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
] {
|
||||
Self::stake_authorize(
|
||||
stake_pool_info.key,
|
||||
stake_account_info.clone(),
|
||||
withdraw_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
new_stake_authority_info.key,
|
||||
*authority,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
}
|
||||
Self::stake_authorize_signed(
|
||||
stake_pool_info.key,
|
||||
stake_account_info.clone(),
|
||||
withdraw_authority_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
new_stake_authority_info.key,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
|
||||
validator_list
|
||||
.validators
|
||||
|
@ -1382,8 +1444,8 @@ impl Processor {
|
|||
let account_info_iter = &mut accounts.iter();
|
||||
let stake_pool_info = next_account_info(account_info_iter)?;
|
||||
let validator_list_info = next_account_info(account_info_iter)?;
|
||||
let deposit_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_info = next_account_info(account_info_iter)?;
|
||||
let deposit_authority_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_authority_info = next_account_info(account_info_iter)?;
|
||||
let stake_info = next_account_info(account_info_iter)?;
|
||||
let validator_stake_account_info = next_account_info(account_info_iter)?;
|
||||
let dest_user_info = next_account_info(account_info_iter)?;
|
||||
|
@ -1406,8 +1468,12 @@ impl Processor {
|
|||
|
||||
//Self::check_stake_activation(stake_info, clock, stake_history)?;
|
||||
|
||||
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
|
||||
stake_pool.check_authority_deposit(deposit_info.key, program_id, stake_pool_info.key)?;
|
||||
stake_pool.check_authority_withdraw(
|
||||
withdraw_authority_info.key,
|
||||
program_id,
|
||||
stake_pool_info.key,
|
||||
)?;
|
||||
stake_pool.check_deposit_authority(deposit_authority_info.key)?;
|
||||
stake_pool.check_mint(pool_mint_info)?;
|
||||
|
||||
if stake_pool.token_program_id != *token_program_info.key {
|
||||
|
@ -1451,34 +1517,33 @@ impl Processor {
|
|||
validator_stake_account_info.lamports()
|
||||
);
|
||||
|
||||
Self::stake_authorize(
|
||||
stake_pool_info.key,
|
||||
stake_info.clone(),
|
||||
deposit_info.clone(),
|
||||
AUTHORITY_DEPOSIT,
|
||||
stake_pool.deposit_bump_seed,
|
||||
withdraw_info.key,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
|
||||
Self::stake_authorize(
|
||||
stake_pool_info.key,
|
||||
stake_info.clone(),
|
||||
deposit_info.clone(),
|
||||
AUTHORITY_DEPOSIT,
|
||||
stake_pool.deposit_bump_seed,
|
||||
withdraw_info.key,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
let (deposit_authority_program_address, deposit_bump_seed) =
|
||||
find_deposit_authority_program_address(program_id, stake_pool_info.key);
|
||||
if *deposit_authority_info.key == deposit_authority_program_address {
|
||||
Self::stake_authorize_signed(
|
||||
stake_pool_info.key,
|
||||
stake_info.clone(),
|
||||
deposit_authority_info.clone(),
|
||||
AUTHORITY_DEPOSIT,
|
||||
deposit_bump_seed,
|
||||
withdraw_authority_info.key,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
} else {
|
||||
Self::stake_authorize(
|
||||
stake_info.clone(),
|
||||
deposit_authority_info.clone(),
|
||||
withdraw_authority_info.key,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
}
|
||||
|
||||
Self::stake_merge(
|
||||
stake_pool_info.key,
|
||||
stake_info.clone(),
|
||||
withdraw_info.clone(),
|
||||
withdraw_authority_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
validator_stake_account_info.clone(),
|
||||
|
@ -1492,7 +1557,7 @@ impl Processor {
|
|||
token_program_info.clone(),
|
||||
pool_mint_info.clone(),
|
||||
dest_user_info.clone(),
|
||||
withdraw_info.clone(),
|
||||
withdraw_authority_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
new_pool_tokens,
|
||||
|
@ -1530,7 +1595,7 @@ impl Processor {
|
|||
let account_info_iter = &mut accounts.iter();
|
||||
let stake_pool_info = next_account_info(account_info_iter)?;
|
||||
let validator_list_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_info = next_account_info(account_info_iter)?;
|
||||
let withdraw_authority_info = next_account_info(account_info_iter)?;
|
||||
let stake_split_from = next_account_info(account_info_iter)?;
|
||||
let stake_split_to = next_account_info(account_info_iter)?;
|
||||
let user_stake_authority = next_account_info(account_info_iter)?;
|
||||
|
@ -1550,8 +1615,12 @@ impl Processor {
|
|||
return Err(StakePoolError::InvalidState.into());
|
||||
}
|
||||
|
||||
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
|
||||
stake_pool.check_mint(pool_mint_info)?;
|
||||
stake_pool.check_authority_withdraw(
|
||||
withdraw_authority_info.key,
|
||||
program_id,
|
||||
stake_pool_info.key,
|
||||
)?;
|
||||
|
||||
if stake_pool.token_program_id != *token_program_info.key {
|
||||
return Err(ProgramError::IncorrectProgramId);
|
||||
|
@ -1601,7 +1670,7 @@ impl Processor {
|
|||
token_program_info.clone(),
|
||||
burn_from_info.clone(),
|
||||
pool_mint_info.clone(),
|
||||
withdraw_info.clone(),
|
||||
withdraw_authority_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
pool_tokens,
|
||||
|
@ -1610,33 +1679,20 @@ impl Processor {
|
|||
Self::stake_split(
|
||||
stake_pool_info.key,
|
||||
stake_split_from.clone(),
|
||||
withdraw_info.clone(),
|
||||
withdraw_authority_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
withdraw_lamports,
|
||||
stake_split_to.clone(),
|
||||
)?;
|
||||
|
||||
Self::stake_authorize(
|
||||
Self::stake_authorize_signed(
|
||||
stake_pool_info.key,
|
||||
stake_split_to.clone(),
|
||||
withdraw_info.clone(),
|
||||
withdraw_authority_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
user_stake_authority.key,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
|
||||
Self::stake_authorize(
|
||||
stake_pool_info.key,
|
||||
stake_split_to.clone(),
|
||||
withdraw_info.clone(),
|
||||
AUTHORITY_WITHDRAW,
|
||||
stake_pool.withdraw_bump_seed,
|
||||
user_stake_authority.key,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
clock_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
)?;
|
||||
|
|
|
@ -39,9 +39,16 @@ pub struct StakePool {
|
|||
/// distribution
|
||||
pub staker: Pubkey,
|
||||
|
||||
/// Deposit authority bump seed
|
||||
/// for `create_program_address(&[state::StakePool account, "deposit"])`
|
||||
pub deposit_bump_seed: u8,
|
||||
/// Deposit authority
|
||||
///
|
||||
/// If a depositor pubkey is specified on initialization, then deposits must be
|
||||
/// signed by this authority. If no deposit authority is specified,
|
||||
/// then the stake pool will default to the result of:
|
||||
/// `Pubkey::find_program_address(
|
||||
/// &[&stake_pool_address.to_bytes()[..32], b"deposit"],
|
||||
/// program_id,
|
||||
/// )`
|
||||
pub deposit_authority: Pubkey,
|
||||
|
||||
/// Withdrawal authority bump seed
|
||||
/// for `create_program_address(&[state::StakePool account, "withdrawal"])`
|
||||
|
@ -165,19 +172,15 @@ impl StakePool {
|
|||
)
|
||||
}
|
||||
/// Checks that the deposit authority is valid
|
||||
pub(crate) fn check_authority_deposit(
|
||||
pub(crate) fn check_deposit_authority(
|
||||
&self,
|
||||
deposit_authority: &Pubkey,
|
||||
program_id: &Pubkey,
|
||||
stake_pool_address: &Pubkey,
|
||||
) -> Result<(), ProgramError> {
|
||||
Self::check_authority(
|
||||
deposit_authority,
|
||||
program_id,
|
||||
stake_pool_address,
|
||||
crate::AUTHORITY_DEPOSIT,
|
||||
self.deposit_bump_seed,
|
||||
)
|
||||
if self.deposit_authority == *deposit_authority {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(StakePoolError::InvalidProgramAddress.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Check staker validity and signature
|
||||
|
|
|
@ -233,10 +233,7 @@ async fn fail_with_unknown_validator() {
|
|||
decrease_lamports,
|
||||
) = setup().await;
|
||||
|
||||
let unknown_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let unknown_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
unknown_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
|
|
@ -102,28 +102,6 @@ async fn test_stake_pool_deposit() {
|
|||
)
|
||||
.await;
|
||||
|
||||
// Change authority to the stake pool's deposit
|
||||
authorize_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&stake_authority,
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
)
|
||||
.await;
|
||||
authorize_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&stake_authority,
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
)
|
||||
.await;
|
||||
|
||||
// make pool token account
|
||||
let user_pool_account = Keypair::new();
|
||||
create_token_account(
|
||||
|
@ -163,6 +141,7 @@ async fn test_stake_pool_deposit() {
|
|||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&stake_authority,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -293,8 +272,8 @@ async fn test_stake_pool_deposit_with_wrong_token_program_id() {
|
|||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: stake_pool_accounts.deposit_authority,
|
||||
withdrawer: stake_pool_accounts.deposit_authority,
|
||||
staker: user.pubkey(),
|
||||
withdrawer: user.pubkey(),
|
||||
};
|
||||
create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
|
@ -323,22 +302,21 @@ async fn test_stake_pool_deposit_with_wrong_token_program_id() {
|
|||
let wrong_token_program = Keypair::new();
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::deposit(
|
||||
&instruction::deposit(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.validator_list.pubkey(),
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.withdraw_authority,
|
||||
&user_stake.pubkey(),
|
||||
&user.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&wrong_token_program.pubkey(),
|
||||
)
|
||||
.unwrap()],
|
||||
),
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
transaction.sign(&[&payer, &user], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
|
@ -368,8 +346,8 @@ async fn test_stake_pool_deposit_with_wrong_validator_list_account() {
|
|||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: stake_pool_accounts.deposit_authority,
|
||||
withdrawer: stake_pool_accounts.deposit_authority,
|
||||
staker: user.pubkey(),
|
||||
withdrawer: user.pubkey(),
|
||||
};
|
||||
create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
|
@ -406,6 +384,7 @@ async fn test_stake_pool_deposit_with_wrong_validator_list_account() {
|
|||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
|
@ -432,10 +411,8 @@ async fn test_stake_pool_deposit_to_unknown_validator() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator_stake_account = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let validator_stake_account =
|
||||
ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
validator_stake_account
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
@ -462,8 +439,8 @@ async fn test_stake_pool_deposit_to_unknown_validator() {
|
|||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: stake_pool_accounts.deposit_authority,
|
||||
withdrawer: stake_pool_accounts.deposit_authority,
|
||||
staker: user.pubkey(),
|
||||
withdrawer: user.pubkey(),
|
||||
};
|
||||
create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
|
@ -484,6 +461,7 @@ async fn test_stake_pool_deposit_to_unknown_validator() {
|
|||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
|
@ -503,75 +481,6 @@ async fn test_stake_pool_deposit_to_unknown_validator() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_deposit_with_wrong_deposit_authority() {
|
||||
let (
|
||||
mut banks_client,
|
||||
payer,
|
||||
recent_blockhash,
|
||||
mut stake_pool_accounts,
|
||||
validator_stake_account,
|
||||
) = setup().await;
|
||||
|
||||
let user = Keypair::new();
|
||||
// make stake account
|
||||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: stake_pool_accounts.deposit_authority,
|
||||
withdrawer: stake_pool_accounts.deposit_authority,
|
||||
};
|
||||
create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake,
|
||||
&authorized,
|
||||
&lockup,
|
||||
TEST_STAKE_AMOUNT,
|
||||
)
|
||||
.await;
|
||||
|
||||
// make pool token account
|
||||
let user_pool_account = Keypair::new();
|
||||
create_token_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_pool_account,
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&user.pubkey(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
stake_pool_accounts.deposit_authority = Keypair::new().pubkey();
|
||||
|
||||
let transaction_error = stake_pool_accounts
|
||||
.deposit_stake(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
match transaction_error {
|
||||
TransportError::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(error_index),
|
||||
)) => {
|
||||
let program_error = error::StakePoolError::InvalidProgramAddress as u32;
|
||||
assert_eq!(error_index, program_error);
|
||||
}
|
||||
_ => panic!("Wrong error occurs while try to make a deposit with wrong deposit authority"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_deposit_with_wrong_withdraw_authority() {
|
||||
let (
|
||||
|
@ -587,8 +496,8 @@ async fn test_stake_pool_deposit_with_wrong_withdraw_authority() {
|
|||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: stake_pool_accounts.deposit_authority,
|
||||
withdrawer: stake_pool_accounts.deposit_authority,
|
||||
staker: user.pubkey(),
|
||||
withdrawer: user.pubkey(),
|
||||
};
|
||||
create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
|
@ -624,6 +533,7 @@ async fn test_stake_pool_deposit_with_wrong_withdraw_authority() {
|
|||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
|
@ -641,76 +551,18 @@ async fn test_stake_pool_deposit_with_wrong_withdraw_authority() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_deposit_with_wrong_set_deposit_authority() {
|
||||
let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake_account) =
|
||||
setup().await;
|
||||
|
||||
let user = Keypair::new();
|
||||
// make stake account
|
||||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: Keypair::new().pubkey(),
|
||||
withdrawer: stake_pool_accounts.deposit_authority,
|
||||
};
|
||||
create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake,
|
||||
&authorized,
|
||||
&lockup,
|
||||
TEST_STAKE_AMOUNT,
|
||||
)
|
||||
.await;
|
||||
// make pool token account
|
||||
let user_pool_account = Keypair::new();
|
||||
create_token_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_pool_account,
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&user.pubkey(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let transaction_error = stake_pool_accounts
|
||||
.deposit_stake(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
match transaction_error {
|
||||
TransportError::TransactionError(TransactionError::InstructionError(_, error)) => {
|
||||
assert_eq!(error, InstructionError::MissingRequiredSignature);
|
||||
}
|
||||
_ => {
|
||||
panic!("Wrong error occurs while try to make deposit with wrong set deposit authority")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_deposit_with_wrong_mint_for_receiver_acc() {
|
||||
let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake_account) =
|
||||
setup().await;
|
||||
|
||||
// make stake account
|
||||
let user = Keypair::new();
|
||||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: stake_pool_accounts.deposit_authority,
|
||||
withdrawer: stake_pool_accounts.deposit_authority,
|
||||
staker: user.pubkey(),
|
||||
withdrawer: user.pubkey(),
|
||||
};
|
||||
create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
|
@ -757,6 +609,7 @@ async fn test_stake_pool_deposit_with_wrong_mint_for_receiver_acc() {
|
|||
&user_stake.pubkey(),
|
||||
&outside_pool_fee_acc.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
|
@ -779,3 +632,180 @@ async fn test_deposit_with_uninitialized_validator_list() {} // TODO
|
|||
|
||||
#[tokio::test]
|
||||
async fn test_deposit_with_out_of_dated_pool_balances() {} // TODO
|
||||
|
||||
#[tokio::test]
|
||||
async fn success_with_deposit_authority() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let deposit_authority = Keypair::new();
|
||||
let stake_pool_accounts = StakePoolAccounts::new_with_deposit_authority(deposit_authority);
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash, 1)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator_stake_account = simple_add_validator_to_pool(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user = Keypair::new();
|
||||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: user.pubkey(),
|
||||
withdrawer: user.pubkey(),
|
||||
};
|
||||
let _stake_lamports = create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake,
|
||||
&authorized,
|
||||
&lockup,
|
||||
TEST_STAKE_AMOUNT,
|
||||
)
|
||||
.await;
|
||||
|
||||
create_vote(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&validator_stake_account.validator,
|
||||
&validator_stake_account.vote,
|
||||
)
|
||||
.await;
|
||||
delegate_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&user,
|
||||
&validator_stake_account.vote.pubkey(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// make pool token account
|
||||
let user_pool_account = Keypair::new();
|
||||
create_token_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_pool_account,
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&user.pubkey(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
stake_pool_accounts
|
||||
.deposit_stake(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fail_without_deposit_authority_signature() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let deposit_authority = Keypair::new();
|
||||
let mut stake_pool_accounts = StakePoolAccounts::new_with_deposit_authority(deposit_authority);
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash, 1)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator_stake_account = simple_add_validator_to_pool(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user = Keypair::new();
|
||||
let user_stake = Keypair::new();
|
||||
let lockup = stake_program::Lockup::default();
|
||||
let authorized = stake_program::Authorized {
|
||||
staker: user.pubkey(),
|
||||
withdrawer: user.pubkey(),
|
||||
};
|
||||
let _stake_lamports = create_independent_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake,
|
||||
&authorized,
|
||||
&lockup,
|
||||
TEST_STAKE_AMOUNT,
|
||||
)
|
||||
.await;
|
||||
|
||||
create_vote(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&validator_stake_account.validator,
|
||||
&validator_stake_account.vote,
|
||||
)
|
||||
.await;
|
||||
delegate_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&user,
|
||||
&validator_stake_account.vote.pubkey(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// make pool token account
|
||||
let user_pool_account = Keypair::new();
|
||||
create_token_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_pool_account,
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&user.pubkey(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let wrong_depositor = Keypair::new();
|
||||
stake_pool_accounts.deposit_authority = wrong_depositor.pubkey();
|
||||
stake_pool_accounts.deposit_authority_keypair = Some(wrong_depositor);
|
||||
|
||||
let error = stake_pool_accounts
|
||||
.deposit_stake(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.pubkey(),
|
||||
&user_pool_account.pubkey(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap();
|
||||
|
||||
match error {
|
||||
TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => {
|
||||
assert_eq!(
|
||||
error_index,
|
||||
error::StakePoolError::InvalidProgramAddress as u32
|
||||
);
|
||||
}
|
||||
_ => panic!("Wrong error occurs while try to make a deposit with wrong stake program ID"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,6 +210,7 @@ pub async fn create_stake_pool(
|
|||
pool_token_account: &Pubkey,
|
||||
manager: &Keypair,
|
||||
staker: &Pubkey,
|
||||
deposit_authority: &Option<Keypair>,
|
||||
fee: &state::Fee,
|
||||
max_validators: u32,
|
||||
) -> Result<(), TransportError> {
|
||||
|
@ -245,6 +246,7 @@ pub async fn create_stake_pool(
|
|||
pool_mint,
|
||||
pool_token_account,
|
||||
&spl_token::id(),
|
||||
deposit_authority.as_ref().map(|k| k.pubkey()),
|
||||
*fee,
|
||||
max_validators,
|
||||
)
|
||||
|
@ -252,10 +254,11 @@ pub async fn create_stake_pool(
|
|||
],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(
|
||||
&[payer, stake_pool, validator_list, manager],
|
||||
*recent_blockhash,
|
||||
);
|
||||
let mut signers = vec![payer, stake_pool, validator_list, manager];
|
||||
if let Some(deposit_authority) = deposit_authority.as_ref() {
|
||||
signers.push(deposit_authority);
|
||||
}
|
||||
transaction.sign(&signers, *recent_blockhash);
|
||||
banks_client.process_transaction(transaction).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -424,14 +427,13 @@ pub async fn authorize_stake_account(
|
|||
pub struct ValidatorStakeAccount {
|
||||
pub stake_account: Pubkey,
|
||||
pub transient_stake_account: Pubkey,
|
||||
pub target_authority: Pubkey,
|
||||
pub vote: Keypair,
|
||||
pub validator: Keypair,
|
||||
pub stake_pool: Pubkey,
|
||||
}
|
||||
|
||||
impl ValidatorStakeAccount {
|
||||
pub fn new_with_target_authority(authority: &Pubkey, stake_pool: &Pubkey) -> Self {
|
||||
pub fn new(stake_pool: &Pubkey) -> Self {
|
||||
let validator = Keypair::new();
|
||||
let vote = Keypair::new();
|
||||
let (stake_account, _) = find_stake_program_address(&id(), &vote.pubkey(), stake_pool);
|
||||
|
@ -440,7 +442,6 @@ impl ValidatorStakeAccount {
|
|||
ValidatorStakeAccount {
|
||||
stake_account,
|
||||
transient_stake_account,
|
||||
target_authority: *authority,
|
||||
vote,
|
||||
validator,
|
||||
stake_pool: *stake_pool,
|
||||
|
@ -473,28 +474,6 @@ impl ValidatorStakeAccount {
|
|||
&self.vote.pubkey(),
|
||||
)
|
||||
.await;
|
||||
|
||||
authorize_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&self.stake_account,
|
||||
&staker,
|
||||
&self.target_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
)
|
||||
.await;
|
||||
|
||||
authorize_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&self.stake_account,
|
||||
&staker,
|
||||
&self.target_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,6 +487,7 @@ pub struct StakePoolAccounts {
|
|||
pub staker: Keypair,
|
||||
pub withdraw_authority: Pubkey,
|
||||
pub deposit_authority: Pubkey,
|
||||
pub deposit_authority_keypair: Option<Keypair>,
|
||||
pub fee: state::Fee,
|
||||
pub max_validators: u32,
|
||||
}
|
||||
|
@ -541,6 +521,7 @@ impl StakePoolAccounts {
|
|||
staker,
|
||||
withdraw_authority,
|
||||
deposit_authority,
|
||||
deposit_authority_keypair: None,
|
||||
fee: state::Fee {
|
||||
numerator: 1,
|
||||
denominator: 100,
|
||||
|
@ -549,6 +530,13 @@ impl StakePoolAccounts {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_with_deposit_authority(deposit_authority: Keypair) -> Self {
|
||||
let mut stake_pool_accounts = Self::new();
|
||||
stake_pool_accounts.deposit_authority = deposit_authority.pubkey();
|
||||
stake_pool_accounts.deposit_authority_keypair = Some(deposit_authority);
|
||||
stake_pool_accounts
|
||||
}
|
||||
|
||||
pub fn calculate_fee(&self, amount: u64) -> u64 {
|
||||
amount * self.fee.numerator / self.fee.denominator
|
||||
}
|
||||
|
@ -601,6 +589,7 @@ impl StakePoolAccounts {
|
|||
&self.pool_fee_account.pubkey(),
|
||||
&self.manager,
|
||||
&self.staker.pubkey(),
|
||||
&self.deposit_authority_keypair,
|
||||
&self.fee,
|
||||
self.max_validators,
|
||||
)
|
||||
|
@ -608,6 +597,7 @@ impl StakePoolAccounts {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn deposit_stake(
|
||||
&self,
|
||||
banks_client: &mut BanksClient,
|
||||
|
@ -616,23 +606,43 @@ impl StakePoolAccounts {
|
|||
stake: &Pubkey,
|
||||
pool_account: &Pubkey,
|
||||
validator_stake_account: &Pubkey,
|
||||
current_staker: &Keypair,
|
||||
) -> Result<(), TransportError> {
|
||||
let transaction = Transaction::new_signed_with_payer(
|
||||
&[instruction::deposit(
|
||||
let mut signers = vec![payer, current_staker];
|
||||
let instructions = if let Some(deposit_authority) = self.deposit_authority_keypair.as_ref()
|
||||
{
|
||||
signers.push(deposit_authority);
|
||||
instruction::deposit_with_authority(
|
||||
&id(),
|
||||
&self.stake_pool.pubkey(),
|
||||
&self.validator_list.pubkey(),
|
||||
&self.deposit_authority,
|
||||
&self.withdraw_authority,
|
||||
stake,
|
||||
¤t_staker.pubkey(),
|
||||
validator_stake_account,
|
||||
pool_account,
|
||||
&self.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
} else {
|
||||
instruction::deposit(
|
||||
&id(),
|
||||
&self.stake_pool.pubkey(),
|
||||
&self.validator_list.pubkey(),
|
||||
&self.withdraw_authority,
|
||||
stake,
|
||||
¤t_staker.pubkey(),
|
||||
validator_stake_account,
|
||||
pool_account,
|
||||
&self.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
)
|
||||
};
|
||||
let transaction = Transaction::new_signed_with_payer(
|
||||
&instructions,
|
||||
Some(&payer.pubkey()),
|
||||
&[payer],
|
||||
&signers,
|
||||
*recent_blockhash,
|
||||
);
|
||||
banks_client.process_transaction(transaction).await?;
|
||||
|
@ -771,7 +781,6 @@ impl StakePoolAccounts {
|
|||
&id(),
|
||||
&self.stake_pool.pubkey(),
|
||||
&self.staker.pubkey(),
|
||||
&self.deposit_authority,
|
||||
&self.withdraw_authority,
|
||||
&self.validator_list.pubkey(),
|
||||
stake,
|
||||
|
@ -874,10 +883,7 @@ pub async fn simple_add_validator_to_pool(
|
|||
recent_blockhash: &Hash,
|
||||
stake_pool_accounts: &StakePoolAccounts,
|
||||
) -> ValidatorStakeAccount {
|
||||
let validator_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let validator_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
validator_stake
|
||||
.create_and_delegate(
|
||||
banks_client,
|
||||
|
@ -970,26 +976,6 @@ impl DepositStakeAccount {
|
|||
recent_blockhash: &Hash,
|
||||
stake_pool_accounts: &StakePoolAccounts,
|
||||
) {
|
||||
authorize_stake_account(
|
||||
banks_client,
|
||||
payer,
|
||||
recent_blockhash,
|
||||
&self.stake.pubkey(),
|
||||
&self.authority,
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
)
|
||||
.await;
|
||||
authorize_stake_account(
|
||||
banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&self.stake.pubkey(),
|
||||
&self.authority,
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
)
|
||||
.await;
|
||||
// make pool token account
|
||||
create_token_account(
|
||||
banks_client,
|
||||
|
@ -1010,6 +996,7 @@ impl DepositStakeAccount {
|
|||
&self.stake.pubkey(),
|
||||
&self.pool_account.pubkey(),
|
||||
&self.validator_stake_account,
|
||||
&self.authority,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -1052,26 +1039,6 @@ pub async fn simple_deposit(
|
|||
&vote_account,
|
||||
)
|
||||
.await;
|
||||
authorize_stake_account(
|
||||
banks_client,
|
||||
payer,
|
||||
recent_blockhash,
|
||||
&stake.pubkey(),
|
||||
&authority,
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
)
|
||||
.await;
|
||||
authorize_stake_account(
|
||||
banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake.pubkey(),
|
||||
&authority,
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
)
|
||||
.await;
|
||||
// make pool token account
|
||||
let pool_account = Keypair::new();
|
||||
create_token_account(
|
||||
|
@ -1094,6 +1061,7 @@ pub async fn simple_deposit(
|
|||
&stake.pubkey(),
|
||||
&pool_account.pubkey(),
|
||||
&validator_stake_account,
|
||||
&authority,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
|
@ -233,10 +233,7 @@ async fn fail_with_unknown_validator() {
|
|||
reserve_lamports,
|
||||
) = setup().await;
|
||||
|
||||
let unknown_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let unknown_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
unknown_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
mod helpers;
|
||||
|
||||
use {
|
||||
borsh::BorshSerialize,
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
helpers::*,
|
||||
solana_program::{
|
||||
borsh::get_packed_len,
|
||||
|
@ -226,6 +226,7 @@ async fn fail_with_wrong_max_validators() {
|
|||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&spl_token::id(),
|
||||
None,
|
||||
stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -296,6 +297,7 @@ async fn fail_with_wrong_mint_authority() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.manager,
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&None,
|
||||
&stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -384,6 +386,7 @@ async fn fail_with_wrong_token_program_id() {
|
|||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&wrong_token_program.pubkey(),
|
||||
None,
|
||||
stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -460,6 +463,7 @@ async fn fail_with_wrong_fee_account() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.manager,
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&None,
|
||||
&stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -547,6 +551,7 @@ async fn fail_with_not_rent_exempt_pool() {
|
|||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&spl_token::id(),
|
||||
None,
|
||||
stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -621,6 +626,7 @@ async fn fail_with_not_rent_exempt_validator_list() {
|
|||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&spl_token::id(),
|
||||
None,
|
||||
stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -793,6 +799,7 @@ async fn fail_with_pre_minted_pool_tokens() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.manager,
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&None,
|
||||
&stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -853,6 +860,7 @@ async fn fail_with_bad_reserve() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.manager,
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&None,
|
||||
&stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -897,6 +905,7 @@ async fn fail_with_bad_reserve() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.manager,
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&None,
|
||||
&stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -944,6 +953,7 @@ async fn fail_with_bad_reserve() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.manager,
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&None,
|
||||
&stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -991,6 +1001,7 @@ async fn fail_with_bad_reserve() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.manager,
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&None,
|
||||
&stake_pool_accounts.fee,
|
||||
stake_pool_accounts.max_validators,
|
||||
)
|
||||
|
@ -1008,3 +1019,23 @@ async fn fail_with_bad_reserve() {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn success_with_required_deposit_authority() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let deposit_authority = Keypair::new();
|
||||
let stake_pool_accounts = StakePoolAccounts::new_with_deposit_authority(deposit_authority);
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash, 1)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Stake pool now exists
|
||||
let stake_pool_account =
|
||||
get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await;
|
||||
let stake_pool = state::StakePool::try_from_slice(stake_pool_account.data.as_slice()).unwrap();
|
||||
assert_eq!(
|
||||
stake_pool.deposit_authority,
|
||||
stake_pool_accounts.deposit_authority
|
||||
);
|
||||
}
|
||||
|
|
|
@ -66,10 +66,7 @@ async fn setup(
|
|||
let mut stake_accounts: Vec<ValidatorStakeAccount> = vec![];
|
||||
let mut deposit_accounts: Vec<DepositStakeAccount> = vec![];
|
||||
for _ in 0..num_validators {
|
||||
let stake_account = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let stake_account = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
stake_account
|
||||
.create_and_delegate(
|
||||
&mut context.banks_client,
|
||||
|
|
|
@ -38,10 +38,7 @@ async fn setup() -> (
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
user_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
@ -126,7 +123,6 @@ async fn fail_with_wrong_validator_list_account() {
|
|||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.staker.pubkey(),
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.withdraw_authority,
|
||||
&wrong_validator_list.pubkey(),
|
||||
&user_stake.stake_account,
|
||||
|
@ -162,10 +158,7 @@ async fn fail_too_little_stake() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
create_vote(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
|
@ -203,28 +196,6 @@ async fn fail_too_little_stake() {
|
|||
|
||||
banks_client.process_transaction(transaction).await.unwrap();
|
||||
|
||||
authorize_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.stake_account,
|
||||
&stake_pool_accounts.staker,
|
||||
&user_stake.target_authority,
|
||||
stake_program::StakeAuthorize::Staker,
|
||||
)
|
||||
.await;
|
||||
|
||||
authorize_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.stake_account,
|
||||
&stake_pool_accounts.staker,
|
||||
&user_stake.target_authority,
|
||||
stake_program::StakeAuthorize::Withdrawer,
|
||||
)
|
||||
.await;
|
||||
|
||||
let error = stake_pool_accounts
|
||||
.add_validator_to_pool(
|
||||
&mut banks_client,
|
||||
|
@ -253,10 +224,7 @@ async fn fail_too_much_stake() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
user_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
@ -344,7 +312,6 @@ async fn fail_wrong_staker() {
|
|||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&malicious.pubkey(),
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.withdraw_authority,
|
||||
&stake_pool_accounts.validator_list.pubkey(),
|
||||
&user_stake.stake_account,
|
||||
|
@ -379,7 +346,6 @@ async fn fail_without_signature() {
|
|||
let accounts = vec![
|
||||
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.deposit_authority, false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
|
||||
AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
|
||||
AccountMeta::new(user_stake.stake_account, false),
|
||||
|
@ -425,7 +391,6 @@ async fn fail_with_wrong_stake_program_id() {
|
|||
let accounts = vec![
|
||||
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), true),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.deposit_authority, false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
|
||||
AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
|
||||
AccountMeta::new(user_stake.stake_account, false),
|
||||
|
@ -468,10 +433,7 @@ async fn fail_add_too_many_validator_stake_accounts() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
user_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
@ -491,10 +453,7 @@ async fn fail_add_too_many_validator_stake_accounts() {
|
|||
.await;
|
||||
assert!(error.is_none());
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
user_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
|
|
@ -38,10 +38,7 @@ async fn setup() -> (
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
user_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
|
|
@ -403,10 +403,8 @@ async fn fail_with_unknown_validator() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator_stake_account = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let validator_stake_account =
|
||||
ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
validator_stake_account
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
@ -416,10 +414,7 @@ async fn fail_with_unknown_validator() {
|
|||
)
|
||||
.await;
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey());
|
||||
user_stake
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
|
|
Loading…
Reference in New Issue