Skip to content

Commit 1a8dd05

Browse files
committed
Merge remote-tracking branch 'origin/master' into chore/anchor-32
2 parents 6711ed3 + 53721d0 commit 1a8dd05

35 files changed

+486
-584
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Features
1111

12+
### Fixes
13+
14+
### Breaking
15+
16+
## [2.146.0] - 2025-11-03
17+
18+
### Features
19+
1220
- program: add isolated_position_deposit to signed msg params
1321

1422
### Fixes

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

programs/drift/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "drift"
3-
version = "2.145.1"
3+
version = "2.146.0"
44
description = "Created with Anchor"
55
edition = "2018"
66

programs/drift/src/controller/amm.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use crate::math::{amm, amm_spread, bn, cp_curve, quote_asset::*};
2929

3030
use crate::state::events::CurveRecord;
3131
use crate::state::oracle::OraclePriceData;
32+
use crate::state::paused_operations::PerpOperation;
3233
use crate::state::perp_market::{PerpMarket, AMM};
3334
use crate::state::spot_market::{SpotBalance, SpotBalanceType, SpotMarket};
3435
use crate::state::user::{SpotPosition, User};
@@ -499,6 +500,10 @@ fn calculate_revenue_pool_transfer(
499500
// If the AMM budget is above `FEE_POOL_TO_REVENUE_POOL_THRESHOLD` (in surplus), settle fees collected to the revenue pool depending on the health of the AMM state
500501
// Otherwise, spull from the revenue pool (up to a constraint amount)
501502

503+
if market.is_operation_paused(PerpOperation::SettleRevPool) {
504+
return Ok(0);
505+
}
506+
502507
let amm_budget_surplus =
503508
terminal_state_surplus.saturating_sub(FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()?);
504509

programs/drift/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,8 @@ pub enum ErrorCode {
692692
Unauthorized,
693693
#[msg("Invalid Lp Pool Id for Operation")]
694694
InvalidLpPoolId,
695+
#[msg("MarketIndexNotFoundAmmCache")]
696+
MarketIndexNotFoundAmmCache,
695697
}
696698

697699
#[macro_export]

programs/drift/src/instructions/admin.rs

Lines changed: 33 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,17 +1107,6 @@ pub fn handle_initialize_perp_market(
11071107

11081108
safe_increment!(state.number_of_markets, 1);
11091109

1110-
let amm_cache = &mut ctx.accounts.amm_cache;
1111-
let current_len = amm_cache.cache.len();
1112-
amm_cache
1113-
.cache
1114-
.resize_with(current_len + 1, CacheInfo::default);
1115-
let current_market_info = amm_cache.cache.get_mut(current_len).unwrap();
1116-
current_market_info.slot = clock_slot;
1117-
current_market_info.oracle = perp_market.amm.oracle;
1118-
current_market_info.oracle_source = u8::from(perp_market.amm.oracle_source);
1119-
amm_cache.validate(state)?;
1120-
11211110
controller::amm::update_concentration_coef(perp_market, concentration_coef_scale)?;
11221111
crate::dlog!(oracle_price);
11231112

@@ -1140,28 +1129,32 @@ pub fn handle_initialize_amm_cache(ctx: Context<InitializeAmmCache>) -> Result<(
11401129
Ok(())
11411130
}
11421131

1143-
pub fn handle_resize_amm_cache(ctx: Context<ResizeAmmCache>) -> Result<()> {
1132+
pub fn handle_add_market_to_amm_cache(ctx: Context<AddMarketToAmmCache>) -> Result<()> {
11441133
let amm_cache = &mut ctx.accounts.amm_cache;
1145-
let state = &ctx.accounts.state;
1134+
let perp_market = ctx.accounts.perp_market.load()?;
1135+
1136+
for cache_info in amm_cache.cache.iter() {
1137+
validate!(
1138+
cache_info.market_index != perp_market.market_index,
1139+
ErrorCode::DefaultError,
1140+
"Market index {} already in amm cache",
1141+
perp_market.market_index
1142+
)?;
1143+
}
1144+
11461145
let current_size = amm_cache.cache.len();
1147-
let new_size = (state.number_of_markets as usize).min(current_size + 20_usize);
1146+
let new_size = current_size.saturating_add(1);
11481147

11491148
msg!(
11501149
"resizing amm cache from {} entries to {}",
11511150
current_size,
11521151
new_size
11531152
);
11541153

1155-
let growth = new_size.saturating_sub(current_size);
1156-
validate!(
1157-
growth <= 20,
1158-
ErrorCode::DefaultError,
1159-
"cannot grow amm_cache by more than 20 entries in a single resize (requested +{})",
1160-
growth
1161-
)?;
1162-
1163-
amm_cache.cache.resize_with(new_size, CacheInfo::default);
1164-
amm_cache.validate(state)?;
1154+
amm_cache.cache.resize_with(new_size, || CacheInfo {
1155+
market_index: perp_market.market_index,
1156+
..CacheInfo::default()
1157+
});
11651158

11661159
Ok(())
11671160
}
@@ -3364,7 +3357,8 @@ pub fn handle_update_perp_market_paused_operations(
33643357

33653358
if *ctx.accounts.admin.key != ctx.accounts.state.admin {
33663359
validate!(
3367-
paused_operations == PerpOperation::UpdateFunding as u8,
3360+
paused_operations == PerpOperation::UpdateFunding as u8
3361+
|| paused_operations == PerpOperation::SettleRevPool as u8,
33683362
ErrorCode::DefaultError,
33693363
"signer must be admin",
33703364
)?;
@@ -3586,20 +3580,6 @@ pub fn handle_update_perp_market_reference_price_offset_deadband_pct(
35863580
Ok(())
35873581
}
35883582

3589-
pub fn handle_update_lp_cooldown_time(
3590-
ctx: Context<AdminUpdateState>,
3591-
lp_cooldown_time: u64,
3592-
) -> Result<()> {
3593-
msg!(
3594-
"lp_cooldown_time: {} -> {}",
3595-
ctx.accounts.state.lp_cooldown_time,
3596-
lp_cooldown_time
3597-
);
3598-
3599-
ctx.accounts.state.lp_cooldown_time = lp_cooldown_time;
3600-
Ok(())
3601-
}
3602-
36033583
pub fn handle_update_perp_fee_structure(
36043584
ctx: Context<AdminUpdateState>,
36053585
fee_structure: FeeStructure,
@@ -3819,7 +3799,14 @@ pub fn handle_update_perp_market_oracle(
38193799
perp_market.amm.oracle = oracle;
38203800
perp_market.amm.oracle_source = oracle_source;
38213801

3822-
amm_cache.update_perp_market_fields(perp_market)?;
3802+
if amm_cache
3803+
.cache
3804+
.iter()
3805+
.find(|cache_info| cache_info.market_index == perp_market.market_index)
3806+
.is_some()
3807+
{
3808+
amm_cache.update_perp_market_fields(perp_market)?;
3809+
}
38233810

38243811
Ok(())
38253812
}
@@ -5511,15 +5498,6 @@ pub struct InitializePerpMarket<'info> {
55115498
payer = admin
55125499
)]
55135500
pub perp_market: AccountLoader<'info, PerpMarket>,
5514-
#[account(
5515-
mut,
5516-
seeds = [AMM_POSITIONS_CACHE.as_ref()],
5517-
bump = amm_cache.bump,
5518-
realloc = AmmCache::space(amm_cache.cache.len() + 1_usize),
5519-
realloc::payer = admin,
5520-
realloc::zero = false,
5521-
)]
5522-
pub amm_cache: Box<Account<'info, AmmCache>>,
55235501
/// CHECK: checked in `initialize_perp_market`
55245502
pub oracle: AccountInfo<'info>,
55255503
pub rent: Sysvar<'info, Rent>,
@@ -5547,7 +5525,7 @@ pub struct InitializeAmmCache<'info> {
55475525
}
55485526

55495527
#[derive(Accounts)]
5550-
pub struct ResizeAmmCache<'info> {
5528+
pub struct AddMarketToAmmCache<'info> {
55515529
#[account(
55525530
mut,
55535531
constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin
@@ -5558,22 +5536,23 @@ pub struct ResizeAmmCache<'info> {
55585536
mut,
55595537
seeds = [AMM_POSITIONS_CACHE.as_ref()],
55605538
bump,
5561-
realloc = AmmCache::space(amm_cache.cache.len() + (state.number_of_markets as usize - amm_cache.cache.len()).min(20_usize)),
5539+
realloc = AmmCache::space(amm_cache.cache.len() + 1),
55625540
realloc::payer = admin,
55635541
realloc::zero = false,
55645542
)]
55655543
pub amm_cache: Box<Account<'info, AmmCache>>,
5544+
pub perp_market: AccountLoader<'info, PerpMarket>,
55665545
pub rent: Sysvar<'info, Rent>,
55675546
pub system_program: Program<'info, System>,
55685547
}
55695548

55705549
#[derive(Accounts)]
55715550
pub struct DeleteAmmCache<'info> {
5572-
#[account(mut)]
5573-
pub admin: Signer<'info>,
55745551
#[account(
5575-
has_one = admin
5552+
mut,
5553+
constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin
55765554
)]
5555+
pub admin: Signer<'info>,
55775556
pub state: Box<Account<'info, State>>,
55785557
#[account(
55795558
mut,

programs/drift/src/instructions/keeper.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,7 +3377,7 @@ pub fn handle_settle_perp_to_lp_pool<'c: 'info, 'info>(
33773377
continue;
33783378
}
33793379

3380-
let cached_info = amm_cache.get_mut(perp_market.market_index as u32);
3380+
let cached_info = amm_cache.get_for_market_index_mut(perp_market.market_index)?;
33813381

33823382
// Early validation checks
33833383
if slot.saturating_sub(cached_info.oracle_slot) > SETTLE_AMM_ORACLE_MAX_DELAY {
@@ -3593,7 +3593,7 @@ pub fn handle_update_amm_cache<'c: 'info, 'info>(
35933593
if perp_market.lp_status == 0 {
35943594
continue;
35953595
}
3596-
let cached_info = amm_cache.get_mut(perp_market.market_index as u32);
3596+
let cached_info = amm_cache.get_for_market_index_mut(perp_market.market_index)?;
35973597

35983598
validate!(
35993599
perp_market.oracle_id() == cached_info.oracle_id()?,

programs/drift/src/instructions/lp_admin.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::ids::{lp_pool_hot_wallet, lp_pool_swap_wallet, WHITELISTED_SWAP_PROGR
44
use crate::instructions::optional_accounts::{get_token_mint, load_maps, AccountMaps};
55
use crate::math::constants::{PRICE_PRECISION_U64, QUOTE_SPOT_MARKET_INDEX};
66
use crate::math::safe_math::SafeMath;
7-
use crate::state::amm_cache::{AmmCache, CacheInfo, AMM_POSITIONS_CACHE};
7+
use crate::state::amm_cache::{AmmCache, AMM_POSITIONS_CACHE};
88
use crate::state::lp_pool::{
99
AmmConstituentDatum, AmmConstituentMapping, Constituent, ConstituentCorrelations,
1010
ConstituentTargetBase, LPPool, TargetsDatum, AMM_MAP_PDA_SEED,
@@ -922,20 +922,6 @@ pub fn handle_update_initial_amm_cache_info<'c: 'info, 'info>(
922922
Ok(())
923923
}
924924

925-
pub fn handle_reset_amm_cache(ctx: Context<ResetAmmCache>) -> Result<()> {
926-
let state = &ctx.accounts.state;
927-
let amm_cache = &mut ctx.accounts.amm_cache;
928-
929-
amm_cache.cache.clear();
930-
amm_cache
931-
.cache
932-
.resize_with(state.number_of_markets as usize, CacheInfo::default);
933-
amm_cache.validate(state)?;
934-
935-
msg!("AMM cache reset. markets: {}", state.number_of_markets);
936-
Ok(())
937-
}
938-
939925
#[derive(Debug, Clone, Copy, AnchorSerialize, AnchorDeserialize, PartialEq, Eq)]
940926
pub struct OverrideAmmCacheParams {
941927
pub quote_owed_from_lp_pool: Option<i64>,

programs/drift/src/instructions/lp_pool.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use crate::{
4343
},
4444
validate,
4545
};
46+
use std::collections::BTreeMap;
4647
use std::iter::Peekable;
4748
use std::slice::Iter;
4849

@@ -96,31 +97,33 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>(
9697
let constituent_map =
9798
ConstituentMap::load(&ConstituentSet::new(), &lp_pool_key, remaining_accounts)?;
9899

99-
let mut amm_inventories: Vec<AmmInventoryAndPricesAndSlots> =
100-
Vec::with_capacity(amm_cache.len() as usize);
100+
let mut amm_inventories: BTreeMap<u16, AmmInventoryAndPricesAndSlots> = BTreeMap::new();
101101
for (_, cache_info) in amm_cache.iter().enumerate() {
102102
if cache_info.lp_status_for_perp_market == 0 {
103103
continue;
104104
}
105105

106-
amm_inventories.push(AmmInventoryAndPricesAndSlots {
107-
inventory: {
108-
let scaled_position = cache_info
109-
.position
110-
.safe_mul(cache_info.amm_position_scalar as i64)?
111-
.safe_div(100)?;
112-
113-
scaled_position.clamp(
114-
-cache_info.amm_inventory_limit,
115-
cache_info.amm_inventory_limit,
116-
)
106+
amm_inventories.insert(
107+
cache_info.market_index,
108+
AmmInventoryAndPricesAndSlots {
109+
inventory: {
110+
let scaled_position = cache_info
111+
.position
112+
.safe_mul(cache_info.amm_position_scalar as i64)?
113+
.safe_div(100)?;
114+
115+
scaled_position.clamp(
116+
-cache_info.amm_inventory_limit,
117+
cache_info.amm_inventory_limit,
118+
)
119+
},
120+
price: cache_info.oracle_price,
121+
last_oracle_slot: cache_info.oracle_slot,
122+
last_position_slot: cache_info.slot,
117123
},
118-
price: cache_info.oracle_price,
119-
last_oracle_slot: cache_info.oracle_slot,
120-
last_position_slot: cache_info.slot,
121-
});
124+
);
122125
}
123-
msg!("amm inventories: {:?}", amm_inventories);
126+
msg!("amm inventories:{:?}", amm_inventories);
124127

125128
if amm_inventories.is_empty() {
126129
msg!("No valid inventories found for constituent target weights update");
@@ -140,7 +143,7 @@ pub fn handle_update_constituent_target_base<'c: 'info, 'info>(
140143

141144
constituent_target_base.update_target_base(
142145
&amm_constituent_mapping,
143-
amm_inventories.as_slice(),
146+
&amm_inventories,
144147
constituent_indexes_and_decimals_and_prices.as_mut_slice(),
145148
slot,
146149
)?;
@@ -1010,7 +1013,7 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>(
10101013
if cache_info.last_fee_pool_token_amount != 0 && cache_info.last_settle_slot != slot {
10111014
msg!(
10121015
"Market {} has not been settled in current slot. Last slot: {}",
1013-
i,
1016+
cache_info.market_index,
10141017
cache_info.last_settle_slot
10151018
);
10161019
return Err(ErrorCode::AMMCacheStale.into());

0 commit comments

Comments
 (0)