Skip to content

Commit 0cd3560

Browse files
authored
Target delay increases fees (#1943)
* only update the last slot if the oracles and perp positions pass the check per constituent * add in uncertainty fee * add simple test for target delays * change target base seed * prettify
1 parent 69afe90 commit 0cd3560

File tree

8 files changed

+391
-124
lines changed

8 files changed

+391
-124
lines changed

programs/drift/src/instructions/keeper.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ use crate::math::spot_withdraw::validate_spot_market_vault_amount;
4242
use crate::optional_accounts::{get_token_mint, update_prelaunch_oracle};
4343
use crate::signer::get_signer_seeds;
4444
use crate::state::amm_cache::CacheInfo;
45-
use crate::state::events::emit_stack;
4645
use crate::state::events::LPSettleRecord;
4746
use crate::state::events::{DeleteUserRecord, OrderActionExplanation, SignedMsgOrderRecord};
4847
use crate::state::fill_mode::FillMode;
@@ -3577,7 +3576,7 @@ pub fn handle_update_amm_cache<'c: 'info, 'info>(
35773576
)?;
35783577

35793578
cached_info.update_perp_market_fields(&perp_market)?;
3580-
cached_info.update_oracle_info(
3579+
cached_info.try_update_oracle_info(
35813580
slot,
35823581
&mm_oracle_price_data,
35833582
&perp_market,

programs/drift/src/instructions/lp_admin.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ pub fn handle_initialize_lp_pool(
8282
gamma_execution: 2,
8383
volatility: 4,
8484
xi: 2,
85-
padding: 0,
85+
target_oracle_delay_fee_bps_per_10_slots: 0,
86+
target_position_delay_fee_bps_per_10_slots: 0,
87+
padding: [0u8; 15],
8688
whitelist_mint,
8789
};
8890

programs/drift/src/instructions/lp_pool.rs

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ use crate::{
3232
update_constituent_target_base_for_derivatives, AmmConstituentDatum,
3333
AmmConstituentMappingFixed, Constituent, ConstituentCorrelationsFixed,
3434
ConstituentTargetBaseFixed, LPPool, TargetsDatum, LP_POOL_SWAP_AUM_UPDATE_DELAY,
35-
MAX_AMM_CACHE_ORACLE_STALENESS_FOR_TARGET_CALC,
36-
MAX_AMM_CACHE_STALENESS_FOR_TARGET_CALC,
35+
MAX_ORACLE_STALENESS_FOR_TARGET_CALC, MAX_STALENESS_FOR_TARGET_CALC,
3736
},
3837
oracle_map::OracleMap,
3938
perp_market_map::MarketSet,
@@ -57,7 +56,7 @@ use crate::controller::spot_balance::update_spot_market_cumulative_interest;
5756
use crate::controller::token::{receive, send_from_program_vault_with_signature_seeds};
5857
use crate::instructions::constraints::*;
5958
use crate::state::lp_pool::{
60-
AmmInventoryAndPrices, ConstituentIndexAndDecimalAndPrice, CONSTITUENT_PDA_SEED,
59+
AmmInventoryAndPricesAndSlots, ConstituentIndexAndDecimalAndPrice, CONSTITUENT_PDA_SEED,
6160
LP_POOL_TOKEN_VAULT_PDA_SEED,
6261
};
6362

@@ -100,37 +99,14 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>(
10099
let constituent_map =
101100
ConstituentMap::load(&ConstituentSet::new(), &lp_pool_key, remaining_accounts)?;
102101

103-
let mut amm_inventories: Vec<AmmInventoryAndPrices> =
102+
let mut amm_inventories: Vec<AmmInventoryAndPricesAndSlots> =
104103
Vec::with_capacity(amm_cache.len() as usize);
105-
for (idx, cache_info) in amm_cache.iter().enumerate() {
104+
for (_, cache_info) in amm_cache.iter().enumerate() {
106105
if cache_info.lp_status_for_perp_market == 0 {
107106
continue;
108107
}
109-
if !is_oracle_valid_for_action(
110-
OracleValidity::try_from(cache_info.oracle_validity)?,
111-
Some(DriftAction::UpdateLpConstituentTargetBase),
112-
)? {
113-
msg!(
114-
"Oracle data for perp market {} is invalid. Skipping update",
115-
idx,
116-
);
117-
continue;
118-
}
119-
120-
if slot.safe_sub(cache_info.slot)? > MAX_AMM_CACHE_STALENESS_FOR_TARGET_CALC {
121-
msg!("Amm cache for perp market {}. Skipping update", idx);
122-
continue;
123-
}
124-
125-
if slot.safe_sub(cache_info.oracle_slot)? > MAX_AMM_CACHE_ORACLE_STALENESS_FOR_TARGET_CALC {
126-
msg!(
127-
"Amm cache oracle for perp market {} is stale. Skipping update",
128-
idx
129-
);
130-
continue;
131-
}
132108

133-
amm_inventories.push(AmmInventoryAndPrices {
109+
amm_inventories.push(AmmInventoryAndPricesAndSlots {
134110
inventory: {
135111
let scaled_position = cache_info
136112
.position
@@ -143,6 +119,8 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>(
143119
)
144120
},
145121
price: cache_info.oracle_price,
122+
last_oracle_slot: cache_info.oracle_slot,
123+
last_position_slot: cache_info.slot,
146124
});
147125
}
148126
msg!("amm inventories: {:?}", amm_inventories);
@@ -400,8 +378,18 @@ pub fn handle_lp_pool_swap<'c: 'info, 'info>(
400378
out_oracle.price,
401379
lp_pool.last_aum,
402380
)?;
381+
let in_target_datum = constituent_target_base.get(in_constituent.constituent_index as u32);
382+
let in_target_position_slot_delay = slot.saturating_sub(in_target_datum.last_position_slot);
383+
let in_target_oracle_slot_delay = slot.saturating_sub(in_target_datum.last_oracle_slot);
384+
let out_target_datum = constituent_target_base.get(out_constituent.constituent_index as u32);
385+
let out_target_position_slot_delay = slot.saturating_sub(out_target_datum.last_position_slot);
386+
let out_target_oracle_slot_delay = slot.saturating_sub(out_target_datum.last_oracle_slot);
403387

404388
let (in_amount, out_amount, in_fee, out_fee) = lp_pool.get_swap_amount(
389+
in_target_position_slot_delay,
390+
out_target_position_slot_delay,
391+
in_target_oracle_slot_delay,
392+
out_target_oracle_slot_delay,
405393
&in_oracle,
406394
&out_oracle,
407395
&in_constituent,
@@ -541,6 +529,9 @@ pub fn handle_view_lp_pool_swap_fees<'c: 'info, 'info>(
541529
let constituent_correlations: AccountZeroCopy<'_, i64, ConstituentCorrelationsFixed> =
542530
ctx.accounts.constituent_correlations.load_zc()?;
543531

532+
let constituent_target_base: AccountZeroCopy<'_, TargetsDatum, ConstituentTargetBaseFixed> =
533+
ctx.accounts.constituent_target_base.load_zc()?;
534+
544535
let AccountMaps {
545536
perp_market_map: _,
546537
spot_market_map,
@@ -580,7 +571,18 @@ pub fn handle_view_lp_pool_swap_fees<'c: 'info, 'info>(
580571
0,
581572
)?;
582573

574+
let in_target_datum = constituent_target_base.get(in_constituent.constituent_index as u32);
575+
let in_target_position_slot_delay = slot.saturating_sub(in_target_datum.last_position_slot);
576+
let in_target_oracle_slot_delay = slot.saturating_sub(in_target_datum.last_oracle_slot);
577+
let out_target_datum = constituent_target_base.get(out_constituent.constituent_index as u32);
578+
let out_target_position_slot_delay = slot.saturating_sub(out_target_datum.last_position_slot);
579+
let out_target_oracle_slot_delay = slot.saturating_sub(out_target_datum.last_oracle_slot);
580+
583581
let (in_amount, out_amount, in_fee, out_fee) = lp_pool.get_swap_amount(
582+
in_target_position_slot_delay,
583+
out_target_position_slot_delay,
584+
in_target_oracle_slot_delay,
585+
out_target_oracle_slot_delay,
584586
&in_oracle,
585587
&out_oracle,
586588
&in_constituent,
@@ -722,8 +724,14 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(
722724

723725
let dlp_total_supply = ctx.accounts.lp_mint.supply;
724726

727+
let in_target_datum = constituent_target_base.get(in_constituent.constituent_index as u32);
728+
let in_target_position_slot_delay = slot.saturating_sub(in_target_datum.last_position_slot);
729+
let in_target_oracle_slot_delay = slot.saturating_sub(in_target_datum.last_oracle_slot);
730+
725731
let (lp_amount, in_amount, lp_fee_amount, in_fee_amount) = lp_pool
726732
.get_add_liquidity_mint_amount(
733+
in_target_position_slot_delay,
734+
in_target_oracle_slot_delay,
727735
&in_spot_market,
728736
&in_constituent,
729737
in_amount,
@@ -930,8 +938,14 @@ pub fn handle_view_lp_pool_add_liquidity_fees<'c: 'info, 'info>(
930938

931939
let dlp_total_supply = ctx.accounts.lp_mint.supply;
932940

941+
let in_target_datum = constituent_target_base.get(in_constituent.constituent_index as u32);
942+
let in_target_position_slot_delay = slot.saturating_sub(in_target_datum.last_position_slot);
943+
let in_target_oracle_slot_delay = slot.saturating_sub(in_target_datum.last_oracle_slot);
944+
933945
let (lp_amount, in_amount, lp_fee_amount, in_fee_amount) = lp_pool
934946
.get_add_liquidity_mint_amount(
947+
in_target_position_slot_delay,
948+
in_target_oracle_slot_delay,
935949
&in_spot_market,
936950
&in_constituent,
937951
in_amount,
@@ -1069,8 +1083,14 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>(
10691083

10701084
let dlp_total_supply = ctx.accounts.lp_mint.supply;
10711085

1086+
let out_target_datum = constituent_target_base.get(out_constituent.constituent_index as u32);
1087+
let out_target_position_slot_delay = slot.saturating_sub(out_target_datum.last_position_slot);
1088+
let out_target_oracle_slot_delay = slot.saturating_sub(out_target_datum.last_oracle_slot);
1089+
10721090
let (lp_burn_amount, out_amount, lp_fee_amount, out_fee_amount) = lp_pool
10731091
.get_remove_liquidity_amount(
1092+
out_target_position_slot_delay,
1093+
out_target_oracle_slot_delay,
10741094
&out_spot_market,
10751095
&out_constituent,
10761096
lp_to_burn,
@@ -1315,8 +1335,14 @@ pub fn handle_view_lp_pool_remove_liquidity_fees<'c: 'info, 'info>(
13151335

13161336
let dlp_total_supply = ctx.accounts.lp_mint.supply;
13171337

1338+
let out_target_datum = constituent_target_base.get(out_constituent.constituent_index as u32);
1339+
let out_target_position_slot_delay = slot.saturating_sub(out_target_datum.last_position_slot);
1340+
let out_target_oracle_slot_delay = slot.saturating_sub(out_target_datum.last_oracle_slot);
1341+
13181342
let (lp_burn_amount, out_amount, lp_fee_amount, out_fee_amount) = lp_pool
13191343
.get_remove_liquidity_amount(
1344+
out_target_position_slot_delay,
1345+
out_target_oracle_slot_delay,
13201346
&out_spot_market,
13211347
&out_constituent,
13221348
lp_to_burn,

programs/drift/src/math/oracle.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub enum DriftAction {
102102
UpdateAMMCurve,
103103
OracleOrderPrice,
104104
UseMMOraclePrice,
105-
UpdateLpConstituentTargetBase,
105+
UpdateAmmCache,
106106
UpdateLpPoolAum,
107107
LpPoolSwap,
108108
}
@@ -153,7 +153,7 @@ pub fn is_oracle_valid_for_action(
153153
| OracleValidity::StaleForMargin
154154
),
155155
DriftAction::FillOrderMatch
156-
| DriftAction::UpdateLpConstituentTargetBase
156+
| DriftAction::UpdateAmmCache
157157
| DriftAction::UpdateLpPoolAum
158158
| DriftAction::LpPoolSwap => !matches!(
159159
oracle_validity,

programs/drift/src/state/amm_cache.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::convert::TryFrom;
33
use crate::error::{DriftResult, ErrorCode};
44
use crate::math::amm::calculate_net_user_pnl;
55
use crate::math::casting::Cast;
6-
use crate::math::oracle::{oracle_validity, LogMode};
6+
use crate::math::oracle::{is_oracle_valid_for_action, oracle_validity, DriftAction, LogMode};
77
use crate::math::safe_math::SafeMath;
88
use crate::math::spot_balance::get_token_amount;
99
use crate::state::oracle::MMOraclePriceData;
@@ -120,17 +120,14 @@ impl CacheInfo {
120120
Ok(())
121121
}
122122

123-
pub fn update_oracle_info(
123+
pub fn try_update_oracle_info(
124124
&mut self,
125125
clock_slot: u64,
126126
oracle_price_data: &MMOraclePriceData,
127127
perp_market: &PerpMarket,
128128
oracle_guard_rails: &OracleGuardRails,
129129
) -> DriftResult<()> {
130130
let safe_oracle_data = oracle_price_data.get_safe_oracle_price_data();
131-
self.oracle_price = safe_oracle_data.price;
132-
self.oracle_slot = clock_slot.safe_sub(safe_oracle_data.delay.max(0) as u64)?;
133-
self.slot = clock_slot;
134131
let validity = oracle_validity(
135132
MarketType::Perp,
136133
perp_market.market_index,
@@ -145,7 +142,18 @@ impl CacheInfo {
145142
LogMode::SafeMMOracle,
146143
perp_market.amm.oracle_slot_delay_override,
147144
)?;
148-
self.oracle_validity = u8::from(validity);
145+
if is_oracle_valid_for_action(validity, Some(DriftAction::UpdateAmmCache))? {
146+
self.oracle_price = safe_oracle_data.price;
147+
self.oracle_slot = clock_slot.safe_sub(safe_oracle_data.delay.max(0) as u64)?;
148+
self.oracle_validity = u8::from(validity);
149+
} else {
150+
msg!(
151+
"Not updating oracle price for perp market {}. Oracle data is invalid",
152+
perp_market.market_index
153+
);
154+
}
155+
self.slot = clock_slot;
156+
149157
Ok(())
150158
}
151159
}
@@ -204,7 +212,7 @@ impl AmmCache {
204212
) -> DriftResult<()> {
205213
let cache_info = self.cache.get_mut(market_index as usize);
206214
if let Some(cache_info) = cache_info {
207-
cache_info.update_oracle_info(
215+
cache_info.try_update_oracle_info(
208216
clock_slot,
209217
oracle_price_data,
210218
perp_market,

0 commit comments

Comments
 (0)