@@ -1956,7 +1956,7 @@ mod calculate_max_perp_order_size {
19561956 use crate :: state:: perp_market_map:: PerpMarketMap ;
19571957 use crate :: state:: spot_market:: { SpotBalanceType , SpotMarket } ;
19581958 use crate :: state:: spot_market_map:: SpotMarketMap ;
1959- use crate :: state:: user:: { Order , PerpPosition , SpotPosition , User } ;
1959+ use crate :: state:: user:: { MarginMode , Order , PerpPosition , SpotPosition , User , UserStatus } ;
19601960 use crate :: test_utils:: get_pyth_price;
19611961 use crate :: test_utils:: * ;
19621962 use crate :: {
@@ -3160,6 +3160,192 @@ mod calculate_max_perp_order_size {
31603160 assert ! ( total_collateral. unsigned_abs( ) - margin_requirement < 100 * QUOTE_PRECISION ) ;
31613161 }
31623162
3163+ #[ test]
3164+ pub fn sol_perp_hlm_with_imf ( ) {
3165+ let slot = 0_u64 ;
3166+
3167+ let mut oracle_price = get_pyth_price ( 100 , 6 ) ;
3168+ let oracle_price_key =
3169+ Pubkey :: from_str ( "J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix" ) . unwrap ( ) ;
3170+ let pyth_program = crate :: ids:: pyth_program:: id ( ) ;
3171+ create_account_info ! (
3172+ oracle_price,
3173+ & oracle_price_key,
3174+ & pyth_program,
3175+ oracle_account_info
3176+ ) ;
3177+ let mut oracle_map = OracleMap :: load_one ( & oracle_account_info, slot, None ) . unwrap ( ) ;
3178+
3179+ let mut market = PerpMarket {
3180+ amm : AMM {
3181+ base_asset_reserve : 100 * AMM_RESERVE_PRECISION ,
3182+ quote_asset_reserve : 100 * AMM_RESERVE_PRECISION ,
3183+ bid_base_asset_reserve : 100 * AMM_RESERVE_PRECISION ,
3184+ bid_quote_asset_reserve : 100 * AMM_RESERVE_PRECISION ,
3185+ ask_base_asset_reserve : 100 * AMM_RESERVE_PRECISION ,
3186+ ask_quote_asset_reserve : 100 * AMM_RESERVE_PRECISION ,
3187+ sqrt_k : 100 * AMM_RESERVE_PRECISION ,
3188+ peg_multiplier : 100 * PEG_PRECISION ,
3189+ max_slippage_ratio : 50 ,
3190+ max_fill_reserve_fraction : 100 ,
3191+ order_step_size : 1000 ,
3192+ order_tick_size : 1 ,
3193+ oracle : oracle_price_key,
3194+ base_spread : 0 , // 1 basis point
3195+ historical_oracle_data : HistoricalOracleData {
3196+ last_oracle_price : ( 100 * PRICE_PRECISION ) as i64 ,
3197+ last_oracle_price_twap : ( 100 * PRICE_PRECISION ) as i64 ,
3198+ last_oracle_price_twap_5min : ( 100 * PRICE_PRECISION ) as i64 ,
3199+
3200+ ..HistoricalOracleData :: default ( )
3201+ } ,
3202+ ..AMM :: default ( )
3203+ } ,
3204+ margin_ratio_initial : 1000 ,
3205+ margin_ratio_maintenance : 500 ,
3206+ high_leverage_margin_ratio_initial : 100 ,
3207+ high_leverage_margin_ratio_maintenance : 66 ,
3208+ imf_factor : 50 ,
3209+ status : MarketStatus :: Active ,
3210+ ..PerpMarket :: default_test ( )
3211+ } ;
3212+ market. amm . max_base_asset_reserve = u128:: MAX ;
3213+ market. amm . min_base_asset_reserve = 0 ;
3214+
3215+ create_anchor_account_info ! ( market, PerpMarket , market_account_info) ;
3216+ let market_map = PerpMarketMap :: load_one ( & market_account_info, true ) . unwrap ( ) ;
3217+
3218+ let mut usdc_spot_market = SpotMarket {
3219+ market_index : 0 ,
3220+ oracle_source : OracleSource :: QuoteAsset ,
3221+ cumulative_deposit_interest : SPOT_CUMULATIVE_INTEREST_PRECISION ,
3222+ decimals : 6 ,
3223+ initial_asset_weight : SPOT_WEIGHT_PRECISION ,
3224+ maintenance_asset_weight : SPOT_WEIGHT_PRECISION ,
3225+ deposit_balance : 10000 * SPOT_BALANCE_PRECISION ,
3226+ liquidator_fee : 0 ,
3227+ historical_oracle_data : HistoricalOracleData {
3228+ last_oracle_price_twap : PRICE_PRECISION_I64 ,
3229+ last_oracle_price_twap_5min : PRICE_PRECISION_I64 ,
3230+ ..HistoricalOracleData :: default ( )
3231+ } ,
3232+ ..SpotMarket :: default ( )
3233+ } ;
3234+ create_anchor_account_info ! ( usdc_spot_market, SpotMarket , usdc_spot_market_account_info) ;
3235+ let spot_market_account_infos = Vec :: from ( [ & usdc_spot_market_account_info] ) ;
3236+ let spot_market_map =
3237+ SpotMarketMap :: load_multiple ( spot_market_account_infos, true ) . unwrap ( ) ;
3238+
3239+ let mut spot_positions = [ SpotPosition :: default ( ) ; 8 ] ;
3240+ spot_positions[ 0 ] = SpotPosition {
3241+ market_index : 0 ,
3242+ balance_type : SpotBalanceType :: Deposit ,
3243+ scaled_balance : 10000 * SPOT_BALANCE_PRECISION_U64 ,
3244+ ..SpotPosition :: default ( )
3245+ } ;
3246+ let mut user = User {
3247+ orders : [ Order :: default ( ) ; 32 ] ,
3248+ perp_positions : get_positions ( PerpPosition {
3249+ market_index : 0 ,
3250+ ..PerpPosition :: default ( )
3251+ } ) ,
3252+ spot_positions,
3253+ margin_mode : MarginMode :: HighLeverage ,
3254+ ..User :: default ( )
3255+ } ;
3256+
3257+ let max_order_size = calculate_max_perp_order_size (
3258+ & user,
3259+ 0 ,
3260+ 0 ,
3261+ PositionDirection :: Short ,
3262+ & market_map,
3263+ & spot_market_map,
3264+ & mut oracle_map,
3265+ )
3266+ . unwrap ( ) ;
3267+ assert_eq ! ( max_order_size, 4098356557000 ) ; // 4098
3268+
3269+ let mut spot_positions = [ SpotPosition :: default ( ) ; 8 ] ;
3270+ spot_positions[ 0 ] = SpotPosition {
3271+ market_index : 0 ,
3272+ balance_type : SpotBalanceType :: Deposit ,
3273+ scaled_balance : 100 * SPOT_BALANCE_PRECISION_U64 ,
3274+ ..SpotPosition :: default ( )
3275+ } ;
3276+ let mut user = User {
3277+ orders : [ Order :: default ( ) ; 32 ] ,
3278+ perp_positions : get_positions ( PerpPosition {
3279+ market_index : 0 ,
3280+ ..PerpPosition :: default ( )
3281+ } ) ,
3282+ spot_positions,
3283+ margin_mode : MarginMode :: HighLeverage ,
3284+ ..User :: default ( )
3285+ } ;
3286+
3287+ let max_order_size = calculate_max_perp_order_size (
3288+ & user,
3289+ 0 ,
3290+ 0 ,
3291+ PositionDirection :: Short ,
3292+ & market_map,
3293+ & spot_market_map,
3294+ & mut oracle_map,
3295+ )
3296+ . unwrap ( ) ;
3297+ assert_eq ! ( max_order_size, 84737288000 ) ; // 84
3298+
3299+
3300+ let mut spot_positions = [ SpotPosition :: default ( ) ; 8 ] ;
3301+ spot_positions[ 0 ] = SpotPosition {
3302+ market_index : 0 ,
3303+ balance_type : SpotBalanceType :: Deposit ,
3304+ scaled_balance : 10 * SPOT_BALANCE_PRECISION_U64 ,
3305+ ..SpotPosition :: default ( )
3306+ } ;
3307+ let mut user = User {
3308+ orders : [ Order :: default ( ) ; 32 ] ,
3309+ perp_positions : get_positions ( PerpPosition {
3310+ market_index : 0 ,
3311+ ..PerpPosition :: default ( )
3312+ } ) ,
3313+ spot_positions,
3314+ margin_mode : MarginMode :: HighLeverage ,
3315+ ..User :: default ( )
3316+ } ;
3317+
3318+ let max_order_size = calculate_max_perp_order_size (
3319+ & user,
3320+ 0 ,
3321+ 0 ,
3322+ PositionDirection :: Short ,
3323+ & market_map,
3324+ & spot_market_map,
3325+ & mut oracle_map,
3326+ )
3327+ . unwrap ( ) ;
3328+ assert_eq ! ( max_order_size, 9605769000 ) ; // 9.6
3329+
3330+ user. perp_positions [ 0 ] . open_orders = 1 ;
3331+ user. perp_positions [ 0 ] . open_asks = -( max_order_size as i64 ) ;
3332+
3333+ let MarginCalculation {
3334+ margin_requirement,
3335+ total_collateral,
3336+ ..
3337+ } = calculate_margin_requirement_and_total_collateral_and_liability_info (
3338+ & user,
3339+ & market_map,
3340+ & spot_market_map,
3341+ & mut oracle_map,
3342+ MarginContext :: standard ( MarginRequirementType :: Initial ) . strict ( true ) ,
3343+ )
3344+ . unwrap ( ) ;
3345+
3346+ assert ! ( total_collateral. unsigned_abs( ) - margin_requirement < QUOTE_PRECISION ) ;
3347+ }
3348+
31633349 #[ test]
31643350 pub fn swift_failure ( ) {
31653351 let clock_slot = 0_u64 ;
0 commit comments