11use std:: collections:: BTreeMap ;
2+ use std:: f32:: consts:: E ;
23
34use crate :: error:: { DriftResult , ErrorCode } ;
45use crate :: math:: casting:: Cast ;
56use crate :: math:: constants:: {
67 BASE_PRECISION_I128 , PERCENTAGE_PRECISION , PERCENTAGE_PRECISION_I128 , PERCENTAGE_PRECISION_I64 ,
78 PERCENTAGE_PRECISION_U64 , PRICE_PRECISION , QUOTE_PRECISION_I128 , QUOTE_PRECISION_U64 ,
89} ;
10+ use crate :: math:: oracle:: { is_oracle_valid_for_action, DriftAction } ;
911use crate :: math:: safe_math:: SafeMath ;
1012use crate :: math:: safe_unwrap:: SafeUnwrap ;
1113use crate :: math:: spot_balance:: { get_signed_token_amount, get_token_amount} ;
1214use crate :: state:: amm_cache:: { AmmCacheFixed , CacheInfo } ;
1315use crate :: state:: constituent_map:: ConstituentMap ;
16+ use crate :: state:: oracle_map:: OracleMap ;
1417use crate :: state:: paused_operations:: ConstituentLpOperation ;
1518use crate :: state:: spot_market_map:: SpotMarketMap ;
19+ use crate :: state:: user:: MarketType ;
1620use anchor_lang:: prelude:: * ;
1721use borsh:: { BorshDeserialize , BorshSerialize } ;
1822use enumflags2:: BitFlags ;
@@ -32,9 +36,8 @@ pub const CONSTITUENT_CORRELATIONS_PDA_SEED: &str = "constituent_correlations";
3236pub const CONSTITUENT_VAULT_PDA_SEED : & str = "CONSTITUENT_VAULT" ;
3337pub const LP_POOL_TOKEN_VAULT_PDA_SEED : & str = "LP_POOL_TOKEN_VAULT" ;
3438
35- pub const BASE_SWAP_FEE : i128 = 300 ; // 0.75% in PERCENTAGE_PRECISION
36- pub const MAX_SWAP_FEE : i128 = 75_000 ; // 0.75% in PERCENTAGE_PRECISION
37- pub const MIN_SWAP_FEE : i128 = 200 ; // 0.75% in PERCENTAGE_PRECISION
39+ pub const BASE_SWAP_FEE : i128 = 300 ; // 0.3% in PERCENTAGE_PRECISION
40+ pub const MAX_SWAP_FEE : i128 = 37_500 ; // 37.5% in PERCENTAGE_PRECISION
3841
3942pub const MIN_AUM_EXECUTION_FEE : u128 = 10_000_000_000_000 ;
4043
@@ -225,6 +228,9 @@ impl LPPool {
225228 out_target_oracle_slot_delay,
226229 ) ?;
227230
231+ in_fee = in_fee. min ( MAX_SWAP_FEE ) ;
232+ out_fee = out_fee. min ( MAX_SWAP_FEE ) ;
233+
228234 let in_fee_amount = in_amount
229235 . cast :: < i128 > ( ) ?
230236 . safe_mul ( in_fee) ?
@@ -279,6 +285,7 @@ impl LPPool {
279285 in_target_position_slot_delay,
280286 in_target_oracle_slot_delay,
281287 ) ?;
288+ in_fee_pct = in_fee_pct. min ( MAX_SWAP_FEE * 2 ) ;
282289
283290 let in_fee_amount = in_amount
284291 . cast :: < i128 > ( ) ?
@@ -383,6 +390,8 @@ impl LPPool {
383390 out_target_oracle_slot_delay,
384391 ) ?;
385392 out_fee_pct = in_fee_pct. safe_add ( out_fee_pct) ?;
393+ out_fee_pct = out_fee_pct. min ( MAX_SWAP_FEE * 2 ) ;
394+
386395 let out_fee_amount = out_amount
387396 . cast :: < i128 > ( ) ?
388397 . safe_mul ( out_fee_pct) ?
@@ -629,10 +638,7 @@ impl LPPool {
629638 . safe_add ( out_quadratic_inventory_fee) ?
630639 . safe_add ( BASE_SWAP_FEE . safe_div ( 2 ) ?) ?;
631640
632- Ok ( (
633- total_in_fee. min ( MAX_SWAP_FEE . safe_div ( 2 ) ?) ,
634- total_out_fee. min ( MAX_SWAP_FEE . safe_div ( 2 ) ?) ,
635- ) )
641+ Ok ( ( total_in_fee, total_out_fee) )
636642 }
637643
638644 pub fn get_target_uncertainty_fees (
@@ -686,6 +692,7 @@ impl LPPool {
686692 slot : u64 ,
687693 constituent_map : & ConstituentMap ,
688694 spot_market_map : & SpotMarketMap ,
695+ oracle_map : & mut OracleMap ,
689696 constituent_target_base : & AccountZeroCopyMut < ' _ , TargetsDatum , ConstituentTargetBaseFixed > ,
690697 amm_cache : & AccountZeroCopyMut < ' _ , CacheInfo , AmmCacheFixed > ,
691698 ) -> DriftResult < ( u128 , i128 , BTreeMap < u16 , Vec < u16 > > ) > {
@@ -723,10 +730,28 @@ impl LPPool {
723730 }
724731
725732 let spot_market = spot_market_map. get_ref ( & constituent. spot_market_index ) ?;
733+ let oracle_and_validity = oracle_map. get_price_data_and_validity (
734+ MarketType :: Spot ,
735+ constituent. spot_market_index ,
736+ & spot_market. oracle_id ( ) ,
737+ spot_market. historical_oracle_data . last_oracle_price_twap ,
738+ spot_market. get_max_confidence_interval_multiplier ( ) ?,
739+ 0 ,
740+ ) ?;
741+ if !is_oracle_valid_for_action (
742+ oracle_and_validity. 1 ,
743+ Some ( DriftAction :: UpdateLpPoolAum ) ,
744+ ) ? {
745+ msg ! (
746+ "Constituent {} oracle is not valid for action" ,
747+ constituent. constituent_index
748+ ) ;
749+ return Err ( ErrorCode :: InvalidOracle . into ( ) ) ;
750+ }
726751
727752 let constituent_aum = constituent
728753 . get_full_token_amount ( & spot_market) ?
729- . safe_mul ( constituent . last_oracle_price as i128 ) ?
754+ . safe_mul ( oracle_and_validity . 0 . price as i128 ) ?
730755 . safe_div ( 10_i128 . pow ( spot_market. decimals ) ) ?;
731756 msg ! (
732757 "constituent: {}, balance: {}, aum: {}, deriv index: {}, bl token balance {}, bl balance type {}, vault balance: {}" ,
@@ -747,7 +772,7 @@ impl LPPool {
747772 . get ( constituent. constituent_index as u32 )
748773 . target_base
749774 . cast :: < i128 > ( ) ?
750- . safe_mul ( constituent . last_oracle_price . cast :: < i128 > ( ) ?) ?
775+ . safe_mul ( oracle_and_validity . 0 . price . cast :: < i128 > ( ) ?) ?
751776 . safe_div ( 10_i128 . pow ( constituent. decimals as u32 ) ) ?
752777 . cast :: < i64 > ( ) ?;
753778 crypto_delta = crypto_delta. safe_add ( constituent_target_notional. cast ( ) ?) ?;
@@ -1579,8 +1604,8 @@ impl ConstituentCorrelations {
15791604 "ConstituentCorrelation correlations must be between 0 and PERCENTAGE_PRECISION"
15801605 ) ?;
15811606
1582- self . correlations [ ( i as usize * num_constituents + j as usize ) ] = corr;
1583- self . correlations [ ( j as usize * num_constituents + i as usize ) ] = corr;
1607+ self . correlations [ i as usize * num_constituents + j as usize ] = corr;
1608+ self . correlations [ j as usize * num_constituents + i as usize ] = corr;
15841609
15851610 self . validate ( ) ?;
15861611
@@ -1662,34 +1687,81 @@ pub fn update_constituent_target_base_for_derivatives(
16621687 derivative_groups : & BTreeMap < u16 , Vec < u16 > > ,
16631688 constituent_map : & ConstituentMap ,
16641689 spot_market_map : & SpotMarketMap ,
1690+ oracle_map : & mut OracleMap ,
16651691 constituent_target_base : & mut AccountZeroCopyMut < ' _ , TargetsDatum , ConstituentTargetBaseFixed > ,
16661692) -> DriftResult < ( ) > {
16671693 for ( parent_index, constituent_indexes) in derivative_groups. iter ( ) {
16681694 let parent_constituent = constituent_map. get_ref ( parent_index) ?;
1695+
1696+ let parent_spot_market = spot_market_map. get_ref ( & parent_constituent. spot_market_index ) ?;
1697+ let parent_oracle_price_and_validity = oracle_map. get_price_data_and_validity (
1698+ MarketType :: Spot ,
1699+ parent_spot_market. market_index ,
1700+ & parent_spot_market. oracle_id ( ) ,
1701+ parent_spot_market
1702+ . historical_oracle_data
1703+ . last_oracle_price_twap ,
1704+ parent_spot_market. get_max_confidence_interval_multiplier ( ) ?,
1705+ 0 ,
1706+ ) ?;
1707+ if !is_oracle_valid_for_action (
1708+ parent_oracle_price_and_validity. 1 ,
1709+ Some ( DriftAction :: UpdateLpPoolAum ) ,
1710+ ) ? {
1711+ msg ! (
1712+ "Parent constituent {} oracle is invalid" ,
1713+ parent_constituent. constituent_index
1714+ ) ;
1715+ return Err ( ErrorCode :: InvalidOracle ) ;
1716+ }
1717+ let parent_constituent_price = parent_oracle_price_and_validity. 0 . price ;
1718+
16691719 let parent_target_base = constituent_target_base
16701720 . get ( * parent_index as u32 )
16711721 . target_base ;
16721722 let target_parent_weight = calculate_target_weight (
16731723 parent_target_base,
16741724 & * spot_market_map. get_ref ( & parent_constituent. spot_market_index ) ?,
1675- parent_constituent . last_oracle_price ,
1725+ parent_oracle_price_and_validity . 0 . price ,
16761726 aum,
16771727 ) ?;
16781728 let mut derivative_weights_sum: u64 = 0 ;
16791729 for constituent_index in constituent_indexes {
16801730 let constituent = constituent_map. get_ref ( constituent_index) ?;
1681- if constituent. last_oracle_price
1682- < parent_constituent
1683- . last_oracle_price
1731+ let constituent_spot_market =
1732+ spot_market_map. get_ref ( & constituent. spot_market_index ) ?;
1733+ let constituent_oracle_price_and_validity = oracle_map. get_price_data_and_validity (
1734+ MarketType :: Spot ,
1735+ constituent. spot_market_index ,
1736+ & constituent_spot_market. oracle_id ( ) ,
1737+ constituent_spot_market
1738+ . historical_oracle_data
1739+ . last_oracle_price_twap ,
1740+ constituent_spot_market. get_max_confidence_interval_multiplier ( ) ?,
1741+ 0 ,
1742+ ) ?;
1743+ if !is_oracle_valid_for_action (
1744+ constituent_oracle_price_and_validity. 1 ,
1745+ Some ( DriftAction :: UpdateLpPoolAum ) ,
1746+ ) ? {
1747+ msg ! (
1748+ "Constituent {} oracle is invalid" ,
1749+ constituent. constituent_index
1750+ ) ;
1751+ return Err ( ErrorCode :: InvalidOracle ) ;
1752+ }
1753+
1754+ if constituent_oracle_price_and_validity. 0 . price
1755+ < parent_constituent_price
16841756 . safe_mul ( constituent. constituent_derivative_depeg_threshold as i64 ) ?
16851757 . safe_div ( PERCENTAGE_PRECISION_I64 ) ?
16861758 {
16871759 msg ! (
16881760 "Constituent {} last oracle price {} is too low compared to parent constituent {} last oracle price {}. Assuming depegging and setting target base to 0." ,
16891761 constituent. constituent_index,
1690- constituent . last_oracle_price ,
1762+ constituent_oracle_price_and_validity . 0 . price ,
16911763 parent_constituent. constituent_index,
1692- parent_constituent . last_oracle_price
1764+ parent_constituent_price
16931765 ) ;
16941766 constituent_target_base
16951767 . get_mut ( * constituent_index as u32 )
@@ -1714,7 +1786,7 @@ pub fn update_constituent_target_base_for_derivatives(
17141786 . safe_mul ( target_weight) ?
17151787 . safe_div ( PERCENTAGE_PRECISION_I128 ) ?
17161788 . safe_mul ( 10_i128 . pow ( constituent. decimals as u32 ) ) ?
1717- . safe_div ( constituent . last_oracle_price as i128 ) ?;
1789+ . safe_div ( constituent_oracle_price_and_validity . 0 . price as i128 ) ?;
17181790
17191791 msg ! (
17201792 "constituent: {}, target base: {}" ,
0 commit comments