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

0xripleys outflow limits #125

Merged

Conversation

0xripleys
Copy link

@0xripleys 0xripleys commented Jan 27, 2023

On any borrow or redeem instruction, we now check that the quantity outflowing doesn't exceed some specified amount per time.

Main Changes:

  1. added a sliding window rate limiter class
  2. add a rate limiter to the Reserve object which tracks outflows in token denominations (eg 1 SOL)
  3. Added a rate limiter to the LendingMarket object which tracks outflows in USD denominations
  4. changed SetLendingMarketOwner to SetLendingMarketOwnerAndConfig
  5. can reset rate limiter with new params via UpdateReserveConfig or SetLendingMarketOwnerAndConfig
  6. Added a bpf test that makes sure you can't borrow over some certain rate limit over a 10 slot period
  7. bpf test that verifies lending market rate limits across diff instructions (borrow, withdraw, redeem)

Other comments:

  • redeem reserve collateral now requires the reserve to be refreshed
  • liquidate instructions are not affected by this outflow rate limit
  • lending market is now mutable on borrow, withdraw_obligation_and_redeem, redeem_reserve_collateral instructions

@@ -659,7 +675,6 @@ fn process_redeem_reserve_collateral(
}
let token_program_id = next_account_info(account_info_iter)?;

_refresh_reserve_interest(program_id, reserve_info, clock)?;
Copy link
Author

Choose a reason for hiding this comment

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

since the lending market rate limiter is denominated in usd, we need an up-to-date price so i removed this function call

@0xripleys 0xripleys marked this pull request as ready for review January 27, 2023 23:34
@codecov-commenter
Copy link

codecov-commenter commented Jan 27, 2023

Codecov Report

Merging #125 (ebec41a) into v2_upcoming (7e2aca3) will increase coverage by 0.91%.
The diff coverage is 98.30%.

📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more

@@               Coverage Diff               @@
##           v2_upcoming     #125      +/-   ##
===============================================
+ Coverage        79.94%   80.86%   +0.91%     
===============================================
  Files               40       42       +2     
  Lines            12712    13373     +661     
===============================================
+ Hits             10163    10814     +651     
- Misses            2549     2559      +10     
Impacted Files Coverage Δ
token-lending/cli/src/main.rs 0.06% <0.00%> (-0.01%) ⬇️
token-lending/sdk/src/error.rs 23.07% <ø> (ø)
token-lending/sdk/src/state/mod.rs 92.30% <ø> (ø)
...lending/program/tests/deposit_reserve_liquidity.rs 95.61% <93.75%> (-0.91%) ⬇️
...lending/program/tests/redeem_reserve_collateral.rs 96.33% <95.23%> (+0.72%) ⬆️
token-lending/program/src/processor.rs 80.33% <95.31%> (+0.30%) ⬆️
token-lending/sdk/src/state/rate_limiter.rs 97.76% <97.76%> (ø)
...nding/program/tests/borrow_obligation_liquidity.rs 98.98% <99.43%> (+0.54%) ⬆️
...nding/program/tests/helpers/solend_program_test.rs 96.64% <100.00%> (+0.03%) ⬆️
token-lending/program/tests/init_lending_market.rs 100.00% <100.00%> (ø)
... and 12 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

let market_value = reserve
.liquidity
.market_price
.try_mul(Decimal::from(liquidity_amount))?;
Copy link
Member

Choose a reason for hiding this comment

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

try_div(10**reserve.liquidity.mint_decimals)

Copy link
Member

Choose a reason for hiding this comment

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

maybe call it redemption_value

let market_value = borrow_reserve
.liquidity
.market_price
.try_mul(borrow_amount)?;
Copy link
Member

Choose a reason for hiding this comment

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

same divide needed

@@ -695,6 +702,10 @@ pub struct ReserveConfig {
pub protocol_liquidation_fee: u8,
/// Protocol take rate is the amount borrowed interest protocol recieves, as a percentage
pub protocol_take_rate: u8,
/// Rate limiter window size in slots
pub window_duration: u64,
Copy link
Member

Choose a reason for hiding this comment

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

no duper pls

@@ -1477,6 +1520,37 @@ fn process_borrow_obligation_liquidity(

let cumulative_borrow_rate_wads = borrow_reserve.liquidity.cumulative_borrow_rate_wads;

// check outflow rate limits
{
let borrow_value = borrow_reserve
Copy link
Member

Choose a reason for hiding this comment

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

maybe make borrow_reserve.market_value(liquidity_amount) method


// assume the prev_window's outflow is even distributed across the window
// this isn't true, but it's a good enough approximation
let prev_weight = Decimal::one().try_sub(
Copy link
Member

Choose a reason for hiding this comment

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

let prev_weight = Decimal::from(self.config.window_duration).try_sub(Decimal::from(cur_slot - self.window_start + 1)).try_div(self.config.window_duration)

@@ -690,9 +709,11 @@ impl LendingInstruction {
buf.extend_from_slice(owner.as_ref());
buf.extend_from_slice(quote_currency.as_ref());
}
Self::SetLendingMarketOwner { new_owner } => {
Self::SetLendingMarketOwnerAndConfig { new_owner, config } => {
Copy link
Member

Choose a reason for hiding this comment

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

rate limiter config

@0xripleys 0xripleys merged commit 62a5e7b into solendprotocol:v2_upcoming Feb 24, 2023
0xripleys added a commit to 0xripleys/solana-program-library that referenced this pull request Mar 7, 2023
Use a sliding window rate limiter to limit borrows and withdraws at the lending pool owner's discretion.
nope-finance pushed a commit that referenced this pull request Mar 28, 2023
* 0xripleys outflow limits (#125)

Use a sliding window rate limiter to limit borrows and withdraws at the lending pool owner's discretion.

* 0xripleys borrow coefficient (#127)

Add a borrow weight to the Reserve

* Two Prices PR (#129)

- Add a smoothed_market_price to Reserve that is used to limit borrows and withdraws in cases where smoothed price and spot price diverge.
- allowed_borrow_value now uses the min(smoothed_market_price, current spot price)
- new field on obligation called borrowed_value_upper_bound that uses max(smoothed_market_price, current spot price)

* audit nits

* audit fixes pt 2

* disable rate limiter if window duration == 0

* cli changes for v2.0.1 (#133)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants