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

bigz/update-spot-tvl-invariant-check #525

Merged
merged 34 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b9bd45
bigz/update-spot-tvl-invariant-check
0xbigz Jul 7, 2023
4dda906
loosen check in update_spot_balances
0xbigz Jul 10, 2023
3e303cd
Merge branch 'master' into bigz/update-spot-tvl-invariant-check
0xbigz Jul 12, 2023
a7e7eac
add tests/spotWithdrawUtil100.ts
0xbigz Jul 13, 2023
360acb8
Merge branch 'master' into bigz/update-spot-tvl-invariant-check
0xbigz Jul 18, 2023
2b58568
in fill spot order, account for tvl leaving system
crispheaney Jul 20, 2023
2058677
test for fulfill_spot_order_with_match with max utilization
crispheaney Jul 20, 2023
61e7de5
more debugging for test
0xbigz Jul 19, 2023
180baf9
sdk: fix bug in transfer account creation (#532)
evanpipta Jul 17, 2023
b9cef29
sdk: release v2.34.1-beta.5
github-actions[bot] Jul 17, 2023
70e0633
sdk: event subscriber avoids web3.js to get performance boost (#542)
crispheaney Jul 17, 2023
ea9715d
sdk: release v2.34.1-beta.6
github-actions[bot] Jul 17, 2023
cabd9b3
sdk: remove extra console.log in fetchLogs
crispheaney Jul 17, 2023
dfddf20
sdk: release v2.34.1-beta.7
github-actions[bot] Jul 17, 2023
21570f3
program: add post only slide for perps (#541)
crispheaney Jul 18, 2023
89f2ed8
sdk: release v2.34.1-beta.8
github-actions[bot] Jul 18, 2023
986ad5d
program: add cancel_orders_by_ids (#540)
crispheaney Jul 18, 2023
fed9249
sdk: release v2.34.1-beta.9
github-actions[bot] Jul 18, 2023
be29a11
v2.35.0
crispheaney Jul 18, 2023
c1e80a2
sdk: release v2.35.1-beta.0
github-actions[bot] Jul 18, 2023
9b2d776
sdk: fixes for lp (liq price and lp share burn) (#522)
lowkeynicc Jul 19, 2023
fb06394
sdk: release v2.35.1-beta.1
github-actions[bot] Jul 19, 2023
edddbef
intermediate testing
0xbigz Jul 20, 2023
1942913
more test progress
0xbigz Jul 21, 2023
b63374d
merge master + cleanup dlogs
0xbigz Jul 24, 2023
d010ef6
merge master
0xbigz Jul 24, 2023
2beb7ac
CHANGELOG fix
crispheaney Jul 26, 2023
2818f8a
fix use of is_leaving_drift
crispheaney Jul 26, 2023
53e203b
more consistent naming
crispheaney Jul 26, 2023
4eab9ee
more consistent naming
crispheaney Jul 26, 2023
4316e65
revert test change
crispheaney Jul 26, 2023
a32d487
merge master
0xbigz Jul 31, 2023
9469385
Merge branch 'master' into bigz/update-spot-tvl-invariant-check
crispheaney Jul 31, 2023
38e9104
CHANGELOG
crispheaney Jul 31, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- program: allow settle pnl and spot fills via match when utilization is 100% ([#525](https://github.com/drift-labs/protocol-v2/pull/525))
- program: new update_perp_bid_ask_twap ix ([#548](https://github.com/drift-labs/protocol-v2/pull/548))
- program: dont check price bands for place order ([#556](https://github.com/drift-labs/protocol-v2/pull/556))

Expand Down
3 changes: 2 additions & 1 deletion programs/drift/src/controller/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,8 +635,9 @@ pub fn update_pool_balances(

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

max_withdraw_amount.max(user_unsettled_pnl)
};

Expand Down
6 changes: 3 additions & 3 deletions programs/drift/src/controller/insurance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,17 +555,17 @@ pub fn settle_revenue_to_insurance_fund(
)?;

let depositors_claim =
validate_spot_market_vault_amount(spot_market, spot_market_vault_amount)?.cast::<u128>()?;
validate_spot_market_vault_amount(spot_market, spot_market_vault_amount)?;

let mut token_amount = get_token_amount(
spot_market.revenue_pool.scaled_balance,
spot_market,
&SpotBalanceType::Deposit,
)?;

if depositors_claim < token_amount {
if depositors_claim < token_amount.cast()? {
// only allow half of withdraw available when utilization is high
token_amount = depositors_claim.safe_div(2)?;
token_amount = depositors_claim.max(0).cast::<u128>()?.safe_div(2)?;
}

if spot_market.insurance_fund.user_shares > 0 {
Expand Down
20 changes: 12 additions & 8 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3286,7 +3286,7 @@ pub fn fill_spot_order(
let base_market = spot_market_map.get_ref(&market_index)?;
let quote_market = spot_market_map.get_quote_spot_market()?;
let (max_base_asset_amount, max_quote_asset_amount) =
get_max_fill_amounts(user, order_index, &base_market, &quote_market)?;
get_max_fill_amounts(user, order_index, &base_market, &quote_market, false)?;
max_base_asset_amount == Some(0) || max_quote_asset_amount == Some(0)
} else {
false
Expand Down Expand Up @@ -3752,7 +3752,7 @@ pub fn fulfill_spot_order_with_match(
}

let (taker_max_base_asset_amount, taker_max_quote_asset_amount) =
get_max_fill_amounts(taker, taker_order_index, base_market, quote_market)?;
get_max_fill_amounts(taker, taker_order_index, base_market, quote_market, false)?;

let taker_base_asset_amount =
if let Some(taker_max_quote_asset_amount) = taker_max_quote_asset_amount {
Expand All @@ -3772,7 +3772,7 @@ pub fn fulfill_spot_order_with_match(
};

let (maker_max_base_asset_amount, maker_max_quote_asset_amount) =
get_max_fill_amounts(maker, maker_order_index, base_market, quote_market)?;
get_max_fill_amounts(maker, maker_order_index, base_market, quote_market, false)?;

let maker_base_asset_amount =
if let Some(maker_max_quote_asset_amount) = maker_max_quote_asset_amount {
Expand Down Expand Up @@ -4058,7 +4058,7 @@ pub fn fulfill_spot_order_with_external_market(
let taker_order_slot = taker.orders[taker_order_index].slot;

let (max_base_asset_amount, max_quote_asset_amount) =
get_max_fill_amounts(taker, taker_order_index, base_market, quote_market)?;
get_max_fill_amounts(taker, taker_order_index, base_market, quote_market, true)?;

let taker_base_asset_amount =
taker_base_asset_amount.min(max_base_asset_amount.unwrap_or(u64::MAX));
Expand Down Expand Up @@ -4206,12 +4206,14 @@ pub fn fulfill_spot_order_with_external_market(
"Fill on external spot market lead to unexpected to update direction"
)?;

let base_update_direction =
taker.orders[taker_order_index].get_spot_position_update_direction(AssetType::Base);
update_spot_balances_and_cumulative_deposits(
base_asset_amount_filled.cast()?,
&taker.orders[taker_order_index].get_spot_position_update_direction(AssetType::Base),
&base_update_direction,
base_market,
taker.force_get_spot_position_mut(base_market.market_index)?,
false,
base_update_direction == SpotBalanceType::Borrow,
None,
)?;

Expand All @@ -4222,12 +4224,14 @@ pub fn fulfill_spot_order_with_external_market(
"Fill on external market lead to unexpected to update direction"
)?;

let quote_update_direction =
taker.orders[taker_order_index].get_spot_position_update_direction(AssetType::Quote);
update_spot_balances_and_cumulative_deposits(
quote_spot_position_delta.cast()?,
&taker.orders[taker_order_index].get_spot_position_update_direction(AssetType::Quote),
&quote_update_direction,
quote_market,
taker.get_quote_spot_position_mut(),
false,
quote_update_direction == SpotBalanceType::Borrow,
Some(quote_asset_amount_filled.cast()?),
)?;

Expand Down
144 changes: 144 additions & 0 deletions programs/drift/src/controller/orders/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4680,9 +4680,11 @@ pub mod fulfill_spot_order_with_match {
LAMPORTS_PER_SOL_I64, LAMPORTS_PER_SOL_U64, PRICE_PRECISION_I64, PRICE_PRECISION_U64,
QUOTE_PRECISION_U64, SPOT_BALANCE_PRECISION, SPOT_BALANCE_PRECISION_U64,
};
use crate::math::spot_balance::calculate_utilization;
use crate::state::spot_market::{SpotBalanceType, SpotMarket};
use crate::state::user::{MarketType, Order, OrderType, SpotPosition, User, UserStats};
use crate::test_utils::get_orders;
use crate::SPOT_UTILIZATION_PRECISION;

use super::*;

Expand Down Expand Up @@ -7113,6 +7115,148 @@ pub mod fulfill_spot_order_with_match {

assert_eq!(base_filled, 166666666);
}

#[test]
fn max_utilization() {
let mut taker_spot_positions = [SpotPosition::default(); 8];
taker_spot_positions[0] = SpotPosition {
market_index: 0,
scaled_balance: 101 * SPOT_BALANCE_PRECISION_U64,
balance_type: SpotBalanceType::Deposit,
..SpotPosition::default()
};
taker_spot_positions[1] = SpotPosition {
market_index: 1,
open_orders: 1,
open_bids: LAMPORTS_PER_SOL_I64,
..SpotPosition::default()
};
let mut taker = User {
orders: get_orders(Order {
market_index: 1,
market_type: MarketType::Spot,
order_type: OrderType::Limit,
direction: PositionDirection::Long,
base_asset_amount: LAMPORTS_PER_SOL_U64,
slot: 0,
price: 100 * PRICE_PRECISION_U64,
..Order::default()
}),
spot_positions: taker_spot_positions,
..User::default()
};

let mut maker_spot_positions = [SpotPosition::default(); 8];
maker_spot_positions[1] = SpotPosition {
market_index: 1,
balance_type: SpotBalanceType::Deposit,
scaled_balance: SPOT_BALANCE_PRECISION_U64,
open_orders: 1,
open_asks: -LAMPORTS_PER_SOL_I64,
..SpotPosition::default()
};
let mut maker = User {
orders: get_orders(Order {
market_index: 1,
post_only: true,
market_type: MarketType::Spot,
order_type: OrderType::Limit,
direction: PositionDirection::Short,
base_asset_amount: LAMPORTS_PER_SOL_U64,
price: 100 * PRICE_PRECISION_U64,
..Order::default()
}),
spot_positions: maker_spot_positions,
..User::default()
};

let mut base_market = SpotMarket {
deposit_balance: SPOT_BALANCE_PRECISION,
borrow_balance: SPOT_BALANCE_PRECISION,
utilization_twap: SPOT_UTILIZATION_PRECISION as u64,
..SpotMarket::default_base_market()
};
let mut quote_market = SpotMarket {
deposit_balance: 101 * SPOT_BALANCE_PRECISION,
borrow_balance: 101 * SPOT_BALANCE_PRECISION,
utilization_twap: SPOT_UTILIZATION_PRECISION as u64,
..SpotMarket::default_quote_market()
};

let base_utilization = calculate_utilization(
base_market.get_deposits().unwrap(),
base_market.get_borrows().unwrap(),
)
.unwrap();

assert_eq!(base_utilization, SPOT_UTILIZATION_PRECISION);

let quote_utilization = calculate_utilization(
base_market.get_deposits().unwrap(),
base_market.get_borrows().unwrap(),
)
.unwrap();

assert_eq!(quote_utilization, SPOT_UTILIZATION_PRECISION);

let now = 1_i64;
let slot = 1_u64;

let fee_structure = get_fee_structure();

let (taker_key, maker_key, filler_key) = get_user_keys();

let mut taker_stats = UserStats::default();
let mut maker_stats = UserStats::default();

fulfill_spot_order_with_match(
&mut base_market,
&mut quote_market,
&mut taker,
&mut taker_stats,
0,
&taker_key,
&mut maker,
&mut Some(&mut maker_stats),
0,
&maker_key,
None,
None,
&filler_key,
now,
slot,
&mut get_oracle_map(),
&fee_structure,
)
.unwrap();

let taker_quote_position = taker.spot_positions[0];
assert_eq!(taker_quote_position.scaled_balance, 950000000);

let taker_base_position = taker.spot_positions[1];
assert_eq!(
taker_base_position.scaled_balance,
SPOT_BALANCE_PRECISION_U64
);
assert_eq!(taker_base_position.open_bids, 0);
assert_eq!(taker_base_position.open_orders, 0);

let base_utilization = calculate_utilization(
base_market.get_deposits().unwrap(),
base_market.get_borrows().unwrap(),
)
.unwrap();

assert_eq!(base_utilization, SPOT_UTILIZATION_PRECISION);

let quote_utilization = calculate_utilization(
base_market.get_deposits().unwrap(),
base_market.get_borrows().unwrap(),
)
.unwrap();

assert_eq!(quote_utilization, SPOT_UTILIZATION_PRECISION);
}
}

pub mod fulfill_spot_order {
Expand Down
2 changes: 0 additions & 2 deletions programs/drift/src/controller/pnl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ pub fn settle_pnl(
crate::controller::lp::settle_funding_payment_then_lp(user, user_key, &mut market, now)?;

let oracle_price = oracle_map.get_price_data(&market.amm.oracle)?.price;

drop(market);

let position_index = get_position_index(&user.perp_positions, market_index)?;
Expand Down Expand Up @@ -129,7 +128,6 @@ pub fn settle_pnl(
user_unsettled_pnl,
now,
)?;

if user_unsettled_pnl == 0 {
msg!("User has no unsettled pnl for market {}", market_index);
return Ok(());
Expand Down
22 changes: 12 additions & 10 deletions programs/drift/src/controller/spot_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ pub fn update_spot_balances(
update_direction: &SpotBalanceType,
spot_market: &mut SpotMarket,
spot_balance: &mut dyn SpotBalance,
force_round_up: bool,
is_leaving_drift: bool,
) -> DriftResult {
let increase_user_existing_balance = update_direction == spot_balance.balance_type();
if increase_user_existing_balance {
Expand All @@ -225,7 +225,7 @@ pub fn update_spot_balances(
// determine how much to reduce balance based on size of current token amount
let (token_delta, balance_delta) = if current_token_amount > token_amount {
let round_up =
force_round_up || spot_balance.balance_type() == &SpotBalanceType::Borrow;
is_leaving_drift || spot_balance.balance_type() == &SpotBalanceType::Borrow;
let balance_delta = get_spot_balance(
token_amount,
spot_market,
Expand All @@ -252,7 +252,7 @@ pub fn update_spot_balances(
}
}

if let SpotBalanceType::Borrow = update_direction {
if is_leaving_drift && update_direction == &SpotBalanceType::Borrow {
let deposit_token_amount = get_token_amount(
spot_market.deposit_balance,
spot_market,
Expand Down Expand Up @@ -293,13 +293,15 @@ pub fn transfer_spot_balances(
return Ok(());
}

validate!(
spot_market.deposit_balance >= from_spot_balance.balance(),
ErrorCode::InvalidSpotMarketState,
"spot_market.deposit_balance={} lower than individual spot balance={}",
spot_market.deposit_balance,
from_spot_balance.balance()
)?;
if from_spot_balance.balance_type() == &SpotBalanceType::Deposit {
validate!(
spot_market.deposit_balance >= from_spot_balance.balance(),
ErrorCode::InvalidSpotMarketState,
"spot_market.deposit_balance={} lower than individual spot balance={}",
spot_market.deposit_balance,
from_spot_balance.balance()
)?;
}

update_spot_balances(
token_amount.unsigned_abs(),
Expand Down
4 changes: 2 additions & 2 deletions programs/drift/src/controller/spot_position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ pub fn update_spot_balances_and_cumulative_deposits(
update_direction: &SpotBalanceType,
spot_market: &mut SpotMarket,
spot_position: &mut SpotPosition,
force_round_up: bool,
is_leaving_drift: bool,
cumulative_deposit_delta: Option<u128>,
) -> DriftResult {
update_spot_balances(
token_amount,
update_direction,
spot_market,
spot_position,
force_round_up,
is_leaving_drift,
)?;

let cumulative_deposit_delta = cumulative_deposit_delta.unwrap_or(token_amount);
Expand Down
15 changes: 11 additions & 4 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,27 +746,34 @@ pub fn get_max_fill_amounts(
user_order_index: usize,
base_market: &SpotMarket,
quote_market: &SpotMarket,
is_leaving_drift: bool,
) -> DriftResult<(Option<u64>, Option<u64>)> {
let direction: PositionDirection = user.orders[user_order_index].direction;
match direction {
PositionDirection::Long => {
let max_quote = get_max_fill_amounts_for_market(user, quote_market)?.cast::<u64>()?;
let max_quote = get_max_fill_amounts_for_market(user, quote_market, is_leaving_drift)?
.cast::<u64>()?;
Ok((None, Some(max_quote)))
}
PositionDirection::Short => {
let max_base = standardize_base_asset_amount(
get_max_fill_amounts_for_market(user, base_market)?.cast::<u64>()?,
get_max_fill_amounts_for_market(user, base_market, is_leaving_drift)?
.cast::<u64>()?,
base_market.order_step_size,
)?;
Ok((Some(max_base), None))
}
}
}

fn get_max_fill_amounts_for_market(user: &User, market: &SpotMarket) -> DriftResult<u128> {
fn get_max_fill_amounts_for_market(
user: &User,
market: &SpotMarket,
is_leaving_drift: bool,
) -> 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(market, token_amount, false)
get_max_withdraw_for_market_with_token_amount(market, token_amount, is_leaving_drift)
}

pub fn find_fallback_maker_order(
Expand Down
Loading
Loading