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: account for reduce only when checking margin in trigger order #583

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

### Fixes

- program: account for reduce only when checking margin in trigger order ([#583](https://github.com/drift-labs/protocol-v2/pull/583))

### Breaking

## [2.38.0] - 2023-08-25
Expand Down
40 changes: 28 additions & 12 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,17 @@ pub fn place_perp_order(
user.perp_positions[position_index].worst_case_base_asset_amount()?;

let position_base_asset_amount = user.perp_positions[position_index].base_asset_amount;
let order_risk_reducing = is_order_risk_decreasing(
let base_asset_amount_unfilled = user.orders[new_order_index]
.get_base_asset_amount_unfilled(Some(position_base_asset_amount))?;
let order_risk_decreasing = is_order_risk_decreasing(
&params.direction,
order_base_asset_amount,
base_asset_amount_unfilled,
position_base_asset_amount,
)?;

let risk_decreasing = worst_case_base_asset_amount_after.unsigned_abs()
<= worst_case_base_asset_amount_before.unsigned_abs()
&& order_risk_reducing;
&& order_risk_decreasing;

// when orders are placed in bulk, only need to check margin on last place
if options.enforce_margin_check {
Expand Down Expand Up @@ -2549,12 +2551,13 @@ pub fn trigger_order(

drop(perp_market);

// If order is risk increasing and user is below initial margin, cancel it
// If order is position reducing and user is below initial margin, cancel it
let order_direction = user.orders[order_index].direction;
let order_base_asset_amount = user.orders[order_index].base_asset_amount;
let position_base_asset_amount = user
.force_get_perp_position_mut(market_index)?
.base_asset_amount;
let order_base_asset_amount = user.orders[order_index]
.get_base_asset_amount_unfilled(Some(position_base_asset_amount))?;
let is_risk_increasing = is_order_risk_increasing(
&order_direction,
order_base_asset_amount,
Expand Down Expand Up @@ -2982,8 +2985,14 @@ pub fn place_spot_order(
let (worst_case_token_amount_after, _) = user.spot_positions[spot_position_index]
.get_worst_case_token_amount(spot_market, &oracle_price_data, None, None)?;

let order_risk_decreasing =
is_spot_order_risk_decreasing(&user.orders[new_order_index], &balance_type, token_amount)?;
let order_direction = user.orders[new_order_index].direction;
let base_asset_amount_unfilled = user.orders[new_order_index]
.get_base_asset_amount_unfilled(Some(signed_token_amount.cast()?))?;
let order_risk_decreasing = is_order_risk_decreasing(
&order_direction,
base_asset_amount_unfilled,
signed_token_amount.cast()?,
)?;

// Order fails if it's risk increasing and it brings the user collateral below the margin requirement
let risk_decreasing = worst_case_token_amount_after.unsigned_abs()
Expand Down Expand Up @@ -4484,15 +4493,22 @@ pub fn trigger_spot_order(
emit!(order_action_record);

let position_index = user.get_spot_position_index(market_index)?;
let token_amount = user.spot_positions[position_index].get_token_amount(&spot_market)?;
let signed_token_amount = user.spot_positions[position_index]
.get_signed_token_amount(&spot_market)?
.cast::<i64>()?;

drop(spot_market);
drop(quote_market);

// If order is risk increasing and user is below initial margin, cancel it
let balance_type = user.spot_positions[position_index].balance_type;
let is_risk_increasing =
is_spot_order_risk_increasing(&user.orders[order_index], &balance_type, token_amount)?;
// If order is position increasing and user is below initial margin, cancel it
let direction = user.orders[order_index].direction;
let order_base_asset_amount_unfilled =
user.orders[order_index].get_base_asset_amount_unfilled(Some(signed_token_amount))?;
let is_risk_increasing = is_order_risk_increasing(
&direction,
order_base_asset_amount_unfilled,
signed_token_amount,
)?;

let meets_initial_margin_requirement =
meets_initial_margin_requirement(user, perp_market_map, spot_market_map, oracle_map)?;
Expand Down
29 changes: 1 addition & 28 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::state::oracle::OraclePriceData;
use crate::state::oracle_map::OracleMap;
use crate::state::perp_market::{PerpMarket, AMM};
use crate::state::perp_market_map::PerpMarketMap;
use crate::state::spot_market::{SpotBalanceType, SpotMarket};
use crate::state::spot_market::SpotMarket;
use crate::state::spot_market_map::SpotMarketMap;
use crate::state::user::{
MarketType, Order, OrderStatus, OrderTriggerCondition, PerpPosition, User,
Expand Down Expand Up @@ -583,33 +583,6 @@ pub fn order_satisfies_trigger_condition(order: &Order, oracle_price: u64) -> Dr
}
}

pub fn is_spot_order_risk_decreasing(
order: &Order,
balance_type: &SpotBalanceType,
token_amount: u128,
) -> DriftResult<bool> {
let risk_decreasing = match (balance_type, order.direction) {
(SpotBalanceType::Deposit, PositionDirection::Short) => {
(order.base_asset_amount as u128) < token_amount.safe_mul(2)?
}
(SpotBalanceType::Borrow, PositionDirection::Long) => {
(order.base_asset_amount as u128) < token_amount.safe_mul(2)?
}
(_, _) => false,
};

Ok(risk_decreasing)
}

pub fn is_spot_order_risk_increasing(
order: &Order,
balance_type: &SpotBalanceType,
token_amount: u128,
) -> DriftResult<bool> {
is_spot_order_risk_decreasing(order, balance_type, token_amount)
.map(|risk_decreasing| !risk_decreasing)
}

pub fn is_order_risk_decreasing(
order_direction: &PositionDirection,
order_base_asset_amount: u64,
Expand Down