@@ -20,7 +20,10 @@ use crate::math::position::calculate_base_asset_value_with_expiry_price;
2020use crate :: math:: safe_math:: SafeMath ;
2121use crate :: math:: spot_balance:: get_token_amount;
2222
23+ use crate :: get_then_update_id;
24+ use crate :: math:: orders:: calculate_existing_position_fields_for_order_action;
2325use crate :: msg;
26+ use crate :: state:: events:: { OrderAction , OrderActionRecord , OrderRecord } ;
2427use crate :: state:: events:: { OrderActionExplanation , SettlePnlExplanation , SettlePnlRecord } ;
2528use crate :: state:: oracle_map:: OracleMap ;
2629use crate :: state:: paused_operations:: PerpOperation ;
@@ -30,7 +33,7 @@ use crate::state::settle_pnl_mode::SettlePnlMode;
3033use crate :: state:: spot_market:: { SpotBalance , SpotBalanceType } ;
3134use crate :: state:: spot_market_map:: SpotMarketMap ;
3235use crate :: state:: state:: State ;
33- use crate :: state:: user:: { MarketType , User } ;
36+ use crate :: state:: user:: { MarketType , Order , OrderStatus , OrderType , User } ;
3437use crate :: validate;
3538use anchor_lang:: prelude:: Pubkey ;
3639use anchor_lang:: prelude:: * ;
@@ -438,6 +441,11 @@ pub fn settle_expired_position(
438441 let base_asset_amount = user. perp_positions [ position_index] . base_asset_amount ;
439442 let quote_entry_amount = user. perp_positions [ position_index] . quote_entry_amount ;
440443
444+ let user_position_direction_to_close =
445+ user. perp_positions [ position_index] . get_direction_to_close ( ) ;
446+ let user_existing_position_params_for_order_action = user. perp_positions [ position_index]
447+ . get_existing_position_params_for_order_action ( user_position_direction_to_close) ;
448+
441449 let position_delta = PositionDelta {
442450 quote_asset_amount : base_asset_value,
443451 base_asset_amount : -user. perp_positions [ position_index] . base_asset_amount ,
@@ -470,6 +478,80 @@ pub fn settle_expired_position(
470478 -pnl_to_settle_with_user. cast ( ) ?,
471479 ) ?;
472480
481+ if position_delta. base_asset_amount != 0 {
482+ // get ids for order fills
483+ let user_order_id = get_then_update_id ! ( user, next_order_id) ;
484+ let fill_record_id = get_then_update_id ! ( perp_market, next_fill_record_id) ;
485+
486+ let base_asset_amount = position_delta. base_asset_amount ;
487+ let user_existing_position_direction = user. perp_positions [ position_index] . get_direction ( ) ;
488+
489+ let user_order = Order {
490+ slot,
491+ base_asset_amount : base_asset_amount. unsigned_abs ( ) ,
492+ order_id : user_order_id,
493+ market_index : perp_market. market_index ,
494+ status : OrderStatus :: Open ,
495+ order_type : OrderType :: Market ,
496+ market_type : MarketType :: Perp ,
497+ direction : user_position_direction_to_close,
498+ existing_position_direction : user_existing_position_direction,
499+ ..Order :: default ( )
500+ } ;
501+
502+ emit ! ( OrderRecord {
503+ ts: now,
504+ user: * user_key,
505+ order: user_order
506+ } ) ;
507+
508+ let ( taker_existing_quote_entry_amount, taker_existing_base_asset_amount) =
509+ calculate_existing_position_fields_for_order_action (
510+ base_asset_amount. unsigned_abs ( ) ,
511+ user_existing_position_params_for_order_action,
512+ ) ?;
513+
514+ let fill_record = OrderActionRecord {
515+ ts : now,
516+ action : OrderAction :: Fill ,
517+ action_explanation : OrderActionExplanation :: MarketExpired ,
518+ market_index : perp_market. market_index ,
519+ market_type : MarketType :: Perp ,
520+ filler : None ,
521+ filler_reward : None ,
522+ fill_record_id : Some ( fill_record_id) ,
523+ base_asset_amount_filled : Some ( base_asset_amount. unsigned_abs ( ) ) ,
524+ quote_asset_amount_filled : Some ( base_asset_value. unsigned_abs ( ) ) ,
525+ taker_fee : Some ( fee. unsigned_abs ( ) ) ,
526+ maker_fee : None ,
527+ referrer_reward : None ,
528+ quote_asset_amount_surplus : None ,
529+ spot_fulfillment_method_fee : None ,
530+ taker : Some ( * user_key) ,
531+ taker_order_id : Some ( user_order_id) ,
532+ taker_order_direction : Some ( user_position_direction_to_close) ,
533+ taker_order_base_asset_amount : Some ( base_asset_amount. unsigned_abs ( ) ) ,
534+ taker_order_cumulative_base_asset_amount_filled : Some ( base_asset_amount. unsigned_abs ( ) ) ,
535+ taker_order_cumulative_quote_asset_amount_filled : Some ( base_asset_value. unsigned_abs ( ) ) ,
536+ maker : None ,
537+ maker_order_id : None ,
538+ maker_order_direction : None ,
539+ maker_order_base_asset_amount : None ,
540+ maker_order_cumulative_base_asset_amount_filled : None ,
541+ maker_order_cumulative_quote_asset_amount_filled : None ,
542+ oracle_price : perp_market. expiry_price ,
543+ bit_flags : 0 ,
544+ taker_existing_quote_entry_amount,
545+ taker_existing_base_asset_amount,
546+ maker_existing_quote_entry_amount : None ,
547+ maker_existing_base_asset_amount : None ,
548+ trigger_price : None ,
549+ builder_idx : None ,
550+ builder_fee : None ,
551+ } ;
552+ emit ! ( fill_record) ;
553+ }
554+
473555 update_settled_pnl ( user, position_index, pnl_to_settle_with_user. cast ( ) ?) ?;
474556
475557 perp_market. amm . base_asset_amount_with_amm = perp_market
0 commit comments