From f52b636a0a2aa6e6ed3654fdb86e7a9fa34e4f50 Mon Sep 17 00:00:00 2001 From: Nour Alharithi Date: Mon, 7 Jul 2025 10:36:28 -0700 Subject: [PATCH 1/5] low hanging fruit comments --- programs/drift/src/instructions/keeper.rs | 4 +- programs/drift/src/instructions/lp_pool.rs | 43 +++++++++++---------- programs/drift/src/state/constituent_map.rs | 8 ++-- programs/drift/src/state/events.rs | 8 ++++ programs/drift/src/state/lp_pool.rs | 3 +- programs/drift/src/state/lp_pool/tests.rs | 2 +- sdk/src/idl/drift.json | 5 ++- 7 files changed, 42 insertions(+), 31 deletions(-) diff --git a/programs/drift/src/instructions/keeper.rs b/programs/drift/src/instructions/keeper.rs index 5e64db7c5f..eb770771ef 100644 --- a/programs/drift/src/instructions/keeper.rs +++ b/programs/drift/src/instructions/keeper.rs @@ -31,8 +31,6 @@ use crate::math::constants::QUOTE_PRECISION; use crate::math::constants::QUOTE_SPOT_MARKET_INDEX; use crate::math::constants::SPOT_BALANCE_PRECISION; use crate::math::margin::{calculate_user_equity, meets_settle_pnl_maintenance_margin_requirement}; -use crate::math::oracle::is_oracle_valid_for_action; -use crate::math::oracle::DriftAction; use crate::math::orders::{estimate_price_from_side, find_bids_and_asks_from_users}; use crate::math::position::calculate_base_asset_value_and_pnl_with_oracle_price; use crate::math::safe_math::SafeMath; @@ -3311,7 +3309,7 @@ pub struct UpdateAmmCache<'info> { pub amm_cache: AccountInfo<'info>, #[account( owner = crate::ID, - seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], + seeds = [b"spot_market", QUOTE_SPOT_MARKET_INDEX.to_le_bytes().as_ref()], bump, )] pub quote_market: AccountLoader<'info, SpotMarket>, diff --git a/programs/drift/src/instructions/lp_pool.rs b/programs/drift/src/instructions/lp_pool.rs index 6bafc6260f..bcd9e5c399 100644 --- a/programs/drift/src/instructions/lp_pool.rs +++ b/programs/drift/src/instructions/lp_pool.rs @@ -5,7 +5,7 @@ use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; use crate::{ controller::{ - self, lp, + self, spot_balance::update_spot_balances, token::{burn_tokens, mint_tokens}, }, @@ -16,8 +16,8 @@ use crate::{ self, casting::Cast, constants::{ - BASE_PRECISION_I128, PERCENTAGE_PRECISION_I128, PERCENTAGE_PRECISION_I64, - PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, QUOTE_PRECISION_I128, + PERCENTAGE_PRECISION_I128, PERCENTAGE_PRECISION_I64, PERCENTAGE_PRECISION_U64, + PRICE_PRECISION_I128, QUOTE_PRECISION_I128, }, oracle::{is_oracle_valid_for_action, oracle_validity, DriftAction}, safe_math::SafeMath, @@ -25,7 +25,7 @@ use crate::{ math_error, msg, safe_decrement, safe_increment, state::{ constituent_map::{ConstituentMap, ConstituentSet}, - events::{LPMintRedeemRecord, LPSwapRecord}, + events::{emit_stack, LPMintRedeemRecord, LPSwapRecord}, lp_pool::{ calculate_target_weight, AmmConstituentDatum, AmmConstituentMappingFixed, Constituent, ConstituentCorrelationsFixed, ConstituentTargetBaseFixed, LPPool, TargetsDatum, @@ -40,6 +40,7 @@ use crate::{ spot_market::{SpotBalanceType, SpotMarket}, spot_market_map::get_writable_spot_market_set_from_many, state::State, + traits::Size, user::MarketType, zero_copy::{AccountZeroCopy, AccountZeroCopyMut, ZeroCopyLoader}, }, @@ -141,7 +142,12 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>( "Amm mapping PDA does not match expected PDA" )?; - let mut amm_inventories: Vec<(u16, i64, i64)> = vec![]; + let remaining_accounts = &mut ctx.remaining_accounts.iter().peekable(); + let constituent_map = + ConstituentMap::load(&ConstituentSet::new(), &lp_pool_key, remaining_accounts)?; + + let mut amm_inventories: Vec<(u16, i64, i64)> = + Vec::with_capacity(amm_constituent_mapping.len() as usize); for (_, datum) in amm_constituent_mapping.iter().enumerate() { let cache_info = amm_cache.get(datum.perp_market_index as u32); @@ -183,11 +189,8 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>( return Ok(()); } - let remaining_accounts = &mut ctx.remaining_accounts.iter().peekable(); - let constituent_map = - ConstituentMap::load(&ConstituentSet::new(), &lp_pool_key, remaining_accounts)?; - - let mut constituent_indexes_and_decimals_and_prices: Vec<(u16, u8, i64)> = vec![]; + let mut constituent_indexes_and_decimals_and_prices: Vec<(u16, u8, i64)> = + Vec::with_capacity(constituent_map.0.len()); for (index, loader) in &constituent_map.0 { let constituent_ref = loader.load()?; constituent_indexes_and_decimals_and_prices.push(( @@ -665,7 +668,7 @@ pub fn handle_lp_pool_swap<'c: 'info, 'info>( let in_swap_id = get_then_update_id!(in_constituent, next_swap_id); let out_swap_id = get_then_update_id!(out_constituent, next_swap_id); - emit!(LPSwapRecord { + emit_stack::<_, { LPSwapRecord::SIZE }>(LPSwapRecord { ts: now, slot, authority: ctx.accounts.authority.key(), @@ -687,19 +690,19 @@ pub fn handle_lp_pool_swap<'c: 'info, 'info>( in_oracle.price, &in_spot_market, 0, - lp_pool.last_aum + lp_pool.last_aum, )?, in_market_target_weight: in_target_weight, out_market_current_weight: out_constituent.get_weight( out_oracle.price, &out_spot_market, 0, - lp_pool.last_aum + lp_pool.last_aum, )?, out_market_target_weight: out_target_weight, in_swap_id, out_swap_id, - }); + })?; receive( &ctx.accounts.token_program, @@ -896,7 +899,7 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>( }; let mint_redeem_id = get_then_update_id!(lp_pool, next_mint_redeem_id); - emit!(LPMintRedeemRecord { + emit_stack::<_, { LPMintRedeemRecord::SIZE }>(LPMintRedeemRecord { ts: now, slot, authority: ctx.accounts.authority.key(), @@ -918,10 +921,10 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>( in_oracle.price, &in_spot_market, 0, - lp_pool.last_aum + lp_pool.last_aum, )?, in_market_target_weight: in_target_weight, - }); + })?; Ok(()) } @@ -1093,7 +1096,7 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>( }; let mint_redeem_id = get_then_update_id!(lp_pool, next_mint_redeem_id); - emit!(LPMintRedeemRecord { + emit_stack::<_, { LPMintRedeemRecord::SIZE }>(LPMintRedeemRecord { ts: now, slot, authority: ctx.accounts.authority.key(), @@ -1115,10 +1118,10 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>( out_oracle.price, &out_spot_market, 0, - lp_pool.last_aum + lp_pool.last_aum, )?, in_market_target_weight: out_target_weight, - }); + })?; Ok(()) } diff --git a/programs/drift/src/state/constituent_map.rs b/programs/drift/src/state/constituent_map.rs index e3e4f6c681..12e77942dd 100644 --- a/programs/drift/src/state/constituent_map.rs +++ b/programs/drift/src/state/constituent_map.rs @@ -62,7 +62,7 @@ impl<'a> ConstituentMap<'a> { None => { let caller = Location::caller(); msg!( - "Could not find perp market {} at {}:{}", + "Could not find constituent {} at {}:{}", market_index, caller.file(), caller.line() @@ -77,7 +77,7 @@ impl<'a> ConstituentMap<'a> { let caller = Location::caller(); msg!("{:?}", e); msg!( - "Could not load perp market {} at {}:{}", + "Could not load constituent {} at {}:{}", market_index, caller.file(), caller.line() @@ -88,7 +88,7 @@ impl<'a> ConstituentMap<'a> { } pub fn load<'b, 'c>( - writable_markets: &'b ConstituentSet, + writable_constituents: &'b ConstituentSet, lp_pool_key: &Pubkey, account_info_iter: &'c mut Peekable>>, ) -> DriftResult> { @@ -145,7 +145,7 @@ impl<'a> ConstituentMap<'a> { let account_info = account_info_iter.next().safe_unwrap()?; let is_writable = account_info.is_writable; - if writable_markets.contains(&constituent_index) && !is_writable { + if writable_constituents.contains(&constituent_index) && !is_writable { return Err(ErrorCode::ConstituentWrongMutability); } diff --git a/programs/drift/src/state/events.rs b/programs/drift/src/state/events.rs index 269e5e927c..77647c795c 100644 --- a/programs/drift/src/state/events.rs +++ b/programs/drift/src/state/events.rs @@ -779,6 +779,10 @@ pub struct LPSwapRecord { pub out_swap_id: u64, } +impl Size for LPSwapRecord { + const SIZE: usize = 376; +} + #[event] #[derive(Default)] pub struct LPMintRedeemRecord { @@ -814,3 +818,7 @@ pub struct LPMintRedeemRecord { pub in_market_current_weight: i64, pub in_market_target_weight: i64, } + +impl Size for LPMintRedeemRecord { + const SIZE: usize = 328; +} diff --git a/programs/drift/src/state/lp_pool.rs b/programs/drift/src/state/lp_pool.rs index dd5b953692..fe638291da 100644 --- a/programs/drift/src/state/lp_pool.rs +++ b/programs/drift/src/state/lp_pool.rs @@ -2,8 +2,7 @@ use crate::error::{DriftResult, ErrorCode}; use crate::math::casting::Cast; use crate::math::constants::{ BASE_PRECISION_I128, PERCENTAGE_PRECISION, PERCENTAGE_PRECISION_I128, PERCENTAGE_PRECISION_I64, - PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, QUOTE_PRECISION, QUOTE_PRECISION_I128, - QUOTE_PRECISION_U64, + PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, QUOTE_PRECISION_I128, }; use crate::math::safe_math::SafeMath; use crate::math::spot_balance::get_token_amount; diff --git a/programs/drift/src/state/lp_pool/tests.rs b/programs/drift/src/state/lp_pool/tests.rs index b935d5ac42..204d65024e 100644 --- a/programs/drift/src/state/lp_pool/tests.rs +++ b/programs/drift/src/state/lp_pool/tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::math::constants::{ - BASE_PRECISION_I64, PERCENTAGE_PRECISION_I64, PRICE_PRECISION_I64, + BASE_PRECISION_I64, PERCENTAGE_PRECISION_I64, PRICE_PRECISION_I64, QUOTE_PRECISION, }; use crate::state::lp_pool::*; use std::{cell::RefCell, marker::PhantomData, vec}; diff --git a/sdk/src/idl/drift.json b/sdk/src/idl/drift.json index ca992f1f84..daa107e644 100644 --- a/sdk/src/idl/drift.json +++ b/sdk/src/idl/drift.json @@ -18263,5 +18263,8 @@ "name": "ConstituentOracleStale", "msg": "Constituent oracle is stale" } - ] + ], + "metadata": { + "address": "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH" + } } \ No newline at end of file From e72a1e8f02a94b455c3c22b024e226f5cf55af0f Mon Sep 17 00:00:00 2001 From: Nour Alharithi Date: Mon, 7 Jul 2025 11:00:24 -0700 Subject: [PATCH 2/5] remove pda checks and store lp pool on zero copy accounts --- programs/drift/src/instructions/admin.rs | 3 + programs/drift/src/instructions/lp_pool.rs | 84 ++++------------------ programs/drift/src/state/lp_pool.rs | 13 +++- sdk/src/idl/drift.json | 24 +++++++ 4 files changed, 50 insertions(+), 74 deletions(-) diff --git a/programs/drift/src/instructions/admin.rs b/programs/drift/src/instructions/admin.rs index affd0fc4e2..e956e3d650 100644 --- a/programs/drift/src/instructions/admin.rs +++ b/programs/drift/src/instructions/admin.rs @@ -4732,6 +4732,7 @@ pub fn handle_initialize_lp_pool( }; let amm_constituent_mapping = &mut ctx.accounts.amm_constituent_mapping; + amm_constituent_mapping.lp_pool = ctx.accounts.lp_pool.key(); amm_constituent_mapping.bump = ctx.bumps.amm_constituent_mapping; amm_constituent_mapping .weights @@ -4739,6 +4740,7 @@ pub fn handle_initialize_lp_pool( amm_constituent_mapping.validate()?; let constituent_target_base = &mut ctx.accounts.constituent_target_base; + constituent_target_base.lp_pool = ctx.accounts.lp_pool.key(); constituent_target_base.bump = ctx.bumps.constituent_target_base; constituent_target_base .targets @@ -4746,6 +4748,7 @@ pub fn handle_initialize_lp_pool( constituent_target_base.validate()?; let consituent_correlations = &mut ctx.accounts.constituent_correlations; + consituent_correlations.lp_pool = ctx.accounts.lp_pool.key(); consituent_correlations.bump = ctx.bumps.constituent_correlations; consituent_correlations.correlations.resize(0 as usize, 0); consituent_correlations.validate()?; diff --git a/programs/drift/src/instructions/lp_pool.rs b/programs/drift/src/instructions/lp_pool.rs index bcd9e5c399..f41fdb1190 100644 --- a/programs/drift/src/instructions/lp_pool.rs +++ b/programs/drift/src/instructions/lp_pool.rs @@ -29,9 +29,8 @@ use crate::{ lp_pool::{ calculate_target_weight, AmmConstituentDatum, AmmConstituentMappingFixed, Constituent, ConstituentCorrelationsFixed, ConstituentTargetBaseFixed, LPPool, TargetsDatum, - WeightValidationFlags, CONSTITUENT_CORRELATIONS_PDA_SEED, - LP_POOL_SWAP_AUM_UPDATE_DELAY, MAX_AMM_CACHE_STALENESS_FOR_TARGET_CALC, - MAX_CONSTITUENT_ORACLE_SLOT_STALENESS_FOR_AUM, + WeightValidationFlags, LP_POOL_SWAP_AUM_UPDATE_DELAY, + MAX_AMM_CACHE_STALENESS_FOR_TARGET_CALC, MAX_CONSTITUENT_ORACLE_SLOT_STALENESS_FOR_AUM, }, oracle::OraclePriceData, oracle_map::OracleMap, @@ -54,8 +53,7 @@ use crate::controller::spot_balance::update_spot_market_cumulative_interest; use crate::controller::token::{receive, send_from_program_vault}; use crate::instructions::constraints::*; use crate::state::lp_pool::{ - AMM_MAP_PDA_SEED, CONSTITUENT_PDA_SEED, CONSTITUENT_TARGET_BASE_PDA_SEED, - LP_POOL_TOKEN_VAULT_PDA_SEED, + CONSTITUENT_PDA_SEED, CONSTITUENT_TARGET_BASE_PDA_SEED, LP_POOL_TOKEN_VAULT_PDA_SEED, }; pub fn handle_update_constituent_target_base<'c: 'info, 'info>( @@ -63,7 +61,6 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>( ) -> Result<()> { let slot = Clock::get()?.slot; - let lp_pool = &ctx.accounts.lp_pool.load()?; let lp_pool_key: &Pubkey = &ctx.accounts.lp_pool.key(); let amm_cache_key: &Pubkey = &ctx.accounts.amm_cache.key(); @@ -88,29 +85,15 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>( )?; let state = &ctx.accounts.state; - let constituent_target_base_key = &ctx.accounts.constituent_target_base.key(); - let amm_mapping_key = &ctx.accounts.amm_constituent_mapping.key(); - let mut constituent_target_base: AccountZeroCopyMut< '_, TargetsDatum, ConstituentTargetBaseFixed, > = ctx.accounts.constituent_target_base.load_zc_mut()?; - - let bump = constituent_target_base.fixed.bump; - let expected_pda = &Pubkey::create_program_address( - &[ - CONSTITUENT_TARGET_BASE_PDA_SEED.as_ref(), - lp_pool.pubkey.as_ref(), - bump.to_le_bytes().as_ref(), - ], - &crate::ID, - ) - .map_err(|_| ErrorCode::InvalidPDA)?; validate!( - expected_pda.eq(constituent_target_base_key), + constituent_target_base.fixed.lp_pool.eq(lp_pool_key), ErrorCode::InvalidPDA, - "Constituent target weights PDA does not match expected PDA" + "Constituent target base lp pool pubkey does not match lp pool pubkey", )?; let num_constituents = constituent_target_base.len(); @@ -125,21 +108,10 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>( AmmConstituentDatum, AmmConstituentMappingFixed, > = ctx.accounts.amm_constituent_mapping.load_zc()?; - - let amm_mapping_bump = amm_constituent_mapping.fixed.bump; - let expected_map_pda = &Pubkey::create_program_address( - &[ - AMM_MAP_PDA_SEED.as_ref(), - lp_pool.pubkey.as_ref(), - amm_mapping_bump.to_le_bytes().as_ref(), - ], - &crate::ID, - ) - .map_err(|_| ErrorCode::InvalidPDA)?; validate!( - expected_map_pda.eq(amm_mapping_key), + amm_constituent_mapping.fixed.lp_pool.eq(lp_pool_key), ErrorCode::InvalidPDA, - "Amm mapping PDA does not match expected PDA" + "Amm constituent mapping lp pool pubkey does not match lp pool pubkey", )?; let remaining_accounts = &mut ctx.remaining_accounts.iter().peekable(); @@ -251,25 +223,15 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>( "Constituent map length does not match lp pool constituent count" )?; - let constituent_target_base_key = &ctx.accounts.constituent_target_base.key(); let mut constituent_target_base: AccountZeroCopyMut< '_, TargetsDatum, ConstituentTargetBaseFixed, > = ctx.accounts.constituent_target_base.load_zc_mut()?; - let expected_pda = &Pubkey::create_program_address( - &[ - CONSTITUENT_TARGET_BASE_PDA_SEED.as_ref(), - lp_pool.pubkey.as_ref(), - constituent_target_base.fixed.bump.to_le_bytes().as_ref(), - ], - &crate::ID, - ) - .map_err(|_| ErrorCode::InvalidPDA)?; validate!( - expected_pda.eq(constituent_target_base_key), + constituent_target_base.fixed.lp_pool.eq(&lp_pool.pubkey), ErrorCode::InvalidPDA, - "Constituent target weights PDA does not match expected PDA" + "Constituent target base lp pool pubkey does not match lp pool pubkey", )?; let amm_cache_key: &Pubkey = &ctx.accounts.amm_cache.key(); @@ -507,40 +469,20 @@ pub fn handle_lp_pool_swap<'c: 'info, 'info>( let mut in_constituent = ctx.accounts.in_constituent.load_mut()?; let mut out_constituent = ctx.accounts.out_constituent.load_mut()?; - let constituent_target_base_key = &ctx.accounts.constituent_target_base.key(); let constituent_target_base: AccountZeroCopy<'_, TargetsDatum, ConstituentTargetBaseFixed> = ctx.accounts.constituent_target_base.load_zc()?; - let expected_pda = &Pubkey::create_program_address( - &[ - CONSTITUENT_TARGET_BASE_PDA_SEED.as_ref(), - lp_pool.pubkey.as_ref(), - constituent_target_base.fixed.bump.to_le_bytes().as_ref(), - ], - &crate::ID, - ) - .map_err(|_| ErrorCode::InvalidPDA)?; validate!( - expected_pda.eq(constituent_target_base_key), + constituent_target_base.fixed.lp_pool.eq(&lp_pool.pubkey), ErrorCode::InvalidPDA, - "Constituent target weights PDA does not match expected PDA" + "Constituent target base lp pool pubkey does not match lp pool pubkey", )?; - let constituent_correlation_key = &ctx.accounts.constituent_correlations.key(); let constituent_correlations: AccountZeroCopy<'_, i64, ConstituentCorrelationsFixed> = ctx.accounts.constituent_correlations.load_zc()?; - let expected_correlation_pda = &Pubkey::create_program_address( - &[ - CONSTITUENT_CORRELATIONS_PDA_SEED.as_ref(), - lp_pool.pubkey.as_ref(), - constituent_correlations.fixed.bump.to_le_bytes().as_ref(), - ], - &crate::ID, - ) - .map_err(|_| ErrorCode::InvalidPDA)?; validate!( - expected_correlation_pda.eq(constituent_correlation_key), + constituent_correlations.fixed.lp_pool.eq(&lp_pool.pubkey), ErrorCode::InvalidPDA, - "Constituent correlations PDA does not match expected PDA" + "Constituent correlations lp pool pubkey does not match lp pool pubkey", )?; let AccountMaps { diff --git a/programs/drift/src/state/lp_pool.rs b/programs/drift/src/state/lp_pool.rs index fe638291da..b35a32ff22 100644 --- a/programs/drift/src/state/lp_pool.rs +++ b/programs/drift/src/state/lp_pool.rs @@ -906,6 +906,7 @@ impl Default for AmmConstituentDatum { #[derive(Debug, Default)] #[repr(C)] pub struct AmmConstituentMappingFixed { + pub lp_pool: Pubkey, pub bump: u8, pub _pad: [u8; 3], pub len: u32, @@ -921,6 +922,7 @@ impl HasLen for AmmConstituentMappingFixed { #[derive(Debug)] #[repr(C)] pub struct AmmConstituentMapping { + pub lp_pool: Pubkey, pub bump: u8, _padding: [u8; 3], // PERCENTAGE_PRECISION. Each datum represents the target weight for a single (AMM, Constituent) pair. @@ -930,7 +932,7 @@ pub struct AmmConstituentMapping { impl AmmConstituentMapping { pub fn space(num_constituents: usize) -> usize { - 8 + 8 + 4 + num_constituents * 24 + 8 + 40 + num_constituents * 24 } pub fn validate(&self) -> DriftResult<()> { @@ -964,6 +966,7 @@ pub struct TargetsDatum { #[derive(Debug, Default)] #[repr(C)] pub struct ConstituentTargetBaseFixed { + pub lp_pool: Pubkey, pub bump: u8, _pad: [u8; 3], /// total elements in the flattened `data` vec @@ -980,6 +983,7 @@ impl HasLen for ConstituentTargetBaseFixed { #[derive(Debug)] #[repr(C)] pub struct ConstituentTargetBase { + pub lp_pool: Pubkey, pub bump: u8, _padding: [u8; 3], // PERCENTAGE_PRECISION. The weights of the target weight matrix. Updated async @@ -988,7 +992,7 @@ pub struct ConstituentTargetBase { impl ConstituentTargetBase { pub fn space(num_constituents: usize) -> usize { - 8 + 8 + 4 + num_constituents * 24 + 8 + 40 + num_constituents * 24 } pub fn validate(&self) -> DriftResult<()> { @@ -1018,6 +1022,7 @@ impl_zero_copy_loader!( impl Default for ConstituentTargetBase { fn default() -> Self { ConstituentTargetBase { + lp_pool: Pubkey::default(), bump: 0, _padding: [0; 3], targets: Vec::with_capacity(0), @@ -1200,6 +1205,7 @@ impl<'a> AccountZeroCopyMut<'a, AmmConstituentDatum, AmmConstituentMappingFixed> #[derive(Debug, Default)] #[repr(C)] pub struct ConstituentCorrelationsFixed { + pub lp_pool: Pubkey, pub bump: u8, _pad: [u8; 3], /// total elements in the flattened `data` vec @@ -1216,6 +1222,7 @@ impl HasLen for ConstituentCorrelationsFixed { #[derive(Debug)] #[repr(C)] pub struct ConstituentCorrelations { + pub lp_pool: Pubkey, pub bump: u8, _padding: [u8; 3], // PERCENTAGE_PRECISION. The weights of the target weight matrix. Updated async @@ -1237,7 +1244,7 @@ impl_zero_copy_loader!( impl ConstituentCorrelations { pub fn space(num_constituents: usize) -> usize { - 8 + 8 + 4 + num_constituents * num_constituents * 8 + 8 + 40 + num_constituents * num_constituents * 8 } pub fn validate(&self) -> DriftResult<()> { diff --git a/sdk/src/idl/drift.json b/sdk/src/idl/drift.json index daa107e644..763812e586 100644 --- a/sdk/src/idl/drift.json +++ b/sdk/src/idl/drift.json @@ -9492,6 +9492,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "lpPool", + "type": "publicKey" + }, { "name": "bump", "type": "u8" @@ -9521,6 +9525,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "lpPool", + "type": "publicKey" + }, { "name": "bump", "type": "u8" @@ -9550,6 +9558,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "lpPool", + "type": "publicKey" + }, { "name": "bump", "type": "u8" @@ -11693,6 +11705,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "lpPool", + "type": "publicKey" + }, { "name": "bump", "type": "u8" @@ -11747,6 +11763,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "lpPool", + "type": "publicKey" + }, { "name": "bump", "type": "u8" @@ -11775,6 +11795,10 @@ "type": { "kind": "struct", "fields": [ + { + "name": "lpPool", + "type": "publicKey" + }, { "name": "bump", "type": "u8" From 5e0efcf69d8df229495733363cf490ec1bdbb649 Mon Sep 17 00:00:00 2001 From: Nour Alharithi Date: Mon, 7 Jul 2025 11:51:53 -0700 Subject: [PATCH 3/5] parameterize depeg threshold --- programs/drift/src/instructions/admin.rs | 2 ++ programs/drift/src/instructions/lp_pool.rs | 4 ++-- programs/drift/src/instructions/optional_accounts.rs | 1 - programs/drift/src/lib.rs | 2 ++ programs/drift/src/state/constituent_map.rs | 2 +- programs/drift/src/state/lp_pool.rs | 5 ++++- sdk/src/adminClient.ts | 3 +++ sdk/src/idl/drift.json | 8 ++++++++ sdk/src/types.ts | 1 + tests/lpPool.ts | 3 +++ 10 files changed, 26 insertions(+), 5 deletions(-) diff --git a/programs/drift/src/instructions/admin.rs b/programs/drift/src/instructions/admin.rs index e956e3d650..815461267e 100644 --- a/programs/drift/src/instructions/admin.rs +++ b/programs/drift/src/instructions/admin.rs @@ -5008,6 +5008,7 @@ pub fn handle_initialize_constituent<'info>( oracle_staleness_threshold: u64, cost_to_trade_bps: i32, constituent_derivative_index: Option, + constituent_derivative_depeg_threshold: u64, derivative_weight: u64, volatility: u64, gamma_execution: u8, @@ -5059,6 +5060,7 @@ pub fn handle_initialize_constituent<'info>( constituent.constituent_index = (constituent_target_base.targets.len() - 1) as u16; constituent.next_swap_id = 1; constituent.constituent_derivative_index = constituent_derivative_index.unwrap_or(-1); + constituent.constituent_derivative_depeg_threshold = constituent_derivative_depeg_threshold; constituent.derivative_weight = derivative_weight; constituent.volatility = volatility; constituent.gamma_execution = gamma_execution; diff --git a/programs/drift/src/instructions/lp_pool.rs b/programs/drift/src/instructions/lp_pool.rs index f41fdb1190..f3c0af54e9 100644 --- a/programs/drift/src/instructions/lp_pool.rs +++ b/programs/drift/src/instructions/lp_pool.rs @@ -382,8 +382,8 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>( if constituent.last_oracle_price < parent_constituent .last_oracle_price - .safe_mul(9)? - .safe_div(10)? + .safe_mul(constituent.constituent_derivative_depeg_threshold as i64)? + .safe_div(PERCENTAGE_PRECISION_I64)? { msg!( "Constituent {} last oracle price {} is too low compared to parent constituent {} last oracle price {}. Assuming depegging and setting target base to 0.", diff --git a/programs/drift/src/instructions/optional_accounts.rs b/programs/drift/src/instructions/optional_accounts.rs index ae89b1c3e2..7abe5c33d2 100644 --- a/programs/drift/src/instructions/optional_accounts.rs +++ b/programs/drift/src/instructions/optional_accounts.rs @@ -1,5 +1,4 @@ use crate::error::{DriftResult, ErrorCode}; -use crate::state::constituent_map::ConstituentSet; use crate::state::high_leverage_mode_config::HighLeverageModeConfig; use std::cell::RefMut; use std::convert::TryFrom; diff --git a/programs/drift/src/lib.rs b/programs/drift/src/lib.rs index 9fa9ed2df5..ae70e7e570 100644 --- a/programs/drift/src/lib.rs +++ b/programs/drift/src/lib.rs @@ -1820,6 +1820,7 @@ pub mod drift { oracle_staleness_threshold: u64, cost_to_trade: i32, constituent_derivative_index: Option, + constituent_derivative_depeg_threshold: u64, derivative_weight: u64, volatility: u64, gamma_execution: u8, @@ -1837,6 +1838,7 @@ pub mod drift { oracle_staleness_threshold, cost_to_trade, constituent_derivative_index, + constituent_derivative_depeg_threshold, derivative_weight, volatility, gamma_execution, diff --git a/programs/drift/src/state/constituent_map.rs b/programs/drift/src/state/constituent_map.rs index 12e77942dd..07bba14e77 100644 --- a/programs/drift/src/state/constituent_map.rs +++ b/programs/drift/src/state/constituent_map.rs @@ -133,7 +133,7 @@ impl<'a> ConstituentMap<'a> { )?; // constituent index 276 bytes from front of account - let constituent_index = u16::from_le_bytes(*array_ref![data, 276, 2]); + let constituent_index = u16::from_le_bytes(*array_ref![data, 284, 2]); if constituent_map.0.contains_key(&constituent_index) { msg!( "Can not include same constituent index twice {}", diff --git a/programs/drift/src/state/lp_pool.rs b/programs/drift/src/state/lp_pool.rs index b35a32ff22..dff0a31546 100644 --- a/programs/drift/src/state/lp_pool.rs +++ b/programs/drift/src/state/lp_pool.rs @@ -760,6 +760,9 @@ pub struct Constituent { pub volatility: u64, // volatility in PERCENTAGE_PRECISION 1=1% + // depeg threshold in relation top parent in PERCENTAGE_PRECISION + pub constituent_derivative_depeg_threshold: u64, + pub constituent_derivative_index: i16, // -1 if a parent index pub spot_market_index: u16, @@ -776,7 +779,7 @@ pub struct Constituent { } impl Size for Constituent { - const SIZE: usize = 288; + const SIZE: usize = 296; } impl Constituent { diff --git a/sdk/src/adminClient.ts b/sdk/src/adminClient.ts index 165294d39c..a02f20eb56 100644 --- a/sdk/src/adminClient.ts +++ b/sdk/src/adminClient.ts @@ -4783,6 +4783,9 @@ export class AdminClient extends DriftClient { initializeConstituentParams.constituentDerivativeIndex != null ? initializeConstituentParams.constituentDerivativeIndex : null, + initializeConstituentParams.constituentDerivativeDepegThreshold != null + ? initializeConstituentParams.constituentDerivativeDepegThreshold + : ZERO, initializeConstituentParams.constituentDerivativeIndex != null ? initializeConstituentParams.derivativeWeight : ZERO, diff --git a/sdk/src/idl/drift.json b/sdk/src/idl/drift.json index 763812e586..ea25b15417 100644 --- a/sdk/src/idl/drift.json +++ b/sdk/src/idl/drift.json @@ -7782,6 +7782,10 @@ "option": "i16" } }, + { + "name": "constituentDerivativeDepegThreshold", + "type": "u64" + }, { "name": "derivativeWeight", "type": "u64" @@ -9443,6 +9447,10 @@ "name": "volatility", "type": "u64" }, + { + "name": "constituentDerivativeDepegThreshold", + "type": "u64" + }, { "name": "constituentDerivativeIndex", "type": "i16" diff --git a/sdk/src/types.ts b/sdk/src/types.ts index 6d9d48a800..dbd1248700 100644 --- a/sdk/src/types.ts +++ b/sdk/src/types.ts @@ -1663,6 +1663,7 @@ export type InitializeConstituentParams = { costToTrade: number; derivativeWeight: BN; constituentDerivativeIndex?: number; + constituentDerivativeDepegThreshold?: BN; constituentCorrelations: BN[]; volatility: BN; gammaExecution?: number; diff --git a/tests/lpPool.ts b/tests/lpPool.ts index 405d14ac43..19f8ae0e9f 100644 --- a/tests/lpPool.ts +++ b/tests/lpPool.ts @@ -400,6 +400,7 @@ describe('LP Pool', () => { swapFeeMax: new BN(2).mul(PERCENTAGE_PRECISION), oracleStalenessThreshold: new BN(400), costToTrade: 1, + constituentDerivativeDepegThreshold: PERCENTAGE_PRECISION.divn(10).muln(9), derivativeWeight: ZERO, volatility: new BN(10).mul(PERCENTAGE_PRECISION), constituentCorrelations: [ZERO], @@ -702,6 +703,7 @@ describe('LP Pool', () => { oracleStalenessThreshold: new BN(400), costToTrade: 1, derivativeWeight: PERCENTAGE_PRECISION.divn(2), + constituentDerivativeDepegThreshold: PERCENTAGE_PRECISION.divn(10).muln(9), volatility: new BN(10).mul(PERCENTAGE_PRECISION), constituentCorrelations: [ZERO, PERCENTAGE_PRECISION.muln(87).divn(100)], constituentDerivativeIndex: 1, @@ -1211,6 +1213,7 @@ describe('LP Pool', () => { oracleStalenessThreshold: new BN(400), costToTrade: 1, derivativeWeight: PERCENTAGE_PRECISION.divn(4), + constituentDerivativeDepegThreshold: PERCENTAGE_PRECISION.divn(10).muln(9), volatility: new BN(10).mul(PERCENTAGE_PRECISION), constituentCorrelations: [ ZERO, From 39dc4b272f76e341a886950ac1009bd8dbabb8c8 Mon Sep 17 00:00:00 2001 From: Nour Alharithi Date: Mon, 7 Jul 2025 12:06:23 -0700 Subject: [PATCH 4/5] make description in lp pool event --- programs/drift/src/instructions/lp_pool.rs | 8 ++++---- programs/drift/src/state/events.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/programs/drift/src/instructions/lp_pool.rs b/programs/drift/src/instructions/lp_pool.rs index f3c0af54e9..d9c96a39b9 100644 --- a/programs/drift/src/instructions/lp_pool.rs +++ b/programs/drift/src/instructions/lp_pool.rs @@ -16,8 +16,8 @@ use crate::{ self, casting::Cast, constants::{ - PERCENTAGE_PRECISION_I128, PERCENTAGE_PRECISION_I64, PERCENTAGE_PRECISION_U64, - PRICE_PRECISION_I128, QUOTE_PRECISION_I128, + PERCENTAGE_PRECISION, PERCENTAGE_PRECISION_I128, PERCENTAGE_PRECISION_I64, + PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, QUOTE_PRECISION_I128, }, oracle::{is_oracle_valid_for_action, oracle_validity, DriftAction}, safe_math::SafeMath, @@ -845,7 +845,7 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>( ts: now, slot, authority: ctx.accounts.authority.key(), - is_minting: true, + description: 1, amount: in_amount, fee: in_fee_amount, spot_market_index: in_market_index, @@ -1042,7 +1042,7 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>( ts: now, slot, authority: ctx.accounts.authority.key(), - is_minting: false, + description: 0, amount: out_amount, fee: out_fee_amount, spot_market_index: out_market_index, diff --git a/programs/drift/src/state/events.rs b/programs/drift/src/state/events.rs index 77647c795c..bd0503d367 100644 --- a/programs/drift/src/state/events.rs +++ b/programs/drift/src/state/events.rs @@ -789,7 +789,7 @@ pub struct LPMintRedeemRecord { pub ts: i64, pub slot: u64, pub authority: Pubkey, - pub is_minting: bool, + pub description: u8, /// precision: continutent mint precision, gross fees pub amount: u128, /// precision: fee on amount, constituent market mint precision From 56b1e19dce2ea0a2f260b6b605c282e7780e1cfe Mon Sep 17 00:00:00 2001 From: Nour Alharithi Date: Mon, 7 Jul 2025 12:11:02 -0700 Subject: [PATCH 5/5] update idl for event change --- sdk/src/idl/drift.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/idl/drift.json b/sdk/src/idl/drift.json index ea25b15417..73e8130abe 100644 --- a/sdk/src/idl/drift.json +++ b/sdk/src/idl/drift.json @@ -16567,8 +16567,8 @@ "index": false }, { - "name": "isMinting", - "type": "bool", + "name": "description", + "type": "u8", "index": false }, {