Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added special case for Liquidation. #66

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions token-lending/program/src/state/reserve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ impl Reserve {
let withdraw_amount;

// Close out obligations that are too small to liquidate normally
if liquidity.borrowed_amount_wads < LIQUIDATION_CLOSE_AMOUNT.into() {
if liquidity.borrowed_amount_wads < LIQUIDATION_CLOSE_AMOUNT.into()
|| collateral.deposited_amount < LIQUIDATION_CLOSE_AMOUNT
{
// settle_amount is fixed, calculate withdraw_amount and repay_amount
settle_amount = liquidity.borrowed_amount_wads;

Expand All @@ -256,7 +258,7 @@ impl Reserve {
repay_amount = max_amount.try_floor_u64()?;
withdraw_amount = Decimal::from(collateral.deposited_amount)
.try_mul(withdraw_pct)?
.try_floor_u64()?;
.try_ceil_u64()?;
}
}
} else {
Expand Down
169 changes: 169 additions & 0 deletions token-lending/program/tests/liquidate_obligation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,175 @@ async fn test_success() {
)
}

#[tokio::test]
async fn test_success_one_lamport() {
let mut test = ProgramTest::new(
"port_finance_variable_rate_lending",
port_finance_variable_rate_lending::id(),
processor!(process_instruction),
);

// limit to track compute unit increase
test.set_bpf_compute_max_units(90_000);

// 1 USDC Collateral
const USDC_DEPOSIT_AMOUNT_LAMPORTS: u64 = 1;
// 40 SOL = 0.8 USDC borrow
const SOL_BORROW_AMOUNT_FRACTIONAL: u64 = 40;
// \
const SOL_LIQUIDATION_AMOUNT_FRACTIONAL: u64 = 20;
//
const USDC_LIQUIDATION_AMOUNT_LAMPORTS: u64 = 1;

const USDC_RESERVE_COLLATERAL_LAMPORTS: u64 = 2 * USDC_DEPOSIT_AMOUNT_LAMPORTS;
const SOL_RESERVE_LIQUIDITY_FRACTIONAL: u64 = 2 * SOL_BORROW_AMOUNT_FRACTIONAL;

let user_accounts_owner = Keypair::new();
let user_transfer_authority = Keypair::new();
let lending_market = add_lending_market(&mut test);

let mut reserve_config = TEST_RESERVE_CONFIG;
reserve_config.loan_to_value_ratio = 50;
reserve_config.liquidation_threshold = 80;
reserve_config.liquidation_bonus = 10;

let sol_oracle = add_sol_pyth_oracle(&mut test);
let sol_test_reserve = add_reserve(
&mut test,
&lending_market,
&sol_oracle,
&user_accounts_owner,
AddReserveArgs {
borrow_amount: SOL_BORROW_AMOUNT_FRACTIONAL,
user_liquidity_amount: SOL_BORROW_AMOUNT_FRACTIONAL,
liquidity_amount: SOL_RESERVE_LIQUIDITY_FRACTIONAL,
liquidity_mint_pubkey: spl_token::native_mint::id(),
liquidity_mint_decimals: 9,
config: reserve_config,
mark_fresh: true,
..AddReserveArgs::default()
},
);

let usdc_mint = add_usdc_mint(&mut test);
let usdc_oracle = add_usdc_pyth_oracle(&mut test);
let usdc_test_reserve = add_reserve(
&mut test,
&lending_market,
&usdc_oracle,
&user_accounts_owner,
AddReserveArgs {
collateral_amount: USDC_RESERVE_COLLATERAL_LAMPORTS,
liquidity_mint_pubkey: usdc_mint.pubkey,
liquidity_mint_decimals: usdc_mint.decimals,
config: reserve_config,
mark_fresh: true,
..AddReserveArgs::default()
},
);

let test_obligation = add_obligation(
&mut test,
&lending_market,
&user_accounts_owner,
AddObligationArgs {
deposits: &[(&usdc_test_reserve, USDC_DEPOSIT_AMOUNT_LAMPORTS)],
borrows: &[(&sol_test_reserve, SOL_BORROW_AMOUNT_FRACTIONAL)],
..AddObligationArgs::default()
},
);

let (mut banks_client, payer, recent_blockhash) = test.start().await;

let initial_user_liquidity_balance =
get_token_balance(&mut banks_client, sol_test_reserve.user_liquidity_pubkey).await;
let initial_liquidity_supply_balance =
get_token_balance(&mut banks_client, sol_test_reserve.liquidity_supply_pubkey).await;
let initial_user_collateral_balance =
get_token_balance(&mut banks_client, usdc_test_reserve.user_collateral_pubkey).await;
let initial_collateral_supply_balance = get_token_balance(
&mut banks_client,
usdc_test_reserve.collateral_supply_pubkey,
)
.await;

let mut transaction = Transaction::new_with_payer(
&[
approve(
&spl_token::id(),
&sol_test_reserve.user_liquidity_pubkey,
&user_transfer_authority.pubkey(),
&user_accounts_owner.pubkey(),
&[],
SOL_LIQUIDATION_AMOUNT_FRACTIONAL,
)
.unwrap(),
refresh_obligation(
port_finance_variable_rate_lending::id(),
test_obligation.pubkey,
vec![usdc_test_reserve.pubkey, sol_test_reserve.pubkey],
),
liquidate_obligation(
port_finance_variable_rate_lending::id(),
SOL_LIQUIDATION_AMOUNT_FRACTIONAL,
sol_test_reserve.user_liquidity_pubkey,
usdc_test_reserve.user_collateral_pubkey,
sol_test_reserve.pubkey,
sol_test_reserve.liquidity_supply_pubkey,
usdc_test_reserve.pubkey,
usdc_test_reserve.collateral_supply_pubkey,
test_obligation.pubkey,
lending_market.pubkey,
user_transfer_authority.pubkey(),
None,
None,
),
],
Some(&payer.pubkey()),
);

transaction.sign(
&[&payer, &user_accounts_owner, &user_transfer_authority],
recent_blockhash,
);
banks_client.process_transaction(transaction).await.unwrap();

let user_liquidity_balance =
get_token_balance(&mut banks_client, sol_test_reserve.user_liquidity_pubkey).await;
assert_eq!(
user_liquidity_balance,
initial_user_liquidity_balance - SOL_LIQUIDATION_AMOUNT_FRACTIONAL
);

let liquidity_supply_balance =
get_token_balance(&mut banks_client, sol_test_reserve.liquidity_supply_pubkey).await;
assert_eq!(
liquidity_supply_balance,
initial_liquidity_supply_balance + SOL_LIQUIDATION_AMOUNT_FRACTIONAL
);

let user_collateral_balance =
get_token_balance(&mut banks_client, usdc_test_reserve.user_collateral_pubkey).await;
assert_eq!(
user_collateral_balance,
initial_user_collateral_balance + USDC_LIQUIDATION_AMOUNT_LAMPORTS
);

let collateral_supply_balance = get_token_balance(
&mut banks_client,
usdc_test_reserve.collateral_supply_pubkey,
)
.await;
assert_eq!(
collateral_supply_balance,
initial_collateral_supply_balance - USDC_LIQUIDATION_AMOUNT_LAMPORTS
);

let obligation = test_obligation.get_state(&mut banks_client).await;
assert_eq!(obligation.deposits.len(), 0);
assert_eq!(obligation.deposits.len(), 0)
}

#[tokio::test]
async fn test_success_with_staking() {
let mut test = ProgramTest::new(
Expand Down