Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions programs/drift/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,8 @@ pub enum ErrorCode {
MintRedeemLpPoolDisabled,
#[msg("Settlement amount exceeded")]
LpPoolSettleInvariantBreached,
#[msg("Invalid constituent operation")]
InvalidConstituentOperation,
}

#[macro_export]
Expand Down
5 changes: 5 additions & 0 deletions programs/drift/src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,8 @@ pub mod amm_spread_adjust_wallet {
#[cfg(feature = "anchor-test")]
declare_id!("1ucYHAGrBbi1PaecC4Ptq5ocZLWGLBmbGWysoDGNB1N");
}

pub mod lp_pool_swap_wallet {
use solana_program::declare_id;
declare_id!("1ucYHAGrBbi1PaecC4Ptq5ocZLWGLBmbGWysoDGNB1N");
}
21 changes: 15 additions & 6 deletions programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::math::amm::calculate_net_user_pnl;
use crate::{msg, FeatureBitFlags};
use anchor_lang::prelude::*;
use anchor_spl::token_2022::Token2022;
Expand Down Expand Up @@ -62,8 +61,8 @@ use crate::state::perp_market_map::{get_writable_perp_market_set, MarketSet};
use crate::state::protected_maker_mode_config::ProtectedMakerModeConfig;
use crate::state::pyth_lazer_oracle::{PythLazerOracle, PYTH_LAZER_ORACLE_SEED};
use crate::state::spot_market::{
AssetTier, InsuranceFund, SpotBalance, SpotBalanceType, SpotFulfillmentConfigStatus,
SpotMarket, TokenProgramFlag,
AssetTier, InsuranceFund, SpotBalanceType, SpotFulfillmentConfigStatus, SpotMarket,
TokenProgramFlag,
};
use crate::state::spot_market_map::get_writable_spot_market_set;
use crate::state::state::{
Expand Down Expand Up @@ -972,10 +971,10 @@ pub fn handle_initialize_perp_market(
protected_maker_dynamic_divisor: 0,
lp_fee_transfer_scalar: 1,
lp_status: 0,
padding1: 0,
lp_exchange_fee_excluscion_scalar: 0,
lp_paused_operations: 0,
last_fill_price: 0,
lp_exchange_fee_excluscion_scalar: 1,
padding: [0; 23],
padding: [0; 24],
amm: AMM {
oracle: *ctx.accounts.oracle.key,
oracle_source,
Expand Down Expand Up @@ -4244,6 +4243,16 @@ pub fn handle_update_perp_market_lp_pool_status(
Ok(())
}

pub fn handle_update_perp_market_lp_pool_paused_operations(
ctx: Context<AdminUpdatePerpMarket>,
lp_paused_operations: u8,
) -> Result<()> {
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;
msg!("perp market {}", perp_market.market_index);
perp_market.lp_paused_operations = lp_paused_operations;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should add a log_all_operations_paused similar other market/if field

Ok(())
}

#[access_control(
perp_market_valid(&ctx.accounts.perp_market)
)]
Expand Down
17 changes: 15 additions & 2 deletions programs/drift/src/instructions/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use crate::state::lp_pool::CONSTITUENT_PDA_SEED;
use crate::state::lp_pool::SETTLE_AMM_ORACLE_MAX_DELAY;
use crate::state::oracle_map::OracleMap;
use crate::state::order_params::{OrderParams, PlaceOrderOptions};
use crate::state::paused_operations::PerpLpOperation;
use crate::state::paused_operations::{PerpOperation, SpotOperation};
use crate::state::perp_market::{ContractType, MarketStatus, PerpMarket};
use crate::state::perp_market_map::{
Expand Down Expand Up @@ -3149,7 +3150,12 @@ pub fn handle_settle_perp_to_lp_pool<'c: 'info, 'info>(

for (_, perp_market_loader) in perp_market_map.0.iter() {
let mut perp_market = perp_market_loader.load_mut()?;
if perp_market.lp_status == 0 {
if perp_market.lp_status == 0
|| PerpLpOperation::is_operation_paused(
perp_market.lp_paused_operations,
PerpLpOperation::SettleQuoteOwed,
)
{
continue;
}

Expand Down Expand Up @@ -3344,7 +3350,14 @@ pub fn handle_update_amm_cache<'c: 'info, 'info>(
&state.oracle_guard_rails,
)?;

amm_cache.update_amount_owed_from_lp_pool(&perp_market, &quote_market)?;
if perp_market.lp_status != 0
&& !PerpLpOperation::is_operation_paused(
perp_market.lp_paused_operations,
PerpLpOperation::TrackAmmRevenue,
)
{
amm_cache.update_amount_owed_from_lp_pool(&perp_market, &quote_market)?;
}
}

Ok(())
Expand Down
76 changes: 70 additions & 6 deletions programs/drift/src/instructions/lp_admin.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::controller;
use crate::controller::token::{receive, send_from_program_vault_with_signature_seeds};
use crate::error::ErrorCode;
use crate::ids::admin_hot_wallet;
use crate::ids::{admin_hot_wallet, lp_pool_swap_wallet};
use crate::instructions::optional_accounts::get_token_mint;
use crate::math::constants::{PRICE_PRECISION_U64, QUOTE_SPOT_MARKET_INDEX};
use crate::math::safe_math::SafeMath;
use crate::state::lp_pool::{
AmmConstituentDatum, AmmConstituentMapping, Constituent, ConstituentCorrelations,
ConstituentTargetBase, LPPool, TargetsDatum, AMM_MAP_PDA_SEED,
ConstituentStatus, ConstituentTargetBase, LPPool, TargetsDatum, AMM_MAP_PDA_SEED,
CONSTITUENT_CORRELATIONS_PDA_SEED, CONSTITUENT_PDA_SEED, CONSTITUENT_TARGET_BASE_PDA_SEED,
CONSTITUENT_VAULT_PDA_SEED,
};
Expand Down Expand Up @@ -215,6 +215,34 @@ pub fn handle_initialize_constituent<'info>(
Ok(())
}

pub fn handle_update_constituent_status<'info>(
ctx: Context<UpdateConstituentStatus>,
new_status: u8,
) -> Result<()> {
let mut constituent = ctx.accounts.constituent.load_mut()?;
msg!(
"constituent status: {:?} -> {:?}",
constituent.status,
new_status
);
constituent.status = new_status;
Ok(())
}

pub fn handle_update_constituent_paused_operations<'info>(
ctx: Context<UpdateConstituentPausedOperations>,
paused_operations: u8,
) -> Result<()> {
let mut constituent = ctx.accounts.constituent.load_mut()?;
msg!(
"constituent paused operations: {:?} -> {:?}",
constituent.paused_operations,
paused_operations
);
constituent.paused_operations = paused_operations;
Ok(())
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
pub struct ConstituentParams {
pub max_weight_deviation: Option<i64>,
Expand Down Expand Up @@ -546,6 +574,21 @@ pub fn handle_begin_lp_swap<'c: 'info, 'info>(
out_market_index: u16,
amount_in: u64,
) -> Result<()> {
// Check admin
let admin = &ctx.accounts.admin;
#[cfg(feature = "anchor-test")]
validate!(
admin.key() == admin_hot_wallet::id() || admin.key() == state.admin,
ErrorCode::Unauthorized,
"Wrong signer for lp taker swap"
)?;
#[cfg(not(feature = "anchor-test"))]
validate!(
admin.key() == lp_pool_swap_wallet::id(),
ErrorCode::DefaultError,
"Wrong signer for lp taker swap"
)?;

let ixs = ctx.accounts.instructions.as_ref();
let current_index = instructions::load_current_index_checked(ixs)? as usize;

Expand Down Expand Up @@ -1012,6 +1055,30 @@ pub struct UpdateConstituentParams<'info> {
pub constituent: AccountLoader<'info, Constituent>,
}

#[derive(Accounts)]
pub struct UpdateConstituentStatus<'info> {
#[account(
mut,
constraint = admin.key() == state.admin
)]
pub admin: Signer<'info>,
pub state: Box<Account<'info, State>>,
#[account(mut)]
pub constituent: AccountLoader<'info, Constituent>,
}

#[derive(Accounts)]
pub struct UpdateConstituentPausedOperations<'info> {
#[account(
mut,
constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin
)]
pub admin: Signer<'info>,
pub state: Box<Account<'info, State>>,
#[account(mut)]
pub constituent: AccountLoader<'info, Constituent>,
}

#[derive(Accounts)]
pub struct UpdateLpPoolParams<'info> {
#[account(mut)]
Expand Down Expand Up @@ -1134,10 +1201,7 @@ pub struct UpdateConstituentCorrelation<'info> {
)]
pub struct LPTakerSwap<'info> {
pub state: Box<Account<'info, State>>,
#[account(
mut,
constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin
)]
#[account(mut)]
pub admin: Signer<'info>,

/// Signer token accounts
Expand Down
42 changes: 38 additions & 4 deletions programs/drift/src/instructions/lp_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};

use crate::math::constants::{PERCENTAGE_PRECISION, PRICE_PRECISION_I64};
use crate::math::oracle::OracleValidity;
use crate::state::paused_operations::ConstituentLpOperation;
use crate::validation::whitelist::validate_whitelist_token;
use crate::{
controller::{
Expand Down Expand Up @@ -285,6 +286,9 @@ pub fn handle_lp_pool_swap<'c: 'info, 'info>(
let mut in_constituent = ctx.accounts.in_constituent.load_mut()?;
let mut out_constituent = ctx.accounts.out_constituent.load_mut()?;

in_constituent.does_constituent_allow_operation(ConstituentLpOperation::Swap)?;
out_constituent.does_constituent_allow_operation(ConstituentLpOperation::Swap)?;

let constituent_target_base_key = &ctx.accounts.constituent_target_base.key();
let constituent_target_base: AccountZeroCopy<'_, TargetsDatum, ConstituentTargetBaseFixed> =
ctx.accounts.constituent_target_base.load_zc()?;
Expand Down Expand Up @@ -320,6 +324,20 @@ pub fn handle_lp_pool_swap<'c: 'info, 'info>(
let in_spot_market = spot_market_map.get_ref(&in_market_index)?;
let out_spot_market = spot_market_map.get_ref(&out_market_index)?;

if in_constituent.is_reduce_only()?
&& !in_constituent.is_operation_reducing(&in_spot_market, true)?
{
msg!("In constituent in reduce only mode");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logging spot market index is nice to have

return Err(ErrorCode::InvalidConstituentOperation.into());
}

if out_constituent.is_reduce_only()?
&& !out_constituent.is_operation_reducing(&out_spot_market, false)?
{
msg!("Out constituent in reduce only mode");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logging spot market index is nice to have

return Err(ErrorCode::InvalidConstituentOperation.into());
}

let in_oracle_id = in_spot_market.oracle_id();
let out_oracle_id = out_spot_market.oracle_id();

Expand Down Expand Up @@ -593,6 +611,9 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(
"Mint/redeem LP pool is disabled"
)?;

let mut in_constituent = ctx.accounts.in_constituent.load_mut()?;
in_constituent.does_constituent_allow_operation(ConstituentLpOperation::Deposit)?;

let slot = Clock::get()?.slot;
let now = Clock::get()?.unix_timestamp;
let lp_pool_key = ctx.accounts.lp_pool.key();
Expand All @@ -611,8 +632,6 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(

let remaining_accounts = &mut ctx.remaining_accounts.iter().peekable();

let mut in_constituent = ctx.accounts.in_constituent.load_mut()?;

let constituent_target_base_key = &ctx.accounts.constituent_target_base.key();
let constituent_target_base: AccountZeroCopy<'_, TargetsDatum, ConstituentTargetBaseFixed> =
ctx.accounts.constituent_target_base.load_zc()?;
Expand Down Expand Up @@ -646,6 +665,13 @@ pub fn handle_lp_pool_add_liquidity<'c: 'info, 'info>(

let mut in_spot_market = spot_market_map.get_ref_mut(&in_market_index)?;

if in_constituent.is_reduce_only()?
&& !in_constituent.is_operation_reducing(&in_spot_market, true)?
{
msg!("In constituent in reduce only mode");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logging spot market index is nice to have

return Err(ErrorCode::InvalidConstituentOperation.into());
}

let in_oracle_id = in_spot_market.oracle_id();

let (in_oracle, in_oracle_validity) = oracle_map.get_price_data_and_validity(
Expand Down Expand Up @@ -936,6 +962,9 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>(

let lp_price_before = lp_pool.get_price(ctx.accounts.lp_mint.supply)?;

let mut out_constituent = ctx.accounts.out_constituent.load_mut()?;
out_constituent.does_constituent_allow_operation(ConstituentLpOperation::Withdraw)?;

// Verify previous settle
let amm_cache: AccountZeroCopy<'_, CacheInfo, _> = ctx.accounts.amm_cache.load_zc()?;
for (i, _) in amm_cache.iter().enumerate() {
Expand All @@ -959,8 +988,6 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>(
return Err(ErrorCode::LpPoolAumDelayed.into());
}

let mut out_constituent = ctx.accounts.out_constituent.load_mut()?;

let constituent_target_base_key = &ctx.accounts.constituent_target_base.key();
let constituent_target_base: AccountZeroCopy<'_, TargetsDatum, ConstituentTargetBaseFixed> =
ctx.accounts.constituent_target_base.load_zc()?;
Expand All @@ -987,6 +1014,13 @@ pub fn handle_lp_pool_remove_liquidity<'c: 'info, 'info>(

let mut out_spot_market = spot_market_map.get_ref_mut(&out_market_index)?;

if out_constituent.is_reduce_only()?
&& !out_constituent.is_operation_reducing(&out_spot_market, false)?
{
msg!("Out constituent in reduce only mode");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logging spot market index is nice to have

return Err(ErrorCode::InvalidConstituentOperation.into());
}

let out_oracle_id = out_spot_market.oracle_id();

let (out_oracle, out_oracle_validity) = oracle_map.get_price_data_and_validity(
Expand Down
21 changes: 21 additions & 0 deletions programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,13 @@ pub mod drift {
handle_update_perp_market_expiry(ctx, expiry_ts)
}

pub fn update_perp_market_lp_pool_paused_operations(
ctx: Context<AdminUpdatePerpMarket>,
lp_paused_operations: u8,
) -> Result<()> {
handle_update_perp_market_lp_pool_paused_operations(ctx, lp_paused_operations)
}

pub fn update_perp_market_lp_pool_status(
ctx: Context<AdminUpdatePerpMarket>,
lp_status: u8,
Expand Down Expand Up @@ -1922,6 +1929,20 @@ pub mod drift {
)
}

pub fn update_constituent_status<'info>(
ctx: Context<'_, '_, '_, 'info, UpdateConstituentStatus<'info>>,
new_status: u8,
) -> Result<()> {
handle_update_constituent_status(ctx, new_status)
}

pub fn update_constituent_paused_operations<'info>(
ctx: Context<'_, '_, '_, 'info, UpdateConstituentPausedOperations<'info>>,
paused_operations: u8,
) -> Result<()> {
handle_update_constituent_paused_operations(ctx, paused_operations)
}

pub fn update_constituent_params(
ctx: Context<UpdateConstituentParams>,
constituent_params: ConstituentParams,
Expand Down
Loading