Skip to content

Commit

Permalink
porgram: add high leverage mode (#1240)
Browse files Browse the repository at this point in the history
* program: high lev mode admin ix

* ix to enter/exit high leverage mode

* update perp market margin ratio

* add logic for high leverage fork in margin ratio

* program: check margin entering/exiting mode

* add init/update high leverage mode

* add updatePerpMarketHighLeverageMarginRatio to sdk

* add enable/disable ix

* add ts types

* add a rust status

* add padding to config

* add missing validate in margin validation

* init sdk work

* add reduce only mode

* CHANGELOG

* yarn prettify:fix

* fix cargo warnings
  • Loading branch information
crispheaney authored Oct 10, 2024
1 parent 57115bf commit e230ee8
Show file tree
Hide file tree
Showing 29 changed files with 771 additions and 31 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- program: high leverage mode ([#1240](https://github.com/drift-labs/protocol-v2/pull/1240))

### Fixes

### Breaking
Expand Down
2 changes: 2 additions & 0 deletions programs/drift/src/controller/liquidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ pub fn liquidate_perp(
let margin_ratio = perp_market_map.get_ref(&market_index)?.get_margin_ratio(
user_base_asset_amount.cast()?,
MarginRequirementType::Maintenance,
user.is_high_leverage_mode(),
)?;

let margin_ratio_with_buffer = margin_ratio.safe_add(liquidation_margin_buffer_ratio)?;
Expand Down Expand Up @@ -891,6 +892,7 @@ pub fn liquidate_perp_with_fill(
let margin_ratio = perp_market_map.get_ref(&market_index)?.get_margin_ratio(
user_base_asset_amount.cast()?,
MarginRequirementType::Maintenance,
user.is_high_leverage_mode(),
)?;

let margin_ratio_with_buffer = margin_ratio.safe_add(liquidation_margin_buffer_ratio)?;
Expand Down
1 change: 1 addition & 0 deletions programs/drift/src/controller/lp/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,7 @@ fn test_lp_margin_calc() {
crate::math::margin::MarginRequirementType::Initial,
0,
false,
false,
)
.unwrap();

Expand Down
1 change: 1 addition & 0 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3086,6 +3086,7 @@ pub fn burn_user_lp_shares_for_risk_reduction(
quote_oracle_price,
margin_calc.margin_shortage()?,
user_custom_margin_ratio,
user.is_high_leverage_mode(),
)?;

let (position_delta, pnl) = burn_lp_shares(
Expand Down
4 changes: 4 additions & 0 deletions programs/drift/src/controller/pnl/delisting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,7 @@ pub mod delisting_test {
MarginRequirementType::Initial,
0,
false,
false,
)
.unwrap();

Expand Down Expand Up @@ -2424,6 +2425,7 @@ pub mod delisting_test {
MarginRequirementType::Initial,
0,
false,
false,
)
.unwrap();

Expand Down Expand Up @@ -2511,6 +2513,7 @@ pub mod delisting_test {
MarginRequirementType::Initial,
0,
false,
false,
)
.unwrap();

Expand Down Expand Up @@ -2602,6 +2605,7 @@ pub mod delisting_test {
MarginRequirementType::Initial,
0,
false,
false,
)
.unwrap();

Expand Down
2 changes: 2 additions & 0 deletions programs/drift/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,8 @@ pub enum ErrorCode {
InvalidSwiftOrderParam,
#[msg("Place and take order success condition failed")]
PlaceAndTakeOrderSuccessConditionFailed,
#[msg("Invalid High Leverage Mode Config")]
InvalidHighLeverageModeConfig,
}

#[macro_export]
Expand Down
119 changes: 118 additions & 1 deletion programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use crate::state::fulfillment_params::phoenix::PhoenixMarketContext;
use crate::state::fulfillment_params::phoenix::PhoenixV1FulfillmentConfig;
use crate::state::fulfillment_params::serum::SerumContext;
use crate::state::fulfillment_params::serum::SerumV3FulfillmentConfig;
use crate::state::high_leverage_mode_config::HighLeverageModeConfig;
use crate::state::insurance_fund_stake::ProtocolIfSharesTransferConfig;
use crate::state::oracle::get_sb_on_demand_price;
use crate::state::oracle::{
Expand Down Expand Up @@ -803,6 +804,8 @@ pub fn handle_initialize_perp_market(
validate_margin(
margin_ratio_initial,
margin_ratio_maintenance,
0,
0,
liquidator_fee,
max_spread,
)?;
Expand Down Expand Up @@ -855,7 +858,10 @@ pub fn handle_initialize_perp_market(
fuel_boost_position: 0,
fuel_boost_taker: 0,
fuel_boost_maker: 0,
padding: [0; 43],
padding1: 0,
high_leverage_margin_ratio_initial: 0,
high_leverage_margin_ratio_maintenance: 0,
padding: [0; 38],
amm: AMM {
oracle: *ctx.accounts.oracle.key,
oracle_source,
Expand Down Expand Up @@ -2227,6 +2233,8 @@ pub fn handle_update_perp_market_margin_ratio(
validate_margin(
margin_ratio_initial,
margin_ratio_maintenance,
perp_market.high_leverage_margin_ratio_initial.cast()?,
perp_market.high_leverage_margin_ratio_maintenance.cast()?,
perp_market.liquidator_fee,
perp_market.amm.max_spread,
)?;
Expand All @@ -2248,6 +2256,48 @@ pub fn handle_update_perp_market_margin_ratio(
Ok(())
}

#[access_control(
perp_market_valid(&ctx.accounts.perp_market)
)]
pub fn handle_update_perp_market_high_leverage_margin_ratio(
ctx: Context<AdminUpdatePerpMarket>,
margin_ratio_initial: u16,
margin_ratio_maintenance: u16,
) -> Result<()> {
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;

msg!(
"updating perp market {} margin ratio",
perp_market.market_index
);

validate_margin(
perp_market.margin_ratio_initial,
perp_market.margin_ratio_maintenance,
margin_ratio_initial.cast()?,
margin_ratio_maintenance.cast()?,
perp_market.liquidator_fee,
perp_market.amm.max_spread,
)?;

msg!(
"perp_market.high_leverage_margin_ratio_initial: {:?} -> {:?}",
perp_market.high_leverage_margin_ratio_initial,
margin_ratio_initial
);

msg!(
"perp_market.high_leverage_margin_ratio_maintenance: {:?} -> {:?}",
perp_market.high_leverage_margin_ratio_maintenance,
margin_ratio_maintenance
);

perp_market.high_leverage_margin_ratio_initial = margin_ratio_initial;
perp_market.high_leverage_margin_ratio_maintenance = margin_ratio_maintenance;

Ok(())
}

#[access_control(
perp_market_valid(&ctx.accounts.perp_market)
)]
Expand Down Expand Up @@ -2400,6 +2450,8 @@ pub fn handle_update_perp_liquidation_fee(
validate_margin(
perp_market.margin_ratio_initial,
perp_market.margin_ratio_maintenance,
perp_market.high_leverage_margin_ratio_initial.cast()?,
perp_market.high_leverage_margin_ratio_maintenance.cast()?,
liquidator_fee,
perp_market.amm.max_spread,
)?;
Expand Down Expand Up @@ -4092,6 +4144,35 @@ pub fn handle_settle_expired_market<'c: 'info, 'info>(
Ok(())
}

pub fn handle_initialize_high_leverage_mode_config(
ctx: Context<InitializeHighLeverageModeConfig>,
max_users: u32,
) -> Result<()> {
let mut config = ctx.accounts.high_leverage_mode_config.load_init()?;

config.max_users = max_users;

config.validate()?;

Ok(())
}

pub fn handle_update_high_leverage_mode_config(
ctx: Context<UpdateHighLeverageModeConfig>,
max_users: u32,
reduce_only: bool,
) -> Result<()> {
let mut config = load_mut!(ctx.accounts.high_leverage_mode_config)?;

config.max_users = max_users;

config.reduce_only = reduce_only as u8;

config.validate()?;

Ok(())
}

#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
Expand Down Expand Up @@ -4706,3 +4787,39 @@ pub struct InitPythPullPriceFeed<'info> {
)]
pub state: Box<Account<'info, State>>,
}

#[derive(Accounts)]
pub struct InitializeHighLeverageModeConfig<'info> {
#[account(mut)]
pub admin: Signer<'info>,
#[account(
init,
seeds = [b"high_leverage_mode_config".as_ref()],
space = HighLeverageModeConfig::SIZE,
bump,
payer = admin
)]
pub high_leverage_mode_config: AccountLoader<'info, HighLeverageModeConfig>,
#[account(
has_one = admin
)]
pub state: Box<Account<'info, State>>,
pub rent: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct UpdateHighLeverageModeConfig<'info> {
#[account(mut)]
pub admin: Signer<'info>,
#[account(
mut,
seeds = [b"high_leverage_mode_config".as_ref()],
bump,
)]
pub high_leverage_mode_config: AccountLoader<'info, HighLeverageModeConfig>,
#[account(
has_one = admin
)]
pub state: Box<Account<'info, State>>,
}
75 changes: 73 additions & 2 deletions programs/drift/src/instructions/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@ use crate::instructions::constraints::*;
use crate::instructions::optional_accounts::{load_maps, AccountMaps};
use crate::math::casting::Cast;
use crate::math::constants::QUOTE_SPOT_MARKET_INDEX;
use crate::math::margin::{calculate_user_equity, meets_settle_pnl_maintenance_margin_requirement};
use crate::math::margin::{
calculate_user_equity, meets_maintenance_margin_requirement,
meets_settle_pnl_maintenance_margin_requirement,
};
use crate::math::orders::{estimate_price_from_side, find_bids_and_asks_from_users};
use crate::math::safe_math::SafeMath;
use crate::math::spot_withdraw::validate_spot_market_vault_amount;
use crate::optional_accounts::{get_token_mint, update_prelaunch_oracle};
use crate::state::fill_mode::FillMode;
use crate::state::fulfillment_params::drift::MatchFulfillmentParams;
use crate::state::fulfillment_params::openbook_v2::OpenbookV2FulfillmentParams;
use crate::state::fulfillment_params::phoenix::PhoenixFulfillmentParams;
use crate::state::fulfillment_params::serum::SerumFulfillmentParams;
use crate::state::high_leverage_mode_config::HighLeverageModeConfig;
use crate::state::insurance_fund_stake::InsuranceFundStake;
use crate::state::oracle_map::OracleMap;
use crate::state::order_params::{
Expand All @@ -43,7 +48,7 @@ use crate::state::spot_market_map::{
};
use crate::state::state::State;
use crate::state::user::{
MarketType, OrderStatus, OrderTriggerCondition, OrderType, User, UserStats,
MarginMode, MarketType, OrderStatus, OrderTriggerCondition, OrderType, User, UserStats,
};
use crate::state::user_map::{load_user_map, load_user_maps, UserMap, UserStatsMap};
use crate::validation::sig_verification::verify_ed25519_ix;
Expand Down Expand Up @@ -1975,6 +1980,62 @@ pub fn handle_update_user_gov_token_insurance_stake(
Ok(())
}

pub fn handle_disable_user_high_leverage_mode<'c: 'info, 'info>(
ctx: Context<'_, '_, 'c, 'info, DisableUserHighLeverageMode<'info>>,
) -> Result<()> {
let state = &ctx.accounts.state;
let mut user = load_mut!(ctx.accounts.user)?;

let slot = Clock::get()?.slot;

let AccountMaps {
perp_market_map,
spot_market_map,
mut oracle_map,
} = load_maps(
&mut ctx.remaining_accounts.iter().peekable(),
&MarketSet::new(),
&MarketSet::new(),
slot,
Some(state.oracle_guard_rails),
)?;

validate!(
user.margin_mode == MarginMode::HighLeverage,
ErrorCode::DefaultError,
"user must be in high leverage mode"
)?;

user.margin_mode = MarginMode::Default;

meets_maintenance_margin_requirement(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
)?;

// only check if signer is not user authority
if user.authority != *ctx.accounts.authority.key {
let slots_since_last_active = slot.safe_sub(user.last_active_slot)?;

validate!(
slots_since_last_active >= 216000, // 60 * 60 * 24 / .4
ErrorCode::DefaultError,
"user not inactive for long enough: {}",
slots_since_last_active
)?;
}

let mut config = load_mut!(ctx.accounts.high_leverage_mode_config)?;

config.current_users = config.current_users.safe_sub(1)?;

config.validate()?;

Ok(())
}

#[derive(Accounts)]
pub struct FillOrder<'info> {
pub state: Box<Account<'info, State>>,
Expand Down Expand Up @@ -2407,3 +2468,13 @@ pub struct UpdatePrelaunchOracle<'info> {
/// CHECK: checked in ix
pub oracle: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct DisableUserHighLeverageMode<'info> {
pub state: Box<Account<'info, State>>,
pub authority: Signer<'info>,
#[account(mut)]
pub user: AccountLoader<'info, User>,
#[account(mut)]
pub high_leverage_mode_config: AccountLoader<'info, HighLeverageModeConfig>,
}
Loading

0 comments on commit e230ee8

Please sign in to comment.