11use crate :: error:: { DriftResult , ErrorCode } ;
22use crate :: math:: casting:: Cast ;
33use crate :: math:: constants:: {
4- BASE_PRECISION_I64 , PERCENTAGE_PRECISION_I128 , PERCENTAGE_PRECISION_I64 , QUOTE_PRECISION ,
4+ BASE_PRECISION_I128 , BASE_PRECISION_I64 , PERCENTAGE_PRECISION_I128 , PERCENTAGE_PRECISION_I64 ,
5+ QUOTE_PRECISION ,
56} ;
67use crate :: math:: safe_math:: SafeMath ;
78use crate :: math:: spot_balance:: get_token_amount;
@@ -565,7 +566,7 @@ impl Constituent {
565566// }
566567
567568#[ zero_copy]
568- #[ derive( Debug , Default , BorshDeserialize , BorshSerialize ) ]
569+ #[ derive( Debug , BorshDeserialize , BorshSerialize ) ]
569570#[ repr( C ) ]
570571pub struct AmmConstituentDatum {
571572 pub perp_market_index : u16 ,
@@ -576,6 +577,18 @@ pub struct AmmConstituentDatum {
576577 pub weight : i64 ,
577578}
578579
580+ impl Default for AmmConstituentDatum {
581+ fn default ( ) -> Self {
582+ AmmConstituentDatum {
583+ perp_market_index : u16:: MAX ,
584+ constituent_index : u16:: MAX ,
585+ _padding : [ 0 ; 4 ] ,
586+ last_slot : 0 ,
587+ weight : 0 ,
588+ }
589+ }
590+ }
591+
579592#[ zero_copy]
580593#[ derive( Debug , Default ) ]
581594#[ repr( C ) ]
@@ -745,13 +758,15 @@ pub fn calculate_target_weight(
745758 lp_pool_aum : u128 ,
746759 validation_flags : WeightValidationFlags ,
747760) -> DriftResult < i64 > {
748- let notional = target_base. safe_mul ( price) ?. safe_div ( BASE_PRECISION_I64 ) ?;
761+ let notional: i128 = ( target_base as i128 )
762+ . safe_mul ( price as i128 ) ?
763+ . safe_div ( BASE_PRECISION_I128 ) ?;
749764
750765 let target_weight = notional
751- . cast :: < i128 > ( ) ?
752766 . safe_mul ( PERCENTAGE_PRECISION_I128 ) ?
753767 . safe_div ( lp_pool_aum. cast :: < i128 > ( ) ?) ?
754- . cast :: < i64 > ( ) ?;
768+ . cast :: < i64 > ( ) ?
769+ . clamp ( -1 * PERCENTAGE_PRECISION_I64 , PERCENTAGE_PRECISION_I64 ) ;
755770
756771 // if (validation_flags as u8 & (WeightValidationFlags::NoNegativeWeights as u8) != 0)
757772 // && target_weight < 0
@@ -781,37 +796,57 @@ impl<'a> AccountZeroCopyMut<'a, TargetsDatum, ConstituentTargetBaseFixed> {
781796 & mut self ,
782797 mapping : & AccountZeroCopy < ' a , AmmConstituentDatum , AmmConstituentMappingFixed > ,
783798 // (perp market index, inventory, price)
784- amm_inventory : & [ ( u16 , i64 ) ] ,
785- constituents_indexes : & [ u16 ] ,
799+ amm_inventory_and_prices : & [ ( u16 , i64 , i64 ) ] ,
800+ constituents_indexes_and_prices : & [ ( u16 , i64 ) ] ,
786801 slot : u64 ,
787802 ) -> DriftResult < Vec < i128 > > {
788- let mut results = Vec :: with_capacity ( constituents_indexes. len ( ) ) ;
789-
790- for ( i, constituent_index) in constituents_indexes. iter ( ) . enumerate ( ) {
791- let mut target_amount = 0i128 ;
792-
793- for ( perp_market_index, inventory) in amm_inventory. iter ( ) {
794- let idx = mapping
795- . iter ( )
796- . position ( |d| & d. perp_market_index == perp_market_index)
797- . expect ( "missing mapping for this market index" ) ;
798- let weight = mapping. get ( idx as u32 ) . weight ; // PERCENTAGE_PRECISION
799-
800- target_amount += ( * inventory as i128 )
803+ let mut results = Vec :: with_capacity ( constituents_indexes_and_prices. len ( ) ) ;
804+ for ( i, constituent_index_and_price) in constituents_indexes_and_prices. iter ( ) . enumerate ( ) {
805+ let mut target_notional = 0i128 ;
806+ let constituent_index = constituent_index_and_price. 0 ;
807+ let price = constituent_index_and_price. 1 ;
808+
809+ for ( perp_market_index, inventory, price) in amm_inventory_and_prices. iter ( ) {
810+ let idx = mapping. iter ( ) . position ( |d| {
811+ & d. perp_market_index == perp_market_index
812+ && d. constituent_index == constituent_index
813+ } ) ;
814+ if idx. is_none ( ) {
815+ msg ! (
816+ "No mapping found for perp market index {} and constituent index {}" ,
817+ perp_market_index,
818+ constituent_index
819+ ) ;
820+ continue ;
821+ }
822+
823+ let weight = mapping. get ( idx. unwrap ( ) as u32 ) . weight ; // PERCENTAGE_PRECISION
824+
825+ let notional: i128 = ( * inventory as i128 )
826+ . safe_mul ( * price as i128 ) ?
827+ . safe_div ( BASE_PRECISION_I128 ) ?;
828+
829+ target_notional += notional
801830 . saturating_mul ( weight as i128 )
802- . saturating_div ( PERCENTAGE_PRECISION_I64 as i128 ) ;
831+ . saturating_div ( PERCENTAGE_PRECISION_I128 ) ;
803832 }
804833
805834 let cell = self . get_mut ( i as u32 ) ;
835+ let target_base = target_notional
836+ . safe_mul ( BASE_PRECISION_I128 ) ?
837+ . safe_div ( price as i128 ) ?
838+ * -1 ; // Want to target opposite sign of total scaled notional inventory
839+
806840 msg ! (
807- "updating constituent index {} target amount to {}" ,
841+ "updating constituent index {} target base to {} from target notional {}" ,
808842 constituent_index,
809- target_amount
843+ target_base,
844+ target_notional,
810845 ) ;
811- cell. target_base = target_amount as i64 ;
846+ cell. target_base = target_base . cast :: < i64 > ( ) ? ;
812847 cell. last_slot = slot;
813848
814- results. push ( target_amount ) ;
849+ results. push ( target_base ) ;
815850 }
816851
817852 Ok ( results)
@@ -825,7 +860,9 @@ impl<'a> AccountZeroCopyMut<'a, AmmConstituentDatum, AmmConstituentMappingFixed>
825860 let mut open_slot_index: Option < u32 > = None ;
826861 for i in 0 ..len {
827862 let cell = self . get ( i as u32 ) ;
828- if cell. constituent_index == datum. constituent_index {
863+ if cell. constituent_index == datum. constituent_index
864+ && cell. perp_market_index == datum. perp_market_index
865+ {
829866 return Err ( ErrorCode :: DefaultError ) ;
830867 }
831868 if cell. last_slot == 0 && open_slot_index. is_none ( ) {
0 commit comments