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

Solend v2.0.1 #131

Merged
merged 7 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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: 6 additions & 0 deletions token-lending/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use lending_state::SolendState;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_sdk::{commitment_config::CommitmentLevel, compute_budget::ComputeBudgetInstruction};
use solend_program::state::{RateLimiterConfig, SLOTS_PER_YEAR};
use solend_sdk::{
instruction::{
liquidate_obligation_and_redeem_reserve_collateral, redeem_reserve_collateral,
Expand Down Expand Up @@ -871,6 +872,7 @@ fn main() {
fee_receiver: liquidity_fee_receiver_keypair.pubkey(),
protocol_liquidation_fee,
protocol_take_rate,
added_borrow_weight_bps: 10000,
},
source_liquidity_pubkey,
source_liquidity_owner_keypair,
Expand Down Expand Up @@ -1675,6 +1677,10 @@ fn command_update_reserve(
&[update_reserve_config(
config.lending_program_id,
reserve.config,
RateLimiterConfig {
window_duration: SLOTS_PER_YEAR / 365,
max_outflow: u64::MAX,
},
reserve_pubkey,
lending_market_pubkey,
lending_market_owner_keypair.pubkey(),
Expand Down
215 changes: 137 additions & 78 deletions token-lending/program/src/processor.rs

Large diffs are not rendered by default.

236 changes: 196 additions & 40 deletions token-lending/program/tests/borrow_obligation_liquidity.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#![cfg(feature = "test-bpf")]

use solend_program::math::TryDiv;
mod helpers;

use solend_program::state::ReserveFees;
use solend_program::state::{RateLimiterConfig, ReserveFees};
use std::collections::HashSet;

use helpers::solend_program_test::{
Expand Down Expand Up @@ -31,8 +32,9 @@ async fn setup(
User,
Info<Obligation>,
User,
User,
) {
let (mut test, lending_market, usdc_reserve, wsol_reserve, _, user) =
let (mut test, lending_market, usdc_reserve, wsol_reserve, lending_market_owner, user) =
setup_world(&test_reserve_config(), wsol_reserve_config).await;

let obligation = lending_market
Expand Down Expand Up @@ -98,21 +100,30 @@ async fn setup(
user,
obligation,
host_fee_receiver,
lending_market_owner,
)
}

#[tokio::test]
async fn test_success() {
let (mut test, lending_market, usdc_reserve, wsol_reserve, user, obligation, host_fee_receiver) =
setup(&ReserveConfig {
fees: ReserveFees {
borrow_fee_wad: 100_000_000_000,
flash_loan_fee_wad: 0,
host_fee_percentage: 20,
},
..test_reserve_config()
})
.await;
let (
mut test,
lending_market,
usdc_reserve,
wsol_reserve,
user,
obligation,
host_fee_receiver,
_,
) = setup(&ReserveConfig {
fees: ReserveFees {
borrow_fee_wad: 100_000_000_000,
flash_loan_fee_wad: 0,
host_fee_percentage: 20,
},
..test_reserve_config()
})
.await;

let balance_checker = BalanceChecker::start(
&mut test,
Expand Down Expand Up @@ -166,26 +177,54 @@ async fn test_success() {
assert_eq!(mint_supply_changes, HashSet::new());

// check program state
let lending_market_post = test.load_account(lending_market.pubkey).await;
assert_eq!(lending_market, lending_market_post);

let wsol_reserve_post = test.load_account::<Reserve>(wsol_reserve.pubkey).await;
let lending_market_post = test
.load_account::<LendingMarket>(lending_market.pubkey)
.await;
assert_eq!(
wsol_reserve_post.account,
Reserve {
last_update: LastUpdate {
slot: 1000,
stale: true
lending_market_post.account,
LendingMarket {
rate_limiter: {
let mut rate_limiter = lending_market.account.rate_limiter;
rate_limiter
.update(
1000,
Decimal::from(10 * (4 * LAMPORTS_PER_SOL + 400))
.try_div(Decimal::from(1_000_000_000_u64))
.unwrap(),
)
.unwrap();
rate_limiter
},
liquidity: ReserveLiquidity {
available_amount: 6 * LAMPORTS_PER_SOL - (4 * LAMPORTS_PER_SOL + 400),
borrowed_amount_wads: Decimal::from(4 * LAMPORTS_PER_SOL + 400),
..wsol_reserve.account.liquidity
},
..wsol_reserve.account
..lending_market.account
}
);

let wsol_reserve_post = test.load_account::<Reserve>(wsol_reserve.pubkey).await;
let expected_wsol_reserve_post = Reserve {
last_update: LastUpdate {
slot: 1000,
stale: true,
},
"{:#?}",
wsol_reserve_post
liquidity: ReserveLiquidity {
available_amount: 6 * LAMPORTS_PER_SOL - (4 * LAMPORTS_PER_SOL + 400),
borrowed_amount_wads: Decimal::from(4 * LAMPORTS_PER_SOL + 400),
..wsol_reserve.account.liquidity
},
rate_limiter: {
let mut rate_limiter = wsol_reserve.account.rate_limiter;
rate_limiter
.update(1000, Decimal::from(4 * LAMPORTS_PER_SOL + 400))
.unwrap();

rate_limiter
},
..wsol_reserve.account
};

assert_eq!(
wsol_reserve_post.account, expected_wsol_reserve_post,
"{:#?} {:#?}",
wsol_reserve_post, expected_wsol_reserve_post
);

let obligation_post = test.load_account::<Obligation>(obligation.pubkey).await;
Expand Down Expand Up @@ -220,16 +259,24 @@ async fn test_success() {
// FIXME this should really be a unit test
#[tokio::test]
async fn test_borrow_max() {
let (mut test, lending_market, usdc_reserve, wsol_reserve, user, obligation, host_fee_receiver) =
setup(&ReserveConfig {
fees: ReserveFees {
borrow_fee_wad: 100_000_000_000,
flash_loan_fee_wad: 0,
host_fee_percentage: 20,
},
..test_reserve_config()
})
.await;
let (
mut test,
lending_market,
usdc_reserve,
wsol_reserve,
user,
obligation,
host_fee_receiver,
_,
) = setup(&ReserveConfig {
fees: ReserveFees {
borrow_fee_wad: 100_000_000_000,
flash_loan_fee_wad: 0,
host_fee_percentage: 20,
},
..test_reserve_config()
})
.await;

let balance_checker = BalanceChecker::start(
&mut test,
Expand Down Expand Up @@ -286,7 +333,7 @@ async fn test_borrow_max() {

#[tokio::test]
async fn test_fail_borrow_over_reserve_borrow_limit() {
let (mut test, lending_market, _, wsol_reserve, user, obligation, host_fee_receiver) =
let (mut test, lending_market, _, wsol_reserve, user, obligation, host_fee_receiver, _) =
setup(&ReserveConfig {
borrow_limit: LAMPORTS_PER_SOL,
..test_reserve_config()
Expand Down Expand Up @@ -315,3 +362,112 @@ async fn test_fail_borrow_over_reserve_borrow_limit() {
)
);
}

#[tokio::test]
async fn test_fail_reserve_borrow_rate_limit_exceeded() {
let (
mut test,
lending_market,
_,
wsol_reserve,
user,
obligation,
host_fee_receiver,
lending_market_owner,
) = setup(&ReserveConfig {
..test_reserve_config()
})
.await;

// ie, within 10 slots, the maximum outflow is 1 SOL
lending_market
.update_reserve_config(
&mut test,
&lending_market_owner,
&wsol_reserve,
wsol_reserve.account.config,
RateLimiterConfig {
window_duration: 10,
max_outflow: LAMPORTS_PER_SOL,
},
None,
)
.await
.unwrap();

// borrow maximum amount
lending_market
.borrow_obligation_liquidity(
&mut test,
&wsol_reserve,
&obligation,
&user,
&host_fee_receiver.get_account(&wsol_mint::id()).unwrap(),
LAMPORTS_PER_SOL,
)
.await
.unwrap();

// for the next 10 slots, we shouldn't be able to borrow anything.
let cur_slot = test.get_clock().await.slot;
for _ in cur_slot..(cur_slot + 10) {
let res = lending_market
.borrow_obligation_liquidity(
&mut test,
&wsol_reserve,
&obligation,
&user,
&host_fee_receiver.get_account(&wsol_mint::id()).unwrap(),
1,
)
.await
.err()
.unwrap()
.unwrap();

assert_eq!(
res,
TransactionError::InstructionError(
3,
InstructionError::Custom(LendingError::OutflowRateLimitExceeded as u32)
)
);

test.advance_clock_by_slots(1).await;
}

// after 10 slots, we should be able to at borrow most 0.1 SOL
let res = lending_market
.borrow_obligation_liquidity(
&mut test,
&wsol_reserve,
&obligation,
&user,
&host_fee_receiver.get_account(&wsol_mint::id()).unwrap(),
LAMPORTS_PER_SOL / 10 + 1,
)
.await
.err()
.unwrap()
.unwrap();

assert_eq!(
res,
TransactionError::InstructionError(
3,
InstructionError::Custom(LendingError::OutflowRateLimitExceeded as u32)
)
);

lending_market
.borrow_obligation_liquidity(
&mut test,
&wsol_reserve,
&obligation,
&user,
&host_fee_receiver.get_account(&wsol_mint::id()).unwrap(),
LAMPORTS_PER_SOL / 10,
)
.await
.unwrap();
}
Loading