Skip to content

Commit

Permalink
program: add buffer to calculating max perp if fee (#635)
Browse files Browse the repository at this point in the history
* program: add buffer to calculating max perp if fee

* update comments

* CHANGELOG
  • Loading branch information
crispheaney committed Oct 3, 2023
1 parent 14489cc commit f2f9bd5
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- program: add buffer to calculating max perp if fee ([#635](https://github.com/drift-labs/protocol-v2/pull/635))
- sdk: remove getMakerLimitBids/Asks ([#632](https://github.com/drift-labs/protocol-v2/pull/632))
- program: add ix to transfer protocol if shares ([#612](https://github.com/drift-labs/protocol-v2/pull/612))

Expand Down
132 changes: 130 additions & 2 deletions programs/drift/src/controller/liquidation/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1929,8 +1929,136 @@ pub mod liquidate_perp {
.unwrap();

let market_after = perp_market_map.get_ref(&0).unwrap();
// .5% * 100 =$0.5
assert_eq!(market_after.amm.total_liquidation_fee, QUOTE_PRECISION / 2);
// .5% * 100 * .95 =$0.475
assert_eq!(market_after.amm.total_liquidation_fee, 475000);
}

#[test]
pub fn successful_liquidation_portion_of_if_fee() {
let now = 0_i64;
let slot = 0_u64;

let mut oracle_price = get_hardcoded_pyth_price(23244136, 6);
let oracle_price_key =
Pubkey::from_str("J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix").unwrap();
let pyth_program = crate::ids::pyth_program::id();
create_account_info!(
oracle_price,
&oracle_price_key,
&pyth_program,
oracle_account_info
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let mut market = PerpMarket {
amm: AMM {
base_asset_reserve: 100 * AMM_RESERVE_PRECISION,
quote_asset_reserve: 100 * AMM_RESERVE_PRECISION,
bid_base_asset_reserve: 101 * AMM_RESERVE_PRECISION,
bid_quote_asset_reserve: 99 * AMM_RESERVE_PRECISION,
ask_base_asset_reserve: 99 * AMM_RESERVE_PRECISION,
ask_quote_asset_reserve: 101 * AMM_RESERVE_PRECISION,
sqrt_k: 100 * AMM_RESERVE_PRECISION,
peg_multiplier: 100 * PEG_PRECISION,
max_slippage_ratio: 50,
max_fill_reserve_fraction: 100,
order_step_size: 10000000,
quote_asset_amount: 50 * QUOTE_PRECISION_I128,
base_asset_amount_with_amm: BASE_PRECISION_I128,
oracle: oracle_price_key,
historical_oracle_data: HistoricalOracleData::default_price(oracle_price.agg.price),
funding_period: 3600,
..AMM::default()
},
margin_ratio_initial: 1000,
margin_ratio_maintenance: 500,
number_of_users_with_base: 1,
number_of_users: 1,
status: MarketStatus::Initialized,
liquidator_fee: LIQUIDATION_FEE_PRECISION / 100,
if_liquidation_fee: LIQUIDATION_FEE_PRECISION / 100,
..PerpMarket::default()
};
create_anchor_account_info!(market, PerpMarket, market_account_info);
let perp_market_map = PerpMarketMap::load_one(&market_account_info, true).unwrap();

let mut spot_market = SpotMarket {
market_index: 0,
oracle_source: OracleSource::QuoteAsset,
cumulative_deposit_interest: SPOT_CUMULATIVE_INTEREST_PRECISION,
decimals: 6,
initial_asset_weight: SPOT_WEIGHT_PRECISION,
historical_oracle_data: HistoricalOracleData {
last_oracle_price_twap: PRICE_PRECISION_I64,
last_oracle_price_twap_5min: PRICE_PRECISION_I64,
..HistoricalOracleData::default()
},
..SpotMarket::default()
};
create_anchor_account_info!(spot_market, SpotMarket, spot_market_account_info);
let spot_market_map = SpotMarketMap::load_one(&spot_market_account_info, true).unwrap();

let mut user = User {
perp_positions: get_positions(PerpPosition {
market_index: 0,
base_asset_amount: -299400000000,
quote_asset_amount: 6959294318,
quote_entry_amount: 6959294318,
quote_break_even_amount: 6959294318,
..PerpPosition::default()
}),
spot_positions: get_spot_positions(SpotPosition {
market_index: 0,
balance_type: SpotBalanceType::Deposit,
scaled_balance: 113838792 * 1000,
..SpotPosition::default()
}),
..User::default()
};

let mut liquidator = User {
spot_positions: get_spot_positions(SpotPosition {
market_index: 0,
balance_type: SpotBalanceType::Deposit,
scaled_balance: 50000 * SPOT_BALANCE_PRECISION_U64,
..SpotPosition::default()
}),
..User::default()
};

let user_key = Pubkey::default();
let liquidator_key = Pubkey::default();

let mut user_stats = UserStats::default();
let mut liquidator_stats = UserStats::default();
let state = State {
liquidation_margin_buffer_ratio: 200,
initial_pct_to_liquidate: LIQUIDATION_PCT_PRECISION as u16,
liquidation_duration: 150,
..Default::default()
};
liquidate_perp(
0,
300 * BASE_PRECISION_U64,
None,
&mut user,
&user_key,
&mut user_stats,
&mut liquidator,
&liquidator_key,
&mut liquidator_stats,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
slot,
now,
&state,
)
.unwrap();

let market_after = perp_market_map.get_ref(&0).unwrap();
assert!(!user.is_being_liquidated());
assert_eq!(market_after.amm.total_liquidation_fee, 41787043);
}
}

Expand Down
24 changes: 15 additions & 9 deletions programs/drift/src/math/liquidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,15 +379,21 @@ pub fn calculate_perp_if_fee(
.safe_div(PRICE_PRECISION)?;

// margin ratio - liquidator fee - (margin shortage / (user base asset amount * price))
let implied_if_fee = margin_ratio.saturating_sub(liquidator_fee).saturating_sub(
margin_shortage
.safe_mul(BASE_PRECISION)?
.safe_div(user_base_asset_amount.cast()?)?
.safe_mul(PRICE_PRECISION)?
.safe_div(price)?
.cast::<u32>()
.unwrap_or(u32::MAX),
);
let implied_if_fee = margin_ratio
.saturating_sub(liquidator_fee)
.saturating_sub(
margin_shortage
.safe_mul(BASE_PRECISION)?
.safe_div(user_base_asset_amount.cast()?)?
.safe_mul(PRICE_PRECISION)?
.safe_div(price)?
.cast::<u32>()
.unwrap_or(u32::MAX),
)
// multiply by 95% to avoid situation where fee leads to deposits == negative pnl
// leading to bankruptcy
.safe_mul(19)?
.safe_div(20)?;

Ok(max_if_liquidation_fee.min(implied_if_fee))
}
Expand Down
4 changes: 2 additions & 2 deletions programs/drift/src/math/liquidation/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ mod calculate_perp_if_fee {
)
.unwrap();

assert_eq!(fee, LIQUIDATION_FEE_PRECISION / 50); // 2%
assert_eq!(fee, 19000); // 2% * .95

let tiny_margin_shortage = QUOTE_PRECISION;
let fee = calculate_perp_if_fee(
Expand All @@ -574,7 +574,7 @@ mod calculate_perp_if_fee {
)
.unwrap();

assert_eq!(fee, 39000); // 3.9%
assert_eq!(fee, 37050); // 3.9% * .95

let huge_margin_shortage = 1000 * QUOTE_PRECISION;
let fee = calculate_perp_if_fee(
Expand Down

0 comments on commit f2f9bd5

Please sign in to comment.