Rework create validator stake account (#1539)
This commit is contained in:
parent
f2de73da8e
commit
9f38a6f4b2
|
@ -277,13 +277,10 @@ fn command_vsa_create(config: &Config, pool: &Pubkey, vote_account: &Pubkey) ->
|
|||
create_validator_stake_account(
|
||||
&spl_stake_pool::id(),
|
||||
&pool,
|
||||
&config.owner.pubkey(),
|
||||
&config.fee_payer.pubkey(),
|
||||
&stake_account,
|
||||
&vote_account,
|
||||
&config.owner.pubkey(),
|
||||
&config.owner.pubkey(),
|
||||
&solana_program::system_program::id(),
|
||||
&stake_program_id(),
|
||||
)?,
|
||||
],
|
||||
Some(&config.fee_payer.pubkey()),
|
||||
|
@ -291,7 +288,10 @@ fn command_vsa_create(config: &Config, pool: &Pubkey, vote_account: &Pubkey) ->
|
|||
|
||||
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
|
||||
check_fee_payer_balance(config, fee_calculator.calculate_fee(&transaction.message()))?;
|
||||
transaction.sign(&[config.fee_payer.as_ref()], recent_blockhash);
|
||||
transaction.sign(
|
||||
&[config.fee_payer.as_ref(), config.owner.as_ref()],
|
||||
recent_blockhash,
|
||||
);
|
||||
send_transaction(&config, transaction)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -377,7 +377,6 @@ fn command_vsa_add(
|
|||
&token_receiver,
|
||||
&pool_data.pool_mint,
|
||||
&spl_token::id(),
|
||||
&stake_program_id(),
|
||||
)?,
|
||||
]);
|
||||
|
||||
|
@ -468,7 +467,6 @@ fn command_vsa_remove(
|
|||
&withdraw_from,
|
||||
&pool_data.pool_mint,
|
||||
&spl_token::id(),
|
||||
&stake_program_id(),
|
||||
)?,
|
||||
],
|
||||
Some(&config.fee_payer.pubkey()),
|
||||
|
@ -645,7 +643,6 @@ fn command_deposit(
|
|||
&pool_data.owner_fee_account,
|
||||
&pool_data.pool_mint,
|
||||
&spl_token::id(),
|
||||
&stake_program_id(),
|
||||
)?,
|
||||
]);
|
||||
|
||||
|
@ -984,7 +981,6 @@ fn command_withdraw(
|
|||
&withdraw_from,
|
||||
&pool_data.pool_mint,
|
||||
&spl_token::id(),
|
||||
&stake_program_id(),
|
||||
withdraw_stake.pool_amount,
|
||||
)?);
|
||||
}
|
||||
|
@ -1163,7 +1159,7 @@ 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")
|
||||
.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)
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use {
|
||||
crate::stake,
|
||||
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
|
||||
solana_program::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
system_program, sysvar,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -48,17 +49,17 @@ pub enum StakePoolInstruction {
|
|||
/// Creates new program account for accumulating stakes for a particular validator
|
||||
///
|
||||
/// 0. `[]` Stake pool account this stake will belong to
|
||||
/// 1. `[ws]` Funding account (must be a system account)
|
||||
/// 2. `[w]` Stake account to be created
|
||||
/// 3. `[]` Validator this stake account will vote for
|
||||
/// 4. `[]` Stake authority for the new stake account
|
||||
/// 5. `[]` Withdraw authority for the new stake account
|
||||
/// 6. `[]` Rent sysvar
|
||||
/// 7. `[]` System program
|
||||
/// 8. `[]` Stake program
|
||||
/// 1. `[s]` Owner
|
||||
/// 2. `[ws]` Funding account (must be a system account)
|
||||
/// 3. `[w]` Stake account to be created
|
||||
/// 4. `[]` Validator this stake account will vote for
|
||||
/// 5. `[]` Rent sysvar
|
||||
/// 6. `[]` System program
|
||||
/// 7. `[]` Stake program
|
||||
CreateValidatorStakeAccount,
|
||||
|
||||
/// Adds validator stake account to the pool
|
||||
/// Adds stake account delegated to validator to the pool's list of
|
||||
/// managed validators
|
||||
///
|
||||
/// 0. `[w]` Stake pool
|
||||
/// 1. `[s]` Owner
|
||||
|
@ -185,24 +186,23 @@ pub fn initialize(
|
|||
pub fn create_validator_stake_account(
|
||||
program_id: &Pubkey,
|
||||
stake_pool: &Pubkey,
|
||||
owner: &Pubkey,
|
||||
funder: &Pubkey,
|
||||
stake_account: &Pubkey,
|
||||
validator: &Pubkey,
|
||||
stake_authority: &Pubkey,
|
||||
withdraw_authority: &Pubkey,
|
||||
system_program_id: &Pubkey,
|
||||
stake_program_id: &Pubkey,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*stake_pool, false),
|
||||
AccountMeta::new_readonly(*owner, true),
|
||||
AccountMeta::new(*funder, true),
|
||||
AccountMeta::new(*stake_account, false),
|
||||
AccountMeta::new_readonly(*validator, false),
|
||||
AccountMeta::new_readonly(*stake_authority, false),
|
||||
AccountMeta::new_readonly(*withdraw_authority, false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(*system_program_id, false),
|
||||
AccountMeta::new_readonly(*stake_program_id, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
AccountMeta::new_readonly(stake::config_id(), false),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(stake::id(), false),
|
||||
];
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
|
@ -220,10 +220,9 @@ pub fn add_validator_to_pool(
|
|||
stake_pool_withdraw: &Pubkey,
|
||||
validator_list: &Pubkey,
|
||||
stake_account: &Pubkey,
|
||||
pool_tokens_to: &Pubkey,
|
||||
pool_token_receiver: &Pubkey,
|
||||
pool_mint: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
stake_program_id: &Pubkey,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let accounts = vec![
|
||||
AccountMeta::new(*stake_pool, false),
|
||||
|
@ -232,12 +231,12 @@ pub fn add_validator_to_pool(
|
|||
AccountMeta::new_readonly(*stake_pool_withdraw, false),
|
||||
AccountMeta::new(*validator_list, false),
|
||||
AccountMeta::new(*stake_account, false),
|
||||
AccountMeta::new(*pool_tokens_to, false),
|
||||
AccountMeta::new(*pool_token_receiver, 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),
|
||||
AccountMeta::new_readonly(stake::id(), false),
|
||||
];
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
|
@ -258,7 +257,6 @@ pub fn remove_validator_from_pool(
|
|||
burn_from: &Pubkey,
|
||||
pool_mint: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
stake_program_id: &Pubkey,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let accounts = vec![
|
||||
AccountMeta::new(*stake_pool, false),
|
||||
|
@ -271,7 +269,7 @@ pub fn remove_validator_from_pool(
|
|||
AccountMeta::new(*pool_mint, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(*token_program_id, false),
|
||||
AccountMeta::new_readonly(*stake_program_id, false),
|
||||
AccountMeta::new_readonly(stake::id(), false),
|
||||
];
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
|
@ -330,7 +328,6 @@ pub fn deposit(
|
|||
pool_fee_to: &Pubkey,
|
||||
pool_mint: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
stake_program_id: &Pubkey,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let accounts = vec![
|
||||
AccountMeta::new(*stake_pool, false),
|
||||
|
@ -345,7 +342,7 @@ pub fn deposit(
|
|||
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),
|
||||
AccountMeta::new_readonly(stake::id(), false),
|
||||
];
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
|
@ -366,7 +363,6 @@ pub fn withdraw(
|
|||
burn_from: &Pubkey,
|
||||
pool_mint: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
stake_program_id: &Pubkey,
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let accounts = vec![
|
||||
|
@ -380,7 +376,7 @@ pub fn withdraw(
|
|||
AccountMeta::new(*pool_mint, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(*token_program_id, false),
|
||||
AccountMeta::new_readonly(*stake_program_id, false),
|
||||
AccountMeta::new_readonly(stake::id(), false),
|
||||
];
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
|
|
|
@ -403,24 +403,38 @@ impl Processor {
|
|||
let account_info_iter = &mut accounts.iter();
|
||||
// Stake pool account
|
||||
let stake_pool_info = next_account_info(account_info_iter)?;
|
||||
// Owner account
|
||||
let owner_info = next_account_info(account_info_iter)?;
|
||||
// Account creation funder account
|
||||
let funder_info = next_account_info(account_info_iter)?;
|
||||
// Stake account to be created
|
||||
let stake_account_info = next_account_info(account_info_iter)?;
|
||||
// Validator this stake account will vote for
|
||||
let validator_info = next_account_info(account_info_iter)?;
|
||||
// Stake authority for the new stake account
|
||||
let stake_authority_info = next_account_info(account_info_iter)?;
|
||||
// Withdraw authority for the new stake account
|
||||
let withdraw_authority_info = next_account_info(account_info_iter)?;
|
||||
// Rent sysvar account
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
let rent = &Rent::from_account_info(rent_info)?;
|
||||
// Clock sysvar account
|
||||
let clock_info = next_account_info(account_info_iter)?;
|
||||
// Stake history sysvar account
|
||||
let stake_history_info = next_account_info(account_info_iter)?;
|
||||
// Stake config sysvar account
|
||||
let stake_config_info = next_account_info(account_info_iter)?;
|
||||
// System program id
|
||||
let system_program_info = next_account_info(account_info_iter)?;
|
||||
// Staking program id
|
||||
let stake_program_info = next_account_info(account_info_iter)?;
|
||||
|
||||
// Get stake pool stake (and check if it is initialized)
|
||||
if stake_pool_info.owner != program_id {
|
||||
return Err(ProgramError::IncorrectProgramId);
|
||||
}
|
||||
let stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?;
|
||||
if !stake_pool.is_valid() {
|
||||
return Err(StakePoolError::InvalidState.into());
|
||||
}
|
||||
stake_pool.check_owner(owner_info)?;
|
||||
|
||||
// Check program ids
|
||||
if *system_program_info.key != solana_program::system_program::id() {
|
||||
return Err(ProgramError::IncorrectProgramId);
|
||||
|
@ -466,8 +480,8 @@ impl Processor {
|
|||
&stake::initialize(
|
||||
&stake_account_info.key,
|
||||
&stake::Authorized {
|
||||
staker: *stake_authority_info.key,
|
||||
withdrawer: *withdraw_authority_info.key,
|
||||
staker: *owner_info.key,
|
||||
withdrawer: *owner_info.key,
|
||||
},
|
||||
&stake::Lockup::default(),
|
||||
),
|
||||
|
@ -476,6 +490,22 @@ impl Processor {
|
|||
rent_info.clone(),
|
||||
stake_program_info.clone(),
|
||||
],
|
||||
)?;
|
||||
|
||||
invoke(
|
||||
&stake::delegate_stake(
|
||||
&stake_account_info.key,
|
||||
&owner_info.key,
|
||||
&validator_info.key,
|
||||
),
|
||||
&[
|
||||
stake_account_info.clone(),
|
||||
validator_info.clone(),
|
||||
clock_info.clone(),
|
||||
stake_history_info.clone(),
|
||||
stake_config_info.clone(),
|
||||
owner_info.clone(),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@ use std::str::FromStr;
|
|||
solana_program::declare_id!("Stake11111111111111111111111111111111111111");
|
||||
|
||||
const STAKE_CONFIG: &str = "StakeConfig11111111111111111111111111111111";
|
||||
/// Id for stake config account
|
||||
pub fn config_id() -> Pubkey {
|
||||
Pubkey::from_str(STAKE_CONFIG).unwrap()
|
||||
}
|
||||
|
||||
/// FIXME copied from solana stake program
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
|
@ -489,8 +493,18 @@ pub fn delegate_stake(
|
|||
AccountMeta::new_readonly(*vote_pubkey, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
AccountMeta::new_readonly(Pubkey::from_str(STAKE_CONFIG).unwrap(), false),
|
||||
AccountMeta::new_readonly(config_id(), false),
|
||||
AccountMeta::new_readonly(*authorized_pubkey, true),
|
||||
];
|
||||
Instruction::new_with_bincode(id(), &StakeInstruction::DelegateStake, account_metas)
|
||||
}
|
||||
|
||||
/// FIXME copied from stake program
|
||||
pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*stake_pubkey, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(*authorized_pubkey, true),
|
||||
];
|
||||
Instruction::new_with_bincode(id(), &StakeInstruction::Deactivate, account_metas)
|
||||
}
|
||||
|
|
|
@ -3,12 +3,16 @@
|
|||
mod helpers;
|
||||
|
||||
use {
|
||||
borsh::BorshDeserialize,
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
helpers::*,
|
||||
solana_program::hash::Hash,
|
||||
solana_program::{
|
||||
hash::Hash,
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
solana_program_test::*,
|
||||
solana_sdk::{
|
||||
instruction::InstructionError,
|
||||
signature::{Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
transaction::TransactionError,
|
||||
|
@ -237,26 +241,32 @@ async fn test_stake_pool_deposit_with_wrong_stake_program_id() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let wrong_stake_program = Keypair::new();
|
||||
let wrong_stake_program = Pubkey::new_unique();
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[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(),
|
||||
&validator_stake_account.stake_account,
|
||||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&wrong_stake_program.pubkey(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
let accounts = vec![
|
||||
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.deposit_authority, false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
|
||||
AccountMeta::new(user_stake.pubkey(), false),
|
||||
AccountMeta::new(validator_stake_account.stake_account, false),
|
||||
AccountMeta::new(user_pool_account.pubkey(), false),
|
||||
AccountMeta::new(stake_pool_accounts.pool_fee_account.pubkey(), false),
|
||||
AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(wrong_stake_program, false),
|
||||
];
|
||||
let instruction = Instruction {
|
||||
program_id: id(),
|
||||
accounts,
|
||||
data: instruction::StakePoolInstruction::Deposit
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
|
@ -392,7 +402,6 @@ async fn test_stake_pool_deposit_with_wrong_token_program_id() {
|
|||
&stake_pool_accounts.pool_fee_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&wrong_token_program.pubkey(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -481,88 +490,6 @@ async fn test_stake_pool_deposit_with_wrong_validator_list_account() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_deposit_where_stake_acc_not_in_stake_state() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator_stake_account = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
|
||||
let user_stake_authority = Keypair::new();
|
||||
create_validator_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&validator_stake_account.stake_pool,
|
||||
&validator_stake_account.stake_account,
|
||||
&validator_stake_account.vote.pubkey(),
|
||||
&user_stake_authority.pubkey(),
|
||||
&validator_stake_account.target_authority,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user_pool_account = Keypair::new();
|
||||
let user = 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 user_stake_acc = Keypair::new();
|
||||
let lockup = stake::Lockup::default();
|
||||
let authorized = stake::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_acc,
|
||||
&authorized,
|
||||
&lockup,
|
||||
)
|
||||
.await;
|
||||
let transaction_error = stake_pool_accounts
|
||||
.deposit_stake(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake_acc.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::WrongStakeState as u32;
|
||||
assert_eq!(error_index, program_error);
|
||||
}
|
||||
_ => panic!(
|
||||
"Wrong error occurs while try to make a deposit when stake acc not in stake state"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_deposit_to_unknown_validator() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
|
@ -577,7 +504,12 @@ async fn test_stake_pool_deposit_to_unknown_validator() {
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
validator_stake_account
|
||||
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user_pool_account = Keypair::new();
|
||||
|
|
|
@ -300,30 +300,26 @@ pub async fn create_validator_stake_account(
|
|||
payer: &Keypair,
|
||||
recent_blockhash: &Hash,
|
||||
stake_pool: &Pubkey,
|
||||
owner: &Keypair,
|
||||
stake_account: &Pubkey,
|
||||
validator: &Pubkey,
|
||||
stake_authority: &Pubkey,
|
||||
withdraw_authority: &Pubkey,
|
||||
) {
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[
|
||||
instruction::create_validator_stake_account(
|
||||
&id(),
|
||||
&stake_pool,
|
||||
&owner.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&stake_account,
|
||||
&validator,
|
||||
&stake_authority,
|
||||
&withdraw_authority,
|
||||
&solana_program::system_program::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap(),
|
||||
system_instruction::transfer(&payer.pubkey(), &stake_account, TEST_STAKE_AMOUNT),
|
||||
],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[payer], *recent_blockhash);
|
||||
transaction.sign(&[payer, owner], *recent_blockhash);
|
||||
banks_client.process_transaction(transaction).await.unwrap();
|
||||
}
|
||||
|
||||
|
@ -393,29 +389,18 @@ impl ValidatorStakeAccount {
|
|||
mut banks_client: &mut BanksClient,
|
||||
payer: &Keypair,
|
||||
recent_blockhash: &Hash,
|
||||
owner: &Keypair,
|
||||
) {
|
||||
// make stake account
|
||||
let user_stake_authority = Keypair::new();
|
||||
create_vote(&mut banks_client, &payer, &recent_blockhash, &self.vote).await;
|
||||
|
||||
create_validator_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&self.stake_pool,
|
||||
owner,
|
||||
&self.stake_account,
|
||||
&self.vote.pubkey(),
|
||||
&user_stake_authority.pubkey(),
|
||||
&self.target_authority,
|
||||
)
|
||||
.await;
|
||||
|
||||
create_vote(&mut banks_client, &payer, &recent_blockhash, &self.vote).await;
|
||||
delegate_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&self.stake_account,
|
||||
&user_stake_authority,
|
||||
&self.vote.pubkey(),
|
||||
)
|
||||
.await;
|
||||
|
||||
|
@ -424,11 +409,22 @@ impl ValidatorStakeAccount {
|
|||
&payer,
|
||||
&recent_blockhash,
|
||||
&self.stake_account,
|
||||
&user_stake_authority,
|
||||
&owner,
|
||||
&self.target_authority,
|
||||
stake::StakeAuthorize::Staker,
|
||||
)
|
||||
.await;
|
||||
|
||||
authorize_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&self.stake_account,
|
||||
&owner,
|
||||
&self.target_authority,
|
||||
stake::StakeAuthorize::Withdrawer,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,7 +538,6 @@ impl StakePoolAccounts {
|
|||
&self.pool_fee_account.pubkey(),
|
||||
&self.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -575,7 +570,6 @@ impl StakePoolAccounts {
|
|||
pool_account,
|
||||
&self.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
amount,
|
||||
)
|
||||
.unwrap()],
|
||||
|
@ -606,7 +600,6 @@ impl StakePoolAccounts {
|
|||
pool_account,
|
||||
&self.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -636,7 +629,6 @@ impl StakePoolAccounts {
|
|||
pool_account,
|
||||
&self.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -657,7 +649,12 @@ pub async fn simple_add_validator_to_pool(
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
user_stake
|
||||
.create_and_delegate(banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user_pool_account = Keypair::new();
|
||||
|
|
|
@ -8,12 +8,12 @@ use {
|
|||
helpers::*,
|
||||
solana_program::{
|
||||
hash::Hash,
|
||||
instruction::{AccountMeta, Instruction},
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
solana_program_test::*,
|
||||
solana_sdk::{
|
||||
instruction::InstructionError,
|
||||
signature::{Keypair, Signer},
|
||||
transaction::{Transaction, TransactionError},
|
||||
transport::TransportError,
|
||||
|
@ -43,7 +43,12 @@ async fn setup() -> (
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
user_stake
|
||||
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
|
||||
// make pool token account
|
||||
|
@ -170,7 +175,6 @@ async fn test_add_validator_to_pool_with_wrong_token_program_id() {
|
|||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&stake::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -215,7 +219,6 @@ async fn test_add_validator_to_pool_with_wrong_pool_mint_account() {
|
|||
&user_pool_account.pubkey(),
|
||||
&wrong_pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -264,7 +267,6 @@ async fn test_add_validator_to_pool_with_wrong_validator_list_account() {
|
|||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -359,7 +361,6 @@ async fn test_not_owner_try_to_add_validator_to_pool() {
|
|||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -436,69 +437,6 @@ async fn test_not_owner_try_to_add_validator_to_pool_without_signature() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_validator_to_pool_when_stake_acc_not_in_stake_state() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let user = Keypair::new();
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake_authority = Keypair::new();
|
||||
create_validator_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.stake_pool,
|
||||
&user_stake.stake_account,
|
||||
&user_stake.vote.pubkey(),
|
||||
&user_stake_authority.pubkey(),
|
||||
&user_stake.target_authority,
|
||||
)
|
||||
.await;
|
||||
|
||||
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
|
||||
.add_validator_to_pool(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.stake_account,
|
||||
&user_pool_account.pubkey(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match transaction_error {
|
||||
TransportError::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(error_index),
|
||||
)) => {
|
||||
let program_error = error::StakePoolError::WrongStakeState as u32;
|
||||
assert_eq!(error_index, program_error);
|
||||
}
|
||||
_ => panic!("Wrong error occurs while try to add validator stake account when it isn't in stake state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_validator_to_pool_with_wrong_stake_program_id() {
|
||||
let (
|
||||
|
@ -510,25 +448,30 @@ async fn test_add_validator_to_pool_with_wrong_stake_program_id() {
|
|||
user_pool_account,
|
||||
) = setup().await;
|
||||
|
||||
let wrong_stake_program = Keypair::new();
|
||||
let wrong_stake_program = Pubkey::new_unique();
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::add_validator_to_pool(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.owner.pubkey(),
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.withdraw_authority,
|
||||
&stake_pool_accounts.validator_list.pubkey(),
|
||||
&user_stake.stake_account,
|
||||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&wrong_stake_program.pubkey(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
let accounts = vec![
|
||||
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.owner.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),
|
||||
AccountMeta::new(user_pool_account.pubkey(), false),
|
||||
AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(wrong_stake_program, false),
|
||||
];
|
||||
let instruction = Instruction {
|
||||
program_id: id(),
|
||||
accounts,
|
||||
data: instruction::StakePoolInstruction::AddValidatorToPool
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
};
|
||||
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
|
||||
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
|
@ -563,7 +506,12 @@ async fn test_add_too_many_validator_stake_accounts() {
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
user_stake
|
||||
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
|
||||
// make pool token account
|
||||
|
@ -595,7 +543,12 @@ async fn test_add_too_many_validator_stake_accounts() {
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
user_stake
|
||||
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
let error = stake_pool_accounts
|
||||
.add_validator_to_pool(
|
||||
|
|
|
@ -2,22 +2,76 @@
|
|||
|
||||
mod helpers;
|
||||
|
||||
use crate::solana_program::pubkey::Pubkey;
|
||||
use helpers::*;
|
||||
|
||||
use bincode::deserialize;
|
||||
use solana_program_test::*;
|
||||
use solana_sdk::{
|
||||
instruction::InstructionError,
|
||||
use {
|
||||
bincode::deserialize,
|
||||
borsh::BorshSerialize,
|
||||
helpers::*,
|
||||
solana_program::{
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
pubkey::Pubkey,
|
||||
system_program, sysvar,
|
||||
},
|
||||
solana_program_test::*,
|
||||
solana_sdk::{
|
||||
signature::{Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
transaction::TransactionError,
|
||||
transport::TransportError,
|
||||
},
|
||||
spl_stake_pool::{error, id, instruction, processor, stake},
|
||||
};
|
||||
use spl_stake_pool::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_validator_stake_account() {
|
||||
async fn success_create_validator_stake_account() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator = Keypair::new();
|
||||
create_vote(&mut banks_client, &payer, &recent_blockhash, &validator).await;
|
||||
|
||||
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
|
||||
&id(),
|
||||
&validator.pubkey(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::create_validator_stake_account(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.owner.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&stake_account,
|
||||
&validator.pubkey(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
|
||||
banks_client.process_transaction(transaction).await.unwrap();
|
||||
|
||||
// Check authorities
|
||||
let stake = get_account(&mut banks_client, &stake_account).await;
|
||||
let stake_state = deserialize::<stake::StakeState>(&stake.data).unwrap();
|
||||
match stake_state {
|
||||
stake::StakeState::Stake(meta, stake) => {
|
||||
assert_eq!(&meta.authorized.staker, &stake_pool_accounts.owner.pubkey());
|
||||
assert_eq!(
|
||||
&meta.authorized.withdrawer,
|
||||
&stake_pool_accounts.owner.pubkey()
|
||||
);
|
||||
assert_eq!(stake.delegation.voter_pubkey, validator.pubkey());
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fail_create_validator_stake_account_on_non_vote_account() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
|
@ -26,8 +80,6 @@ async fn test_create_validator_stake_account() {
|
|||
.unwrap();
|
||||
|
||||
let validator = Pubkey::new_unique();
|
||||
let user_stake_authority = Keypair::new();
|
||||
let user_withdraw_authority = Keypair::new();
|
||||
|
||||
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
|
||||
&id(),
|
||||
|
@ -39,37 +91,136 @@ async fn test_create_validator_stake_account() {
|
|||
&[instruction::create_validator_stake_account(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.owner.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&stake_account,
|
||||
&validator,
|
||||
&user_stake_authority.pubkey(),
|
||||
&user_withdraw_authority.pubkey(),
|
||||
&solana_program::system_program::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
banks_client.process_transaction(transaction).await.unwrap();
|
||||
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
.err()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
// Check authorities
|
||||
let stake = get_account(&mut banks_client, &stake_account).await;
|
||||
let stake_state = deserialize::<stake::StakeState>(&stake.data).unwrap();
|
||||
match stake_state {
|
||||
stake::StakeState::Initialized(meta) => {
|
||||
assert_eq!(&meta.authorized.staker, &user_stake_authority.pubkey());
|
||||
assert_eq!(
|
||||
&meta.authorized.withdrawer,
|
||||
&user_withdraw_authority.pubkey()
|
||||
transaction_error,
|
||||
TransactionError::InstructionError(0, InstructionError::IncorrectProgramId,)
|
||||
);
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_validator_stake_account_with_incorrect_address() {
|
||||
async fn fail_create_validator_stake_account_with_wrong_system_program() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator = Pubkey::new_unique();
|
||||
|
||||
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
|
||||
&id(),
|
||||
&validator,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let wrong_system_program = Pubkey::new_unique();
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.owner.pubkey(), true),
|
||||
AccountMeta::new(payer.pubkey(), true),
|
||||
AccountMeta::new(stake_account, false),
|
||||
AccountMeta::new_readonly(validator, false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
AccountMeta::new_readonly(stake::config_id(), false),
|
||||
AccountMeta::new_readonly(wrong_system_program, false),
|
||||
AccountMeta::new_readonly(stake::id(), false),
|
||||
];
|
||||
let instruction = Instruction {
|
||||
program_id: id(),
|
||||
accounts,
|
||||
data: instruction::StakePoolInstruction::CreateValidatorStakeAccount
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
|
||||
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
.err()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
TransactionError::InstructionError(0, InstructionError::IncorrectProgramId,)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fail_create_validator_stake_account_with_wrong_stake_program() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator = Pubkey::new_unique();
|
||||
|
||||
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
|
||||
&id(),
|
||||
&validator,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let wrong_stake_program = Pubkey::new_unique();
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.owner.pubkey(), true),
|
||||
AccountMeta::new(payer.pubkey(), true),
|
||||
AccountMeta::new(stake_account, false),
|
||||
AccountMeta::new_readonly(validator, false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
AccountMeta::new_readonly(stake::config_id(), false),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(wrong_stake_program, false),
|
||||
];
|
||||
let instruction = Instruction {
|
||||
program_id: id(),
|
||||
accounts,
|
||||
data: instruction::StakePoolInstruction::CreateValidatorStakeAccount
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
|
||||
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
.err()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
TransactionError::InstructionError(0, InstructionError::IncorrectProgramId,)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fail_create_validator_stake_account_with_incorrect_address() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
|
@ -78,26 +229,21 @@ async fn test_create_validator_stake_account_with_incorrect_address() {
|
|||
.unwrap();
|
||||
|
||||
let validator = Pubkey::new_unique();
|
||||
let user_stake_authority = Keypair::new();
|
||||
let user_withdraw_authority = Keypair::new();
|
||||
let stake_account = Keypair::new();
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::create_validator_stake_account(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.owner.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&stake_account.pubkey(),
|
||||
&validator,
|
||||
&user_stake_authority.pubkey(),
|
||||
&user_withdraw_authority.pubkey(),
|
||||
&solana_program::system_program::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
|
@ -117,109 +263,3 @@ async fn test_create_validator_stake_account_with_incorrect_address() {
|
|||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_validator_stake_account_with_wrong_system_program() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator = Pubkey::new_unique();
|
||||
let user_stake_authority = Keypair::new();
|
||||
let user_withdraw_authority = Keypair::new();
|
||||
|
||||
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
|
||||
&id(),
|
||||
&validator,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
|
||||
let wrong_system_program = Keypair::new();
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::create_validator_stake_account(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&stake_account,
|
||||
&validator,
|
||||
&user_stake_authority.pubkey(),
|
||||
&user_withdraw_authority.pubkey(),
|
||||
&wrong_system_program.pubkey(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
match transaction_error {
|
||||
TransportError::TransactionError(TransactionError::InstructionError(_, error)) => {
|
||||
assert_eq!(error, InstructionError::IncorrectProgramId);
|
||||
}
|
||||
_ => panic!(
|
||||
"Wrong error occurs while try to create validator stake account with wrong token program ID"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_validator_stake_account_with_wrong_stake_program() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator = Pubkey::new_unique();
|
||||
let user_stake_authority = Keypair::new();
|
||||
let user_withdraw_authority = Keypair::new();
|
||||
|
||||
let (stake_account, _) = processor::Processor::find_stake_address_for_validator(
|
||||
&id(),
|
||||
&validator,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
|
||||
let wrong_stake_program = Keypair::new();
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::create_validator_stake_account(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&stake_account,
|
||||
&validator,
|
||||
&user_stake_authority.pubkey(),
|
||||
&user_withdraw_authority.pubkey(),
|
||||
&solana_program::system_program::id(),
|
||||
&wrong_stake_program.pubkey(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
match transaction_error {
|
||||
TransportError::TransactionError(TransactionError::InstructionError(_, error)) => {
|
||||
assert_eq!(error, InstructionError::IncorrectProgramId);
|
||||
}
|
||||
_ => panic!(
|
||||
"Wrong error occurs while try to create validator stake account with wrong stake program ID"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,12 @@ use {
|
|||
helpers::*,
|
||||
solana_program::{
|
||||
hash::Hash,
|
||||
instruction::{AccountMeta, Instruction},
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
solana_program_test::*,
|
||||
solana_sdk::{
|
||||
instruction::InstructionError,
|
||||
signature::{Keypair, Signer},
|
||||
transaction::{Transaction, TransactionError},
|
||||
transport::TransportError,
|
||||
|
@ -45,7 +44,12 @@ async fn setup() -> (
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
user_stake
|
||||
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
|
||||
// make pool token account
|
||||
|
@ -165,26 +169,31 @@ async fn test_remove_validator_from_pool_with_wrong_stake_program_id() {
|
|||
_,
|
||||
) = setup().await;
|
||||
|
||||
let wrong_stake_program = Keypair::new();
|
||||
let wrong_stake_program = Pubkey::new_unique();
|
||||
|
||||
let new_authority = Pubkey::new_unique();
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::remove_validator_from_pool(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.owner.pubkey(),
|
||||
&stake_pool_accounts.withdraw_authority,
|
||||
&new_authority,
|
||||
&stake_pool_accounts.validator_list.pubkey(),
|
||||
&user_stake.stake_account,
|
||||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&wrong_stake_program.pubkey(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
let accounts = vec![
|
||||
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.owner.pubkey(), true),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
|
||||
AccountMeta::new_readonly(new_authority, false),
|
||||
AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
|
||||
AccountMeta::new(user_stake.stake_account, false),
|
||||
AccountMeta::new(user_pool_account.pubkey(), false),
|
||||
AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(wrong_stake_program, false),
|
||||
];
|
||||
let instruction = Instruction {
|
||||
program_id: id(),
|
||||
accounts,
|
||||
data: instruction::StakePoolInstruction::RemoveValidatorFromPool
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
|
||||
transaction.sign(&[&payer, &stake_pool_accounts.owner], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
|
@ -230,7 +239,6 @@ async fn test_remove_validator_from_pool_with_wrong_token_program_id() {
|
|||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&wrong_token_program.pubkey(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -277,7 +285,6 @@ async fn test_remove_validator_from_pool_with_wrong_pool_mint_account() {
|
|||
&user_pool_account.pubkey(),
|
||||
&wrong_pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -328,7 +335,6 @@ async fn test_remove_validator_from_pool_with_wrong_validator_list_account() {
|
|||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -444,7 +450,6 @@ async fn test_not_owner_try_to_remove_validator_from_pool() {
|
|||
&user_pool_account.pubkey(),
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&stake::id(),
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
|
@ -523,72 +528,6 @@ async fn test_not_owner_try_to_remove_validator_from_pool_without_signature() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_remove_validator_from_pool_when_stake_acc_not_in_stake_state() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let user = Keypair::new();
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
let user_stake_authority = Keypair::new();
|
||||
create_validator_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.stake_pool,
|
||||
&user_stake.stake_account,
|
||||
&user_stake.vote.pubkey(),
|
||||
&user_stake_authority.pubkey(),
|
||||
&user_stake.target_authority,
|
||||
)
|
||||
.await;
|
||||
|
||||
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 new_authority = Pubkey::new_unique();
|
||||
|
||||
let transaction_error = stake_pool_accounts
|
||||
.remove_validator_from_pool(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake.stake_account,
|
||||
&user_pool_account.pubkey(),
|
||||
&new_authority,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match transaction_error {
|
||||
TransportError::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(error_index),
|
||||
)) => {
|
||||
let program_error = error::StakePoolError::WrongStakeState as u32;
|
||||
assert_eq!(error_index, program_error);
|
||||
}
|
||||
_ => panic!("Wrong error occurs while try to add validator stake account when it isn't in stake state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_remove_validator_from_pool_from_unupdated_stake_pool() {} // TODO
|
||||
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
mod helpers;
|
||||
|
||||
use {
|
||||
borsh::BorshDeserialize,
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
helpers::*,
|
||||
solana_program::hash::Hash,
|
||||
solana_program::pubkey::Pubkey,
|
||||
solana_program::{
|
||||
hash::Hash,
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
solana_program_test::*,
|
||||
solana_sdk::{
|
||||
instruction::InstructionError,
|
||||
signature::{Keypair, Signer},
|
||||
transaction::{Transaction, TransactionError},
|
||||
transport::TransportError,
|
||||
|
@ -204,26 +207,30 @@ async fn test_stake_pool_withdraw_with_wrong_stake_program() {
|
|||
let user_stake_recipient = Keypair::new();
|
||||
|
||||
let new_authority = Pubkey::new_unique();
|
||||
let wrong_stake_program = Keypair::new();
|
||||
let wrong_stake_program = Pubkey::new_unique();
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::withdraw(
|
||||
&id(),
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
&stake_pool_accounts.validator_list.pubkey(),
|
||||
&stake_pool_accounts.withdraw_authority,
|
||||
&validator_stake_account.stake_account,
|
||||
&user_stake_recipient.pubkey(),
|
||||
&new_authority,
|
||||
&deposit_info.user_pool_account,
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&spl_token::id(),
|
||||
&wrong_stake_program.pubkey(),
|
||||
tokens_to_burn,
|
||||
)
|
||||
.unwrap()],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
let accounts = vec![
|
||||
AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false),
|
||||
AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false),
|
||||
AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false),
|
||||
AccountMeta::new(validator_stake_account.stake_account, false),
|
||||
AccountMeta::new(user_stake_recipient.pubkey(), false),
|
||||
AccountMeta::new_readonly(new_authority, false),
|
||||
AccountMeta::new(deposit_info.user_pool_account, false),
|
||||
AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(wrong_stake_program, false),
|
||||
];
|
||||
let instruction = Instruction {
|
||||
program_id: id(),
|
||||
accounts,
|
||||
data: instruction::StakePoolInstruction::Withdraw(tokens_to_burn)
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
let transaction_error = banks_client
|
||||
.process_transaction(transaction)
|
||||
|
@ -314,7 +321,6 @@ async fn test_stake_pool_withdraw_with_wrong_token_program_id() {
|
|||
&deposit_info.user_pool_account,
|
||||
&stake_pool_accounts.pool_mint.pubkey(),
|
||||
&wrong_token_program.pubkey(),
|
||||
&stake::id(),
|
||||
tokens_to_burn,
|
||||
)
|
||||
.unwrap()],
|
||||
|
@ -382,112 +388,6 @@ async fn test_stake_pool_withdraw_with_wrong_validator_list() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_withdraw_when_stake_acc_not_in_stake_state() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
let stake_pool_accounts = StakePoolAccounts::new();
|
||||
stake_pool_accounts
|
||||
.initialize_stake_pool(&mut banks_client, &payer, &recent_blockhash)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let validator_stake_account = ValidatorStakeAccount::new_with_target_authority(
|
||||
&stake_pool_accounts.deposit_authority,
|
||||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
|
||||
let user_stake_authority = Keypair::new();
|
||||
create_validator_stake_account(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&validator_stake_account.stake_pool,
|
||||
&validator_stake_account.stake_account,
|
||||
&validator_stake_account.vote.pubkey(),
|
||||
&user_stake_authority.pubkey(),
|
||||
&validator_stake_account.target_authority,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user = Keypair::new();
|
||||
// make stake account
|
||||
let user_stake = Keypair::new();
|
||||
let lockup = stake::Lockup::default();
|
||||
let authorized = stake::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,
|
||||
)
|
||||
.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 user_pool_account = user_pool_account.pubkey();
|
||||
let pool_tokens = get_token_balance(&mut banks_client, &user_pool_account).await;
|
||||
|
||||
let tokens_to_burn = pool_tokens / 4;
|
||||
|
||||
// Delegate tokens for burning
|
||||
delegate_tokens(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_pool_account,
|
||||
&user,
|
||||
&stake_pool_accounts.withdraw_authority,
|
||||
tokens_to_burn,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Create stake account to withdraw to
|
||||
let user_stake_recipient = Keypair::new();
|
||||
|
||||
let new_authority = Pubkey::new_unique();
|
||||
|
||||
let transaction_error = stake_pool_accounts
|
||||
.withdraw_stake(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&user_stake_recipient.pubkey(),
|
||||
&user_pool_account,
|
||||
&validator_stake_account.stake_account,
|
||||
&new_authority,
|
||||
tokens_to_burn,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
match transaction_error {
|
||||
TransportError::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(error_index),
|
||||
)) => {
|
||||
let program_error = error::StakePoolError::WrongStakeState as u32;
|
||||
assert_eq!(error_index, program_error);
|
||||
}
|
||||
_ => panic!("Wrong error occurs while try to withdraw when stake acc not in stake state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stake_pool_withdraw_from_unknown_validator() {
|
||||
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
||||
|
@ -502,7 +402,12 @@ async fn test_stake_pool_withdraw_from_unknown_validator() {
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
validator_stake_account
|
||||
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user_stake = ValidatorStakeAccount::new_with_target_authority(
|
||||
|
@ -510,7 +415,12 @@ async fn test_stake_pool_withdraw_from_unknown_validator() {
|
|||
&stake_pool_accounts.stake_pool.pubkey(),
|
||||
);
|
||||
user_stake
|
||||
.create_and_delegate(&mut banks_client, &payer, &recent_blockhash)
|
||||
.create_and_delegate(
|
||||
&mut banks_client,
|
||||
&payer,
|
||||
&recent_blockhash,
|
||||
&stake_pool_accounts.owner,
|
||||
)
|
||||
.await;
|
||||
|
||||
let user_pool_account = Keypair::new();
|
||||
|
|
Loading…
Reference in New Issue