diff --git a/CHANGELOG.md b/CHANGELOG.md index ae2d4751ed..6ba708082b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- program: perp market amm oracle delay override ([#1679](https://github.com/drift-labs/protocol-v2/pull/1679)) - program: sanitize long tail perp market orders less frequently ([#1641](https://github.com/drift-labs/protocol-v2/pull/1641)) ### Fixes diff --git a/programs/drift/src/controller/orders.rs b/programs/drift/src/controller/orders.rs index f2c437ada1..5d9818172b 100644 --- a/programs/drift/src/controller/orders.rs +++ b/programs/drift/src/controller/orders.rs @@ -1074,6 +1074,7 @@ pub fn fill_perp_order( &market.oracle_id(), market.amm.historical_oracle_data.last_oracle_price_twap, market.get_max_confidence_interval_multiplier()?, + market.amm.oracle_slot_delay_override, )?; oracle_valid_for_amm_fill = @@ -2987,6 +2988,7 @@ pub fn trigger_order( .historical_oracle_data .last_oracle_price_twap, perp_market.get_max_confidence_interval_multiplier()?, + 0, )?; let is_oracle_valid = @@ -5341,6 +5343,7 @@ pub fn trigger_spot_order( &spot_market.oracle_id(), spot_market.historical_oracle_data.last_oracle_price_twap, spot_market.get_max_confidence_interval_multiplier()?, + 0, )?; let strict_oracle_price = StrictOraclePrice { current: oracle_price_data.price, diff --git a/programs/drift/src/controller/orders/tests.rs b/programs/drift/src/controller/orders/tests.rs index 475393c563..2f752066b8 100644 --- a/programs/drift/src/controller/orders/tests.rs +++ b/programs/drift/src/controller/orders/tests.rs @@ -2159,6 +2159,7 @@ pub mod fulfill_order_with_maker_order { &(oracle_price_key, OracleSource::Pyth), market.amm.historical_oracle_data.last_oracle_price_twap, market.get_max_confidence_interval_multiplier().unwrap(), + 0, ) .unwrap(); diff --git a/programs/drift/src/controller/pnl.rs b/programs/drift/src/controller/pnl.rs index 8f34da5061..13c29ada7d 100644 --- a/programs/drift/src/controller/pnl.rs +++ b/programs/drift/src/controller/pnl.rs @@ -165,6 +165,7 @@ pub fn settle_pnl( .historical_oracle_data .last_oracle_price_twap, perp_market.get_max_confidence_interval_multiplier()?, + 0, )?; if !is_oracle_valid_for_action(oracle_validity, Some(DriftAction::SettlePnl))? diff --git a/programs/drift/src/controller/repeg.rs b/programs/drift/src/controller/repeg.rs index 965895715d..a9f55fe107 100644 --- a/programs/drift/src/controller/repeg.rs +++ b/programs/drift/src/controller/repeg.rs @@ -161,6 +161,7 @@ pub fn _update_amm( market.get_max_confidence_interval_multiplier()?, &market.amm.oracle_source, true, + 0, )?; let mut amm_update_cost = 0; @@ -249,6 +250,7 @@ pub fn update_amm_and_check_validity( market.get_max_confidence_interval_multiplier()?, &market.amm.oracle_source, false, + 0, )?; validate!( diff --git a/programs/drift/src/controller/repeg/tests.rs b/programs/drift/src/controller/repeg/tests.rs index 1131b58b1c..4871e653c7 100644 --- a/programs/drift/src/controller/repeg/tests.rs +++ b/programs/drift/src/controller/repeg/tests.rs @@ -107,6 +107,7 @@ pub fn update_amm_test() { market.get_max_confidence_interval_multiplier().unwrap(), &market.amm.oracle_source, false, + 0, ) .unwrap() == OracleValidity::Valid; @@ -235,6 +236,7 @@ pub fn update_amm_test_bad_oracle() { market.get_max_confidence_interval_multiplier().unwrap(), &market.amm.oracle_source, false, + 0, ) .unwrap() == OracleValidity::Valid; diff --git a/programs/drift/src/controller/spot_balance.rs b/programs/drift/src/controller/spot_balance.rs index 724df7c591..11f9511c02 100644 --- a/programs/drift/src/controller/spot_balance.rs +++ b/programs/drift/src/controller/spot_balance.rs @@ -404,6 +404,7 @@ pub fn update_spot_market_and_check_validity( spot_market.get_max_confidence_interval_multiplier()?, &spot_market.oracle_source, false, + 0, )?; validate!( diff --git a/programs/drift/src/instructions/admin.rs b/programs/drift/src/instructions/admin.rs index 7bb4411258..65efdc8ca0 100644 --- a/programs/drift/src/instructions/admin.rs +++ b/programs/drift/src/instructions/admin.rs @@ -1040,7 +1040,7 @@ pub fn handle_initialize_perp_market( last_oracle_valid: false, target_base_asset_amount_per_lp: 0, per_lp_base: 0, - padding1: 0, + oracle_slot_delay_override: 0, taker_speed_bump_override: 0, amm_spread_adjustment: 0, total_fee_earned_per_lp: 0, @@ -4028,6 +4028,26 @@ pub fn handle_update_perp_market_amm_spread_adjustment( Ok(()) } +#[access_control( + perp_market_valid(&ctx.accounts.perp_market) +)] +pub fn handle_update_perp_market_oracle_slot_delay_override( + ctx: Context, + oracle_slot_delay_override: i8, +) -> Result<()> { + let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; + msg!("perp market {}", perp_market.market_index); + + msg!( + "perp_market.amm.oracle_slot_delay_override: {:?} -> {:?}", + perp_market.amm.oracle_slot_delay_override, + oracle_slot_delay_override + ); + + perp_market.amm.oracle_slot_delay_override = oracle_slot_delay_override; + Ok(()) +} + #[access_control( spot_market_valid(&ctx.accounts.spot_market) )] diff --git a/programs/drift/src/instructions/user.rs b/programs/drift/src/instructions/user.rs index a3a7ce6d7e..0b4307c639 100644 --- a/programs/drift/src/instructions/user.rs +++ b/programs/drift/src/instructions/user.rs @@ -1627,6 +1627,7 @@ pub fn handle_transfer_perp_position<'c: 'info, 'info>( .historical_oracle_data .last_oracle_price_twap, perp_market.get_max_confidence_interval_multiplier()?, + perp_market.amm.oracle_slot_delay_override, )?; step_size = perp_market.amm.order_step_size; tick_size = perp_market.amm.order_tick_size; diff --git a/programs/drift/src/lib.rs b/programs/drift/src/lib.rs index cf6fa3bdef..e77fb8244e 100644 --- a/programs/drift/src/lib.rs +++ b/programs/drift/src/lib.rs @@ -1547,6 +1547,13 @@ pub mod drift { handle_update_perp_market_amm_spread_adjustment(ctx, amm_spread_adjustment) } + pub fn update_perp_market_oracle_slot_delay_override( + ctx: Context, + oracle_slot_delay_override: i8, + ) -> Result<()> { + handle_update_perp_market_oracle_slot_delay_override(ctx, oracle_slot_delay_override) + } + pub fn update_spot_market_fuel( ctx: Context, fuel_boost_deposits: Option, diff --git a/programs/drift/src/math/margin.rs b/programs/drift/src/math/margin.rs index 580f826796..73415cb58b 100644 --- a/programs/drift/src/math/margin.rs +++ b/programs/drift/src/math/margin.rs @@ -268,6 +268,7 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info( &spot_market.oracle_id(), spot_market.historical_oracle_data.last_oracle_price_twap, spot_market.get_max_confidence_interval_multiplier()?, + 0, )?; let mut skip_token_value = false; @@ -519,6 +520,7 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info( .historical_oracle_data .last_oracle_price_twap, quote_spot_market.get_max_confidence_interval_multiplier()?, + 0, )?; let strict_quote_price = StrictOraclePrice::new( @@ -536,6 +538,7 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info( &market.oracle_id(), market.amm.historical_oracle_data.last_oracle_price_twap, market.get_max_confidence_interval_multiplier()?, + 0, )?; let ( @@ -909,6 +912,7 @@ pub fn calculate_user_equity( &spot_market.oracle_id(), spot_market.historical_oracle_data.last_oracle_price_twap, spot_market.get_max_confidence_interval_multiplier()?, + 0, )?; all_oracles_valid &= is_oracle_valid_for_action(oracle_validity, Some(DriftAction::MarginCalc))?; @@ -938,6 +942,7 @@ pub fn calculate_user_equity( .historical_oracle_data .last_oracle_price_twap, quote_spot_market.get_max_confidence_interval_multiplier()?, + 0, )?; all_oracles_valid &= @@ -952,6 +957,7 @@ pub fn calculate_user_equity( &market.oracle_id(), market.amm.historical_oracle_data.last_oracle_price_twap, market.get_max_confidence_interval_multiplier()?, + 0, )?; all_oracles_valid &= diff --git a/programs/drift/src/math/oracle.rs b/programs/drift/src/math/oracle.rs index 621bf90697..13d5da5fa0 100644 --- a/programs/drift/src/math/oracle.rs +++ b/programs/drift/src/math/oracle.rs @@ -188,6 +188,7 @@ pub fn get_oracle_status( market.get_max_confidence_interval_multiplier()?, &market.amm.oracle_source, false, + 0, )?; let oracle_reserve_price_spread_pct = amm::calculate_oracle_twap_5min_price_spread_pct(&market.amm, reserve_price)?; @@ -213,6 +214,7 @@ pub fn oracle_validity( max_confidence_interval_multiplier: u64, oracle_source: &OracleSource, log_validity: bool, + slots_before_stale_for_amm_override: i8, ) -> DriftResult { let OraclePriceData { price: oracle_price, @@ -237,7 +239,11 @@ pub fn oracle_validity( .confidence_interval_max_size .safe_mul(max_confidence_interval_multiplier)?); - let is_stale_for_amm = oracle_delay.gt(&valid_oracle_guard_rails.slots_before_stale_for_amm); + let is_stale_for_amm = if slots_before_stale_for_amm_override != 0 { + oracle_delay.gt(&slots_before_stale_for_amm_override.max(0).cast()?) + } else { + oracle_delay.gt(&valid_oracle_guard_rails.slots_before_stale_for_amm) + }; let is_stale_for_margin = if matches!( oracle_source, diff --git a/programs/drift/src/math/repeg.rs b/programs/drift/src/math/repeg.rs index 3d7d0088ef..725e404d5f 100644 --- a/programs/drift/src/math/repeg.rs +++ b/programs/drift/src/math/repeg.rs @@ -45,6 +45,7 @@ pub fn calculate_repeg_validity_from_oracle_account( market.get_max_confidence_interval_multiplier()?, &market.amm.oracle_source, true, + 0, )? == OracleValidity::Valid; let (oracle_is_valid, direction_valid, profitability_valid, price_impact_valid) = diff --git a/programs/drift/src/state/oracle_map.rs b/programs/drift/src/state/oracle_map.rs index 441260bd91..9f70ec4a92 100644 --- a/programs/drift/src/state/oracle_map.rs +++ b/programs/drift/src/state/oracle_map.rs @@ -88,6 +88,7 @@ impl<'a> OracleMap<'a> { oracle_id: &OracleIdentifier, last_oracle_price_twap: i64, max_confidence_interval_multiplier: u64, + slots_before_stale_for_amm_override: i8, ) -> DriftResult<(&OraclePriceData, OracleValidity)> { if self.should_get_quote_asset_price_data(&oracle_id.0) { return Ok((&self.quote_asset_price_data, OracleValidity::Valid)); @@ -108,6 +109,7 @@ impl<'a> OracleMap<'a> { max_confidence_interval_multiplier, &oracle_id.1, true, + slots_before_stale_for_amm_override, )?; self.validity.insert(*oracle_id, oracle_validity); oracle_validity @@ -137,6 +139,7 @@ impl<'a> OracleMap<'a> { max_confidence_interval_multiplier, &oracle_id.1, true, + slots_before_stale_for_amm_override, )?; self.validity.insert(*oracle_id, oracle_validity); diff --git a/programs/drift/src/state/perp_market.rs b/programs/drift/src/state/perp_market.rs index 94a5ef9e81..21ea5e1ad9 100644 --- a/programs/drift/src/state/perp_market.rs +++ b/programs/drift/src/state/perp_market.rs @@ -1050,7 +1050,7 @@ pub struct AMM { pub taker_speed_bump_override: i8, /// signed scale amm_spread similar to fee_adjustment logic (-100 = 0, 100 = double) pub amm_spread_adjustment: i8, - pub padding1: u8, + pub oracle_slot_delay_override: i8, pub total_fee_earned_per_lp: u64, pub net_unsettled_funding_pnl: i64, pub quote_asset_amount_with_unsettled_lp: i64, @@ -1140,7 +1140,7 @@ impl Default for AMM { per_lp_base: 0, taker_speed_bump_override: 0, amm_spread_adjustment: 0, - padding1: 0, + oracle_slot_delay_override: 0, total_fee_earned_per_lp: 0, net_unsettled_funding_pnl: 0, quote_asset_amount_with_unsettled_lp: 0,