Skip to content

Commit

Permalink
new test
Browse files Browse the repository at this point in the history
  • Loading branch information
0xripleys committed Aug 31, 2023
1 parent 27abb3f commit 93e08b1
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 70 deletions.
28 changes: 28 additions & 0 deletions token-lending/program/tests/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,34 @@ pub const QUOTE_CURRENCY: [u8; 32] =
pub const LAMPORTS_TO_SOL: u64 = 1_000_000_000;
pub const FRACTIONAL_TO_USDC: u64 = 1_000_000;

pub fn zero_fee_reserve_config() -> ReserveConfig {
ReserveConfig {
optimal_utilization_rate: 80,
max_utilization_rate: 80,
loan_to_value_ratio: 50,
liquidation_bonus: 0,
max_liquidation_bonus: 0,
liquidation_threshold: 55,
max_liquidation_threshold: 65,
min_borrow_rate: 0,
optimal_borrow_rate: 0,
max_borrow_rate: 0,
super_max_borrow_rate: 0,
fees: ReserveFees {
borrow_fee_wad: 0,
flash_loan_fee_wad: 0,
host_fee_percentage: 0,
},
deposit_limit: u64::MAX,
borrow_limit: u64::MAX,
fee_receiver: Keypair::new().pubkey(),
protocol_liquidation_fee: 0,
protocol_take_rate: 0,
added_borrow_weight_bps: 0,
reserve_type: ReserveType::Regular,
}
}

pub fn test_reserve_config() -> ReserveConfig {
ReserveConfig {
optimal_utilization_rate: 80,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#![cfg(feature = "test-bpf")]

use crate::solend_program_test::TokenBalanceChange;
use solana_sdk::instruction::InstructionError;
use solana_sdk::transaction::TransactionError;
use std::collections::HashSet;

use crate::solend_program_test::custom_scenario;
use crate::solend_program_test::find_reserve;
use crate::solend_program_test::User;
Expand All @@ -8,26 +13,147 @@ use crate::solend_program_test::BalanceChecker;
use crate::solend_program_test::ObligationArgs;
use crate::solend_program_test::PriceArgs;
use crate::solend_program_test::ReserveArgs;
use crate::solend_program_test::TokenBalanceChange;

use solana_program::native_token::LAMPORTS_PER_SOL;
use solana_sdk::instruction::InstructionError;

use solana_sdk::signer::Signer;
use solana_sdk::transaction::TransactionError;
use solend_program::error::LendingError;

use solend_program::state::ReserveConfig;

use solend_sdk::state::ReserveFees;
mod helpers;

use helpers::*;
use solana_program_test::*;
use wrapper::processor::liquidate_without_receiving_ctokens;

use std::collections::HashSet;

#[tokio::test]
async fn test_liquidate() {
let (mut test, lending_market, reserves, obligations, _users, lending_market_owner) =
custom_scenario(
&[
ReserveArgs {
mint: usdc_mint::id(),
config: zero_fee_reserve_config(),
liquidity_amount: 10 * FRACTIONAL_TO_USDC,
price: PriceArgs {
price: 10,
conf: 0,
expo: -1,
ema_price: 10,
ema_conf: 0,
},
},
ReserveArgs {
mint: wsol_mint::id(),
config: zero_fee_reserve_config(),
liquidity_amount: 100 * LAMPORTS_PER_SOL,
price: PriceArgs {
price: 10,
conf: 0,
expo: 0,
ema_price: 10,
ema_conf: 0,
},
},
],
&[
ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
},
ObligationArgs {
deposits: vec![(wsol_mint::id(), 100_000 * LAMPORTS_PER_SOL)],
borrows: vec![],
},
],
)
.await;

test.advance_clock_by_slots(1).await;

let repay_reserve = find_reserve(&reserves, &wsol_mint::id()).unwrap();
let withdraw_reserve = find_reserve(&reserves, &usdc_mint::id()).unwrap();

lending_market
.update_reserve_config(
&mut test,
&lending_market_owner,
&repay_reserve,
ReserveConfig {
added_borrow_weight_bps: u64::MAX,
..repay_reserve.account.config
},
repay_reserve.account.rate_limiter.config,
None,
)
.await
.unwrap();

test.advance_clock_by_slots(1).await;

let liquidator = User::new_with_balances(
&mut test,
&[
(&wsol_mint::id(), 100 * LAMPORTS_TO_SOL),
(&withdraw_reserve.account.collateral.mint_pubkey, 0),
(&usdc_mint::id(), 0),
],
)
.await;

let balance_checker = BalanceChecker::start(&mut test, &[&liquidator]).await;

let mut instructions = lending_market
.build_refresh_instructions(&mut test, &obligations[0], None)
.await;

instructions.push(liquidate_without_receiving_ctokens(
wrapper::id(),
u64::MAX,
solend_program::id(),
liquidator
.get_account(&repay_reserve.account.liquidity.mint_pubkey)
.unwrap(),
liquidator
.get_account(&withdraw_reserve.account.collateral.mint_pubkey)
.unwrap(),
liquidator
.get_account(&withdraw_reserve.account.liquidity.mint_pubkey)
.unwrap(),
repay_reserve.pubkey,
repay_reserve.account.liquidity.supply_pubkey,
withdraw_reserve.pubkey,
withdraw_reserve.account.collateral.mint_pubkey,
withdraw_reserve.account.collateral.supply_pubkey,
withdraw_reserve.account.liquidity.supply_pubkey,
withdraw_reserve.account.config.fee_receiver,
obligations[0].pubkey,
obligations[0].account.lending_market,
liquidator.keypair.pubkey(),
));

test.process_transaction(&instructions, Some(&[&liquidator.keypair]))
.await
.unwrap();

let (balance_changes, _) = balance_checker.find_balance_changes(&mut test).await;
let expected_balances_changes = HashSet::from([
TokenBalanceChange {
token_account: liquidator.get_account(&usdc_mint::id()).unwrap(),
mint: usdc_mint::id(),
diff: (10 * FRACTIONAL_TO_USDC - 1) as i128,
},
TokenBalanceChange {
token_account: liquidator.get_account(&wsol_mint::id()).unwrap(),
mint: wsol_mint::id(),
diff: -(LAMPORTS_PER_SOL as i128),
},
]);
assert_eq!(balance_changes, expected_balances_changes);
}

#[tokio::test]
async fn test_liquidate_fail() {
let (mut test, lending_market, reserves, obligations, users, lending_market_owner) =
custom_scenario(
&[
Expand Down Expand Up @@ -146,10 +272,17 @@ async fn test_liquidate() {
liquidator.keypair.pubkey(),
));

test.process_transaction(&instructions, Some(&[&liquidator.keypair]))
let err = test
.process_transaction(&instructions, Some(&[&liquidator.keypair]))
.await
.err()
.unwrap()
.unwrap();

let balances = balance_checker.find_balance_changes(&mut test).await;
println!("balances changes: {:#?}", balances);
assert_eq!(
err,
TransactionError::InstructionError(3, InstructionError::Custom(0))
);
let (balance_changes, _) = balance_checker.find_balance_changes(&mut test).await;
assert!(balance_changes.is_empty());
}
67 changes: 7 additions & 60 deletions token-lending/wrapper/src/processor.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
//! Program state processor
use borsh::{BorshDeserialize, BorshSerialize};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use solana_program::pubkey::PUBKEY_BYTES;
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::ProgramResult,
instruction::{AccountMeta, Instruction},
msg,
program::{invoke, invoke_signed},
program::invoke,
program_error::ProgramError,
program_pack::{IsInitialized, Pack},
program_pack::Pack,
pubkey::Pubkey,
system_instruction::create_account,
sysvar::instructions::{load_current_index_checked, load_instruction_at_checked},
sysvar::{
clock::{self, Clock},
rent::Rent,
Sysvar,
},
};
use thiserror::Error;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use solend_sdk::instruction::liquidate_obligation_and_redeem_reserve_collateral;
use thiserror::Error;

/// Instruction types
#[derive(BorshSerialize, BorshDeserialize)]
Expand All @@ -38,7 +31,7 @@ pub enum WrapperInstruction {

/// Processes an instruction
pub fn process_instruction(
program_id: &Pubkey,
_program_id: &Pubkey,
accounts: &[AccountInfo],
input: &[u8],
) -> ProgramResult {
Expand All @@ -65,51 +58,6 @@ pub fn process_instruction(
let user_transfer_authority_info = next_account_info(account_info_iter)?;
let token_program_id = next_account_info(account_info_iter)?;

// print all info variables
msg!("solend_program_info: {}", solend_program_info.key);
msg!("source_liquidity_info: {}", source_liquidity_info.key);
msg!(
"destination_collateral_info: {}",
destination_collateral_info.key
);
msg!(
"destination_liquidity_info: {}",
destination_liquidity_info.key
);
msg!("repay_reserve_info: {}", repay_reserve_info.key);
msg!(
"repay_reserve_liquidity_supply_info: {}",
repay_reserve_liquidity_supply_info.key
);
msg!("withdraw_reserve_info: {}", withdraw_reserve_info.key);
msg!(
"withdraw_reserve_collateral_mint_info: {}",
withdraw_reserve_collateral_mint_info.key
);
msg!(
"withdraw_reserve_collateral_supply_info: {}",
withdraw_reserve_collateral_supply_info.key
);
msg!(
"withdraw_reserve_liquidity_supply_info: {}",
withdraw_reserve_liquidity_supply_info.key
);
msg!(
"withdraw_reserve_liquidity_fee_receiver_info: {}",
withdraw_reserve_liquidity_fee_receiver_info.key
);
msg!("obligation_info: {}", obligation_info.key);
msg!("lending_market_info: {}", lending_market_info.key);
msg!(
"lending_market_authority_info: {}",
lending_market_authority_info.key
);
msg!(
"user_transfer_authority_info: {}",
user_transfer_authority_info.key
);
msg!("token_program_id: {}", token_program_id.key);

let instruction = liquidate_obligation_and_redeem_reserve_collateral(
*solend_program_info.key,
liquidity_amount,
Expand Down Expand Up @@ -168,13 +116,12 @@ pub fn process_instruction(
Ok(())
}


/// Errors that may be returned by the TokenLending program.
#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)]
pub enum WrapperError {
/// Received ctokens
#[error("Received ctokens")]
ReceivedCTokens
ReceivedCTokens,
}

impl From<WrapperError> for ProgramError {
Expand Down

0 comments on commit 93e08b1

Please sign in to comment.