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: fill_perp checks maintenance margin req if position is reduced #714

Merged
merged 7 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
79 changes: 51 additions & 28 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,8 @@

let mut base_asset_amount = 0_u64;
let mut quote_asset_amount = 0_u64;
let mut makers_filled: BTreeMap<Pubkey, bool> = BTreeMap::new();
let mut makers_filled: BTreeMap<Pubkey, i64> = BTreeMap::new();
let maker_direction = user.orders[user_order_index].direction.opposite();
for fulfillment_method in fulfillment_methods.iter() {
if user.orders[user_order_index].status != OrderStatus::Open {
break;
Expand Down Expand Up @@ -1573,7 +1574,7 @@
Some(&maker),
)?;

let (fill_base_asset_amount, fill_quote_asset_amount) =
let (fill_base_asset_amount, fill_quote_asset_amount, maker_fill_base_asset_amount) =
fulfill_perp_order_with_match(
market.deref_mut(),
user,
Expand All @@ -1598,8 +1599,18 @@
oracle_map,
)?;

if fill_base_asset_amount != 0 {
makers_filled.insert(*maker_key, true);
if maker_fill_base_asset_amount != 0 {
let signed_maker_fill_base_asset_amount = match maker_direction {
PositionDirection::Long => maker_fill_base_asset_amount.cast::<i64>()?,
PositionDirection::Short => -maker_fill_base_asset_amount.cast::<i64>()?,
};

if let Some(maker_filled) = makers_filled.get_mut(maker_key) {
*maker_filled =
maker_filled.safe_add(signed_maker_fill_base_asset_amount)?;
} else {
makers_filled.insert(*maker_key, signed_maker_fill_base_asset_amount);
}
}

(fill_base_asset_amount, fill_quote_asset_amount)
Expand Down Expand Up @@ -1643,16 +1654,22 @@
return Err(ErrorCode::InsufficientCollateral);
}

for (maker_key, _) in makers_filled {
for (maker_key, maker_base_asset_amount_filled) in makers_filled {
let maker = makers_and_referrer.get_ref(&maker_key)?;

let margin_type = select_margin_type_for_perp_maker(
&maker,
maker_base_asset_amount_filled,
market_index,
)?;

let maker_margin_calculation =
calculate_margin_requirement_and_total_collateral_and_liability_info(
&maker,
perp_market_map,
spot_market_map,
oracle_map,
MarginContext::standard(MarginRequirementType::Fill),
MarginContext::standard(margin_type),
)?;

if !maker_margin_calculation.meets_margin_requirement() {
Expand Down Expand Up @@ -2006,12 +2023,12 @@
slot: u64,
fee_structure: &FeeStructure,
oracle_map: &mut OracleMap,
) -> DriftResult<(u64, u64)> {
) -> DriftResult<(u64, u64, u64)> {
if !are_orders_same_market_but_different_sides(
&maker.orders[maker_order_index],
&taker.orders[taker_order_index],
) {
return Ok((0_u64, 0_u64));
return Ok((0_u64, 0_u64, 0_u64));
}

let (bid_price, ask_price) = market.amm.bid_ask_price(market.amm.reserve_price()?)?;
Expand Down Expand Up @@ -2060,7 +2077,7 @@
maker_price,
taker_price
);
return Ok((0_u64, 0_u64));
return Ok((0_u64, 0_u64, 0_u64));
}

let (base_asset_amount, _) = calculate_fill_for_matched_orders(
Expand All @@ -2072,7 +2089,7 @@
)?;

if base_asset_amount == 0 {
return Ok((0_u64, 0_u64));
return Ok((0_u64, 0_u64, 0_u64));

Check warning on line 2092 in programs/drift/src/controller/orders.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/orders.rs#L2092

Added line #L2092 was not covered by tests
}

let sanitize_clamp_denominator = market.get_sanitize_clamp_denominator()?;
Expand Down Expand Up @@ -2133,17 +2150,18 @@
let taker_base_asset_amount = taker.orders[taker_order_index]
.get_base_asset_amount_unfilled(Some(taker_existing_position))?;

let (base_asset_amount_fulfilled, quote_asset_amount) = calculate_fill_for_matched_orders(
maker_base_asset_amount,
maker_price,
taker_base_asset_amount,
PERP_DECIMALS,
maker_direction,
)?;
let (base_asset_amount_fulfilled_by_maker, quote_asset_amount) =
calculate_fill_for_matched_orders(
maker_base_asset_amount,
maker_price,
taker_base_asset_amount,
PERP_DECIMALS,
maker_direction,
)?;

validate_fill_price(
quote_asset_amount,
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
BASE_PRECISION_U64,
taker_direction,
taker_price,
Expand All @@ -2152,14 +2170,15 @@

validate_fill_price(
quote_asset_amount,
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
BASE_PRECISION_U64,
maker_direction,
maker_price,
false,
)?;

total_base_asset_amount = total_base_asset_amount.safe_add(base_asset_amount_fulfilled)?;
total_base_asset_amount =
total_base_asset_amount.safe_add(base_asset_amount_fulfilled_by_maker)?;
total_quote_asset_amount = total_quote_asset_amount.safe_add(quote_asset_amount)?;

let maker_position_index = get_position_index(
Expand All @@ -2168,7 +2187,7 @@
)?;

let maker_position_delta = get_position_delta_for_fill(
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
quote_asset_amount,
maker.orders[maker_order_index].direction,
)?;
Expand All @@ -2192,7 +2211,7 @@
)?;

let taker_position_delta = get_position_delta_for_fill(
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
quote_asset_amount,
taker.orders[taker_order_index].direction,
)?;
Expand Down Expand Up @@ -2304,26 +2323,26 @@

update_order_after_fill(
&mut taker.orders[taker_order_index],
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
quote_asset_amount,
)?;

decrease_open_bids_and_asks(
&mut taker.perp_positions[taker_position_index],
&taker.orders[taker_order_index].direction,
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
)?;

update_order_after_fill(
&mut maker.orders[maker_order_index],
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
quote_asset_amount,
)?;

decrease_open_bids_and_asks(
&mut maker.perp_positions[maker_position_index],
&maker.orders[maker_order_index].direction,
base_asset_amount_fulfilled,
base_asset_amount_fulfilled_by_maker,
)?;

let fill_record_id = get_then_update_id!(market, next_fill_record_id);
Expand All @@ -2340,7 +2359,7 @@
Some(*filler_key),
Some(fill_record_id),
Some(filler_reward),
Some(base_asset_amount_fulfilled),
Some(base_asset_amount_fulfilled_by_maker),
Some(quote_asset_amount),
Some(taker_fee),
Some(maker_rebate),
Expand Down Expand Up @@ -2369,7 +2388,11 @@
market_position.open_orders -= 1;
}

Ok((total_base_asset_amount, total_quote_asset_amount))
Ok((
total_base_asset_amount,
total_quote_asset_amount,
base_asset_amount_fulfilled_by_maker,
))
}

pub fn update_order_after_fill(
Expand Down
12 changes: 6 additions & 6 deletions programs/drift/src/controller/orders/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ pub mod fulfill_order_with_maker_order {
.get_limit_price(None, None, slot, market.amm.order_tick_size)
.unwrap();

let (base_asset_amount, _) = fulfill_perp_order_with_match(
let (base_asset_amount, _, _) = fulfill_perp_order_with_match(
&mut market,
&mut taker,
&mut taker_stats,
Expand Down Expand Up @@ -669,7 +669,7 @@ pub mod fulfill_order_with_maker_order {
.get_limit_price(None, None, slot, market.amm.order_tick_size)
.unwrap();

let (base_asset_amount, _) = fulfill_perp_order_with_match(
let (base_asset_amount, _, _) = fulfill_perp_order_with_match(
&mut market,
&mut taker,
&mut taker_stats,
Expand Down Expand Up @@ -755,7 +755,7 @@ pub mod fulfill_order_with_maker_order {
.get_limit_price(None, None, slot, market.amm.order_tick_size)
.unwrap();

let (base_asset_amount, _) = fulfill_perp_order_with_match(
let (base_asset_amount, _, _) = fulfill_perp_order_with_match(
&mut market,
&mut taker,
&mut taker_stats,
Expand Down Expand Up @@ -841,7 +841,7 @@ pub mod fulfill_order_with_maker_order {
.get_limit_price(None, None, slot, market.amm.order_tick_size)
.unwrap();

let (base_asset_amount, _) = fulfill_perp_order_with_match(
let (base_asset_amount, _, _) = fulfill_perp_order_with_match(
&mut market,
&mut taker,
&mut taker_stats,
Expand Down Expand Up @@ -1516,7 +1516,7 @@ pub mod fulfill_order_with_maker_order {
.get_limit_price(None, None, slot, market.amm.order_tick_size)
.unwrap();

let (base_asset_amount, _) = fulfill_perp_order_with_match(
let (base_asset_amount, _, _) = fulfill_perp_order_with_match(
&mut market,
&mut taker,
&mut taker_stats,
Expand Down Expand Up @@ -1632,7 +1632,7 @@ pub mod fulfill_order_with_maker_order {
.get_limit_price(None, None, slot, market.amm.order_tick_size)
.unwrap();

let (base_asset_amount, _) = fulfill_perp_order_with_match(
let (base_asset_amount, _, _) = fulfill_perp_order_with_match(
&mut market,
&mut taker,
&mut taker_stats,
Expand Down
19 changes: 19 additions & 0 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,3 +1247,22 @@ pub fn estimate_price_from_side(side: &Side, depth: u64) -> DriftResult<Option<u

Ok(price)
}

pub fn select_margin_type_for_perp_maker(
maker: &User,
based_asset_amount_filled: i64,
market_index: u16,
) -> DriftResult<MarginRequirementType> {
let current_position = maker
Copy link
Member

Choose a reason for hiding this comment

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

this is position after fill? maybe good to specify somewhere

.get_perp_position(market_index)
.map_or(0, |p| p.base_asset_amount);
let position_before = current_position.safe_sub(based_asset_amount_filled)?;

if current_position.signum() == position_before.signum()
&& current_position.abs() < position_before.abs()
Copy link
Member

@0xbigz 0xbigz Nov 24, 2023

Choose a reason for hiding this comment

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

good candidate for helper function

position_after.was_reduced(position_before)

{
return Ok(MarginRequirementType::Maintenance);
}

Ok(MarginRequirementType::Fill)
}
Loading
Loading