Skip to content

Commit 5bc8dd0

Browse files
authored
program: add max margin ratio per position (#1847)
* program: add max margin ratio perp position * program: test for custom perp position margin ratio * test * make max margin ratio persist * update user level max margin ratio * naming nit * CHANGELOG
1 parent ecfc19a commit 5bc8dd0

File tree

9 files changed

+419
-14
lines changed

9 files changed

+419
-14
lines changed

CHANGELOG.md

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

1010
### Features
1111

12+
- program: perp position max margin ratio ([#1847](https://github.com/drift-labs/protocol-v2/pull/1847))
1213
- program: add padding to swift messages ([#1845](https://github.com/drift-labs/protocol-v2/pull/1845))
1314
- program: rm lp ([#1755](https://github.com/drift-labs/protocol-v2/pull/1755))
1415

programs/drift/src/controller/position.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,19 @@ pub fn add_new_position(
4949
.position(|market_position| market_position.is_available())
5050
.ok_or(ErrorCode::MaxNumberOfPositions)?;
5151

52+
let max_margin_ratio = {
53+
let old_position = &user_positions[new_position_index];
54+
55+
if old_position.market_index == market_index {
56+
old_position.max_margin_ratio
57+
} else {
58+
0_u16
59+
}
60+
};
61+
5262
let new_market_position = PerpPosition {
5363
market_index,
64+
max_margin_ratio,
5465
..PerpPosition::default()
5566
};
5667

programs/drift/src/instructions/keeper.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::cell::RefMut;
2+
use std::collections::BTreeMap;
23
use std::convert::TryFrom;
34

45
use anchor_lang::prelude::*;
@@ -26,6 +27,7 @@ use crate::instructions::constraints::*;
2627
use crate::instructions::optional_accounts::{load_maps, AccountMaps};
2728
use crate::math::casting::Cast;
2829
use crate::math::constants::QUOTE_SPOT_MARKET_INDEX;
30+
use crate::math::margin::get_margin_calculation_for_disable_high_leverage_mode;
2931
use crate::math::margin::{calculate_user_equity, meets_settle_pnl_maintenance_margin_requirement};
3032
use crate::math::orders::{estimate_price_from_side, find_bids_and_asks_from_users};
3133
use crate::math::position::calculate_base_asset_value_and_pnl_with_oracle_price;
@@ -2803,20 +2805,13 @@ pub fn handle_disable_user_high_leverage_mode<'c: 'info, 'info>(
28032805
}
28042806
}
28052807

2806-
let custom_margin_ratio_before = user.max_margin_ratio;
2807-
user.max_margin_ratio = 0;
2808-
2809-
let margin_calc = calculate_margin_requirement_and_total_collateral_and_liability_info(
2810-
&user,
2808+
let margin_calc = get_margin_calculation_for_disable_high_leverage_mode(
2809+
&mut user,
28112810
&perp_market_map,
28122811
&spot_market_map,
28132812
&mut oracle_map,
2814-
MarginContext::standard(MarginRequirementType::Initial)
2815-
.margin_buffer(MARGIN_PRECISION / 100), // 1% buffer
28162813
)?;
28172814

2818-
user.max_margin_ratio = custom_margin_ratio_before;
2819-
28202815
if margin_calc.num_perp_liabilities > 0 {
28212816
let mut requires_invariant_check = false;
28222817

programs/drift/src/instructions/user.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2945,6 +2945,20 @@ pub fn handle_update_user_custom_margin_ratio(
29452945
Ok(())
29462946
}
29472947

2948+
pub fn handle_update_user_perp_position_custom_margin_ratio(
2949+
ctx: Context<UpdateUserPerpPositionCustomMarginRatio>,
2950+
_sub_account_id: u16,
2951+
perp_market_index: u16,
2952+
margin_ratio: u16,
2953+
) -> Result<()> {
2954+
let mut user = load_mut!(ctx.accounts.user)?;
2955+
2956+
user.update_perp_position_max_margin_ratio(perp_market_index, margin_ratio)?;
2957+
2958+
Ok(())
2959+
}
2960+
2961+
29482962
pub fn handle_update_user_margin_trading_enabled<'c: 'info, 'info>(
29492963
ctx: Context<'_, '_, 'c, 'info, UpdateUser<'info>>,
29502964
_sub_account_id: u16,
@@ -4432,6 +4446,21 @@ pub struct UpdateUser<'info> {
44324446
pub authority: Signer<'info>,
44334447
}
44344448

4449+
#[derive(Accounts)]
4450+
#[instruction(
4451+
sub_account_id: u16,
4452+
)]
4453+
pub struct UpdateUserPerpPositionCustomMarginRatio<'info> {
4454+
#[account(
4455+
mut,
4456+
seeds = [b"user", authority.key.as_ref(), sub_account_id.to_le_bytes().as_ref()],
4457+
bump,
4458+
constraint = can_sign_for_user(&user, &authority)?
4459+
)]
4460+
pub user: AccountLoader<'info, User>,
4461+
pub authority: Signer<'info>,
4462+
}
4463+
44354464
#[derive(Accounts)]
44364465
pub struct DeleteUser<'info> {
44374466
#[account(

programs/drift/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,15 @@ pub mod drift {
367367
handle_update_user_custom_margin_ratio(ctx, _sub_account_id, margin_ratio)
368368
}
369369

370+
pub fn update_user_perp_position_custom_margin_ratio(
371+
ctx: Context<UpdateUserPerpPositionCustomMarginRatio>,
372+
_sub_account_id: u16,
373+
perp_market_index: u16,
374+
margin_ratio: u16,
375+
) -> Result<()> {
376+
handle_update_user_perp_position_custom_margin_ratio(ctx, _sub_account_id, perp_market_index, margin_ratio)
377+
}
378+
370379
pub fn update_user_margin_trading_enabled<'c: 'info, 'info>(
371380
ctx: Context<'_, '_, 'c, 'info, UpdateUser<'info>>,
372381
_sub_account_id: u16,

programs/drift/src/math/margin.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::math::constants::{
66
};
77
use crate::math::position::calculate_base_asset_value_and_pnl_with_oracle_price;
88

9+
use crate::MARGIN_PRECISION;
910
use crate::{validate, PRICE_PRECISION_I128};
1011
use crate::{validation, PRICE_PRECISION_I64};
1112

@@ -27,6 +28,7 @@ use crate::state::spot_market_map::SpotMarketMap;
2728
use crate::state::user::{MarketType, OrderFillSimulation, PerpPosition, User};
2829
use num_integer::Roots;
2930
use std::cmp::{max, min, Ordering};
31+
use std::collections::BTreeMap;
3032

3133
#[cfg(test)]
3234
mod tests;
@@ -535,6 +537,12 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info(
535537
0,
536538
)?;
537539

540+
let perp_position_custom_margin_ratio = if context.margin_type == MarginRequirementType::Initial {
541+
market_position.max_margin_ratio as u32
542+
} else {
543+
0_u32
544+
};
545+
538546
let (
539547
perp_margin_requirement,
540548
weighted_pnl,
@@ -547,7 +555,7 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info(
547555
oracle_price_data,
548556
&strict_quote_price,
549557
context.margin_type,
550-
user_custom_margin_ratio,
558+
user_custom_margin_ratio.max(perp_position_custom_margin_ratio),
551559
user_high_leverage_mode,
552560
calculation.track_open_orders_fraction(),
553561
)?;
@@ -884,6 +892,42 @@ pub fn validate_spot_margin_trading(
884892
Ok(())
885893
}
886894

895+
pub fn get_margin_calculation_for_disable_high_leverage_mode(
896+
user: &mut User,
897+
perp_market_map: &PerpMarketMap,
898+
spot_market_map: &SpotMarketMap,
899+
oracle_map: &mut OracleMap,
900+
) -> DriftResult<MarginCalculation> {
901+
let custom_margin_ratio_before = user.max_margin_ratio;
902+
903+
904+
let mut perp_position_max_margin_ratio_map = BTreeMap::new();
905+
for (index, position) in user.perp_positions.iter_mut().enumerate() {
906+
if position.max_margin_ratio == 0 {
907+
continue;
908+
}
909+
910+
perp_position_max_margin_ratio_map.insert(index, position.max_margin_ratio);
911+
position.max_margin_ratio = 0;
912+
}
913+
914+
let margin_buffer = MARGIN_PRECISION / 100; // 1% buffer
915+
let margin_calc = calculate_margin_requirement_and_total_collateral_and_liability_info(
916+
user,
917+
perp_market_map,
918+
spot_market_map,
919+
oracle_map,
920+
MarginContext::standard(MarginRequirementType::Initial).margin_buffer(margin_buffer),
921+
)?;
922+
923+
user.max_margin_ratio = custom_margin_ratio_before;
924+
for (index, perp_position_max_margin_ratio) in perp_position_max_margin_ratio_map.iter() {
925+
user.perp_positions[*index].max_margin_ratio = *perp_position_max_margin_ratio;
926+
}
927+
928+
Ok(margin_calc)
929+
}
930+
887931
pub fn calculate_user_equity(
888932
user: &User,
889933
perp_market_map: &PerpMarketMap,

0 commit comments

Comments
 (0)