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

program: tweak withdraw limits to be more lax #400

Merged
merged 5 commits into from
Mar 20, 2023
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixes

- program: borrow liquidity check accounts for if user has borrow or deposit ([#400](https://github.com/drift-labs/protocol-v2/pull/400))
- program: slightly relax withdraw limits ([#400](https://github.com/drift-labs/protocol-v2/pull/400))

### Breaking

## [2.21.0] - 2023-03-19
Expand Down
11 changes: 5 additions & 6 deletions programs/drift/src/controller/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use crate::math::cp_curve::get_update_k_result;
use crate::math::repeg::get_total_fee_lower_bound;
use crate::math::safe_math::SafeMath;
use crate::math::spot_balance::get_token_amount;
use crate::math::spot_withdraw::validate_spot_balances;
use crate::math::spot_withdraw::{
get_max_withdraw_for_market_with_token_amount, validate_spot_balances,
};
use crate::math::{amm, amm_spread, bn, cp_curve, quote_asset::*};

use crate::state::events::CurveRecord;
Expand Down Expand Up @@ -555,11 +557,8 @@ pub fn update_pool_balances(

// dont settle negative pnl to spot borrows when utilization is high (> 80%)
let max_withdraw_amount =
-crate::math::orders::get_max_withdraw_for_market_with_token_amount(
token_amount,
spot_market,
)?
.cast::<i128>()?;
-get_max_withdraw_for_market_with_token_amount(spot_market, token_amount)?
.cast::<i128>()?;

max_withdraw_amount.max(user_unsettled_pnl)
};
Expand Down
26 changes: 13 additions & 13 deletions programs/drift/src/controller/spot_balance/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ fn test_daily_withdraw_limits() {
assert_eq!(spot_market.deposit_balance, 499999999);
assert_eq!(spot_market.borrow_balance, 0);

// .50 * .2 = .1
// .50 * .25 = .125
update_spot_balances_and_cumulative_deposits_with_limits(
((amount / 10) - 2) as u128,
(125000 - 2) as u128,
&SpotBalanceType::Borrow,
&mut spot_market,
&mut user,
Expand All @@ -197,19 +197,19 @@ fn test_daily_withdraw_limits() {
.is_err());
spot_market = spot_market_backup;
user = user_backup;
assert_eq!(spot_market.deposit_balance, 400001998);
assert_eq!(user.spot_positions[0].scaled_balance, 400001998);
assert_eq!(spot_market.deposit_balance, 375001998);
assert_eq!(user.spot_positions[0].scaled_balance, 375001998);
assert_eq!(user.spot_positions[0].market_index, 0);

let old_twap = spot_market.deposit_token_twap;
update_spot_market_cumulative_interest(&mut spot_market, None, now + 3600).unwrap();
assert_eq!(spot_market.deposit_token_twap, 495834);
assert_eq!(spot_market.deposit_token_twap, 494792);
update_spot_market_cumulative_interest(&mut spot_market, None, now + 3600 * 24).unwrap();
assert_eq!(spot_market.deposit_token_twap, 403993); // little bit slower than 1 day
assert_eq!(spot_market.deposit_token_twap, 379991); // little bit slower than 1 day
update_spot_market_cumulative_interest(&mut spot_market, None, now + 3600 * 48 + 100).unwrap();
let new_twap = spot_market.deposit_token_twap;
assert!(old_twap >= new_twap);
assert_eq!(new_twap, 400001);
assert_eq!(new_twap, 375001);

// Borrowing blocks

Expand All @@ -220,16 +220,16 @@ fn test_daily_withdraw_limits() {
&mut user,
)
.unwrap();
assert_eq!(spot_market.deposit_balance, 100000400001998);
assert_eq!(user.spot_positions[0].scaled_balance, 100000400001998);
assert_eq!(spot_market.deposit_balance, 100000375001998);
assert_eq!(user.spot_positions[0].scaled_balance, 100000375001998);
assert_eq!(user.spot_positions[1].scaled_balance, 0);

spot_market.last_interest_ts = now as u64;
spot_market.last_twap_ts = now as u64;
update_spot_market_cumulative_interest(&mut spot_market, None, now + 3600).unwrap();
assert_eq!(spot_market.deposit_token_twap, 4167066666); //$4167.06
assert_eq!(spot_market.deposit_token_twap, 4167041666); //$4167.04
update_spot_market_cumulative_interest(&mut spot_market, None, now + 3600 * 44).unwrap();
assert_eq!(spot_market.deposit_token_twap, 99999780926); //$4167.06
assert_eq!(spot_market.deposit_token_twap, 99999755926);

// tiny whale who will grow
let mut whale = User {
Expand Down Expand Up @@ -419,7 +419,7 @@ fn test_check_withdraw_limits() {
deposit_balance: 2 * SPOT_BALANCE_PRECISION,
borrow_balance: SPOT_BALANCE_PRECISION,
liquidator_fee: LIQUIDATION_FEE_PRECISION / 1000,
deposit_token_twap: 26_000_000_000_u64,
deposit_token_twap: 28_000_000_000_u64,
status: MarketStatus::Active,

..SpotMarket::default()
Expand Down Expand Up @@ -450,7 +450,7 @@ fn test_check_withdraw_limits() {
};

let mdt = calculate_min_deposit_token(QUOTE_PRECISION, 0).unwrap();
assert_eq!(mdt, QUOTE_PRECISION - QUOTE_PRECISION * 2 / 10);
assert_eq!(mdt, QUOTE_PRECISION - QUOTE_PRECISION / 4);

let mbt = calculate_max_borrow_token_amount(QUOTE_PRECISION, QUOTE_PRECISION / 2, 0).unwrap();
assert_eq!(mbt, 600000);
Expand Down
16 changes: 2 additions & 14 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::math::margin::{
use crate::math::position::calculate_entry_price;
use crate::math::safe_math::SafeMath;
use crate::math::spot_balance::{get_strict_token_value, get_token_value};
use crate::math::spot_withdraw::calculate_availability_borrow_liquidity;
use crate::math::spot_withdraw::get_max_withdraw_for_market_with_token_amount;
use crate::math_error;
use crate::print_error;
use crate::state::oracle_map::OracleMap;
Expand Down Expand Up @@ -580,19 +580,7 @@ pub fn get_max_fill_amounts(
fn get_max_fill_amounts_for_market(user: &User, market: &SpotMarket) -> DriftResult<u128> {
let position_index = user.get_spot_position_index(market.market_index)?;
let token_amount = user.spot_positions[position_index].get_signed_token_amount(market)?;
get_max_withdraw_for_market_with_token_amount(token_amount, market)
}

#[inline(always)]
pub fn get_max_withdraw_for_market_with_token_amount(
token_amount: i128,
market: &SpotMarket,
) -> DriftResult<u128> {
let available_borrow_liquidity = calculate_availability_borrow_liquidity(market)?;
token_amount
.max(0)
.unsigned_abs()
.safe_add(available_borrow_liquidity)
get_max_withdraw_for_market_with_token_amount(market, token_amount)
}

pub fn find_fallback_maker_order(
Expand Down
13 changes: 11 additions & 2 deletions programs/drift/src/math/orders/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,11 +532,16 @@ mod get_max_fill_amounts {
use crate::state::spot_market::{SpotBalanceType, SpotMarket};
use crate::state::user::{Order, SpotPosition, User};
use crate::test_utils::get_orders;
use crate::LAMPORTS_PER_SOL_U64;
use anchor_spl::token::spl_token::solana_program::native_token::LAMPORTS_PER_SOL;

#[test]
fn fully_collateralized_selling_base() {
let base_market = SpotMarket::default_base_market();
let base_market = SpotMarket {
deposit_balance: 4 * 100 * SPOT_BALANCE_PRECISION,
deposit_token_twap: 4 * 100 * LAMPORTS_PER_SOL_U64,
..SpotMarket::default_base_market()
};
let quote_market = SpotMarket::default_quote_market();

let mut spot_positions = [SpotPosition::default(); 8];
Expand Down Expand Up @@ -653,7 +658,11 @@ mod get_max_fill_amounts {
#[test]
fn fully_collateralized_selling_quote() {
let base_market = SpotMarket::default_base_market();
let quote_market = SpotMarket::default_quote_market();
let quote_market = SpotMarket {
deposit_balance: 4 * 100 * SPOT_BALANCE_PRECISION,
deposit_token_twap: 4 * 100 * QUOTE_PRECISION_U64,
..SpotMarket::default_quote_market()
};

let mut spot_positions = [SpotPosition::default(); 8];
spot_positions[0] = SpotPosition {
Expand Down
36 changes: 26 additions & 10 deletions programs/drift/src/math/spot_withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn calculate_min_deposit_token(
withdraw_guard_threshold: u128,
) -> DriftResult<u128> {
let min_deposit_token = deposit_token_twap
.safe_sub((deposit_token_twap / 5).max(withdraw_guard_threshold.min(deposit_token_twap)))?;
.safe_sub((deposit_token_twap / 4).max(withdraw_guard_threshold.min(deposit_token_twap)))?;

Ok(min_deposit_token)
}
Expand Down Expand Up @@ -136,13 +136,33 @@ pub fn check_withdraw_limits(
Ok(valid_withdrawal)
}

pub fn calculate_availability_borrow_liquidity(spot_market: &SpotMarket) -> DriftResult<u128> {
pub fn get_max_withdraw_for_market_with_token_amount(
spot_market: &SpotMarket,
token_amount: i128,
) -> DriftResult<u128> {
let deposit_token_amount = get_token_amount(
spot_market.deposit_balance,
spot_market,
&SpotBalanceType::Deposit,
)?;

let mut max_withdraw_amount = 0_u128;
if token_amount > 0 {
let min_deposit_token = calculate_min_deposit_token(
spot_market.deposit_token_twap.cast()?,
spot_market.withdraw_guard_threshold.cast()?,
)?;

let withdraw_limit = deposit_token_amount.saturating_sub(min_deposit_token);

let token_amount = token_amount.unsigned_abs();
if withdraw_limit <= token_amount {
return Ok(withdraw_limit);
}

max_withdraw_amount = token_amount;
}

let borrow_token_amount = get_token_amount(
spot_market.borrow_balance,
spot_market,
Expand All @@ -155,15 +175,11 @@ pub fn calculate_availability_borrow_liquidity(spot_market: &SpotMarket) -> Drif
spot_market.withdraw_guard_threshold.cast()?,
)?;

let min_deposit_token = calculate_min_deposit_token(
spot_market.deposit_token_twap.cast()?,
spot_market.withdraw_guard_threshold.cast()?,
)?;

Ok(max_borrow_token
let borrow_limit = max_borrow_token
.saturating_sub(borrow_token_amount)
.min(deposit_token_amount.saturating_sub(min_deposit_token))
.min(deposit_token_amount.saturating_sub(borrow_token_amount)))
.min(deposit_token_amount.saturating_sub(borrow_token_amount));
Copy link
Member

@0xbigz 0xbigz Mar 20, 2023

Choose a reason for hiding this comment

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

jw, is this just a redundancy guard? should never allow borrow > deposit through rest of system, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah it will fail elsewhere if this isn't here


max_withdraw_amount.safe_add(borrow_limit)
}

pub fn validate_spot_balances(spot_market: &SpotMarket) -> DriftResult<u64> {
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/math/spotBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ export function calculateWithdrawLimit(

const minDepositTokens = depositTokenTwapLive.sub(
BN.max(
depositTokenTwapLive.div(new BN(5)),
depositTokenTwapLive.div(new BN(4)),
BN.min(spotMarket.withdrawGuardThreshold, depositTokenTwapLive)
)
);
Expand Down