1130 lines
32 KiB
Rust
1130 lines
32 KiB
Rust
#![cfg(feature = "test-sbf")]
|
|
|
|
use borsh::de::BorshDeserialize;
|
|
use solana_program::{hash::Hash, program_pack::Pack, pubkey::Pubkey, system_instruction};
|
|
use solana_program_test::*;
|
|
use solana_sdk::{
|
|
account::Account,
|
|
signature::{Keypair, Signer},
|
|
transaction::Transaction,
|
|
transport::TransportError,
|
|
};
|
|
use spl_binary_oracle_pair::*;
|
|
|
|
pub fn program_test() -> ProgramTest {
|
|
ProgramTest::new(
|
|
"spl_binary_oracle_pair",
|
|
id(),
|
|
processor!(processor::Processor::process_instruction),
|
|
)
|
|
}
|
|
|
|
pub async fn create_token_account(
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
account: &Keypair,
|
|
mint: &Pubkey,
|
|
owner: &Pubkey,
|
|
) -> Result<(), TransportError> {
|
|
let rent = banks_client.get_rent().await.unwrap();
|
|
let account_rent = rent.minimum_balance(spl_token::state::Account::LEN);
|
|
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[
|
|
system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&account.pubkey(),
|
|
account_rent,
|
|
spl_token::state::Account::LEN as u64,
|
|
&spl_token::id(),
|
|
),
|
|
spl_token::instruction::initialize_account(
|
|
&spl_token::id(),
|
|
&account.pubkey(),
|
|
mint,
|
|
owner,
|
|
)
|
|
.unwrap(),
|
|
],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
transaction.sign(&[payer, account], *recent_blockhash);
|
|
banks_client.process_transaction(transaction).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn mint_tokens_to(
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
mint: &Pubkey,
|
|
destination: &Pubkey,
|
|
authority: &Keypair,
|
|
amount: u64,
|
|
) -> Result<(), TransportError> {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[spl_token::instruction::mint_to(
|
|
&spl_token::id(),
|
|
mint,
|
|
destination,
|
|
&authority.pubkey(),
|
|
&[&authority.pubkey()],
|
|
amount,
|
|
)
|
|
.unwrap()],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
transaction.sign(&[payer, authority], *recent_blockhash);
|
|
banks_client.process_transaction(transaction).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn approve_delegate(
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
source: &Pubkey,
|
|
delegate: &Pubkey,
|
|
source_owner: &Keypair,
|
|
amount: u64,
|
|
) -> Result<(), TransportError> {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[spl_token::instruction::approve(
|
|
&spl_token::id(),
|
|
source,
|
|
delegate,
|
|
&source_owner.pubkey(),
|
|
&[&source_owner.pubkey()],
|
|
amount,
|
|
)
|
|
.unwrap()],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
transaction.sign(&[payer, source_owner], *recent_blockhash);
|
|
banks_client.process_transaction(transaction).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn make_decision(
|
|
program_context: &mut ProgramTestContext,
|
|
pool_account: &Pubkey,
|
|
decider: &Keypair,
|
|
decision: bool,
|
|
) -> Result<(), TransportError> {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[instruction::decide(&id(), pool_account, &decider.pubkey(), decision).unwrap()],
|
|
Some(&program_context.payer.pubkey()),
|
|
);
|
|
|
|
transaction.sign(
|
|
&[&program_context.payer, decider],
|
|
program_context.last_blockhash,
|
|
);
|
|
program_context
|
|
.banks_client
|
|
.process_transaction(transaction)
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub async fn make_withdraw(
|
|
program_context: &mut ProgramTestContext,
|
|
pool_account: &Pubkey,
|
|
authority: &Pubkey,
|
|
user_transfer_authority: &Pubkey,
|
|
pool_deposit_account: &Pubkey,
|
|
user_pass_account: &Pubkey,
|
|
user_fail_account: &Pubkey,
|
|
token_pass_mint: &Pubkey,
|
|
token_fail_mint: &Pubkey,
|
|
user_account: &Pubkey,
|
|
withdraw_amount: u64,
|
|
) -> Result<(), TransportError> {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[instruction::withdraw(
|
|
&id(),
|
|
pool_account,
|
|
authority,
|
|
user_transfer_authority,
|
|
pool_deposit_account,
|
|
user_pass_account,
|
|
user_fail_account,
|
|
token_pass_mint,
|
|
token_fail_mint,
|
|
user_account,
|
|
&spl_token::id(),
|
|
withdraw_amount,
|
|
)
|
|
.unwrap()],
|
|
Some(&program_context.payer.pubkey()),
|
|
);
|
|
transaction.sign(&[&program_context.payer], program_context.last_blockhash);
|
|
program_context
|
|
.banks_client
|
|
.process_transaction(transaction)
|
|
.await
|
|
.unwrap();
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_token_balance(banks_client: &mut BanksClient, token: &Pubkey) -> u64 {
|
|
let token_account = banks_client.get_account(*token).await.unwrap().unwrap();
|
|
let account_info: spl_token::state::Account =
|
|
spl_token::state::Account::unpack_from_slice(token_account.data.as_slice()).unwrap();
|
|
account_info.amount
|
|
}
|
|
|
|
pub struct TestPool {
|
|
pub pool_account: Keypair,
|
|
pub authority: Pubkey,
|
|
pub bump_seed: u8,
|
|
pub deposit_token_mint: Keypair,
|
|
pub deposit_token_mint_owner: Keypair,
|
|
pub pool_deposit_account: Keypair,
|
|
pub token_pass_mint: Keypair,
|
|
pub token_fail_mint: Keypair,
|
|
pub decider: Keypair,
|
|
pub mint_end_slot: u64,
|
|
pub decide_end_slot: u64,
|
|
}
|
|
|
|
impl TestPool {
|
|
pub fn new() -> Self {
|
|
let pool_account = Keypair::new();
|
|
let (authority, bump_seed) =
|
|
Pubkey::find_program_address(&[&pool_account.pubkey().to_bytes()[..32]], &id());
|
|
Self {
|
|
pool_account,
|
|
authority,
|
|
bump_seed,
|
|
deposit_token_mint: Keypair::new(),
|
|
deposit_token_mint_owner: Keypair::new(),
|
|
pool_deposit_account: Keypair::new(),
|
|
token_pass_mint: Keypair::new(),
|
|
token_fail_mint: Keypair::new(),
|
|
decider: Keypair::new(),
|
|
mint_end_slot: 2,
|
|
decide_end_slot: 2000,
|
|
}
|
|
}
|
|
|
|
pub async fn init_pool(
|
|
&self,
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
) {
|
|
let rent = banks_client.get_rent().await.unwrap();
|
|
let pool_rent = rent.minimum_balance(state::Pool::LEN);
|
|
let mint_rent = rent.minimum_balance(spl_token::state::Mint::LEN);
|
|
let account_rent = rent.minimum_balance(spl_token::state::Account::LEN);
|
|
|
|
// create pool account
|
|
create_account(
|
|
banks_client,
|
|
payer,
|
|
recent_blockhash,
|
|
&self.pool_account,
|
|
pool_rent,
|
|
state::Pool::LEN as u64,
|
|
&id(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// create mint of deposit token
|
|
create_mint(
|
|
banks_client,
|
|
payer,
|
|
recent_blockhash,
|
|
&self.deposit_token_mint,
|
|
mint_rent,
|
|
&self.deposit_token_mint_owner.pubkey(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let init_args = instruction::InitArgs {
|
|
mint_end_slot: self.mint_end_slot,
|
|
decide_end_slot: self.decide_end_slot,
|
|
bump_seed: self.bump_seed,
|
|
};
|
|
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[
|
|
system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&self.pool_deposit_account.pubkey(),
|
|
account_rent,
|
|
spl_token::state::Account::LEN as u64,
|
|
&spl_token::id(),
|
|
),
|
|
system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&self.token_pass_mint.pubkey(),
|
|
mint_rent,
|
|
spl_token::state::Mint::LEN as u64,
|
|
&spl_token::id(),
|
|
),
|
|
system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&self.token_fail_mint.pubkey(),
|
|
mint_rent,
|
|
spl_token::state::Mint::LEN as u64,
|
|
&spl_token::id(),
|
|
),
|
|
instruction::init_pool(
|
|
&id(),
|
|
&self.pool_account.pubkey(),
|
|
&self.authority,
|
|
&self.decider.pubkey(),
|
|
&self.deposit_token_mint.pubkey(),
|
|
&self.pool_deposit_account.pubkey(),
|
|
&self.token_pass_mint.pubkey(),
|
|
&self.token_fail_mint.pubkey(),
|
|
&spl_token::id(),
|
|
init_args,
|
|
)
|
|
.unwrap(),
|
|
],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
|
|
transaction.sign(
|
|
&[
|
|
payer,
|
|
&self.pool_deposit_account,
|
|
&self.token_pass_mint,
|
|
&self.token_fail_mint,
|
|
],
|
|
*recent_blockhash,
|
|
);
|
|
banks_client.process_transaction(transaction).await.unwrap();
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub async fn prepare_accounts_for_deposit(
|
|
&self,
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
deposit_tokens_to_mint: u64,
|
|
deposit_tokens_for_allowance: u64,
|
|
user_account: &Keypair,
|
|
authority: &Pubkey,
|
|
user_account_owner: &Keypair,
|
|
user_pass_account: &Keypair,
|
|
user_fail_account: &Keypair,
|
|
) {
|
|
// Create user account
|
|
create_token_account(
|
|
banks_client,
|
|
payer,
|
|
recent_blockhash,
|
|
user_account,
|
|
&self.deposit_token_mint.pubkey(),
|
|
&user_account_owner.pubkey(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Mint to him some deposit tokens
|
|
mint_tokens_to(
|
|
banks_client,
|
|
payer,
|
|
recent_blockhash,
|
|
&self.deposit_token_mint.pubkey(),
|
|
&user_account.pubkey(),
|
|
&self.deposit_token_mint_owner,
|
|
deposit_tokens_to_mint,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Give allowance to pool authority
|
|
approve_delegate(
|
|
banks_client,
|
|
payer,
|
|
recent_blockhash,
|
|
&user_account.pubkey(),
|
|
authority,
|
|
user_account_owner,
|
|
deposit_tokens_for_allowance,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create token accounts for PASS and FAIL tokens
|
|
create_token_account(
|
|
banks_client,
|
|
payer,
|
|
recent_blockhash,
|
|
user_pass_account,
|
|
&self.token_pass_mint.pubkey(),
|
|
&user_account_owner.pubkey(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
create_token_account(
|
|
banks_client,
|
|
payer,
|
|
recent_blockhash,
|
|
user_fail_account,
|
|
&self.token_fail_mint.pubkey(),
|
|
&user_account_owner.pubkey(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub async fn make_deposit(
|
|
&self,
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
user_account: &Keypair,
|
|
user_pass_account: &Keypair,
|
|
user_fail_account: &Keypair,
|
|
deposit_amount: u64,
|
|
) {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[instruction::deposit(
|
|
&id(),
|
|
&self.pool_account.pubkey(),
|
|
&self.authority,
|
|
&self.authority,
|
|
&user_account.pubkey(),
|
|
&self.pool_deposit_account.pubkey(),
|
|
&self.token_pass_mint.pubkey(),
|
|
&self.token_fail_mint.pubkey(),
|
|
&user_pass_account.pubkey(),
|
|
&user_fail_account.pubkey(),
|
|
&spl_token::id(),
|
|
deposit_amount,
|
|
)
|
|
.unwrap()],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
transaction.sign(&[payer], *recent_blockhash);
|
|
banks_client.process_transaction(transaction).await.unwrap();
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub async fn make_deposit_with_user_transfer_authority(
|
|
&self,
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
user_account: &Keypair,
|
|
user_authority: &Keypair,
|
|
user_pass_account: &Keypair,
|
|
user_fail_account: &Keypair,
|
|
deposit_amount: u64,
|
|
) {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[instruction::deposit(
|
|
&id(),
|
|
&self.pool_account.pubkey(),
|
|
&self.authority,
|
|
&user_authority.pubkey(),
|
|
&user_account.pubkey(),
|
|
&self.pool_deposit_account.pubkey(),
|
|
&self.token_pass_mint.pubkey(),
|
|
&self.token_fail_mint.pubkey(),
|
|
&user_pass_account.pubkey(),
|
|
&user_fail_account.pubkey(),
|
|
&spl_token::id(),
|
|
deposit_amount,
|
|
)
|
|
.unwrap()],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
transaction.sign(&[payer, user_authority], *recent_blockhash);
|
|
banks_client.process_transaction(transaction).await.unwrap();
|
|
}
|
|
}
|
|
impl Default for TestPool {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
pub async fn create_mint(
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
mint_account: &Keypair,
|
|
mint_rent: u64,
|
|
owner: &Pubkey,
|
|
) -> Result<(), TransportError> {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[
|
|
system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&mint_account.pubkey(),
|
|
mint_rent,
|
|
spl_token::state::Mint::LEN as u64,
|
|
&spl_token::id(),
|
|
),
|
|
spl_token::instruction::initialize_mint(
|
|
&spl_token::id(),
|
|
&mint_account.pubkey(),
|
|
owner,
|
|
None,
|
|
0,
|
|
)
|
|
.unwrap(),
|
|
],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
transaction.sign(&[payer, mint_account], *recent_blockhash);
|
|
banks_client.process_transaction(transaction).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn create_account(
|
|
banks_client: &mut BanksClient,
|
|
payer: &Keypair,
|
|
recent_blockhash: &Hash,
|
|
account: &Keypair,
|
|
rent: u64,
|
|
space: u64,
|
|
owner: &Pubkey,
|
|
) -> Result<(), TransportError> {
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&account.pubkey(),
|
|
rent,
|
|
space,
|
|
owner,
|
|
)],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
|
|
transaction.sign(&[payer, account], *recent_blockhash);
|
|
banks_client.process_transaction(transaction).await?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn get_account(banks_client: &mut BanksClient, pubkey: &Pubkey) -> Account {
|
|
banks_client
|
|
.get_account(*pubkey)
|
|
.await
|
|
.expect("account not found")
|
|
.expect("account empty")
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_init_pool() {
|
|
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
|
|
|
let pool = TestPool::new();
|
|
|
|
pool.init_pool(&mut banks_client, &payer, &recent_blockhash)
|
|
.await;
|
|
|
|
let pool_account_data = get_account(&mut banks_client, &pool.pool_account.pubkey()).await;
|
|
|
|
assert_eq!(pool_account_data.data.len(), state::Pool::LEN);
|
|
assert_eq!(pool_account_data.owner, id());
|
|
|
|
// check if Pool is initialized
|
|
let pool = state::Pool::try_from_slice(pool_account_data.data.as_slice()).unwrap();
|
|
assert!(pool.is_initialized());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_deposit_with_program_authority() {
|
|
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
|
|
|
let deposit_amount = 100;
|
|
|
|
let pool = TestPool::new();
|
|
|
|
pool.init_pool(&mut banks_client, &payer, &recent_blockhash)
|
|
.await;
|
|
|
|
let user_account = Keypair::new();
|
|
let user_account_owner = Keypair::new();
|
|
let user_pass_account = Keypair::new();
|
|
let user_fail_account = Keypair::new();
|
|
|
|
pool.prepare_accounts_for_deposit(
|
|
&mut banks_client,
|
|
&payer,
|
|
&recent_blockhash,
|
|
deposit_amount,
|
|
deposit_amount,
|
|
&user_account,
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
)
|
|
.await;
|
|
|
|
let user_balance_before = get_token_balance(&mut banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_before, deposit_amount);
|
|
|
|
// Make deposit
|
|
pool.make_deposit(
|
|
&mut banks_client,
|
|
&payer,
|
|
&recent_blockhash,
|
|
&user_account,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
deposit_amount,
|
|
)
|
|
.await;
|
|
|
|
// Check balance of user account
|
|
let user_balance_after = get_token_balance(&mut banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_after, 0);
|
|
|
|
// Check balance of pool deposit account
|
|
let pool_deposit_account_balance =
|
|
get_token_balance(&mut banks_client, &pool.pool_deposit_account.pubkey()).await;
|
|
assert_eq!(pool_deposit_account_balance, deposit_amount);
|
|
|
|
// Check if user has PASS and FAIL tokens
|
|
let user_pass_tokens = get_token_balance(&mut banks_client, &user_pass_account.pubkey()).await;
|
|
assert_eq!(user_pass_tokens, deposit_amount);
|
|
|
|
let user_fail_tokens = get_token_balance(&mut banks_client, &user_fail_account.pubkey()).await;
|
|
assert_eq!(user_fail_tokens, deposit_amount);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_deposit_with_user_authority() {
|
|
let (mut banks_client, payer, recent_blockhash) = program_test().start().await;
|
|
|
|
let deposit_amount = 100;
|
|
|
|
let pool = TestPool::new();
|
|
|
|
pool.init_pool(&mut banks_client, &payer, &recent_blockhash)
|
|
.await;
|
|
|
|
let user_account = Keypair::new();
|
|
let user_account_owner = Keypair::new();
|
|
let user_transfer_authority = Keypair::new();
|
|
let user_pass_account = Keypair::new();
|
|
let user_fail_account = Keypair::new();
|
|
|
|
pool.prepare_accounts_for_deposit(
|
|
&mut banks_client,
|
|
&payer,
|
|
&recent_blockhash,
|
|
deposit_amount,
|
|
deposit_amount,
|
|
&user_account,
|
|
&user_transfer_authority.pubkey(),
|
|
&user_account_owner,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
)
|
|
.await;
|
|
|
|
let user_balance_before = get_token_balance(&mut banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_before, deposit_amount);
|
|
|
|
// Make deposit
|
|
pool.make_deposit_with_user_transfer_authority(
|
|
&mut banks_client,
|
|
&payer,
|
|
&recent_blockhash,
|
|
&user_account,
|
|
&user_transfer_authority,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
deposit_amount,
|
|
)
|
|
.await;
|
|
|
|
// Check balance of user account
|
|
let user_balance_after = get_token_balance(&mut banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_after, 0);
|
|
|
|
// Check balance of pool deposit account
|
|
let pool_deposit_account_balance =
|
|
get_token_balance(&mut banks_client, &pool.pool_deposit_account.pubkey()).await;
|
|
assert_eq!(pool_deposit_account_balance, deposit_amount);
|
|
|
|
// Check if user has PASS and FAIL tokens
|
|
let user_pass_tokens = get_token_balance(&mut banks_client, &user_pass_account.pubkey()).await;
|
|
assert_eq!(user_pass_tokens, deposit_amount);
|
|
|
|
let user_fail_tokens = get_token_balance(&mut banks_client, &user_fail_account.pubkey()).await;
|
|
assert_eq!(user_fail_tokens, deposit_amount);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_withdraw_no_decision() {
|
|
let mut program_context = program_test().start_with_context().await;
|
|
|
|
let deposit_amount = 100;
|
|
let withdraw_amount = 50;
|
|
|
|
let pool = TestPool::new();
|
|
|
|
pool.init_pool(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
)
|
|
.await;
|
|
|
|
let user_account = Keypair::new();
|
|
let user_account_owner = Keypair::new();
|
|
let user_pass_account = Keypair::new();
|
|
let user_fail_account = Keypair::new();
|
|
|
|
pool.prepare_accounts_for_deposit(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
deposit_amount,
|
|
deposit_amount,
|
|
&user_account,
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
)
|
|
.await;
|
|
|
|
// Make deposit
|
|
pool.make_deposit(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_account,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
deposit_amount,
|
|
)
|
|
.await;
|
|
|
|
// Set allowances to burn PASS and FAIL tokens
|
|
approve_delegate(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_pass_account.pubkey(),
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
deposit_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
approve_delegate(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_fail_account.pubkey(),
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
deposit_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let user_balance_before =
|
|
get_token_balance(&mut program_context.banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_before, 0);
|
|
|
|
// Check balance of pool deposit account
|
|
let pool_deposit_account_balance = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&pool.pool_deposit_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(pool_deposit_account_balance, deposit_amount);
|
|
|
|
// Check if user has PASS and FAIL tokens
|
|
let user_pass_tokens = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_pass_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_pass_tokens, deposit_amount);
|
|
|
|
let user_fail_tokens = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_fail_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_fail_tokens, deposit_amount);
|
|
|
|
make_withdraw(
|
|
&mut program_context,
|
|
&pool.pool_account.pubkey(),
|
|
&pool.authority,
|
|
&pool.authority,
|
|
&pool.pool_deposit_account.pubkey(),
|
|
&user_pass_account.pubkey(),
|
|
&user_fail_account.pubkey(),
|
|
&pool.token_pass_mint.pubkey(),
|
|
&pool.token_fail_mint.pubkey(),
|
|
&user_account.pubkey(),
|
|
withdraw_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let user_balance_after =
|
|
get_token_balance(&mut program_context.banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_after, withdraw_amount);
|
|
|
|
// Check balance of pool deposit account after withdraw
|
|
let pool_deposit_account_balance_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&pool.pool_deposit_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(
|
|
pool_deposit_account_balance_after,
|
|
deposit_amount - withdraw_amount
|
|
);
|
|
|
|
// Check if program burned PASS and FAIL tokens
|
|
let user_pass_tokens_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_pass_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_pass_tokens_after, deposit_amount - withdraw_amount);
|
|
|
|
let user_fail_tokens_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_fail_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_fail_tokens_after, deposit_amount - withdraw_amount);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_withdraw_pass_decision() {
|
|
let mut program_context = program_test().start_with_context().await;
|
|
|
|
let deposit_amount = 100;
|
|
let withdraw_amount = 50;
|
|
|
|
let pool = TestPool::new();
|
|
|
|
pool.init_pool(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
)
|
|
.await;
|
|
|
|
let user_account = Keypair::new();
|
|
let user_account_owner = Keypair::new();
|
|
let user_pass_account = Keypair::new();
|
|
let user_fail_account = Keypair::new();
|
|
|
|
pool.prepare_accounts_for_deposit(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
deposit_amount,
|
|
deposit_amount,
|
|
&user_account,
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
)
|
|
.await;
|
|
|
|
// Make deposit
|
|
pool.make_deposit(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_account,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
deposit_amount,
|
|
)
|
|
.await;
|
|
|
|
// Set allowances to burn PASS and FAIL tokens
|
|
approve_delegate(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_pass_account.pubkey(),
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
deposit_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
approve_delegate(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_fail_account.pubkey(),
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
deposit_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let decision = true;
|
|
|
|
program_context
|
|
.warp_to_slot(pool.mint_end_slot + 1)
|
|
.unwrap();
|
|
|
|
make_decision(
|
|
&mut program_context,
|
|
&pool.pool_account.pubkey(),
|
|
&pool.decider,
|
|
decision,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
make_withdraw(
|
|
&mut program_context,
|
|
&pool.pool_account.pubkey(),
|
|
&pool.authority,
|
|
&pool.authority,
|
|
&pool.pool_deposit_account.pubkey(),
|
|
&user_pass_account.pubkey(),
|
|
&user_fail_account.pubkey(),
|
|
&pool.token_pass_mint.pubkey(),
|
|
&pool.token_fail_mint.pubkey(),
|
|
&user_account.pubkey(),
|
|
withdraw_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let user_balance_after =
|
|
get_token_balance(&mut program_context.banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_after, withdraw_amount);
|
|
|
|
// Check balance of pool deposit account after withdraw
|
|
let pool_deposit_account_balance_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&pool.pool_deposit_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(
|
|
pool_deposit_account_balance_after,
|
|
deposit_amount - withdraw_amount
|
|
);
|
|
|
|
// Check if program burned PASS and FAIL tokens
|
|
let user_pass_tokens_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_pass_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_pass_tokens_after, deposit_amount - withdraw_amount);
|
|
|
|
let user_fail_tokens_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_fail_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_fail_tokens_after, deposit_amount);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_withdraw_fail_decision() {
|
|
let mut program_context = program_test().start_with_context().await;
|
|
|
|
let deposit_amount = 100;
|
|
let withdraw_amount = 50;
|
|
|
|
let pool = TestPool::new();
|
|
|
|
pool.init_pool(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
)
|
|
.await;
|
|
|
|
let user_account = Keypair::new();
|
|
let user_account_owner = Keypair::new();
|
|
let user_pass_account = Keypair::new();
|
|
let user_fail_account = Keypair::new();
|
|
|
|
pool.prepare_accounts_for_deposit(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
deposit_amount,
|
|
deposit_amount,
|
|
&user_account,
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
)
|
|
.await;
|
|
|
|
// Make deposit
|
|
pool.make_deposit(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_account,
|
|
&user_pass_account,
|
|
&user_fail_account,
|
|
deposit_amount,
|
|
)
|
|
.await;
|
|
|
|
// Set allowances to burn PASS and FAIL tokens
|
|
approve_delegate(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_pass_account.pubkey(),
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
deposit_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
approve_delegate(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
&user_fail_account.pubkey(),
|
|
&pool.authority,
|
|
&user_account_owner,
|
|
deposit_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let decision = false;
|
|
|
|
program_context
|
|
.warp_to_slot(pool.mint_end_slot + 1)
|
|
.unwrap();
|
|
|
|
make_decision(
|
|
&mut program_context,
|
|
&pool.pool_account.pubkey(),
|
|
&pool.decider,
|
|
decision,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
make_withdraw(
|
|
&mut program_context,
|
|
&pool.pool_account.pubkey(),
|
|
&pool.authority,
|
|
&pool.authority,
|
|
&pool.pool_deposit_account.pubkey(),
|
|
&user_pass_account.pubkey(),
|
|
&user_fail_account.pubkey(),
|
|
&pool.token_pass_mint.pubkey(),
|
|
&pool.token_fail_mint.pubkey(),
|
|
&user_account.pubkey(),
|
|
withdraw_amount,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let user_balance_after =
|
|
get_token_balance(&mut program_context.banks_client, &user_account.pubkey()).await;
|
|
assert_eq!(user_balance_after, withdraw_amount);
|
|
|
|
// Check balance of pool deposit account after withdraw
|
|
let pool_deposit_account_balance_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&pool.pool_deposit_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(
|
|
pool_deposit_account_balance_after,
|
|
deposit_amount - withdraw_amount
|
|
);
|
|
|
|
// Check if program burned PASS and FAIL tokens
|
|
let user_pass_tokens_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_pass_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_pass_tokens_after, deposit_amount);
|
|
|
|
let user_fail_tokens_after = get_token_balance(
|
|
&mut program_context.banks_client,
|
|
&user_fail_account.pubkey(),
|
|
)
|
|
.await;
|
|
assert_eq!(user_fail_tokens_after, deposit_amount - withdraw_amount);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_decide() {
|
|
let mut program_context = program_test().start_with_context().await;
|
|
|
|
let pool = TestPool::new();
|
|
|
|
pool.init_pool(
|
|
&mut program_context.banks_client,
|
|
&program_context.payer,
|
|
&program_context.last_blockhash,
|
|
)
|
|
.await;
|
|
|
|
let pool_account_data_before = program_context
|
|
.banks_client
|
|
.get_account(pool.pool_account.pubkey())
|
|
.await
|
|
.unwrap()
|
|
.unwrap();
|
|
|
|
let pool_data_before =
|
|
state::Pool::try_from_slice(pool_account_data_before.data.as_slice()).unwrap();
|
|
|
|
assert_eq!(pool_data_before.decision, state::Decision::Undecided);
|
|
|
|
let decision = true;
|
|
|
|
program_context
|
|
.warp_to_slot(pool.mint_end_slot + 1)
|
|
.unwrap();
|
|
|
|
make_decision(
|
|
&mut program_context,
|
|
&pool.pool_account.pubkey(),
|
|
&pool.decider,
|
|
decision,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let pool_account_data_after = program_context
|
|
.banks_client
|
|
.get_account(pool.pool_account.pubkey())
|
|
.await
|
|
.unwrap()
|
|
.unwrap();
|
|
|
|
let pool_data_after =
|
|
state::Pool::try_from_slice(pool_account_data_after.data.as_slice()).unwrap();
|
|
|
|
assert_eq!(pool_data_after.decision, state::Decision::Pass);
|
|
}
|