Skip to content

Commit a9c187a

Browse files
committed
program: add existing position fields to order records (#1614)
* program: add quote entry amount to order records * fix cargo fmt and test * more reusable code * more reusable code * add another comment * fix math * account for pos flip * fix typo * missed commit * more fixes * align naming * fix typo * CHANGELOG
1 parent 52bd40a commit a9c187a

File tree

7 files changed

+175
-11
lines changed

7 files changed

+175
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
### Fixes
1313

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

1617
### Breaking
1718

programs/drift/src/controller/liquidation.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ use crate::math::margin::{
4242
};
4343
use crate::math::oracle::DriftAction;
4444
use crate::math::orders::{
45-
get_position_delta_for_fill, is_multiple_of_step_size, is_oracle_too_divergent_with_twap_5min,
46-
standardize_base_asset_amount, standardize_base_asset_amount_ceil,
45+
calculate_existing_position_fields_for_order_action, get_position_delta_for_fill, is_multiple_of_step_size,
46+
is_oracle_too_divergent_with_twap_5min, standardize_base_asset_amount,
47+
standardize_base_asset_amount_ceil,
4748
};
4849
use crate::math::position::calculate_base_asset_value_with_oracle_price;
4950
use crate::math::safe_math::SafeMath;
@@ -497,13 +498,17 @@ pub fn liquidate_perp(
497498
let (
498499
user_existing_position_direction,
499500
user_position_direction_to_close,
501+
user_existing_position_params_for_order_action,
500502
liquidator_existing_position_direction,
503+
liquidator_existing_position_params_for_order_action,
501504
) = {
502505
let mut market = perp_market_map.get_ref_mut(&market_index)?;
503506

504507
let user_position = user.get_perp_position_mut(market_index)?;
505508
let user_existing_position_direction = user_position.get_direction();
506509
let user_position_direction_to_close = user_position.get_direction_to_close();
510+
let user_existing_position_params = user_position
511+
.get_existing_position_params_for_order_action(user_position_direction_to_close);
507512
update_position_and_market(user_position, &mut market, &user_position_delta)?;
508513
update_quote_asset_and_break_even_amount(user_position, &mut market, liquidator_fee)?;
509514
update_quote_asset_and_break_even_amount(user_position, &mut market, if_fee)?;
@@ -521,6 +526,8 @@ pub fn liquidate_perp(
521526

522527
let liquidator_position = liquidator.force_get_perp_position_mut(market_index)?;
523528
let liquidator_existing_position_direction = liquidator_position.get_direction();
529+
let liquidator_existing_position_params = liquidator_position
530+
.get_existing_position_params_for_order_action(user_existing_position_direction);
524531
update_position_and_market(liquidator_position, &mut market, &liquidator_position_delta)?;
525532
update_quote_asset_and_break_even_amount(
526533
liquidator_position,
@@ -547,7 +554,9 @@ pub fn liquidate_perp(
547554
(
548555
user_existing_position_direction,
549556
user_position_direction_to_close,
557+
user_existing_position_params,
550558
liquidator_existing_position_direction,
559+
liquidator_existing_position_params,
551560
)
552561
};
553562

@@ -632,6 +641,12 @@ pub fn liquidate_perp(
632641
order: liquidator_order
633642
});
634643

644+
let (taker_existing_quote_entry_amount, taker_existing_base_asset_amount) =
645+
calculate_existing_position_fields_for_order_action(base_asset_amount, user_existing_position_params_for_order_action)?;
646+
647+
let (maker_existing_quote_entry_amount, maker_existing_base_asset_amount) =
648+
calculate_existing_position_fields_for_order_action(base_asset_amount, liquidator_existing_position_params_for_order_action)?;
649+
635650
let fill_record = OrderActionRecord {
636651
ts: now,
637652
action: OrderAction::Fill,
@@ -666,6 +681,10 @@ pub fn liquidate_perp(
666681
maker_order_cumulative_quote_asset_amount_filled: Some(base_asset_value),
667682
oracle_price,
668683
bit_flags: 0,
684+
taker_existing_quote_entry_amount: taker_existing_quote_entry_amount,
685+
taker_existing_base_asset_amount: taker_existing_base_asset_amount,
686+
maker_existing_quote_entry_amount: maker_existing_quote_entry_amount,
687+
maker_existing_base_asset_amount: maker_existing_base_asset_amount,
669688
};
670689
emit!(fill_record);
671690

programs/drift/src/controller/orders.rs

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,10 @@ pub fn place_perp_order(
424424
maker_order,
425425
oracle_map.get_price_data(&market.oracle_id())?.price,
426426
bit_flags,
427+
None,
428+
None,
429+
None,
430+
None,
427431
)?;
428432
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
429433

@@ -699,6 +703,10 @@ pub fn cancel_order(
699703
maker_order,
700704
oracle_map.get_price_data(&oracle_id)?.price,
701705
0,
706+
None,
707+
None,
708+
None,
709+
None,
702710
)?;
703711
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
704712
}
@@ -2165,6 +2173,9 @@ pub fn fulfill_perp_order_with_amm(
21652173

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

2176+
let existing_position_params_for_order_action = user.perp_positions[position_index]
2177+
.get_existing_position_params_for_order_action(order_direction);
2178+
21682179
let market_side_price = match order_direction {
21692180
PositionDirection::Long => market.amm.ask_price(reserve_price_before)?,
21702181
PositionDirection::Short => market.amm.bid_price(reserve_price_before)?,
@@ -2355,6 +2366,15 @@ pub fn fulfill_perp_order_with_amm(
23552366
order_action_bit_flags,
23562367
user.orders[order_index].is_signed_msg(),
23572368
);
2369+
let (taker_existing_quote_entry_amount, taker_existing_base_asset_amount, maker_existing_quote_entry_amount, maker_existing_base_asset_amount) = {
2370+
let (existing_quote_entry_amount, existing_base_asset_amount) =
2371+
calculate_existing_position_fields_for_order_action(base_asset_amount, existing_position_params_for_order_action)?;
2372+
if taker.is_some() {
2373+
(existing_quote_entry_amount, existing_base_asset_amount, None, None)
2374+
} else {
2375+
(None, None, existing_quote_entry_amount, existing_base_asset_amount)
2376+
}
2377+
};
23582378
let order_action_record = get_order_action_record(
23592379
now,
23602380
OrderAction::Fill,
@@ -2380,6 +2400,10 @@ pub fn fulfill_perp_order_with_amm(
23802400
maker_order,
23812401
oracle_map.get_price_data(&market.oracle_id())?.price,
23822402
order_action_bit_flags,
2403+
taker_existing_quote_entry_amount,
2404+
taker_existing_base_asset_amount,
2405+
maker_existing_quote_entry_amount,
2406+
maker_existing_base_asset_amount,
23832407
)?;
23842408
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
23852409

@@ -2480,9 +2504,14 @@ pub fn fulfill_perp_order_with_match(
24802504
.get_base_asset_amount_unfilled(Some(taker_existing_position))?;
24812505

24822506
let maker_direction = maker.orders[maker_order_index].direction;
2483-
let maker_existing_position = maker
2484-
.get_perp_position(market.market_index)?
2485-
.base_asset_amount;
2507+
let (maker_existing_position, maker_existing_position_params_for_order_action) = {
2508+
let maker_position = maker.get_perp_position(market.market_index)?;
2509+
2510+
(
2511+
maker_position.base_asset_amount,
2512+
maker_position.get_existing_position_params_for_order_action(maker_direction),
2513+
)
2514+
};
24862515
let maker_base_asset_amount = maker.orders[maker_order_index]
24872516
.get_base_asset_amount_unfilled(Some(maker_existing_position))?;
24882517

@@ -2564,9 +2593,14 @@ pub fn fulfill_perp_order_with_match(
25642593
total_quote_asset_amount = quote_asset_amount_filled_by_amm
25652594
}
25662595

2567-
let taker_existing_position = taker
2568-
.get_perp_position(market.market_index)?
2569-
.base_asset_amount;
2596+
let (taker_existing_position, taker_existing_position_params_for_order_action) = {
2597+
let taker_position = taker.get_perp_position(market.market_index)?;
2598+
2599+
(
2600+
taker_position.base_asset_amount,
2601+
taker_position.get_existing_position_params_for_order_action(taker_direction),
2602+
)
2603+
};
25702604

25712605
let taker_base_asset_amount = taker.orders[taker_order_index]
25722606
.get_base_asset_amount_unfilled(Some(taker_existing_position))?;
@@ -2780,6 +2814,14 @@ pub fn fulfill_perp_order_with_match(
27802814
order_action_bit_flags,
27812815
taker.orders[taker_order_index].is_signed_msg(),
27822816
);
2817+
let (taker_existing_quote_entry_amount, taker_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
2818+
base_asset_amount_fulfilled_by_maker,
2819+
taker_existing_position_params_for_order_action,
2820+
)?;
2821+
let (maker_existing_quote_entry_amount, maker_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
2822+
base_asset_amount_fulfilled_by_maker,
2823+
maker_existing_position_params_for_order_action,
2824+
)?;
27832825
let order_action_record = get_order_action_record(
27842826
now,
27852827
OrderAction::Fill,
@@ -2801,6 +2843,10 @@ pub fn fulfill_perp_order_with_match(
28012843
Some(maker.orders[maker_order_index]),
28022844
oracle_map.get_price_data(&market.oracle_id())?.price,
28032845
order_action_bit_flags,
2846+
taker_existing_quote_entry_amount,
2847+
taker_existing_base_asset_amount,
2848+
maker_existing_quote_entry_amount,
2849+
maker_existing_base_asset_amount,
28042850
)?;
28052851
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
28062852

@@ -3018,6 +3064,10 @@ pub fn trigger_order(
30183064
None,
30193065
oracle_price,
30203066
0,
3067+
None,
3068+
None,
3069+
None,
3070+
None,
30213071
)?;
30223072
emit!(order_action_record);
30233073

@@ -3689,6 +3739,10 @@ pub fn place_spot_order(
36893739
maker_order,
36903740
oracle_price_data.price,
36913741
0,
3742+
None,
3743+
None,
3744+
None,
3745+
None,
36923746
)?;
36933747
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
36943748

@@ -4916,6 +4970,10 @@ pub fn fulfill_spot_order_with_match(
49164970
Some(maker.orders[maker_order_index]),
49174971
oracle_map.get_price_data(&base_market.oracle_id())?.price,
49184972
0,
4973+
None,
4974+
None,
4975+
None,
4976+
None,
49194977
)?;
49204978
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
49214979

@@ -5182,6 +5240,10 @@ pub fn fulfill_spot_order_with_external_market(
51825240
None,
51835241
oracle_price,
51845242
0,
5243+
None,
5244+
None,
5245+
None,
5246+
None,
51855247
)?;
51865248
emit_stack::<_, { OrderActionRecord::SIZE }>(order_action_record)?;
51875249

@@ -5374,6 +5436,10 @@ pub fn trigger_spot_order(
53745436
None,
53755437
oracle_price,
53765438
0,
5439+
None,
5440+
None,
5441+
None,
5442+
None,
53775443
)?;
53785444

53795445
emit!(order_action_record);

programs/drift/src/instructions/user.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use crate::math::margin::{
4040
};
4141
use crate::math::oracle::is_oracle_valid_for_action;
4242
use crate::math::oracle::DriftAction;
43+
use crate::math::orders::calculate_existing_position_fields_for_order_action;
4344
use crate::math::orders::get_position_delta_for_fill;
4445
use crate::math::orders::is_multiple_of_step_size;
4546
use crate::math::orders::standardize_price_i64;
@@ -1707,20 +1708,33 @@ pub fn handle_transfer_perp_position<'c: 'info, 'info>(
17071708
.force_get_perp_position_mut(market_index)
17081709
.map(|position| position.get_direction())?;
17091710

1710-
{
1711+
let (from_existing_quote_entry_amount, from_existing_base_asset_amount, to_existing_quote_entry_amount, to_existing_base_asset_amount) = {
17111712
let mut market = perp_market_map.get_ref_mut(&market_index)?;
17121713

17131714
let from_user_position = from_user.force_get_perp_position_mut(market_index)?;
17141715

1716+
let (from_existing_quote_entry_amount, from_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
1717+
transfer_amount_abs,
1718+
from_user_position.get_existing_position_params_for_order_action(direction_to_close),
1719+
)?;
1720+
17151721
update_position_and_market(from_user_position, &mut market, &from_user_position_delta)?;
17161722

17171723
let to_user_position = to_user.force_get_perp_position_mut(market_index)?;
17181724

1725+
let (to_existing_quote_entry_amount, to_existing_base_asset_amount) = calculate_existing_position_fields_for_order_action(
1726+
transfer_amount_abs,
1727+
to_user_position
1728+
.get_existing_position_params_for_order_action(direction_to_close.opposite()),
1729+
)?;
1730+
17191731
update_position_and_market(to_user_position, &mut market, &to_user_position_delta)?;
17201732

17211733
validate_perp_position_with_perp_market(from_user_position, &market)?;
17221734
validate_perp_position_with_perp_market(to_user_position, &market)?;
1723-
}
1735+
1736+
(from_existing_quote_entry_amount, from_existing_base_asset_amount, to_existing_quote_entry_amount, to_existing_base_asset_amount)
1737+
};
17241738

17251739
let from_user_margin_calculation =
17261740
calculate_margin_requirement_and_total_collateral_and_liability_info(
@@ -1842,6 +1856,10 @@ pub fn handle_transfer_perp_position<'c: 'info, 'info>(
18421856
maker_order_cumulative_quote_asset_amount_filled: Some(base_asset_value),
18431857
oracle_price,
18441858
bit_flags: 0,
1859+
taker_existing_quote_entry_amount: to_existing_quote_entry_amount,
1860+
taker_existing_base_asset_amount: to_existing_base_asset_amount,
1861+
maker_existing_quote_entry_amount: from_existing_quote_entry_amount,
1862+
maker_existing_base_asset_amount: from_existing_base_asset_amount,
18451863
};
18461864

18471865
emit_stack::<_, { OrderActionRecord::SIZE }>(fill_record)?;

programs/drift/src/math/orders.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::math::casting::Cast;
1212
use crate::state::fill_mode::FillMode;
1313
use crate::state::protected_maker_mode_config::ProtectedMakerParams;
1414
use crate::state::user::OrderBitFlag;
15+
use crate::BASE_PRECISION_U64;
1516
use crate::{
1617
load, math, FeeTier, State, BASE_PRECISION_I128, FEE_ADJUSTMENT_MAX,
1718
MAX_PREDICTION_MARKET_PRICE, MAX_PREDICTION_MARKET_PRICE_I64, OPEN_ORDER_MARGIN_REQUIREMENT,
@@ -1407,3 +1408,27 @@ pub fn set_is_signed_msg_flag(mut flags: u8, value: bool) -> u8 {
14071408
}
14081409
flags
14091410
}
1411+
1412+
pub fn calculate_existing_position_fields_for_order_action(
1413+
base_asset_amount_filled: u64,
1414+
existing_position_params: Option<(u64, u64)>,
1415+
) -> DriftResult<(Option<u64>, Option<u64>)> {
1416+
if let Some((quote_entry_amount, base_asset_amount)) = existing_position_params {
1417+
if base_asset_amount == 0 {
1418+
return Ok((None, None));
1419+
}
1420+
1421+
if base_asset_amount_filled > base_asset_amount {
1422+
return Ok((Some(quote_entry_amount), Some(base_asset_amount)));
1423+
} else {
1424+
return Ok((
1425+
Some(quote_entry_amount
1426+
.safe_mul(base_asset_amount_filled)?
1427+
.safe_div(base_asset_amount)?),
1428+
None,
1429+
));
1430+
}
1431+
} else {
1432+
Ok((None, None))
1433+
}
1434+
}

programs/drift/src/state/events.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,22 @@ pub struct OrderActionRecord {
242242
/// Bit flags:
243243
/// 0: is_signed_message
244244
pub bit_flags: u8,
245+
/// precision: QUOTE_PRECISION
246+
/// Only Some if the taker reduced position
247+
pub taker_existing_quote_entry_amount: Option<u64>,
248+
/// precision: BASE_PRECISION
249+
/// Only Some if the taker flipped position direction
250+
pub taker_existing_base_asset_amount: Option<u64>,
251+
/// precision: QUOTE_PRECISION
252+
/// Only Some if the maker reduced position
253+
pub maker_existing_quote_entry_amount: Option<u64>,
254+
/// precision: BASE_PRECISION
255+
/// Only Some if the maker flipped position direction
256+
pub maker_existing_base_asset_amount: Option<u64>,
245257
}
246258

247259
impl Size for OrderActionRecord {
248-
const SIZE: usize = 384;
260+
const SIZE: usize = 416;
249261
}
250262

251263
pub fn get_order_action_record(
@@ -269,6 +281,10 @@ pub fn get_order_action_record(
269281
maker_order: Option<Order>,
270282
oracle_price: i64,
271283
bit_flags: u8,
284+
taker_existing_quote_entry_amount: Option<u64>,
285+
taker_existing_base_asset_amount: Option<u64>,
286+
maker_existing_quote_entry_amount: Option<u64>,
287+
maker_existing_base_asset_amount: Option<u64>,
272288
) -> DriftResult<OrderActionRecord> {
273289
Ok(OrderActionRecord {
274290
ts,
@@ -317,6 +333,10 @@ pub fn get_order_action_record(
317333
.map(|order| order.quote_asset_amount_filled),
318334
oracle_price,
319335
bit_flags,
336+
taker_existing_quote_entry_amount,
337+
taker_existing_base_asset_amount,
338+
maker_existing_quote_entry_amount,
339+
maker_existing_base_asset_amount,
320340
})
321341
}
322342

0 commit comments

Comments
 (0)