@@ -30,6 +30,8 @@ use crate::{
30
30
calculate_target_weight, AmmConstituentDatum , AmmConstituentMappingFixed , Constituent ,
31
31
ConstituentCorrelationsFixed , ConstituentTargetBaseFixed , LPPool , TargetsDatum ,
32
32
WeightValidationFlags , CONSTITUENT_CORRELATIONS_PDA_SEED ,
33
+ LP_POOL_SWAP_AUM_UPDATE_DELAY , MAX_AMM_CACHE_STALENESS_FOR_TARGET_CALC ,
34
+ MAX_CONSTITUENT_ORACLE_SLOT_STALENESS_FOR_AUM ,
33
35
} ,
34
36
oracle:: OraclePriceData ,
35
37
oracle_map:: OracleMap ,
@@ -58,13 +60,18 @@ use crate::state::lp_pool::{
58
60
pub fn handle_update_constituent_target_base < ' c : ' info , ' info > (
59
61
ctx : Context < ' _ , ' _ , ' c , ' info , UpdateConstituentTargetBase < ' info > > ,
60
62
) -> Result < ( ) > {
63
+ let slot = Clock :: get ( ) ?. slot ;
64
+
61
65
let lp_pool = & ctx. accounts . lp_pool . load ( ) ?;
62
66
let lp_pool_key: & Pubkey = & ctx. accounts . lp_pool . key ( ) ;
63
67
let amm_cache_key: & Pubkey = & ctx. accounts . amm_cache . key ( ) ;
64
68
65
69
let amm_cache: AccountZeroCopy < ' _ , CacheInfo , AmmCacheFixed > =
66
70
ctx. accounts . amm_cache . load_zc ( ) ?;
67
71
72
+ amm_cache. check_oracle_staleness ( slot, MAX_AMM_CACHE_STALENESS_FOR_TARGET_CALC ) ?;
73
+ amm_cache. check_perp_market_staleness ( slot, MAX_AMM_CACHE_STALENESS_FOR_TARGET_CALC ) ?;
74
+
68
75
let expected_cache_pda = & Pubkey :: create_program_address (
69
76
& [
70
77
AMM_POSITIONS_CACHE . as_ref ( ) ,
@@ -223,7 +230,7 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
223
230
let AccountMaps {
224
231
perp_market_map : _,
225
232
spot_market_map,
226
- mut oracle_map,
233
+ oracle_map : _ ,
227
234
} = load_maps (
228
235
remaining_accounts,
229
236
& MarketSet :: new ( ) ,
@@ -284,7 +291,19 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
284
291
let mut oldest_slot = u64:: MAX ;
285
292
let mut derivative_groups: BTreeMap < u16 , Vec < u16 > > = BTreeMap :: new ( ) ;
286
293
for i in 0 ..lp_pool. constituents as usize {
287
- let mut constituent = constituent_map. get_ref_mut ( & ( i as u16 ) ) ?;
294
+ let constituent = constituent_map. get_ref ( & ( i as u16 ) ) ?;
295
+ if slot. saturating_sub ( constituent. last_oracle_slot )
296
+ > MAX_CONSTITUENT_ORACLE_SLOT_STALENESS_FOR_AUM
297
+ {
298
+ msg ! (
299
+ "Constituent {} oracle slot is too stale: {}, current slot: {}" ,
300
+ constituent. constituent_index,
301
+ constituent. last_oracle_slot,
302
+ slot
303
+ ) ;
304
+ return Err ( ErrorCode :: ConstituentOracleStale . into ( ) ) ;
305
+ }
306
+
288
307
if constituent. constituent_derivative_index >= 0 && constituent. derivative_weight != 0 {
289
308
if !derivative_groups. contains_key ( & ( constituent. constituent_derivative_index as u16 ) ) {
290
309
derivative_groups. insert (
@@ -301,40 +320,7 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
301
320
302
321
let spot_market = spot_market_map. get_ref ( & constituent. spot_market_index ) ?;
303
322
304
- let oracle_data = oracle_map. get_price_data_and_validity (
305
- MarketType :: Spot ,
306
- constituent. spot_market_index ,
307
- & spot_market. oracle_id ( ) ,
308
- spot_market. historical_oracle_data . last_oracle_price_twap ,
309
- spot_market. get_max_confidence_interval_multiplier ( ) ?,
310
- 0 ,
311
- ) ?;
312
-
313
- let oracle_slot = slot - oracle_data. 0 . delay . max ( 0i64 ) . cast :: < u64 > ( ) ?;
314
- let oracle_price: Option < i64 > = {
315
- if !is_oracle_valid_for_action ( oracle_data. 1 , Some ( DriftAction :: UpdateLpPoolAum ) ) ? {
316
- msg ! (
317
- "Oracle data for spot market {} is invalid. Skipping update" ,
318
- spot_market. market_index,
319
- ) ;
320
- if slot. saturating_sub ( constituent. last_oracle_slot )
321
- >= constituent. oracle_staleness_threshold
322
- {
323
- None
324
- } else {
325
- Some ( constituent. last_oracle_price )
326
- }
327
- } else {
328
- Some ( oracle_data. 0 . price )
329
- }
330
- } ;
331
-
332
- if oracle_price. is_none ( ) {
333
- return Err ( ErrorCode :: OracleTooStaleForLPAUMUpdate . into ( ) ) ;
334
- }
335
-
336
- constituent. last_oracle_price = oracle_price. unwrap ( ) ;
337
- constituent. last_oracle_slot = oracle_slot;
323
+ let oracle_slot = constituent. last_oracle_slot ;
338
324
339
325
if oracle_slot < oldest_slot {
340
326
oldest_slot = oracle_slot;
@@ -350,7 +336,7 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
350
336
. get_full_balance ( & spot_market) ?
351
337
. safe_mul ( numerator_scale) ?
352
338
. safe_div ( denominator_scale) ?
353
- . safe_mul ( oracle_price . unwrap ( ) as i128 ) ?
339
+ . safe_mul ( constituent . last_oracle_price as i128 ) ?
354
340
. safe_div ( PRICE_PRECISION_I128 ) ?
355
341
. max ( 0 ) ;
356
342
msg ! (
@@ -366,15 +352,15 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
366
352
. get ( constituent. constituent_index as u32 )
367
353
. target_base
368
354
. safe_mul ( constituent. last_oracle_price ) ?
369
- . safe_div ( 10_i64 . pow ( spot_market . decimals as u32 ) ) ?;
355
+ . safe_div ( 10_i64 . pow ( constituent . decimals as u32 ) ) ?;
370
356
crypto_delta = crypto_delta. safe_add ( constituent_target_notional. cast ( ) ?) ?;
371
357
}
372
358
aum = aum. safe_add ( constituent_aum. cast ( ) ?) ?;
373
359
}
374
360
375
361
for cache_datum in amm_cache. iter ( ) {
376
362
if cache_datum. quote_owed_from_lp > 0 {
377
- aum = aum. safe_sub ( cache_datum. quote_owed_from_lp . abs ( ) . cast :: < u128 > ( ) ?) ? ;
363
+ aum = aum. saturating_sub ( cache_datum. quote_owed_from_lp . abs ( ) . cast :: < u128 > ( ) ?) ;
378
364
} else {
379
365
aum = aum. safe_add ( cache_datum. quote_owed_from_lp . abs ( ) . cast :: < u128 > ( ) ?) ?;
380
366
}
@@ -487,6 +473,15 @@ pub fn handle_lp_pool_swap<'c: 'info, 'info>(
487
473
let state = & ctx. accounts . state ;
488
474
let lp_pool = & ctx. accounts . lp_pool . load ( ) ?;
489
475
476
+ if slot. saturating_sub ( lp_pool. last_aum_slot ) > LP_POOL_SWAP_AUM_UPDATE_DELAY {
477
+ msg ! (
478
+ "Must update LP pool AUM before swap, last_aum_slot: {}, current slot: {}" ,
479
+ lp_pool. last_aum_slot,
480
+ slot
481
+ ) ;
482
+ return Err ( ErrorCode :: LpPoolAumDelayed . into ( ) ) ;
483
+ }
484
+
490
485
let mut in_constituent = ctx. accounts . in_constituent . load_mut ( ) ?;
491
486
let mut out_constituent = ctx. accounts . out_constituent . load_mut ( ) ?;
492
487
@@ -729,6 +724,15 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(
729
724
let state = & ctx. accounts . state ;
730
725
let mut lp_pool = ctx. accounts . lp_pool . load_mut ( ) ?;
731
726
727
+ if slot. saturating_sub ( lp_pool. last_aum_slot ) > LP_POOL_SWAP_AUM_UPDATE_DELAY {
728
+ msg ! (
729
+ "Must update LP pool AUM before swap, last_aum_slot: {}, current slot: {}" ,
730
+ lp_pool. last_aum_slot,
731
+ slot
732
+ ) ;
733
+ return Err ( ErrorCode :: LpPoolAumDelayed . into ( ) ) ;
734
+ }
735
+
732
736
let mut in_constituent = ctx. accounts . in_constituent . load_mut ( ) ?;
733
737
734
738
let constituent_target_base = ctx. accounts . constituent_target_base . load_zc ( ) ?;
@@ -917,6 +921,15 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>(
917
921
let state = & ctx. accounts . state ;
918
922
let mut lp_pool = ctx. accounts . lp_pool . load_mut ( ) ?;
919
923
924
+ if slot. saturating_sub ( lp_pool. last_aum_slot ) > LP_POOL_SWAP_AUM_UPDATE_DELAY {
925
+ msg ! (
926
+ "Must update LP pool AUM before swap, last_aum_slot: {}, current slot: {}" ,
927
+ lp_pool. last_aum_slot,
928
+ slot
929
+ ) ;
930
+ return Err ( ErrorCode :: LpPoolAumDelayed . into ( ) ) ;
931
+ }
932
+
920
933
let mut out_constituent = ctx. accounts . out_constituent . load_mut ( ) ?;
921
934
922
935
let constituent_target_base = ctx. accounts . constituent_target_base . load_zc ( ) ?;
0 commit comments