Skip to content

Commit ffe43ff

Browse files
committed
address some perp comments
1 parent f2d263b commit ffe43ff

File tree

13 files changed

+228
-278
lines changed

13 files changed

+228
-278
lines changed

programs/drift/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,10 @@ pub enum ErrorCode {
672672
MaxDlpAumBreached,
673673
#[msg("Settle Lp Pool Disabled")]
674674
SettleLpPoolDisabled,
675+
#[msg("Mint/Redeem Lp Pool Disabled")]
676+
MintRedeemLpPoolDisabled,
677+
#[msg("Settlement amount exceeded")]
678+
LpPoolSettleInvariantBreached,
675679
}
676680

677681
#[macro_export]

programs/drift/src/instructions/admin.rs

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ use crate::state::spot_market::{
8080
SpotMarket, TokenProgramFlag,
8181
};
8282
use crate::state::spot_market_map::get_writable_spot_market_set;
83-
use crate::state::state::{ExchangeStatus, FeeStructure, OracleGuardRails, State};
83+
use crate::state::state::{
84+
ExchangeStatus, FeeStructure, LpPoolFeatureBitFlags, OracleGuardRails, State,
85+
};
8486
use crate::state::traits::Size;
8587
use crate::state::user::{User, UserStats};
8688
use crate::validate;
@@ -133,7 +135,8 @@ pub fn handle_initialize(ctx: Context<Initialize>) -> Result<()> {
133135
max_number_of_sub_accounts: 0,
134136
max_initialize_user_fee: 0,
135137
feature_bit_flags: 0,
136-
padding: [0; 9],
138+
lp_pool_feature_bit_flags: 0,
139+
padding: [0; 8],
137140
};
138141

139142
Ok(())
@@ -4761,12 +4764,24 @@ pub fn handle_initialize_lp_pool(
47614764
max_settle_quote_amount_per_market: u64,
47624765
) -> Result<()> {
47634766
let mut lp_pool = ctx.accounts.lp_pool.load_init()?;
4764-
let mint = ctx.accounts.mint.key();
4767+
let mint = &ctx.accounts.mint;
4768+
4769+
validate!(
4770+
mint.decimals == 6,
4771+
ErrorCode::DefaultError,
4772+
"lp mint must have 6 decimals"
4773+
)?;
4774+
4775+
validate!(
4776+
mint.mint_authority == Some(ctx.accounts.drift_signer.key()).into(),
4777+
ErrorCode::DefaultError,
4778+
"lp mint must have drift_signer as mint authority"
4779+
)?;
47654780

47664781
*lp_pool = LPPool {
47674782
name,
47684783
pubkey: ctx.accounts.lp_pool.key(),
4769-
mint,
4784+
mint: mint.key(),
47704785
constituents: 0,
47714786
max_aum,
47724787
last_aum: 0,
@@ -5190,11 +5205,13 @@ pub fn handle_update_feature_bit_flags_settle_lp_pool(
51905205
"Only state admin can re-enable after kill switch"
51915206
)?;
51925207

5193-
msg!("Setting third bit to 1, enabling settle LP pool");
5194-
state.feature_bit_flags = state.feature_bit_flags | (FeatureBitFlags::SettleLpPool as u8);
5208+
msg!("Setting first bit to 1, enabling settle LP pool");
5209+
state.lp_pool_feature_bit_flags =
5210+
state.lp_pool_feature_bit_flags | (LpPoolFeatureBitFlags::SettleLpPool as u8);
51955211
} else {
5196-
msg!("Setting third bit to 0, disabling settle LP pool");
5197-
state.feature_bit_flags = state.feature_bit_flags & !(FeatureBitFlags::SettleLpPool as u8);
5212+
msg!("Setting first bit to 0, disabling settle LP pool");
5213+
state.lp_pool_feature_bit_flags =
5214+
state.lp_pool_feature_bit_flags & !(LpPoolFeatureBitFlags::SettleLpPool as u8);
51985215
}
51995216
Ok(())
52005217
}
@@ -5211,11 +5228,36 @@ pub fn handle_update_feature_bit_flags_swap_lp_pool(
52115228
"Only state admin can re-enable after kill switch"
52125229
)?;
52135230

5214-
msg!("Setting fourth bit to 1, enabling swapping with LP pool");
5215-
state.feature_bit_flags = state.feature_bit_flags | (FeatureBitFlags::SwapLpPool as u8);
5231+
msg!("Setting second bit to 1, enabling swapping with LP pool");
5232+
state.lp_pool_feature_bit_flags =
5233+
state.lp_pool_feature_bit_flags | (LpPoolFeatureBitFlags::SwapLpPool as u8);
5234+
} else {
5235+
msg!("Setting second bit to 0, disabling swapping with LP pool");
5236+
state.lp_pool_feature_bit_flags =
5237+
state.lp_pool_feature_bit_flags & !(LpPoolFeatureBitFlags::SwapLpPool as u8);
5238+
}
5239+
Ok(())
5240+
}
5241+
5242+
pub fn handle_update_feature_bit_flags_mint_redeem_lp_pool(
5243+
ctx: Context<HotAdminUpdateState>,
5244+
enable: bool,
5245+
) -> Result<()> {
5246+
let state = &mut ctx.accounts.state;
5247+
if enable {
5248+
validate!(
5249+
ctx.accounts.admin.key().eq(&state.admin),
5250+
ErrorCode::DefaultError,
5251+
"Only state admin can re-enable after kill switch"
5252+
)?;
5253+
5254+
msg!("Setting third bit to 1, enabling minting and redeeming with LP pool");
5255+
state.lp_pool_feature_bit_flags =
5256+
state.lp_pool_feature_bit_flags | (LpPoolFeatureBitFlags::MintRedeemLpPool as u8);
52165257
} else {
5217-
msg!("Setting fourth bit to 0, disabling swapping with LP pool");
5218-
state.feature_bit_flags = state.feature_bit_flags & !(FeatureBitFlags::SwapLpPool as u8);
5258+
msg!("Setting third bit to 0, disabling minting and redeeming with LP pool");
5259+
state.lp_pool_feature_bit_flags =
5260+
state.lp_pool_feature_bit_flags & !(LpPoolFeatureBitFlags::MintRedeemLpPool as u8);
52195261
}
52205262
Ok(())
52215263
}
@@ -6866,7 +6908,6 @@ pub struct InitializeLpPool<'info> {
68666908
payer = admin
68676909
)]
68686910
pub lp_pool: AccountLoader<'info, LPPool>,
6869-
68706911
pub mint: Account<'info, anchor_spl::token::Mint>,
68716912

68726913
#[account(

programs/drift/src/instructions/keeper.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3223,17 +3223,12 @@ pub fn handle_settle_perp_to_lp_pool<'c: 'info, 'info>(
32233223
&SpotBalanceType::Deposit,
32243224
)?,
32253225
quote_market,
3226+
max_settle_quote_amount: lp_pool.max_settle_quote_amount,
32263227
};
32273228

32283229
// Calculate settlement
3229-
let mut settlement_result = calculate_settlement_amount(&settlement_ctx)?;
3230-
3231-
// If transfering from perp market, dont do more than the max allowed
3232-
if settlement_result.direction == SettlementDirection::ToLpPool {
3233-
settlement_result.amount_transferred = settlement_result
3234-
.amount_transferred
3235-
.min(lp_pool.max_settle_quote_amount);
3236-
}
3230+
let settlement_result = calculate_settlement_amount(&settlement_ctx)?;
3231+
validate_settlement_amount(&settlement_ctx, &settlement_result)?;
32373232

32383233
if settlement_result.direction == SettlementDirection::None {
32393234
continue;

programs/drift/src/instructions/lp_pool.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,10 +626,16 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(
626626
ErrorCode::UnauthorizedDlpAuthority,
627627
"User is not whitelisted for DLP deposits"
628628
)?;
629+
let state = &ctx.accounts.state;
630+
631+
validate!(
632+
state.allow_mint_redeem_lp_pool(),
633+
ErrorCode::MintRedeemLpPoolDisabled,
634+
"Mint/redeem LP pool is disabled"
635+
)?;
629636

630637
let slot = Clock::get()?.slot;
631638
let now = Clock::get()?.unix_timestamp;
632-
let state = &ctx.accounts.state;
633639
let mut lp_pool = ctx.accounts.lp_pool.load_mut()?;
634640

635641
let lp_price_before = lp_pool.get_price(ctx.accounts.lp_mint.supply)?;
@@ -934,6 +940,13 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>(
934940
let slot = Clock::get()?.slot;
935941
let now = Clock::get()?.unix_timestamp;
936942
let state = &ctx.accounts.state;
943+
944+
validate!(
945+
state.allow_mint_redeem_lp_pool(),
946+
ErrorCode::MintRedeemLpPoolDisabled,
947+
"Mint/redeem LP pool is disabled"
948+
)?;
949+
937950
let mut lp_pool = ctx.accounts.lp_pool.load_mut()?;
938951

939952
let lp_price_before = lp_pool.get_price(ctx.accounts.lp_mint.supply)?;

programs/drift/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,13 @@ pub mod drift {
18541854
handle_update_feature_bit_flags_swap_lp_pool(ctx, enable)
18551855
}
18561856

1857+
pub fn update_feature_bit_flags_mint_redeem_lp_pool(
1858+
ctx: Context<HotAdminUpdateState>,
1859+
enable: bool,
1860+
) -> Result<()> {
1861+
handle_update_feature_bit_flags_mint_redeem_lp_pool(ctx, enable)
1862+
}
1863+
18571864
pub fn initialize_constituent<'info>(
18581865
ctx: Context<'_, '_, '_, 'info, InitializeConstituent<'info>>,
18591866
spot_market_index: u16,

programs/drift/src/math/lp_pool.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ pub mod perp_lp_pool_settlement {
22
use core::slice::Iter;
33
use std::iter::Peekable;
44

5+
use crate::error::ErrorCode;
6+
use crate::math::casting::Cast;
57
use crate::state::spot_market::SpotBalanceType;
68
use crate::{
79
math::safe_math::SafeMath,
810
state::{
911
perp_market::{CacheInfo, PerpMarket},
10-
spot_market::{SpotBalance, SpotMarket},
12+
spot_market::SpotMarket,
1113
},
1214
*,
1315
};
@@ -34,6 +36,7 @@ pub mod perp_lp_pool_settlement {
3436
pub fee_pool_balance: u128,
3537
pub pnl_pool_balance: u128,
3638
pub quote_market: &'a SpotMarket,
39+
pub max_settle_quote_amount: u64,
3740
}
3841

3942
pub fn calculate_settlement_amount(ctx: &SettlementContext) -> Result<SettlementResult> {
@@ -51,6 +54,21 @@ pub mod perp_lp_pool_settlement {
5154
}
5255
}
5356

57+
pub fn validate_settlement_amount(
58+
ctx: &SettlementContext,
59+
result: &SettlementResult,
60+
) -> Result<()> {
61+
if result.amount_transferred > ctx.max_settle_quote_amount as u64 {
62+
msg!(
63+
"Amount to settle exceeds maximum allowed, {} > {}",
64+
result.amount_transferred,
65+
ctx.max_settle_quote_amount
66+
);
67+
return Err(ErrorCode::LpPoolSettleInvariantBreached.into());
68+
}
69+
Ok(())
70+
}
71+
5472
fn calculate_lp_to_perp_settlement(ctx: &SettlementContext) -> Result<SettlementResult> {
5573
if ctx.quote_constituent_token_balance == 0 {
5674
return Ok(SettlementResult {
@@ -61,12 +79,11 @@ pub mod perp_lp_pool_settlement {
6179
});
6280
}
6381

64-
let amount_to_send = if ctx.quote_owed_from_lp > ctx.quote_constituent_token_balance as i64
65-
{
66-
ctx.quote_constituent_token_balance
67-
} else {
68-
ctx.quote_owed_from_lp as u64
69-
};
82+
let amount_to_send = ctx
83+
.quote_owed_from_lp
84+
.cast::<u64>()?
85+
.min(ctx.quote_constituent_token_balance)
86+
.min(ctx.max_settle_quote_amount);
7087

7188
Ok(SettlementResult {
7289
amount_transferred: amount_to_send,
@@ -77,7 +94,7 @@ pub mod perp_lp_pool_settlement {
7794
}
7895

7996
fn calculate_perp_to_lp_settlement(ctx: &SettlementContext) -> Result<SettlementResult> {
80-
let amount_to_send = ctx.quote_owed_from_lp.abs() as u64;
97+
let amount_to_send = (ctx.quote_owed_from_lp.abs() as u64).min(ctx.max_settle_quote_amount);
8198

8299
if ctx.fee_pool_balance >= amount_to_send as u128 {
83100
// Fee pool can cover entire amount
@@ -133,7 +150,7 @@ pub mod perp_lp_pool_settlement {
133150
match result.direction {
134151
SettlementDirection::FromLpPool => {
135152
controller::spot_balance::update_spot_balances(
136-
(result.amount_transferred as u128),
153+
result.amount_transferred as u128,
137154
&SpotBalanceType::Deposit,
138155
quote_spot_market,
139156
&mut perp_market.amm.fee_pool,

programs/drift/src/state/lp_pool.rs

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ impl LPPool {
738738
msg!("Aum before quote owed from lp pool: {}", aum);
739739

740740
for cache_datum in amm_cache.iter() {
741-
aum -= cache_datum.quote_owed_from_lp_pool as i128;
741+
aum = aum.saturating_sub(cache_datum.quote_owed_from_lp_pool as i128);
742742
}
743743

744744
let aum_u128 = aum.max(0i128).cast::<u128>()?;
@@ -944,35 +944,6 @@ impl Constituent {
944944
.safe_div(token_precision)
945945
}
946946

947-
/// Returns the fee to charge for a swap to/from this constituent
948-
/// The fee is a linear interpolation between the swap_fee_min and swap_fee_max based on the post-swap deviation from the target weight
949-
/// precision: PERCENTAGE_PRECISION
950-
pub fn get_fee_to_charge(&self, post_swap_weight: i64, target_weight: i64) -> DriftResult<i64> {
951-
let min_weight = target_weight.safe_sub(self.max_weight_deviation as i64)?;
952-
let max_weight = target_weight.safe_add(self.max_weight_deviation as i64)?;
953-
let (slope_numerator, slope_denominator) = if post_swap_weight > target_weight {
954-
let num = self.swap_fee_max.safe_sub(self.swap_fee_min)?;
955-
let denom = max_weight.safe_sub(target_weight)?;
956-
(num, denom)
957-
} else {
958-
let num = self.swap_fee_min.safe_sub(self.swap_fee_max)?;
959-
let denom = target_weight.safe_sub(min_weight)?;
960-
(num, denom)
961-
};
962-
if slope_denominator == 0 {
963-
return Ok(self.swap_fee_min);
964-
}
965-
let b = self
966-
.swap_fee_min
967-
.safe_mul(slope_denominator)?
968-
.safe_sub(target_weight.safe_mul(slope_numerator)?)?;
969-
Ok(post_swap_weight
970-
.safe_mul(slope_numerator)?
971-
.safe_add(b)?
972-
.safe_div(slope_denominator)?
973-
.clamp(self.swap_fee_min, self.swap_fee_max))
974-
}
975-
976947
pub fn sync_token_balance(&mut self, token_account_amount: u64) {
977948
self.token_balance = token_account_amount;
978949
}
@@ -1249,9 +1220,11 @@ impl<'a> AccountZeroCopyMut<'a, TargetsDatum, ConstituentTargetBaseFixed> {
12491220
.safe_mul(*price as i128)?
12501221
.safe_div(BASE_PRECISION_I128)?;
12511222

1252-
target_notional += notional
1253-
.saturating_mul(weight as i128)
1254-
.saturating_div(PERCENTAGE_PRECISION_I128);
1223+
target_notional = target_notional.saturating_add(
1224+
notional
1225+
.saturating_mul(weight as i128)
1226+
.saturating_div(PERCENTAGE_PRECISION_I128),
1227+
);
12551228
}
12561229

12571230
let cell = self.get_mut(i as u32);
@@ -1550,7 +1523,7 @@ pub fn update_constituent_target_base_for_derivatives(
15501523
aum,
15511524
WeightValidationFlags::NONE,
15521525
)?;
1553-
let mut derivative_weights_sum = 0;
1526+
let mut derivative_weights_sum: u64 = 0;
15541527
for constituent_index in constituent_indexes {
15551528
let constituent = constituent_map.get_ref(constituent_index)?;
15561529
if constituent.last_oracle_price
@@ -1572,11 +1545,12 @@ pub fn update_constituent_target_base_for_derivatives(
15721545
continue;
15731546
}
15741547

1575-
derivative_weights_sum += constituent.derivative_weight;
1548+
derivative_weights_sum =
1549+
derivative_weights_sum.saturating_add(constituent.derivative_weight);
15761550

1577-
let target_weight = target_parent_weight
1578-
.safe_mul(constituent.derivative_weight as i64)?
1579-
.safe_div(PERCENTAGE_PRECISION_I64)?;
1551+
let target_weight = (target_parent_weight as i128)
1552+
.safe_mul(constituent.derivative_weight.cast::<i128>()?)?
1553+
.safe_div(PERCENTAGE_PRECISION_I128)?;
15801554

15811555
msg!(
15821556
"constituent: {}, target weight: {}",
@@ -1585,7 +1559,7 @@ pub fn update_constituent_target_base_for_derivatives(
15851559
);
15861560
let target_base = aum
15871561
.cast::<i128>()?
1588-
.safe_mul(target_weight as i128)?
1562+
.safe_mul(target_weight)?
15891563
.safe_div(PERCENTAGE_PRECISION_I128)?
15901564
.safe_mul(10_i128.pow(constituent.decimals as u32))?
15911565
.safe_div(constituent.last_oracle_price as i128)?;

0 commit comments

Comments
 (0)