Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixes

- sdk: fix to getMaxTradeSizeUSDCForPerp which was previously overshooting max allowed size due to IMF factor
- program: add existing position fields to order records ([#1614](https://github.com/drift-labs/protocol-v2/pull/1614))

### Breaking

Expand Down
23 changes: 21 additions & 2 deletions programs/drift/src/controller/liquidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ use crate::math::margin::{
};
use crate::math::oracle::DriftAction;
use crate::math::orders::{
get_position_delta_for_fill, is_multiple_of_step_size, is_oracle_too_divergent_with_twap_5min,
standardize_base_asset_amount, standardize_base_asset_amount_ceil,
calculate_existing_position_fields_for_order_action, get_position_delta_for_fill, is_multiple_of_step_size,
is_oracle_too_divergent_with_twap_5min, standardize_base_asset_amount,
standardize_base_asset_amount_ceil,
};
use crate::math::position::calculate_base_asset_value_with_oracle_price;
use crate::math::safe_math::SafeMath;
Expand Down Expand Up @@ -497,13 +498,17 @@ pub fn liquidate_perp(
let (
user_existing_position_direction,
user_position_direction_to_close,
user_existing_position_params_for_order_action,
liquidator_existing_position_direction,
liquidator_existing_position_params_for_order_action,
) = {
let mut market = perp_market_map.get_ref_mut(&market_index)?;

let user_position = user.get_perp_position_mut(market_index)?;
let user_existing_position_direction = user_position.get_direction();
let user_position_direction_to_close = user_position.get_direction_to_close();
let user_existing_position_params = user_position
.get_existing_position_params_for_order_action(user_position_direction_to_close);
update_position_and_market(user_position, &mut market, &user_position_delta)?;
update_quote_asset_and_break_even_amount(user_position, &mut market, liquidator_fee)?;
update_quote_asset_and_break_even_amount(user_position, &mut market, if_fee)?;
Expand All @@ -521,6 +526,8 @@ pub fn liquidate_perp(

let liquidator_position = liquidator.force_get_perp_position_mut(market_index)?;
let liquidator_existing_position_direction = liquidator_position.get_direction();
let liquidator_existing_position_params = liquidator_position
.get_existing_position_params_for_order_action(user_existing_position_direction);
update_position_and_market(liquidator_position, &mut market, &liquidator_position_delta)?;
update_quote_asset_and_break_even_amount(
liquidator_position,
Expand All @@ -547,7 +554,9 @@ pub fn liquidate_perp(
(
user_existing_position_direction,
user_position_direction_to_close,
user_existing_position_params,
liquidator_existing_position_direction,
liquidator_existing_position_params,
)
};

Expand Down Expand Up @@ -632,6 +641,12 @@ pub fn liquidate_perp(
order: liquidator_order
});

let (taker_existing_quote_entry_amount, taker_existing_base_asset_amount) =
calculate_existing_position_fields_for_order_action(base_asset_amount, user_existing_position_params_for_order_action)?;

let (maker_existing_quote_entry_amount, maker_existing_base_asset_amount) =
calculate_existing_position_fields_for_order_action(base_asset_amount, liquidator_existing_position_params_for_order_action)?;

let fill_record = OrderActionRecord {
ts: now,
action: OrderAction::Fill,
Expand Down Expand Up @@ -666,6 +681,10 @@ pub fn liquidate_perp(
maker_order_cumulative_quote_asset_amount_filled: Some(base_asset_value),
oracle_price,
bit_flags: 0,
taker_existing_quote_entry_amount: taker_existing_quote_entry_amount,
taker_existing_base_asset_amount: taker_existing_base_asset_amount,
maker_existing_quote_entry_amount: maker_existing_quote_entry_amount,
maker_existing_base_asset_amount: maker_existing_base_asset_amount,
};
emit!(fill_record);

Expand Down
78 changes: 72 additions & 6 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ pub fn place_perp_order(
maker_order,
oracle_map.get_price_data(&market.oracle_id())?.price,
bit_flags,
None,
None,
None,
None,
)?;
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;

Expand Down Expand Up @@ -699,6 +703,10 @@ pub fn cancel_order(
maker_order,
oracle_map.get_price_data(&oracle_id)?.price,
0,
None,
None,
None,
None,
)?;
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
}
Expand Down Expand Up @@ -2165,6 +2173,9 @@ pub fn fulfill_perp_order_with_amm(

validation::perp_market::validate_amm_account_for_fill(&market.amm, order_direction)?;

let existing_position_params_for_order_action = user.perp_positions[position_index]
.get_existing_position_params_for_order_action(order_direction);

let market_side_price = match order_direction {
PositionDirection::Long => market.amm.ask_price(reserve_price_before)?,
PositionDirection::Short => market.amm.bid_price(reserve_price_before)?,
Expand Down Expand Up @@ -2355,6 +2366,15 @@ pub fn fulfill_perp_order_with_amm(
order_action_bit_flags,
user.orders[order_index].is_signed_msg(),
);
let (taker_existing_quote_entry_amount, taker_existing_base_asset_amount, maker_existing_quote_entry_amount, maker_existing_base_asset_amount) = {
let (existing_quote_entry_amount, existing_base_asset_amount) =
calculate_existing_position_fields_for_order_action(base_asset_amount, existing_position_params_for_order_action)?;
if taker.is_some() {
(existing_quote_entry_amount, existing_base_asset_amount, None, None)
} else {
(None, None, existing_quote_entry_amount, existing_base_asset_amount)
}
};
let order_action_record = get_order_action_record(
now,
OrderAction::Fill,
Expand All @@ -2380,6 +2400,10 @@ pub fn fulfill_perp_order_with_amm(
maker_order,
oracle_map.get_price_data(&market.oracle_id())?.price,
order_action_bit_flags,
taker_existing_quote_entry_amount,
taker_existing_base_asset_amount,
maker_existing_quote_entry_amount,
maker_existing_base_asset_amount,
)?;
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;

Expand Down Expand Up @@ -2480,9 +2504,14 @@ pub fn fulfill_perp_order_with_match(
.get_base_asset_amount_unfilled(Some(taker_existing_position))?;

let maker_direction = maker.orders[maker_order_index].direction;
let maker_existing_position = maker
.get_perp_position(market.market_index)?
.base_asset_amount;
let (maker_existing_position, maker_existing_position_params_for_order_action) = {
let maker_position = maker.get_perp_position(market.market_index)?;

(
maker_position.base_asset_amount,
maker_position.get_existing_position_params_for_order_action(maker_direction),
)
};
let maker_base_asset_amount = maker.orders[maker_order_index]
.get_base_asset_amount_unfilled(Some(maker_existing_position))?;

Expand Down Expand Up @@ -2564,9 +2593,14 @@ pub fn fulfill_perp_order_with_match(
total_quote_asset_amount = quote_asset_amount_filled_by_amm
}

let taker_existing_position = taker
.get_perp_position(market.market_index)?
.base_asset_amount;
let (taker_existing_position, taker_existing_position_params_for_order_action) = {
let taker_position = taker.get_perp_position(market.market_index)?;

(
taker_position.base_asset_amount,
taker_position.get_existing_position_params_for_order_action(taker_direction),
)
};

let taker_base_asset_amount = taker.orders[taker_order_index]
.get_base_asset_amount_unfilled(Some(taker_existing_position))?;
Expand Down Expand Up @@ -2780,6 +2814,14 @@ pub fn fulfill_perp_order_with_match(
order_action_bit_flags,
taker.orders[taker_order_index].is_signed_msg(),
);
let (taker_existing_quote_entry_amount, taker_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
base_asset_amount_fulfilled_by_maker,
taker_existing_position_params_for_order_action,
)?;
let (maker_existing_quote_entry_amount, maker_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
base_asset_amount_fulfilled_by_maker,
maker_existing_position_params_for_order_action,
)?;
let order_action_record = get_order_action_record(
now,
OrderAction::Fill,
Expand All @@ -2801,6 +2843,10 @@ pub fn fulfill_perp_order_with_match(
Some(maker.orders[maker_order_index]),
oracle_map.get_price_data(&market.oracle_id())?.price,
order_action_bit_flags,
taker_existing_quote_entry_amount,
taker_existing_base_asset_amount,
maker_existing_quote_entry_amount,
maker_existing_base_asset_amount,
)?;
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;

Expand Down Expand Up @@ -3018,6 +3064,10 @@ pub fn trigger_order(
None,
oracle_price,
0,
None,
None,
None,
None,
)?;
emit!(order_action_record);

Expand Down Expand Up @@ -3689,6 +3739,10 @@ pub fn place_spot_order(
maker_order,
oracle_price_data.price,
0,
None,
None,
None,
None,
)?;
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;

Expand Down Expand Up @@ -4916,6 +4970,10 @@ pub fn fulfill_spot_order_with_match(
Some(maker.orders[maker_order_index]),
oracle_map.get_price_data(&base_market.oracle_id())?.price,
0,
None,
None,
None,
None,
)?;
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;

Expand Down Expand Up @@ -5182,6 +5240,10 @@ pub fn fulfill_spot_order_with_external_market(
None,
oracle_price,
0,
None,
None,
None,
None,
)?;
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;

Expand Down Expand Up @@ -5374,6 +5436,10 @@ pub fn trigger_spot_order(
None,
oracle_price,
0,
None,
None,
None,
None,
)?;

emit!(order_action_record);
Expand Down
22 changes: 20 additions & 2 deletions programs/drift/src/instructions/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use crate::math::margin::{
};
use crate::math::oracle::is_oracle_valid_for_action;
use crate::math::oracle::DriftAction;
use crate::math::orders::calculate_existing_position_fields_for_order_action;
use crate::math::orders::get_position_delta_for_fill;
use crate::math::orders::is_multiple_of_step_size;
use crate::math::orders::standardize_price_i64;
Expand Down Expand Up @@ -1707,20 +1708,33 @@ pub fn handle_transfer_perp_position<'c: 'info, 'info>(
.force_get_perp_position_mut(market_index)
.map(|position| position.get_direction())?;

{
let (from_existing_quote_entry_amount, from_existing_base_asset_amount, to_existing_quote_entry_amount, to_existing_base_asset_amount) = {
let mut market = perp_market_map.get_ref_mut(&market_index)?;

let from_user_position = from_user.force_get_perp_position_mut(market_index)?;

let (from_existing_quote_entry_amount, from_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
transfer_amount_abs,
from_user_position.get_existing_position_params_for_order_action(direction_to_close),
)?;

update_position_and_market(from_user_position, &mut market, &from_user_position_delta)?;

let to_user_position = to_user.force_get_perp_position_mut(market_index)?;

let (to_existing_quote_entry_amount, to_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
transfer_amount_abs,
to_user_position
.get_existing_position_params_for_order_action(direction_to_close.opposite()),
)?;

update_position_and_market(to_user_position, &mut market, &to_user_position_delta)?;

validate_perp_position_with_perp_market(from_user_position, &market)?;
validate_perp_position_with_perp_market(to_user_position, &market)?;
}

(from_existing_quote_entry_amount, from_existing_base_asset_amount, to_existing_quote_entry_amount, to_existing_base_asset_amount)
};

let from_user_margin_calculation =
calculate_margin_requirement_and_total_collateral_and_liability_info(
Expand Down Expand Up @@ -1842,6 +1856,10 @@ pub fn handle_transfer_perp_position<'c: 'info, 'info>(
maker_order_cumulative_quote_asset_amount_filled: Some(base_asset_value),
oracle_price,
bit_flags: 0,
taker_existing_quote_entry_amount: to_existing_quote_entry_amount,
taker_existing_base_asset_amount: to_existing_base_asset_amount,
maker_existing_quote_entry_amount: from_existing_quote_entry_amount,
maker_existing_base_asset_amount: from_existing_base_asset_amount,
};

emit_stack::<_, { OrderActionRecord::SIZE }>(fill_record)?;
Expand Down
25 changes: 25 additions & 0 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::math::casting::Cast;
use crate::state::fill_mode::FillMode;
use crate::state::protected_maker_mode_config::ProtectedMakerParams;
use crate::state::user::OrderBitFlag;
use crate::BASE_PRECISION_U64;
use crate::{
load, math, FeeTier, State, BASE_PRECISION_I128, FEE_ADJUSTMENT_MAX,
MAX_PREDICTION_MARKET_PRICE, MAX_PREDICTION_MARKET_PRICE_I64, OPEN_ORDER_MARGIN_REQUIREMENT,
Expand Down Expand Up @@ -1407,3 +1408,27 @@ pub fn set_is_signed_msg_flag(mut flags: u8, value: bool) -> u8 {
}
flags
}

pub fn calculate_existing_position_fields_for_order_action(
base_asset_amount_filled: u64,
existing_position_params: Option<(u64, u64)>,
) -> DriftResult<(Option<u64>, Option<u64>)> {
if let Some((quote_entry_amount, base_asset_amount)) = existing_position_params {
if base_asset_amount == 0 {
return Ok((None, None));
}

if base_asset_amount_filled > base_asset_amount {
return Ok((Some(quote_entry_amount), Some(base_asset_amount)));
} else {
return Ok((
Some(quote_entry_amount
.safe_mul(base_asset_amount_filled)?
.safe_div(base_asset_amount)?),
None,
));
}
} else {
Ok((None, None))
}
}
22 changes: 21 additions & 1 deletion programs/drift/src/state/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,22 @@ pub struct OrderActionRecord {
/// Bit flags:
/// 0: is_signed_message
pub bit_flags: u8,
/// precision: QUOTE_PRECISION
/// Only Some if the taker reduced position
pub taker_existing_quote_entry_amount: Option<u64>,
/// precision: BASE_PRECISION
/// Only Some if the taker flipped position direction
pub taker_existing_base_asset_amount: Option<u64>,
/// precision: QUOTE_PRECISION
/// Only Some if the maker reduced position
pub maker_existing_quote_entry_amount: Option<u64>,
/// precision: BASE_PRECISION
/// Only Some if the maker flipped position direction
pub maker_existing_base_asset_amount: Option<u64>,
}

impl Size for OrderActionRecord {
const SIZE: usize = 384;
const SIZE: usize = 416;
}

pub fn get_order_action_record(
Expand All @@ -269,6 +281,10 @@ pub fn get_order_action_record(
maker_order: Option<Order>,
oracle_price: i64,
bit_flags: u8,
taker_existing_quote_entry_amount: Option<u64>,

Choose a reason for hiding this comment

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

very verbose naming, would shorten

Copy link

Choose a reason for hiding this comment

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

+2 to this

taker_existing_base_asset_amount: Option<u64>,
maker_existing_quote_entry_amount: Option<u64>,
maker_existing_base_asset_amount: Option<u64>,
) -> DriftResult<OrderActionRecord> {
Ok(OrderActionRecord {
ts,
Expand Down Expand Up @@ -317,6 +333,10 @@ pub fn get_order_action_record(
.map(|order| order.quote_asset_amount_filled),
oracle_price,
bit_flags,
taker_existing_quote_entry_amount,
taker_existing_base_asset_amount,
maker_existing_quote_entry_amount,
maker_existing_base_asset_amount,
})
}

Expand Down
Loading
Loading