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

Solend v2.0.1 #131

merged 7 commits into from
Mar 28, 2023

Conversation

0xripleys
Copy link

@0xripleys 0xripleys commented Feb 24, 2023

This PR is 3 different features combined into one:

  • outflow limits
  • borrow coefficient
  • using two prices to limit borrows and withdraws

The first 3 commits link to descriptions of each feature.

tbh idk how PR diffs work but i wouldn't trust the individual feature PR diffs. I would only trust the commit diffs in this PR. In all likelihood, everything should be identical (i did check). But yeah I'm paranoid

@codecov-commenter
Copy link

codecov-commenter commented Feb 24, 2023

Codecov Report

Merging #131 (477d85d) into upcoming (5a53f75) will increase coverage by 2.94%.
The diff coverage is 99.31%.

📣 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              @@
##           upcoming     #131      +/-   ##
============================================
+ Coverage     79.96%   82.90%   +2.94%     
============================================
  Files            40       44       +4     
  Lines         12715    14814    +2099     
============================================
+ Hits          10167    12281    +2114     
+ Misses         2548     2533      -15     
Impacted Files Coverage Δ
token-lending/cli/src/main.rs 0.06% <0.00%> (-0.01%) ⬇️
...ng/program/tests/withdraw_obligation_collateral.rs 100.00% <ø> (ø)
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/sdk/src/oracles.rs 99.45% <97.05%> (+3.03%) ⬆️
token-lending/program/src/processor.rs 80.60% <97.14%> (+0.57%) ⬆️
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%) ⬆️
... and 20 more

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

@0xripleys 0xripleys changed the title 0xripleys outflow limits (#125) Solend v2.1 Feb 24, 2023
@nope-finance nope-finance changed the title Solend v2.1 Solend v2.0.1 Feb 25, 2023
@0xripleys 0xripleys marked this pull request as ready for review February 28, 2023 20:00
Use a sliding window rate limiter to limit borrows and withdraws at the lending pool owner's discretion.
Add a borrow weight to the Reserve
- 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)
@@ -2024,6 +2071,11 @@ fn process_update_reserve_config(
return Err(LendingError::InvalidMarketAuthority.into());
}

// if window duration and max outflow are different, then create a new rate limiter instance.

Choose a reason for hiding this comment

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

nit: "and" should be "or"

Copy link

@chen-robert chen-robert left a comment

Choose a reason for hiding this comment

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

Why are there rate limits on collateral redemptions (but not for liquidations?).

It seems like both cases should be similar -- my argument for collateral redemption safety is that the collateral must have been introduced into the system at some point by the same person. Absent some ctoken interest manipulation, it seems unlikely to incur that much additional risk. It's also not great UX if you deposit a lot and are unable to immediately withdraw I think.

On the other hand, maybe worth keeping as defense in depth.

pub allowed_borrow_value: Decimal,
/// The dangerous borrow value at the weighted average liquidation threshold
/// The dangerous borrow value at the weighted average liquidation threshold.
/// ie sum(d.deposited_amount * d.liquidation_threshold * min(d.current_spot_price, d.smoothed_price)

Choose a reason for hiding this comment

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

This comment seems inaccurate, it doesn't consider the smoothed price for liquidation threshold right?

Copy link
Author

Choose a reason for hiding this comment

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

😅

let market_price = pyth_price_to_decimal(&pyth_price);
let ema_price = {
let price_feed = price_account.to_price_feed(pyth_price_info.key);
// this can be unchecked bc the ema price is only used to _limit_ borrows and withdraws.

Choose a reason for hiding this comment

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

This seems true but also might be bad UX if you have a really outdated ema price that's never updated and users can never initiate a borrow/withdraw.

That being said, from my light skimming of pyth code it seems like EMA should always be updated the same slot as the latest valid price update, so not sure if it practically matters

Copy link
Author

Choose a reason for hiding this comment

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

That being said, from my light skimming of pyth code it seems like EMA should always be updated the same slot as the latest valid price update, so not sure if it practically matters

err yeah this was also partially my reasoning, ill update the comment

@@ -62,6 +65,8 @@ pub struct InitLendingMarketParams {
pub oracle_program_id: Pubkey,
/// Oracle (Switchboard) program id
pub switchboard_oracle_program_id: Pubkey,
/// Current slot
pub current_slot: u64,

Choose a reason for hiding this comment

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

Why was this added?

Copy link
Author

Choose a reason for hiding this comment

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

ah, i used to call RateLimiter::new() in init_lending_market, which needed the current slot. but then later i added a Default implementation. will remove

}
withdraw_amount
};
if withdraw_amount == 0 {

Choose a reason for hiding this comment

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

Why was this removed? I don't think it has an impact but just curious

Copy link
Author

Choose a reason for hiding this comment

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

all this logic got moved into max_withdraw_amount in reserve.rs for easier testing, and also i think it was hard to modify this logic as is after adding the two prices stuff

Choose a reason for hiding this comment

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

max_withdraw_amount and withdraw_amount are separate and I don't think this check gets added to the other call right

Copy link
Author

@0xripleys 0xripleys Mar 15, 2023

Choose a reason for hiding this comment

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

oh sorry were you asking specifically about if withdraw_amount == 0? Yeah I guess it doesn't matter, although I think i just I just forgot to re-add it

edit: i did add this check further below

    if max_withdraw_amount == 0 {
        msg!("Maximum withdraw value is zero");
        return Err(LendingError::WithdrawTooLarge.into());
    }

which yeah i guess isn't the same thing. i could change it back i guess, don't think it matters

Choose a reason for hiding this comment

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

yeah don't feel too strongly (but why risk it)

Copy link
Author

Choose a reason for hiding this comment

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

will change tmrw

@@ -55,6 +55,11 @@ impl Decimal {
Self(U192::from(percent as u64 * PERCENT_SCALER))
}

/// Create scaled decimal from bps value
pub fn from_bps(bps: u64) -> Self {

Choose a reason for hiding this comment

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

This (and the other from_percent) breaks at around 1800% since you multiply before calling ::from. Just a heads up

Copy link
Author

Choose a reason for hiding this comment

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

ah good catch. yeah i think we want to set the borrow weight as high as possible. will fix

.rate_limiter
.update(
clock.slot,
reserve.market_value(Decimal::from(liquidity_amount))?,

Choose a reason for hiding this comment

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

It seems like this should be based on worst-case market value right?

Copy link
Author

Choose a reason for hiding this comment

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

heh, yeah. i did this PR before adding the 2 prices stuff. will change

@nope-finance
Copy link
Member

Why are there rate limits on collateral redemptions (but not for liquidations?).

usually exploits occur able to overborrow or overwithdraw (or both) so having the limit on both makes sense.

for liquidations, without the ability to reliably internalize liquidations it's not great to implicitly block liquidations from happening when needed with a rate limiter as liquidators will just run out of money pretty quickly on a large price movement.

@nope-finance nope-finance merged commit 5122002 into upcoming Mar 28, 2023
@nope-finance nope-finance deleted the v2_upcoming branch March 28, 2023 02:50
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.

4 participants