Skip to content
Merged
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
8 changes: 4 additions & 4 deletions .github/workflows/pull-request-token-lending.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ name: Token Lending Pull Request
on:
pull_request:
paths:
- 'token-lending/**'
- 'token/**'
- "token-lending/**"
- "token/**"
push:
branches: [master]
paths:
- 'token-lending/**'
- 'token/**'
- "token-lending/**"
- "token/**"

jobs:
cargo-test-bpf:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ name: Pull Request
on:
pull_request:
paths-ignore:
- 'docs/**'
- "docs/**"
push:
branches: [master, upcoming]
paths-ignore:
- 'docs/**'
- "docs/**"

jobs:
all_github_action_checks:
Expand Down
16 changes: 9 additions & 7 deletions token-lending/program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1540,13 +1540,15 @@ fn _withdraw_obligation_collateral<'a>(
.clone() // remaining_outflow is a mutable call, but we don't have mutable access here
.remaining_outflow(clock.slot)?;

let max_lending_market_outflow_liquidity_amount = withdraw_reserve
.usd_to_liquidity_amount_lower_bound(min(
max_outflow_usd,
// min here bc this function can overflow if max_outflow_usd is u64::MAX
// the actual value doesn't matter too much as long as its sensible
obligation.deposited_value.try_mul(2)?,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or use a static value here that doesn't overflow

))?;
// min here bc this function can overflow if max_outflow_usd is u64::MAX
// the actual value doesn't matter too much as long as its sensible
let max_outflow_usd_capped = min(
max_outflow_usd,
Decimal::from(100_000_000_000u64), // enough USD to cover all requests
);

let max_lending_market_outflow_liquidity_amount =
withdraw_reserve.usd_to_liquidity_amount_lower_bound(max_outflow_usd_capped)?;

let max_reserve_outflow_liquidity_amount = withdraw_reserve
.rate_limiter
Expand Down
6 changes: 6 additions & 0 deletions token-lending/program/tests/attributed_borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ async fn test_refresh_obligation() {
(usdc_mint::id(), 10 * FRACTIONAL_TO_USDC),
(wsol_mint::id(), LAMPORTS_PER_SOL),
],
..Default::default()
},
ObligationArgs {
deposits: vec![
Expand All @@ -102,6 +103,7 @@ async fn test_refresh_obligation() {
(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC),
(wsol_mint::id(), 2 * LAMPORTS_PER_SOL),
],
..Default::default()
},
],
)
Expand Down Expand Up @@ -230,6 +232,7 @@ async fn test_calculations() {
(usdc_mint::id(), 10 * FRACTIONAL_TO_USDC),
(wsol_mint::id(), LAMPORTS_PER_SOL),
],
..Default::default()
},
ObligationArgs {
deposits: vec![
Expand All @@ -240,6 +243,7 @@ async fn test_calculations() {
(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC),
(wsol_mint::id(), 2 * LAMPORTS_PER_SOL),
],
..Default::default()
},
],
)
Expand Down Expand Up @@ -599,6 +603,7 @@ async fn test_withdraw() {
(wsol_mint::id(), 2 * LAMPORTS_PER_SOL),
],
borrows: vec![(usdc_mint::id(), 10 * FRACTIONAL_TO_USDC)],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -796,6 +801,7 @@ async fn test_liquidate() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), FRACTIONAL_TO_USDC / 2)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL / 40)],
..Default::default()
}],
)
.await;
Expand Down
1 change: 1 addition & 0 deletions token-lending/program/tests/borrow_obligation_liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ async fn test_borrow_max_rate_limiter() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![],
..Default::default()
}],
)
.await;
Expand Down
4 changes: 4 additions & 0 deletions token-lending/program/tests/forgive_debt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,12 @@ async fn test_forgive_debt_success_easy() {
ObligationArgs {
deposits: vec![(usdc_mint::id(), 20 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
},
ObligationArgs {
deposits: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
borrows: vec![],
..Default::default()
},
],
)
Expand Down Expand Up @@ -272,6 +274,7 @@ async fn test_forgive_debt_fail_invalid_signer() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 200 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), 10 * LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -373,6 +376,7 @@ async fn test_forgive_debt_fail_no_signer() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 200 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), 10 * LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down
33 changes: 25 additions & 8 deletions token-lending/program/tests/helpers/solend_program_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,17 @@ pub struct ReserveArgs {
pub struct ObligationArgs {
pub deposits: Vec<(Pubkey, u64)>,
pub borrows: Vec<(Pubkey, u64)>,
pub should_refresh: bool,
}

impl Default for ObligationArgs {
fn default() -> Self {
ObligationArgs {
deposits: vec![],
borrows: vec![],
should_refresh: true,
}
}
}

pub async fn custom_scenario(
Expand Down Expand Up @@ -1987,17 +1998,19 @@ pub async fn custom_scenario(
}
}

for (i, obligation_arg) in obligation_args.iter().enumerate() {
for ((obligation, obligation_owner), obligation_arg) in obligations
.iter_mut()
.zip(obligation_owners.iter_mut())
.zip(obligation_args.iter())
{
for (mint, amount) in obligation_arg.borrows.iter() {
let reserve = reserves
.iter()
.find(|reserve| reserve.account.liquidity.mint_pubkey == *mint)
.unwrap();

obligation_owners[i]
.create_token_account(mint, &mut test)
.await;
obligation_owners[i]
obligation_owner.create_token_account(mint, &mut test).await;
obligation_owner
.create_token_account(&reserve.account.collateral.mint_pubkey, &mut test)
.await;

Expand All @@ -2007,8 +2020,8 @@ pub async fn custom_scenario(
.borrow_obligation_liquidity(
&mut test,
reserve,
&obligations[i],
&obligation_owners[i],
obligation,
obligation_owner,
fee_receiver.get_account(mint),
*amount,
)
Expand All @@ -2017,7 +2030,11 @@ pub async fn custom_scenario(
}
}

for obligation in obligations.iter_mut() {
for obligation in obligations
.iter_mut()
.zip(obligation_args.iter())
.filter_map(|(obligation, arg)| arg.should_refresh.then_some(obligation))
{
lending_market
.refresh_obligation(&mut test, obligation)
.await
Expand Down
5 changes: 5 additions & 0 deletions token-lending/program/tests/isolated_tier_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ async fn test_refresh_obligation() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -173,6 +174,7 @@ async fn borrow_isolated_asset() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -269,6 +271,7 @@ async fn borrow_isolated_asset_invalid() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), 1)],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -354,6 +357,7 @@ async fn borrow_regular_asset_invalid() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![(bonk_mint::id(), 1)],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -449,6 +453,7 @@ async fn invalid_borrow_due_to_reserve_config_change() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![(bonk_mint::id(), 1), (wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ async fn test_liquidity_ordering() {
(wsol_mint::id(), LAMPORTS_PER_SOL),
(usdc_mint::id(), FRACTIONAL_TO_USDC),
],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -705,6 +706,7 @@ async fn test_liquidate_closeable_obligation() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 20 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down
2 changes: 2 additions & 0 deletions token-lending/program/tests/mark_obligation_as_closeable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ async fn test_mark_obligation_as_closeable_success() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 20 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -176,6 +177,7 @@ async fn invalid_signer() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 20 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down
1 change: 1 addition & 0 deletions token-lending/program/tests/refresh_obligation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ async fn test_obligation_liquidity_ordering() {
(usdc_mint::id(), 1),
(bonk_mint::id(), 1),
],
..Default::default()
}],
)
.await;
Expand Down
3 changes: 3 additions & 0 deletions token-lending/program/tests/two_prices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ async fn test_borrow() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -204,6 +205,7 @@ async fn test_withdraw() {
(usdt_mint::id(), 20 * FRACTIONAL_TO_USDC),
],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -340,6 +342,7 @@ async fn test_liquidation_doesnt_use_smoothed_price() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)],
borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)],
..Default::default()
}],
)
.await;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ async fn test_withdraw_max_rate_limiter() {
&[ObligationArgs {
deposits: vec![(wsol_mint::id(), 50 * LAMPORTS_PER_SOL)],
borrows: vec![],
..Default::default()
}],
)
.await;
Expand Down Expand Up @@ -299,11 +300,50 @@ async fn test_withdraw_no_borrows() {
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100_000 * FRACTIONAL_TO_USDC)],
borrows: vec![],
..Default::default()
}],
)
.await;

test.advance_clock_by_slots(1).await;
lending_market
.withdraw_obligation_collateral_and_redeem_reserve_collateral(
&mut test,
&reserves[0],
&obligations[0],
&users[0],
100_000 * FRACTIONAL_TO_USDC,
)
.await
.unwrap();
}

/// If someone creates an obligation, deposits collateral, then they should be
/// able to withdraw that collateral without ever refreshing the obligation.
#[tokio::test]
async fn test_withdraw_no_borrows_no_refresh() {
let (mut test, lending_market, reserves, obligations, users, _) = custom_scenario(
&[ReserveArgs {
mint: usdc_mint::id(),
config: test_reserve_config(),
liquidity_amount: 100_000 * FRACTIONAL_TO_USDC,
price: PriceArgs {
price: 10,
conf: 0,
expo: -1,
ema_price: 10,
ema_conf: 1,
},
}],
&[ObligationArgs {
deposits: vec![(usdc_mint::id(), 100_000 * FRACTIONAL_TO_USDC)],
borrows: vec![],
should_refresh: false,
}],
)
.await;

test.advance_clock_by_slots(100).await;

lending_market
.withdraw_obligation_collateral_and_redeem_reserve_collateral(
Expand Down
Loading