From 93e08b1cd5d1c7ba34b4f597c1fc87dc97bb2062 Mon Sep 17 00:00:00 2001 From: 0xripleys <0xripleys@solend.fi> Date: Wed, 30 Aug 2023 20:23:07 -0400 Subject: [PATCH] new test --- token-lending/program/tests/helpers/mod.rs | 28 ++++ ...te_obligation_without_receiving_ctokens.rs | 153 ++++++++++++++++-- token-lending/wrapper/src/processor.rs | 67 +------- 3 files changed, 178 insertions(+), 70 deletions(-) diff --git a/token-lending/program/tests/helpers/mod.rs b/token-lending/program/tests/helpers/mod.rs index 556ffa3ded4..0ca87cea9d8 100644 --- a/token-lending/program/tests/helpers/mod.rs +++ b/token-lending/program/tests/helpers/mod.rs @@ -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, diff --git a/token-lending/program/tests/liquidate_obligation_without_receiving_ctokens.rs b/token-lending/program/tests/liquidate_obligation_without_receiving_ctokens.rs index 580150d69ef..849d0400629 100644 --- a/token-lending/program/tests/liquidate_obligation_without_receiving_ctokens.rs +++ b/token-lending/program/tests/liquidate_obligation_without_receiving_ctokens.rs @@ -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; @@ -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( &[ @@ -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()); } diff --git a/token-lending/wrapper/src/processor.rs b/token-lending/wrapper/src/processor.rs index 607741d093f..02b9e4382ef 100644 --- a/token-lending/wrapper/src/processor.rs +++ b/token-lending/wrapper/src/processor.rs @@ -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)] @@ -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 { @@ -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, @@ -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 for ProgramError {