diff --git a/programs/drift/src/instructions/admin.rs b/programs/drift/src/instructions/admin.rs index 2746f28191..f84d944bac 100644 --- a/programs/drift/src/instructions/admin.rs +++ b/programs/drift/src/instructions/admin.rs @@ -355,31 +355,6 @@ pub fn handle_initialize_spot_market( Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_pool_id( - ctx: Context, - pool_id: u8, -) -> Result<()> { - let mut spot_market = load_mut!(ctx.accounts.spot_market)?; - msg!( - "updating spot market {} pool id to {}", - spot_market.market_index, - pool_id - ); - - validate!( - spot_market.status == MarketStatus::Initialized, - ErrorCode::DefaultError, - "Market must be just initialized to update pool" - )?; - - spot_market.pool_id = pool_id; - - Ok(()) -} - pub fn handle_initialize_serum_fulfillment_config( ctx: Context, market_index: u16, @@ -1433,41 +1408,6 @@ pub fn handle_init_user_fuel( Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_expiry( - ctx: Context, - expiry_ts: i64, -) -> Result<()> { - let clock: Clock = Clock::get()?; - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("updating perp market {} expiry", perp_market.market_index); - - validate!( - clock.unix_timestamp < expiry_ts, - ErrorCode::DefaultError, - "Market expiry ts must later than current clock timestamp" - )?; - - msg!( - "perp_market.status {:?} -> {:?}", - perp_market.status, - MarketStatus::ReduceOnly - ); - msg!( - "perp_market.expiry_ts {} -> {}", - perp_market.expiry_ts, - expiry_ts - ); - - // automatically enter reduce only - perp_market.status = MarketStatus::ReduceOnly; - perp_market.expiry_ts = expiry_ts; - - Ok(()) -} - #[access_control( perp_market_valid(&ctx.accounts.perp_market) )] @@ -2515,3350 +2455,2996 @@ pub fn handle_reset_amm_oracle_twap(ctx: Context) -> Result<()> { } #[access_control( - perp_market_valid(&ctx.accounts.perp_market) + spot_market_valid(&ctx.accounts.spot_market) )] -pub fn handle_update_perp_market_margin_ratio( - ctx: Context, - margin_ratio_initial: u32, - margin_ratio_maintenance: u32, +pub fn handle_update_insurance_fund_unstaking_period( + ctx: Context, + insurance_fund_unstaking_period: i64, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - - msg!( - "updating perp market {} margin ratio", - perp_market.market_index - ); - - validate_margin( - margin_ratio_initial, - margin_ratio_maintenance, - perp_market.high_leverage_margin_ratio_initial.cast()?, - perp_market.high_leverage_margin_ratio_maintenance.cast()?, - perp_market.liquidator_fee, - perp_market.amm.max_spread, - )?; - - msg!( - "perp_market.margin_ratio_initial: {:?} -> {:?}", - perp_market.margin_ratio_initial, - margin_ratio_initial - ); + let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; + msg!("updating spot market {} IF unstaking period"); msg!( - "perp_market.margin_ratio_maintenance: {:?} -> {:?}", - perp_market.margin_ratio_maintenance, - margin_ratio_maintenance + "spot_market.insurance_fund.unstaking_period: {:?} -> {:?}", + spot_market.insurance_fund.unstaking_period, + insurance_fund_unstaking_period ); - perp_market.margin_ratio_initial = margin_ratio_initial; - perp_market.margin_ratio_maintenance = margin_ratio_maintenance; + spot_market.insurance_fund.unstaking_period = insurance_fund_unstaking_period; Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_high_leverage_margin_ratio( - ctx: Context, - margin_ratio_initial: u16, - margin_ratio_maintenance: u16, +pub fn handle_update_perp_fee_structure( + ctx: Context, + fee_structure: FeeStructure, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - - msg!( - "updating perp market {} margin ratio", - perp_market.market_index - ); - - validate_margin( - perp_market.margin_ratio_initial, - perp_market.margin_ratio_maintenance, - margin_ratio_initial.cast()?, - margin_ratio_maintenance.cast()?, - perp_market.liquidator_fee, - perp_market.amm.max_spread, - )?; - - msg!( - "perp_market.high_leverage_margin_ratio_initial: {:?} -> {:?}", - perp_market.high_leverage_margin_ratio_initial, - margin_ratio_initial - ); + validate_fee_structure(&fee_structure)?; msg!( - "perp_market.high_leverage_margin_ratio_maintenance: {:?} -> {:?}", - perp_market.high_leverage_margin_ratio_maintenance, - margin_ratio_maintenance + "perp_fee_structure: {:?} -> {:?}", + ctx.accounts.state.perp_fee_structure, + fee_structure ); - perp_market.high_leverage_margin_ratio_initial = margin_ratio_initial; - perp_market.high_leverage_margin_ratio_maintenance = margin_ratio_maintenance; - + ctx.accounts.state.perp_fee_structure = fee_structure; Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_funding_period( - ctx: Context, - funding_period: i64, +pub fn handle_update_spot_fee_structure( + ctx: Context, + fee_structure: FeeStructure, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; + validate_fee_structure(&fee_structure)?; msg!( - "updating funding period for perp market {}", - perp_market.market_index + "spot_fee_structure: {:?} -> {:?}", + ctx.accounts.state.spot_fee_structure, + fee_structure ); - validate!(funding_period >= 0, ErrorCode::DefaultError)?; + ctx.accounts.state.spot_fee_structure = fee_structure; + Ok(()) +} +pub fn handle_update_oracle_guard_rails( + ctx: Context, + oracle_guard_rails: OracleGuardRails, +) -> Result<()> { msg!( - "perp_market.amm.funding_period: {:?} -> {:?}", - perp_market.amm.funding_period, - funding_period + "oracle_guard_rails: {:?} -> {:?}", + ctx.accounts.state.oracle_guard_rails, + oracle_guard_rails ); - perp_market.amm.funding_period = funding_period; + ctx.accounts.state.oracle_guard_rails = oracle_guard_rails; Ok(()) } #[access_control( perp_market_valid(&ctx.accounts.perp_market) )] -pub fn handle_update_perp_market_max_imbalances( - ctx: Context, - unrealized_max_imbalance: u64, - max_revenue_withdraw_per_period: u64, - quote_max_insurance: u64, +pub fn handle_update_perp_market_oracle( + ctx: Context, + oracle: Pubkey, + oracle_source: OracleSource, + skip_invariant_check: bool, ) -> Result<()> { let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; + msg!("perp market {}", perp_market.market_index); - msg!( - "updating perp market {} max imbalances", - perp_market.market_index - ); + let clock = Clock::get()?; - let max_insurance_for_tier = match perp_market.contract_tier { - ContractTier::A => INSURANCE_A_MAX, - ContractTier::B => INSURANCE_B_MAX, - ContractTier::C => INSURANCE_C_MAX, - ContractTier::Speculative => INSURANCE_SPECULATIVE_MAX, - ContractTier::HighlySpeculative => INSURANCE_SPECULATIVE_MAX, - ContractTier::Isolated => INSURANCE_SPECULATIVE_MAX, - }; + OracleMap::validate_oracle_account_info(&ctx.accounts.oracle)?; validate!( - max_revenue_withdraw_per_period - <= max_insurance_for_tier.max(FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()?) - && unrealized_max_imbalance <= max_insurance_for_tier + 1 - && quote_max_insurance <= max_insurance_for_tier, + ctx.accounts.oracle.key == &oracle, ErrorCode::DefaultError, - "all maxs must be less than max_insurance for ContractTier ={}", - max_insurance_for_tier + "oracle account info ({:?}) and ix data ({:?}) must match", + ctx.accounts.oracle.key, + oracle )?; validate!( - perp_market.insurance_claim.quote_settled_insurance <= quote_max_insurance, + ctx.accounts.old_oracle.key == &perp_market.amm.oracle, ErrorCode::DefaultError, - "quote_max_insurance must be above market.insurance_claim.quote_settled_insurance={}", - perp_market.insurance_claim.quote_settled_insurance + "old oracle account info ({:?}) and perp market oracle ({:?}) must match", + ctx.accounts.old_oracle.key, + perp_market.amm.oracle )?; + // Verify new oracle is readable + let OraclePriceData { + price: new_oracle_price, + delay: _oracle_delay, + .. + } = get_oracle_price(&oracle_source, &ctx.accounts.oracle, clock.slot)?; + msg!( - "market.max_revenue_withdraw_per_period: {:?} -> {:?}", - perp_market.insurance_claim.max_revenue_withdraw_per_period, - max_revenue_withdraw_per_period + "perp_market.amm.oracle: {:?} -> {:?}", + perp_market.amm.oracle, + oracle ); msg!( - "market.unrealized_max_imbalance: {:?} -> {:?}", - perp_market.unrealized_pnl_max_imbalance, - unrealized_max_imbalance + "perp_market.amm.oracle_source: {:?} -> {:?}", + perp_market.amm.oracle_source, + oracle_source ); + let OraclePriceData { + price: old_oracle_price, + .. + } = get_oracle_price( + &perp_market.amm.oracle_source, + &ctx.accounts.old_oracle, + clock.slot, + )?; + msg!( - "market.quote_max_insurance: {:?} -> {:?}", - perp_market.insurance_claim.quote_max_insurance, - quote_max_insurance + "Oracle Price: {:?} -> {:?}", + old_oracle_price, + new_oracle_price ); - perp_market.insurance_claim.max_revenue_withdraw_per_period = max_revenue_withdraw_per_period; - perp_market.unrealized_pnl_max_imbalance = unrealized_max_imbalance; - perp_market.insurance_claim.quote_max_insurance = quote_max_insurance; + if !skip_invariant_check { + validate!( + new_oracle_price > 0, + ErrorCode::DefaultError, + "invalid oracle price, must be greater than 0" + )?; - // ensure altered max_revenue_withdraw_per_period doesn't break invariant check - crate::validation::perp_market::validate_perp_market(perp_market)?; + let oracle_change_divergence = new_oracle_price + .safe_sub(old_oracle_price)? + .safe_mul(PERCENTAGE_PRECISION_I64)? + .safe_div(old_oracle_price)?; - Ok(()) -} + validate!( + oracle_change_divergence.abs() < (PERCENTAGE_PRECISION_I64 / 10), + ErrorCode::DefaultError, + "invalid new oracle price, more than 10% divergence" + )?; + } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_name( - ctx: Context, - name: [u8; 32], -) -> Result<()> { - let mut perp_market = load_mut!(ctx.accounts.perp_market)?; - msg!("perp_market.name: {:?} -> {:?}", perp_market.name, name); - perp_market.name = name; - Ok(()) -} + perp_market.amm.oracle = oracle; + perp_market.amm.oracle_source = oracle_source; -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_name( - ctx: Context, - name: [u8; 32], -) -> Result<()> { - let mut spot_market = load_mut!(ctx.accounts.spot_market)?; - msg!("spot_market.name: {:?} -> {:?}", spot_market.name, name); - spot_market.name = name; Ok(()) } #[access_control( perp_market_valid(&ctx.accounts.perp_market) )] -pub fn handle_update_perp_liquidation_fee( - ctx: Context, - liquidator_fee: u32, - if_liquidation_fee: u32, +pub fn handle_update_amm_jit_intensity( + ctx: Context, + amm_jit_intensity: u8, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - - msg!( - "updating perp market {} liquidation fee", - perp_market.market_index - ); - - validate!( - liquidator_fee.safe_add(if_liquidation_fee)? < LIQUIDATION_FEE_PRECISION, - ErrorCode::DefaultError, - "Total liquidation fee must be less than 100%" - )?; - validate!( - if_liquidation_fee < LIQUIDATION_FEE_PRECISION, + (0..=200).contains(&amm_jit_intensity), ErrorCode::DefaultError, - "If liquidation fee must be less than 100%" + "invalid amm_jit_intensity", )?; - validate_margin( - perp_market.margin_ratio_initial, - perp_market.margin_ratio_maintenance, - perp_market.high_leverage_margin_ratio_initial.cast()?, - perp_market.high_leverage_margin_ratio_maintenance.cast()?, - liquidator_fee, - perp_market.amm.max_spread, - )?; + let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; + msg!("perp market {}", perp_market.market_index); msg!( - "perp_market.liquidator_fee: {:?} -> {:?}", - perp_market.liquidator_fee, - liquidator_fee + "perp_market.amm.amm_jit_intensity: {} -> {}", + perp_market.amm.amm_jit_intensity, + amm_jit_intensity ); - msg!( - "perp_market.if_liquidation_fee: {:?} -> {:?}", - perp_market.if_liquidation_fee, - if_liquidation_fee - ); + perp_market.amm.amm_jit_intensity = amm_jit_intensity; - perp_market.liquidator_fee = liquidator_fee; - perp_market.if_liquidation_fee = if_liquidation_fee; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_insurance_fund_unstaking_period( - ctx: Context, - insurance_fund_unstaking_period: i64, +pub fn handle_update_spot_market_fuel( + ctx: Context, + fuel_boost_deposits: Option, + fuel_boost_borrows: Option, + fuel_boost_taker: Option, + fuel_boost_maker: Option, + fuel_boost_insurance: Option, ) -> Result<()> { let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; + msg!("spot market {}", spot_market.market_index); - msg!("updating spot market {} IF unstaking period"); - msg!( - "spot_market.insurance_fund.unstaking_period: {:?} -> {:?}", - spot_market.insurance_fund.unstaking_period, - insurance_fund_unstaking_period - ); - - spot_market.insurance_fund.unstaking_period = insurance_fund_unstaking_period; - Ok(()) -} - -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_liquidation_fee( - ctx: Context, - liquidator_fee: u32, - if_liquidation_fee: u32, -) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!( - "updating spot market {} liquidation fee", - spot_market.market_index - ); + if let Some(fuel_boost_taker) = fuel_boost_taker { + msg!( + "spot_market.fuel_boost_taker: {:?} -> {:?}", + spot_market.fuel_boost_taker, + fuel_boost_taker + ); + spot_market.fuel_boost_taker = fuel_boost_taker; + } else { + msg!("spot_market.fuel_boost_taker: unchanged"); + } - validate!( - liquidator_fee.safe_add(if_liquidation_fee)? < LIQUIDATION_FEE_PRECISION, - ErrorCode::DefaultError, - "Total liquidation fee must be less than 100%" - )?; + if let Some(fuel_boost_maker) = fuel_boost_maker { + msg!( + "spot_market.fuel_boost_maker: {:?} -> {:?}", + spot_market.fuel_boost_maker, + fuel_boost_maker + ); + spot_market.fuel_boost_maker = fuel_boost_maker; + } else { + msg!("spot_market.fuel_boost_maker: unchanged"); + } - validate!( - if_liquidation_fee <= LIQUIDATION_FEE_PRECISION / 10, - ErrorCode::DefaultError, - "if_liquidation_fee must be <= 10%" - )?; + if let Some(fuel_boost_deposits) = fuel_boost_deposits { + msg!( + "spot_market.fuel_boost_deposits: {:?} -> {:?}", + spot_market.fuel_boost_deposits, + fuel_boost_deposits + ); + spot_market.fuel_boost_deposits = fuel_boost_deposits; + } else { + msg!("spot_market.fuel_boost_deposits: unchanged"); + } - msg!( - "spot_market.liquidator_fee: {:?} -> {:?}", - spot_market.liquidator_fee, - liquidator_fee - ); + if let Some(fuel_boost_borrows) = fuel_boost_borrows { + msg!( + "spot_market.fuel_boost_borrows: {:?} -> {:?}", + spot_market.fuel_boost_borrows, + fuel_boost_borrows + ); + spot_market.fuel_boost_borrows = fuel_boost_borrows; + } else { + msg!("spot_market.fuel_boost_borrows: unchanged"); + } - msg!( - "spot_market.if_liquidation_fee: {:?} -> {:?}", - spot_market.if_liquidation_fee, - if_liquidation_fee - ); + if let Some(fuel_boost_insurance) = fuel_boost_insurance { + msg!( + "spot_market.fuel_boost_insurance: {:?} -> {:?}", + spot_market.fuel_boost_insurance, + fuel_boost_insurance + ); + spot_market.fuel_boost_insurance = fuel_boost_insurance; + } else { + msg!("spot_market.fuel_boost_insurance: unchanged"); + } - spot_market.liquidator_fee = liquidator_fee; - spot_market.if_liquidation_fee = if_liquidation_fee; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_withdraw_guard_threshold( - ctx: Context, - withdraw_guard_threshold: u64, +pub fn handle_admin_disable_update_perp_bid_ask_twap( + ctx: Context, + disable: bool, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!( - "updating spot market withdraw guard threshold {}", - spot_market.market_index - ); + let mut user_stats = load_mut!(ctx.accounts.user_stats)?; msg!( - "spot_market.withdraw_guard_threshold: {:?} -> {:?}", - spot_market.withdraw_guard_threshold, - withdraw_guard_threshold + "disable_update_perp_bid_ask_twap: {:?} -> {:?}", + user_stats.disable_update_perp_bid_ask_twap, + disable ); - spot_market.withdraw_guard_threshold = withdraw_guard_threshold; + + user_stats.disable_update_perp_bid_ask_twap = disable; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_if_factor( - ctx: Context, - spot_market_index: u16, - user_if_factor: u32, - total_if_factor: u32, +pub fn handle_initialize_protocol_if_shares_transfer_config( + ctx: Context, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - - msg!("spot market {}", spot_market.market_index); - - validate!( - spot_market.market_index == spot_market_index, - ErrorCode::DefaultError, - "spot_market_index dne spot_market.index" - )?; - - validate!( - user_if_factor <= total_if_factor, - ErrorCode::DefaultError, - "user_if_factor must be <= total_if_factor" - )?; - - validate!( - total_if_factor <= IF_FACTOR_PRECISION.cast()?, - ErrorCode::DefaultError, - "total_if_factor must be <= 100%" - )?; + let mut config = ctx + .accounts + .protocol_if_shares_transfer_config + .load_init()?; + let now = Clock::get()?.unix_timestamp; msg!( - "spot_market.user_if_factor: {:?} -> {:?}", - spot_market.insurance_fund.user_factor, - user_if_factor - ); - msg!( - "spot_market.total_if_factor: {:?} -> {:?}", - spot_market.insurance_fund.total_factor, - total_if_factor + "next_epoch_ts: {:?} -> {:?}", + config.next_epoch_ts, + now.safe_add(EPOCH_DURATION)? ); - - spot_market.insurance_fund.user_factor = user_if_factor; - spot_market.insurance_fund.total_factor = total_if_factor; + config.next_epoch_ts = now.safe_add(EPOCH_DURATION)?; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_revenue_settle_period( - ctx: Context, - revenue_settle_period: i64, +pub fn handle_update_protocol_if_shares_transfer_config( + ctx: Context, + whitelisted_signers: Option<[Pubkey; 4]>, + max_transfer_per_epoch: Option, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); + let mut config = ctx.accounts.protocol_if_shares_transfer_config.load_mut()?; + + if let Some(whitelisted_signers) = whitelisted_signers { + msg!( + "whitelisted_signers: {:?} -> {:?}", + config.whitelisted_signers, + whitelisted_signers + ); + config.whitelisted_signers = whitelisted_signers; + } else { + msg!("whitelisted_signers: unchanged"); + } + + if let Some(max_transfer_per_epoch) = max_transfer_per_epoch { + msg!( + "max_transfer_per_epoch: {:?} -> {:?}", + config.max_transfer_per_epoch, + max_transfer_per_epoch + ); + config.max_transfer_per_epoch = max_transfer_per_epoch; + } else { + msg!("max_transfer_per_epoch: unchanged"); + } - validate!(revenue_settle_period > 0, ErrorCode::DefaultError)?; - msg!( - "spot_market.revenue_settle_period: {:?} -> {:?}", - spot_market.insurance_fund.revenue_settle_period, - revenue_settle_period - ); - spot_market.insurance_fund.revenue_settle_period = revenue_settle_period; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_status( - ctx: Context, - status: MarketStatus, +pub fn handle_initialize_prelaunch_oracle( + ctx: Context, + params: PrelaunchOracleParams, ) -> Result<()> { - status.validate_not_deprecated()?; - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); + let mut oracle = ctx.accounts.prelaunch_oracle.load_init()?; + msg!("perp market {}", params.perp_market_index); - msg!( - "spot_market.status: {:?} -> {:?}", - spot_market.status, - status - ); + oracle.perp_market_index = params.perp_market_index; + if let Some(price) = params.price { + oracle.price = price; + } + if let Some(max_price) = params.max_price { + oracle.max_price = max_price; + } + + oracle.validate()?; - spot_market.status = status; Ok(()) } -#[access_control( -spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_paused_operations( - ctx: Context, - paused_operations: u8, +pub fn handle_update_prelaunch_oracle_params( + ctx: Context, + params: PrelaunchOracleParams, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); + let mut oracle = ctx.accounts.prelaunch_oracle.load_mut()?; + let mut perp_market = ctx.accounts.perp_market.load_mut()?; + msg!("perp market {}", perp_market.market_index); - spot_market.paused_operations = paused_operations; + let now = Clock::get()?.unix_timestamp; - SpotOperation::log_all_operations_paused(spot_market.paused_operations); + if let Some(price) = params.price { + oracle.price = price; - Ok(()) -} + msg!("before mark twap ts = {:?} mark twap = {:?} mark twap 5min = {:?} bid twap = {:?} ask twap {:?}", perp_market.amm.last_mark_price_twap_ts, perp_market.amm.last_mark_price_twap, perp_market.amm.last_mark_price_twap_5min, perp_market.amm.last_bid_price_twap, perp_market.amm.last_ask_price_twap); -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_asset_tier( - ctx: Context, - asset_tier: AssetTier, -) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); + perp_market.amm.last_mark_price_twap_ts = now; + perp_market.amm.last_mark_price_twap = price.cast()?; + perp_market.amm.last_mark_price_twap_5min = price.cast()?; + perp_market.amm.last_bid_price_twap = + perp_market.amm.last_bid_price_twap.min(price.cast()?); + perp_market.amm.last_ask_price_twap = + perp_market.amm.last_ask_price_twap.max(price.cast()?); - if spot_market.initial_asset_weight > 0 { - validate!( - matches!(asset_tier, AssetTier::Collateral | AssetTier::Protected), - ErrorCode::DefaultError, - "initial_asset_weight > 0 so AssetTier must be collateral or protected" - )?; + msg!("after mark twap ts = {:?} mark twap = {:?} mark twap 5min = {:?} bid twap = {:?} ask twap {:?}", perp_market.amm.last_mark_price_twap_ts, perp_market.amm.last_mark_price_twap, perp_market.amm.last_mark_price_twap_5min, perp_market.amm.last_bid_price_twap, perp_market.amm.last_ask_price_twap); + } else { + msg!("mark twap ts, mark twap, mark twap 5min, bid twap, ask twap: unchanged"); } - msg!( - "spot_market.asset_tier: {:?} -> {:?}", - spot_market.asset_tier, - asset_tier - ); + if let Some(max_price) = params.max_price { + msg!("max price: {:?} -> {:?}", oracle.max_price, max_price); + oracle.max_price = max_price; + } else { + msg!("max price: unchanged") + } + + oracle.validate()?; - spot_market.asset_tier = asset_tier; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_margin_weights( - ctx: Context, - initial_asset_weight: u32, - maintenance_asset_weight: u32, - initial_liability_weight: u32, - maintenance_liability_weight: u32, - imf_factor: u32, +pub fn handle_delete_prelaunch_oracle( + ctx: Context, + _perp_market_index: u16, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); - - validate_margin_weights( - spot_market.market_index, - initial_asset_weight, - maintenance_asset_weight, - initial_liability_weight, - maintenance_liability_weight, - imf_factor, - )?; + let perp_market = ctx.accounts.perp_market.load()?; + msg!("perp market {}", perp_market.market_index); - msg!( - "spot_market.initial_asset_weight: {:?} -> {:?}", - spot_market.initial_asset_weight, - initial_asset_weight - ); - - msg!( - "spot_market.maintenance_asset_weight: {:?} -> {:?}", - spot_market.maintenance_asset_weight, - maintenance_asset_weight - ); - - msg!( - "spot_market.initial_liability_weight: {:?} -> {:?}", - spot_market.initial_liability_weight, - initial_liability_weight - ); - - msg!( - "spot_market.maintenance_liability_weight: {:?} -> {:?}", - spot_market.maintenance_liability_weight, - maintenance_liability_weight - ); - - msg!( - "spot_market.imf_factor: {:?} -> {:?}", - spot_market.imf_factor, - imf_factor - ); - - spot_market.initial_asset_weight = initial_asset_weight; - spot_market.maintenance_asset_weight = maintenance_asset_weight; - spot_market.initial_liability_weight = initial_liability_weight; - spot_market.maintenance_liability_weight = maintenance_liability_weight; - spot_market.imf_factor = imf_factor; + validate!( + perp_market.amm.oracle != ctx.accounts.prelaunch_oracle.key(), + ErrorCode::DefaultError, + "prelaunch oracle currently in use" + )?; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_borrow_rate( - ctx: Context, - optimal_utilization: u32, - optimal_borrow_rate: u32, - max_borrow_rate: u32, - min_borrow_rate: Option, +pub fn handle_initialize_pyth_pull_oracle( + ctx: Context, + feed_id: [u8; 32], ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); - - validate_borrow_rate( - optimal_utilization, - optimal_borrow_rate, - max_borrow_rate, - min_borrow_rate - .unwrap_or(spot_market.min_borrow_rate) - .cast::()? - * ((PERCENTAGE_PRECISION / 200) as u32), - )?; - - msg!( - "spot_market.optimal_utilization: {:?} -> {:?}", - spot_market.optimal_utilization, - optimal_utilization - ); - - msg!( - "spot_market.optimal_borrow_rate: {:?} -> {:?}", - spot_market.optimal_borrow_rate, - optimal_borrow_rate - ); - - msg!( - "spot_market.max_borrow_rate: {:?} -> {:?}", - spot_market.max_borrow_rate, - max_borrow_rate - ); + let cpi_program = ctx.accounts.pyth_solana_receiver.to_account_info(); + let cpi_accounts = InitPriceUpdate { + payer: ctx.accounts.admin.to_account_info(), + price_update_account: ctx.accounts.price_feed.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + write_authority: ctx.accounts.price_feed.to_account_info(), + }; - spot_market.optimal_utilization = optimal_utilization; - spot_market.optimal_borrow_rate = optimal_borrow_rate; - spot_market.max_borrow_rate = max_borrow_rate; + let seeds = &[ + PTYH_PRICE_FEED_SEED_PREFIX, + feed_id.as_ref(), + &[ctx.bumps.price_feed], + ]; + let signer_seeds = &[&seeds[..]]; + let cpi_context = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds); - if let Some(min_borrow_rate) = min_borrow_rate { - msg!( - "spot_market.min_borrow_rate: {:?} -> {:?}", - spot_market.min_borrow_rate, - min_borrow_rate - ); - spot_market.min_borrow_rate = min_borrow_rate - } + pyth_solana_receiver_sdk::cpi::init_price_update(cpi_context, feed_id)?; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_max_token_deposits( - ctx: Context, - max_token_deposits: u64, +pub fn handle_initialize_pyth_lazer_oracle( + ctx: Context, + feed_id: u32, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); - + let pubkey = ctx.accounts.lazer_oracle.to_account_info().key; msg!( - "spot_market.max_token_deposits: {:?} -> {:?}", - spot_market.max_token_deposits, - max_token_deposits + "Lazer price feed initted {} with feed_id {}", + pubkey, + feed_id ); - - spot_market.max_token_deposits = max_token_deposits; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_max_token_borrows( - ctx: Context, - max_token_borrows_fraction: u16, +pub fn handle_settle_expired_market<'c: 'info, 'info>( + ctx: Context<'_, '_, 'c, 'info, AdminUpdatePerpMarket<'info>>, + market_index: u16, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); + let clock = Clock::get()?; + let _now = clock.unix_timestamp; + let state = &ctx.accounts.state; - msg!( - "spot_market.max_token_borrows_fraction: {:?} -> {:?}", - spot_market.max_token_borrows_fraction, - max_token_borrows_fraction - ); + let AccountMaps { + perp_market_map, + spot_market_map, + mut oracle_map, + } = load_maps( + &mut ctx.remaining_accounts.iter().peekable(), + &get_writable_perp_market_set(market_index), + &get_writable_spot_market_set(QUOTE_SPOT_MARKET_INDEX), + clock.slot, + Some(state.oracle_guard_rails), + )?; - let current_spot_tokens_borrows: u64 = spot_market.get_borrows()?.cast()?; - let new_max_token_borrows = spot_market - .max_token_deposits - .safe_mul(max_token_borrows_fraction.cast()?)? - .safe_div(10000)?; + controller::repeg::update_amm( + market_index, + &perp_market_map, + &mut oracle_map, + state, + &clock, + )?; - validate!( - current_spot_tokens_borrows <= new_max_token_borrows, - ErrorCode::InvalidSpotMarketInitialization, - "spot borrows {} > max_token_borrows {}", - current_spot_tokens_borrows, - max_token_borrows_fraction + controller::repeg::settle_expired_market( + market_index, + &perp_market_map, + &mut oracle_map, + &spot_market_map, + state, + &clock, )?; - spot_market.max_token_borrows_fraction = max_token_borrows_fraction; Ok(()) } -#[access_control( -spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_scale_initial_asset_weight_start( - ctx: Context, - scale_initial_asset_weight_start: u64, +pub fn handle_initialize_high_leverage_mode_config( + ctx: Context, + max_users: u32, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); + let mut config = ctx.accounts.high_leverage_mode_config.load_init()?; - msg!( - "spot_market.scale_initial_asset_weight_start: {:?} -> {:?}", - spot_market.scale_initial_asset_weight_start, - scale_initial_asset_weight_start - ); + config.max_users = max_users; + + config.validate()?; - spot_market.scale_initial_asset_weight_start = scale_initial_asset_weight_start; Ok(()) } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_orders_enabled( - ctx: Context, - orders_enabled: bool, +pub fn handle_update_high_leverage_mode_config( + ctx: Context, + max_users: u32, + reduce_only: bool, + current_users: Option, ) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); + let mut config = load_mut!(ctx.accounts.high_leverage_mode_config)?; - msg!( - "spot_market.orders_enabled: {:?} -> {:?}", - spot_market.orders_enabled, - orders_enabled - ); + config.max_users = max_users; - spot_market.orders_enabled = orders_enabled; - Ok(()) -} + config.reduce_only = reduce_only as u8; + + if let Some(current_users) = current_users { + config.current_users = current_users; + } + + config.validate()?; -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_if_paused_operations( - ctx: Context, - paused_operations: u8, -) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - spot_market.if_paused_operations = paused_operations; - msg!("spot market {}", spot_market.market_index); - InsuranceFundOperation::log_all_operations_paused(paused_operations); Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_status( - ctx: Context, - status: MarketStatus, +pub fn handle_initialize_protected_maker_mode_config( + ctx: Context, + max_users: u32, ) -> Result<()> { - validate!( - !matches!(status, MarketStatus::Delisted | MarketStatus::Settlement), - ErrorCode::DefaultError, - "must set settlement/delist through another instruction", - )?; - - status.validate_not_deprecated()?; - - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - - msg!("perp market {}", perp_market.market_index); + let mut config = ctx.accounts.protected_maker_mode_config.load_init()?; - msg!( - "perp_market.status: {:?} -> {:?}", - perp_market.status, - status - ); + config.max_users = max_users; - perp_market.status = status; Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_paused_operations( - ctx: Context, - paused_operations: u8, +pub fn handle_update_protected_maker_mode_config( + ctx: Context, + max_users: u32, + reduce_only: bool, + current_users: Option, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - perp_market.paused_operations = paused_operations; + let mut config = load_mut!(ctx.accounts.protected_maker_mode_config)?; - if perp_market.is_prediction_market() { - validate!( - perp_market.is_operation_paused(PerpOperation::UpdateFunding), - ErrorCode::DefaultError, - "prediction market must have funding paused" - )?; + if current_users.is_some() { + config.current_users = current_users.unwrap(); } + config.max_users = max_users; + config.reduce_only = reduce_only as u8; - PerpOperation::log_all_operations_paused(perp_market.paused_operations); + config.validate()?; Ok(()) } #[access_control( - perp_market_valid(&ctx.accounts.perp_market) + deposit_not_paused(&ctx.accounts.state) )] -pub fn handle_update_perp_market_contract_tier( - ctx: Context, - contract_tier: ContractTier, +pub fn handle_admin_deposit<'c: 'info, 'info>( + ctx: Context<'_, '_, 'c, 'info, AdminDeposit<'info>>, + market_index: u16, + amount: u64, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - msg!( - "perp_market.contract_tier: {:?} -> {:?}", - perp_market.contract_tier, - contract_tier - ); + let user_key = ctx.accounts.user.key(); + let user = &mut load_mut!(ctx.accounts.user)?; - perp_market.contract_tier = contract_tier; - Ok(()) -} + let state = &ctx.accounts.state; + let clock = Clock::get()?; + let now = clock.unix_timestamp; + let slot = clock.slot; -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_imf_factor( - ctx: Context, - imf_factor: u32, - unrealized_pnl_imf_factor: u32, -) -> Result<()> { - validate!( - imf_factor <= SPOT_IMF_PRECISION, - ErrorCode::DefaultError, - "invalid imf factor", - )?; - validate!( - unrealized_pnl_imf_factor <= SPOT_IMF_PRECISION, - ErrorCode::DefaultError, - "invalid unrealized pnl imf factor", + let remaining_accounts_iter = &mut ctx.remaining_accounts.iter().peekable(); + let AccountMaps { + perp_market_map: _, + spot_market_map, + mut oracle_map, + } = load_maps( + remaining_accounts_iter, + &MarketSet::new(), + &get_writable_spot_market_set(market_index), + clock.slot, + Some(state.oracle_guard_rails), )?; - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - msg!( - "perp_market.imf_factor: {:?} -> {:?}", - perp_market.imf_factor, - imf_factor - ); + let mint = get_token_mint(remaining_accounts_iter)?; - msg!( - "perp_market.unrealized_pnl_imf_factor: {:?} -> {:?}", - perp_market.unrealized_pnl_imf_factor, - unrealized_pnl_imf_factor - ); + if amount == 0 { + return Err(ErrorCode::InsufficientDeposit.into()); + } - perp_market.imf_factor = imf_factor; - perp_market.unrealized_pnl_imf_factor = unrealized_pnl_imf_factor; - Ok(()) -} + validate!(!user.is_bankrupt(), ErrorCode::UserBankrupt)?; + + let mut spot_market = spot_market_map.get_ref_mut(&market_index)?; + let oracle_price_data = *oracle_map.get_price_data(&spot_market.oracle_id())?; -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_unrealized_asset_weight( - ctx: Context, - unrealized_initial_asset_weight: u32, - unrealized_maintenance_asset_weight: u32, -) -> Result<()> { validate!( - unrealized_initial_asset_weight <= SPOT_WEIGHT_PRECISION.cast()?, - ErrorCode::DefaultError, - "invalid unrealized_initial_asset_weight", + user.pool_id == spot_market.pool_id, + ErrorCode::InvalidPoolId, + "user pool id ({}) != market pool id ({})", + user.pool_id, + spot_market.pool_id )?; + validate!( - unrealized_maintenance_asset_weight <= SPOT_WEIGHT_PRECISION.cast()?, - ErrorCode::DefaultError, - "invalid unrealized_maintenance_asset_weight", + !matches!(spot_market.status, MarketStatus::Initialized), + ErrorCode::MarketBeingInitialized, + "Market is being initialized" )?; - validate!( - unrealized_initial_asset_weight <= unrealized_maintenance_asset_weight, - ErrorCode::DefaultError, - "must enforce unrealized_initial_asset_weight <= unrealized_maintenance_asset_weight", + + controller::spot_balance::update_spot_market_cumulative_interest( + &mut spot_market, + Some(&oracle_price_data), + now, )?; - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - msg!( - "perp_market.unrealized_initial_asset_weight: {:?} -> {:?}", - perp_market.unrealized_pnl_initial_asset_weight, - unrealized_initial_asset_weight - ); + let position_index = user.force_get_spot_position_index(spot_market.market_index)?; - msg!( - "perp_market.unrealized_maintenance_asset_weight: {:?} -> {:?}", - perp_market.unrealized_pnl_maintenance_asset_weight, - unrealized_maintenance_asset_weight - ); + // if reduce only, have to compare ix amount to current borrow amount + let amount = if (spot_market.is_reduce_only()) + && user.spot_positions[position_index].balance_type == SpotBalanceType::Borrow + { + user.spot_positions[position_index] + .get_token_amount(&spot_market)? + .cast::()? + .min(amount) + } else { + amount + }; - perp_market.unrealized_pnl_initial_asset_weight = unrealized_initial_asset_weight; - perp_market.unrealized_pnl_maintenance_asset_weight = unrealized_maintenance_asset_weight; - Ok(()) -} + let total_deposits_after = user.total_deposits; + let total_withdraws_after = user.total_withdraws; -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_concentration_coef( - ctx: Context, - concentration_scale: u128, -) -> Result<()> { - validate!( - concentration_scale > 0, - ErrorCode::DefaultError, - "invalid concentration_scale", + let spot_position = &mut user.spot_positions[position_index]; + controller::spot_position::update_spot_balances_and_cumulative_deposits( + amount as u128, + &SpotBalanceType::Deposit, + &mut spot_market, + spot_position, + false, + None, )?; - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); + let token_amount = spot_position.get_token_amount(&spot_market)?; + if token_amount == 0 { + validate!( + spot_position.scaled_balance == 0, + ErrorCode::InvalidSpotPosition, + "deposit left user with invalid position. scaled balance = {} token amount = {}", + spot_position.scaled_balance, + token_amount + )?; + } - let prev_concentration_coef = perp_market.amm.concentration_coef; - controller::amm::update_concentration_coef(perp_market, concentration_scale)?; - let new_concentration_coef = perp_market.amm.concentration_coef; + if spot_position.balance_type == SpotBalanceType::Deposit && spot_position.scaled_balance > 0 { + validate!( + matches!(spot_market.status, MarketStatus::Active), + ErrorCode::MarketActionPaused, + "spot_market not active", + )?; + } - msg!( - "perp_market.amm.concentration_coef: {} -> {}", - prev_concentration_coef, - new_concentration_coef - ); + drop(spot_market); - Ok(()) -} + user.update_last_active_slot(slot); -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_curve_update_intensity( - ctx: Context, - curve_update_intensity: u8, -) -> Result<()> { - // (0, 100] is for repeg / formulaic k intensity - // (100, 200] is for reference price offset intensity - validate!( - curve_update_intensity <= 200, - ErrorCode::DefaultError, - "invalid curve_update_intensity", - )?; - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); + let spot_market = &mut spot_market_map.get_ref_mut(&market_index)?; - msg!( - "perp_market.amm.curve_update_intensity: {} -> {}", - perp_market.amm.curve_update_intensity, - curve_update_intensity - ); + controller::token::receive( + &ctx.accounts.token_program, + &ctx.accounts.admin_token_account, + &ctx.accounts.spot_market_vault, + &ctx.accounts.admin, + amount, + &mint, + if spot_market.has_transfer_hook() { + Some(remaining_accounts_iter) + } else { + None + }, + )?; + ctx.accounts.spot_market_vault.reload()?; + validate_spot_market_vault_amount(spot_market, ctx.accounts.spot_market_vault.amount)?; - perp_market.amm.curve_update_intensity = curve_update_intensity; - Ok(()) -} + let deposit_record_id = get_then_update_id!(spot_market, next_deposit_record_id); + let oracle_price = oracle_price_data.price; + let deposit_record = DepositRecord { + ts: now, + deposit_record_id, + user_authority: user.authority, + user: user_key, + direction: DepositDirection::Deposit, + amount, + oracle_price, + market_deposit_balance: spot_market.deposit_balance, + market_withdraw_balance: spot_market.borrow_balance, + market_cumulative_deposit_interest: spot_market.cumulative_deposit_interest, + market_cumulative_borrow_interest: spot_market.cumulative_borrow_interest, + total_deposits_after, + total_withdraws_after, + market_index, + explanation: DepositExplanation::Reward, + transfer_user: None, + }; + emit!(deposit_record); -pub fn handle_update_lp_cooldown_time( - ctx: Context, - lp_cooldown_time: u64, -) -> Result<()> { - msg!( - "lp_cooldown_time: {} -> {}", - ctx.accounts.state.lp_cooldown_time, - lp_cooldown_time - ); + spot_market.validate_max_token_deposits_and_borrows(false)?; - ctx.accounts.state.lp_cooldown_time = lp_cooldown_time; Ok(()) } -pub fn handle_update_perp_fee_structure( - ctx: Context, - fee_structure: FeeStructure, +pub fn handle_initialize_if_rebalance_config( + ctx: Context, + params: IfRebalanceConfigParams, ) -> Result<()> { - validate_fee_structure(&fee_structure)?; + let pubkey = ctx.accounts.if_rebalance_config.to_account_info().key; + let mut config = ctx.accounts.if_rebalance_config.load_init()?; - msg!( - "perp_fee_structure: {:?} -> {:?}", - ctx.accounts.state.perp_fee_structure, - fee_structure - ); + config.pubkey = *pubkey; + config.total_in_amount = params.total_in_amount; + config.current_in_amount = 0; + config.epoch_max_in_amount = params.epoch_max_in_amount; + config.epoch_duration = params.epoch_duration; + config.out_market_index = params.out_market_index; + config.in_market_index = params.in_market_index; + config.max_slippage_bps = params.max_slippage_bps; + config.swap_mode = params.swap_mode; + config.status = 0; + + config.validate()?; - ctx.accounts.state.perp_fee_structure = fee_structure; Ok(()) } -pub fn handle_update_spot_fee_structure( - ctx: Context, - fee_structure: FeeStructure, +pub fn handle_update_if_rebalance_config( + ctx: Context, + params: IfRebalanceConfigParams, ) -> Result<()> { - validate_fee_structure(&fee_structure)?; + let mut config = load_mut!(ctx.accounts.if_rebalance_config)?; - msg!( - "spot_fee_structure: {:?} -> {:?}", - ctx.accounts.state.spot_fee_structure, - fee_structure - ); + config.total_in_amount = params.total_in_amount; + config.epoch_max_in_amount = params.epoch_max_in_amount; + config.epoch_duration = params.epoch_duration; + config.max_slippage_bps = params.max_slippage_bps; + + config.validate()?; - ctx.accounts.state.spot_fee_structure = fee_structure; Ok(()) } -pub fn handle_update_initial_pct_to_liquidate( - ctx: Context, - initial_pct_to_liquidate: u16, -) -> Result<()> { - msg!( - "initial_pct_to_liquidate: {} -> {}", - ctx.accounts.state.initial_pct_to_liquidate, - initial_pct_to_liquidate +pub fn handle_update_mm_oracle_native(accounts: &[AccountInfo], data: &[u8]) -> Result<()> { + // Verify this ix is allowed + let state = &accounts[3].data.borrow(); + assert!(state[982] & 1 > 0, "ix disabled by admin state"); + + let signer_account = &accounts[1]; + #[cfg(not(feature = "anchor-test"))] + assert!( + signer_account.is_signer && *signer_account.key == mm_oracle_crank_wallet::id(), + "signer must be mm oracle crank wallet, signer: {}, mm oracle crank wallet: {}", + signer_account.key, + mm_oracle_crank_wallet::id() ); - ctx.accounts.state.initial_pct_to_liquidate = initial_pct_to_liquidate; - Ok(()) -} + let mut perp_market = accounts[0].data.borrow_mut(); + let perp_market_sequence_id = u64::from_le_bytes(perp_market[936..944].try_into().unwrap()); + let incoming_sequence_id = u64::from_le_bytes(data[8..16].try_into().unwrap()); -pub fn handle_update_liquidation_duration( - ctx: Context, - liquidation_duration: u8, -) -> Result<()> { - msg!( - "liquidation_duration: {} -> {}", - ctx.accounts.state.liquidation_duration, - liquidation_duration - ); + if incoming_sequence_id > perp_market_sequence_id { + let clock_account = &accounts[2]; + let clock_data = clock_account.data.borrow(); + + perp_market[832..840].copy_from_slice(&clock_data[0..8]); + perp_market[912..920].copy_from_slice(&data[0..8]); + perp_market[936..944].copy_from_slice(&data[8..16]); + } - ctx.accounts.state.liquidation_duration = liquidation_duration; Ok(()) } -pub fn handle_update_liquidation_margin_buffer_ratio( - ctx: Context, - liquidation_margin_buffer_ratio: u32, +pub fn handle_update_amm_spread_adjustment_native( + accounts: &[AccountInfo], + data: &[u8], ) -> Result<()> { - msg!( - "liquidation_margin_buffer_ratio: {} -> {}", - ctx.accounts.state.liquidation_margin_buffer_ratio, - liquidation_margin_buffer_ratio + let signer_account = &accounts[1]; + #[cfg(not(feature = "anchor-test"))] + assert!( + signer_account.is_signer && *signer_account.key == amm_spread_adjust_wallet::id(), + "signer must be amm spread adjust wallet, signer: {}, amm spread adjust wallet: {}", + signer_account.key, + amm_spread_adjust_wallet::id() ); + let mut perp_market = accounts[0].data.borrow_mut(); + perp_market[934..935].copy_from_slice(&[data[0]]); - ctx.accounts.state.liquidation_margin_buffer_ratio = liquidation_margin_buffer_ratio; Ok(()) } -pub fn handle_update_oracle_guard_rails( - ctx: Context, - oracle_guard_rails: OracleGuardRails, +pub fn handle_update_feature_bit_flags_mm_oracle( + ctx: Context, + enable: bool, ) -> Result<()> { - msg!( - "oracle_guard_rails: {:?} -> {:?}", - ctx.accounts.state.oracle_guard_rails, - oracle_guard_rails - ); - - ctx.accounts.state.oracle_guard_rails = oracle_guard_rails; - Ok(()) -} - -pub fn handle_update_state_settlement_duration( - ctx: Context, - settlement_duration: u16, -) -> Result<()> { - msg!( - "settlement_duration: {} -> {}", - ctx.accounts.state.settlement_duration, - settlement_duration - ); - - ctx.accounts.state.settlement_duration = settlement_duration; - Ok(()) -} - -pub fn handle_update_state_max_number_of_sub_accounts( - ctx: Context, - max_number_of_sub_accounts: u16, -) -> Result<()> { - msg!( - "max_number_of_sub_accounts: {} -> {}", - ctx.accounts.state.max_number_of_sub_accounts, - max_number_of_sub_accounts - ); + let state = &mut ctx.accounts.state; + if enable { + validate!( + ctx.accounts.admin.key().eq(&state.admin), + ErrorCode::DefaultError, + "Only state admin can re-enable after kill switch" + )?; - ctx.accounts.state.max_number_of_sub_accounts = max_number_of_sub_accounts; + msg!("Setting first bit to 1, enabling mm oracle update"); + state.feature_bit_flags = state.feature_bit_flags | (FeatureBitFlags::MmOracleUpdate as u8); + } else { + msg!("Setting first bit to 0, disabling mm oracle update"); + state.feature_bit_flags = + state.feature_bit_flags & !(FeatureBitFlags::MmOracleUpdate as u8); + } Ok(()) } -pub fn handle_update_state_max_initialize_user_fee( - ctx: Context, - max_initialize_user_fee: u16, +pub fn handle_update_feature_bit_flags_median_trigger_price( + ctx: Context, + enable: bool, ) -> Result<()> { - msg!( - "max_initialize_user_fee: {} -> {}", - ctx.accounts.state.max_initialize_user_fee, - max_initialize_user_fee - ); + let state = &mut ctx.accounts.state; + if enable { + validate!( + ctx.accounts.admin.key().eq(&state.admin), + ErrorCode::DefaultError, + "Only state admin can re-enable after kill switch" + )?; - ctx.accounts.state.max_initialize_user_fee = max_initialize_user_fee; + msg!("Setting second bit to 1, enabling median trigger price"); + state.feature_bit_flags = + state.feature_bit_flags | (FeatureBitFlags::MedianTriggerPrice as u8); + } else { + msg!("Setting second bit to 0, disabling median trigger price"); + state.feature_bit_flags = + state.feature_bit_flags & !(FeatureBitFlags::MedianTriggerPrice as u8); + } Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_oracle( - ctx: Context, - oracle: Pubkey, - oracle_source: OracleSource, - skip_invariant_check: bool, +pub fn handle_update_delegate_user_gov_token_insurance_stake( + ctx: Context, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - let clock = Clock::get()?; - - OracleMap::validate_oracle_account_info(&ctx.accounts.oracle)?; - - validate!( - ctx.accounts.oracle.key == &oracle, - ErrorCode::DefaultError, - "oracle account info ({:?}) and ix data ({:?}) must match", - ctx.accounts.oracle.key, - oracle - )?; + let insurance_fund_stake = &mut load_mut!(ctx.accounts.insurance_fund_stake)?; + let user_stats = &mut load_mut!(ctx.accounts.user_stats)?; + let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; validate!( - ctx.accounts.old_oracle.key == &perp_market.amm.oracle, - ErrorCode::DefaultError, - "old oracle account info ({:?}) and perp market oracle ({:?}) must match", - ctx.accounts.old_oracle.key, - perp_market.amm.oracle - )?; - - // Verify new oracle is readable - let OraclePriceData { - price: new_oracle_price, - delay: _oracle_delay, - .. - } = get_oracle_price(&oracle_source, &ctx.accounts.oracle, clock.slot)?; - - msg!( - "perp_market.amm.oracle: {:?} -> {:?}", - perp_market.amm.oracle, - oracle - ); - - msg!( - "perp_market.amm.oracle_source: {:?} -> {:?}", - perp_market.amm.oracle_source, - oracle_source - ); - - let OraclePriceData { - price: old_oracle_price, - .. - } = get_oracle_price( - &perp_market.amm.oracle_source, - &ctx.accounts.old_oracle, - clock.slot, + insurance_fund_stake.market_index == GOV_SPOT_MARKET_INDEX, + ErrorCode::IncorrectSpotMarketAccountPassed, + "insurance_fund_stake is not for governance market index = {}", + GOV_SPOT_MARKET_INDEX )?; - msg!( - "Oracle Price: {:?} -> {:?}", - old_oracle_price, - new_oracle_price - ); - - if !skip_invariant_check { - validate!( - new_oracle_price > 0, - ErrorCode::DefaultError, - "invalid oracle price, must be greater than 0" - )?; - - let oracle_change_divergence = new_oracle_price - .safe_sub(old_oracle_price)? - .safe_mul(PERCENTAGE_PRECISION_I64)? - .safe_div(old_oracle_price)?; + if insurance_fund_stake.market_index == GOV_SPOT_MARKET_INDEX + && spot_market.market_index == GOV_SPOT_MARKET_INDEX + { + let clock = Clock::get()?; + let now = clock.unix_timestamp; - validate!( - oracle_change_divergence.abs() < (PERCENTAGE_PRECISION_I64 / 10), - ErrorCode::DefaultError, - "invalid new oracle price, more than 10% divergence" + crate::controller::insurance::update_user_stats_if_stake_amount( + 0, + ctx.accounts.insurance_fund_vault.amount, + insurance_fund_stake, + user_stats, + spot_market, + now, )?; } - perp_market.amm.oracle = oracle; - perp_market.amm.oracle_source = oracle_source; - Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_base_spread( - ctx: Context, - base_spread: u32, +pub fn handle_update_feature_bit_flags_builder_codes( + ctx: Context, + enable: bool, ) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - msg!( - "perp_market.amm.base_spread: {:?} -> {:?}", - perp_market.amm.base_spread, - base_spread - ); - - msg!( - "perp_market.amm.long_spread: {:?} -> {:?}", - perp_market.amm.long_spread, - base_spread / 2 - ); - - msg!( - "perp_market.amm.short_spread: {:?} -> {:?}", - perp_market.amm.short_spread, - base_spread / 2 - ); + let state = &mut ctx.accounts.state; + if enable { + validate!( + ctx.accounts.admin.key().eq(&state.admin), + ErrorCode::DefaultError, + "Only state admin can enable feature bit flags" + )?; - perp_market.amm.base_spread = base_spread; - perp_market.amm.long_spread = base_spread / 2; - perp_market.amm.short_spread = base_spread / 2; + msg!("Setting 3rd bit to 1, enabling builder codes"); + state.feature_bit_flags = state.feature_bit_flags | (FeatureBitFlags::BuilderCodes as u8); + } else { + msg!("Setting 3rd bit to 0, disabling builder codes"); + state.feature_bit_flags = state.feature_bit_flags & !(FeatureBitFlags::BuilderCodes as u8); + } Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_amm_jit_intensity( - ctx: Context, - amm_jit_intensity: u8, +pub fn handle_update_feature_bit_flags_builder_referral( + ctx: Context, + enable: bool, ) -> Result<()> { - validate!( - (0..=200).contains(&amm_jit_intensity), - ErrorCode::DefaultError, - "invalid amm_jit_intensity", - )?; - - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - msg!( - "perp_market.amm.amm_jit_intensity: {} -> {}", - perp_market.amm.amm_jit_intensity, - amm_jit_intensity - ); - - perp_market.amm.amm_jit_intensity = amm_jit_intensity; + let state = &mut ctx.accounts.state; + if enable { + validate!( + ctx.accounts.admin.key().eq(&state.admin), + ErrorCode::DefaultError, + "Only state admin can enable feature bit flags" + )?; + msg!("Setting 4th bit to 1, enabling builder referral"); + state.feature_bit_flags = + state.feature_bit_flags | (FeatureBitFlags::BuilderReferral as u8); + } else { + msg!("Setting 4th bit to 0, disabling builder referral"); + state.feature_bit_flags = + state.feature_bit_flags & !(FeatureBitFlags::BuilderReferral as u8); + } Ok(()) } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_max_spread( - ctx: Context, - max_spread: u32, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + init, + seeds = [b"drift_state".as_ref()], + space = State::SIZE, + bump, + payer = admin + )] + pub state: Box>, + pub quote_asset_mint: Box>, + /// CHECK: checked in `initialize` + pub drift_signer: AccountInfo<'info>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, + pub token_program: Interface<'info, TokenInterface>, +} - validate!( - max_spread >= perp_market.amm.base_spread, - ErrorCode::DefaultError, - "invalid max_spread < base_spread", - )?; - - validate!( - max_spread <= perp_market.margin_ratio_initial * 100, - ErrorCode::DefaultError, - "invalid max_spread > market.margin_ratio_initial * 100", - )?; - - msg!( - "perp_market.amm.max_spread: {:?} -> {:?}", - perp_market.amm.max_spread, - max_spread - ); - - perp_market.amm.max_spread = max_spread; - - Ok(()) +#[derive(Accounts)] +pub struct InitializeSpotMarket<'info> { + #[account( + init, + seeds = [b"spot_market", state.number_of_spot_markets.to_le_bytes().as_ref()], + space = SpotMarket::SIZE, + bump, + payer = admin + )] + pub spot_market: AccountLoader<'info, SpotMarket>, + #[account( + mint::token_program = token_program, + )] + pub spot_market_mint: Box>, + #[account( + init, + seeds = [b"spot_market_vault".as_ref(), state.number_of_spot_markets.to_le_bytes().as_ref()], + bump, + payer = admin, + space = get_vault_len(&spot_market_mint)?, + owner = token_program.key() + )] + /// CHECK: checked in `initialize_spot_market` + pub spot_market_vault: AccountInfo<'info>, + #[account( + init, + seeds = [b"insurance_fund_vault".as_ref(), state.number_of_spot_markets.to_le_bytes().as_ref()], + bump, + payer = admin, + space = get_vault_len(&spot_market_mint)?, + owner = token_program.key() + )] + /// CHECK: checked in `initialize_spot_market` + pub insurance_fund_vault: AccountInfo<'info>, + #[account( + constraint = state.signer.eq(&drift_signer.key()) + )] + /// CHECK: program signer + pub drift_signer: AccountInfo<'info>, + #[account(mut)] + pub state: Box>, + /// CHECK: checked in `initialize_spot_market` + pub oracle: AccountInfo<'info>, + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, + pub token_program: Interface<'info, TokenInterface>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_step_size_and_tick_size( - ctx: Context, - step_size: u64, - tick_size: u64, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - validate!(step_size > 0 && tick_size > 0, ErrorCode::DefaultError)?; - validate!(step_size <= 2000000000, ErrorCode::DefaultError)?; // below i32 max for lp's remainder_base_asset - - msg!( - "perp_market.amm.order_step_size: {:?} -> {:?}", - perp_market.amm.order_step_size, - step_size - ); - - msg!( - "perp_market.amm.order_tick_size: {:?} -> {:?}", - perp_market.amm.order_tick_size, - tick_size - ); - - perp_market.amm.order_step_size = step_size; - perp_market.amm.order_tick_size = tick_size; - Ok(()) +#[derive(Accounts)] +#[instruction(market_index: u16)] +pub struct DeleteInitializedSpotMarket<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + mut, + has_one = admin + )] + pub state: Box>, + #[account(mut, close = admin)] + pub spot_market: AccountLoader<'info, SpotMarket>, + #[account( + mut, + seeds = [b"spot_market_vault".as_ref(), market_index.to_le_bytes().as_ref()], + bump, + )] + pub spot_market_vault: Box>, + #[account( + mut, + seeds = [b"insurance_fund_vault".as_ref(), market_index.to_le_bytes().as_ref()], + bump, + )] + pub insurance_fund_vault: Box>, + /// CHECK: program signer + pub drift_signer: AccountInfo<'info>, + pub token_program: Interface<'info, TokenInterface>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_min_order_size( - ctx: Context, - order_size: u64, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - validate!(order_size > 0, ErrorCode::DefaultError)?; - - msg!( - "perp_market.amm.min_order_size: {:?} -> {:?}", - perp_market.amm.min_order_size, - order_size - ); - - perp_market.amm.min_order_size = order_size; - Ok(()) +#[derive(Accounts)] +#[instruction(market_index: u16)] +pub struct InitializeSerumFulfillmentConfig<'info> { + #[account( + seeds = [b"spot_market", market_index.to_le_bytes().as_ref()], + bump, + )] + pub base_spot_market: AccountLoader<'info, SpotMarket>, + #[account( + seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], + bump, + )] + pub quote_spot_market: AccountLoader<'info, SpotMarket>, + #[account( + mut, + has_one = admin + )] + pub state: Box>, + /// CHECK: checked in ix + pub serum_program: AccountInfo<'info>, + /// CHECK: checked in ix + pub serum_market: AccountInfo<'info>, + #[account( + mut, + seeds = [b"serum_open_orders".as_ref(), serum_market.key.as_ref()], + bump, + )] + /// CHECK: checked in ix + pub serum_open_orders: AccountInfo<'info>, + #[account( + constraint = state.signer.eq(&drift_signer.key()) + )] + /// CHECK: program signer + pub drift_signer: AccountInfo<'info>, + #[account( + init, + seeds = [b"serum_fulfillment_config".as_ref(), serum_market.key.as_ref()], + space = SerumV3FulfillmentConfig::SIZE, + bump, + payer = admin, + )] + pub serum_fulfillment_config: AccountLoader<'info, SerumV3FulfillmentConfig>, + #[account(mut)] + pub admin: Signer<'info>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_step_size_and_tick_size( - ctx: Context, - step_size: u64, - tick_size: u64, -) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); - - validate!( - spot_market.market_index == 0 || step_size > 0 && tick_size > 0, - ErrorCode::DefaultError - )?; - - msg!( - "spot_market.order_step_size: {:?} -> {:?}", - spot_market.order_step_size, - step_size - ); - - msg!( - "spot_market.order_tick_size: {:?} -> {:?}", - spot_market.order_tick_size, - tick_size - ); - - spot_market.order_step_size = step_size; - spot_market.order_tick_size = tick_size; - Ok(()) +#[derive(Accounts)] +pub struct UpdateSerumFulfillmentConfig<'info> { + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub serum_fulfillment_config: AccountLoader<'info, SerumV3FulfillmentConfig>, + #[account(mut)] + pub admin: Signer<'info>, } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_min_order_size( - ctx: Context, - order_size: u64, -) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); - - validate!( - spot_market.market_index == 0 || order_size > 0, - ErrorCode::DefaultError - )?; - - msg!( - "spot_market.min_order_size: {:?} -> {:?}", - spot_market.min_order_size, - order_size - ); +#[derive(Accounts)] +#[instruction(market_index: u16)] +pub struct InitializePhoenixFulfillmentConfig<'info> { + #[account( + seeds = [b"spot_market", market_index.to_le_bytes().as_ref()], + bump, + )] + pub base_spot_market: AccountLoader<'info, SpotMarket>, + #[account( + seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], + bump, + )] + pub quote_spot_market: AccountLoader<'info, SpotMarket>, + #[account( + mut, + has_one = admin + )] + pub state: Box>, + /// CHECK: checked in ix + pub phoenix_program: AccountInfo<'info>, + /// CHECK: checked in ix + pub phoenix_market: AccountInfo<'info>, + #[account( + constraint = state.signer.eq(&drift_signer.key()) + )] + /// CHECK: program signer + pub drift_signer: AccountInfo<'info>, + #[account( + init, + seeds = [b"phoenix_fulfillment_config".as_ref(), phoenix_market.key.as_ref()], + space = PhoenixV1FulfillmentConfig::SIZE, + bump, + payer = admin, + )] + pub phoenix_fulfillment_config: AccountLoader<'info, PhoenixV1FulfillmentConfig>, + #[account(mut)] + pub admin: Signer<'info>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, +} - spot_market.min_order_size = order_size; - Ok(()) +#[derive(Accounts)] +pub struct UpdatePhoenixFulfillmentConfig<'info> { + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub phoenix_fulfillment_config: AccountLoader<'info, PhoenixV1FulfillmentConfig>, + #[account(mut)] + pub admin: Signer<'info>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_max_slippage_ratio( - ctx: Context, - max_slippage_ratio: u16, -) -> Result<()> { - validate!(max_slippage_ratio > 0, ErrorCode::DefaultError)?; - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - msg!( - "perp_market.amm.max_slippage_ratio: {:?} -> {:?}", - perp_market.amm.max_slippage_ratio, - max_slippage_ratio - ); - - perp_market.amm.max_slippage_ratio = max_slippage_ratio; - Ok(()) +#[derive(Accounts)] +pub struct UpdateSerumVault<'info> { + #[account( + mut, + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub admin: Signer<'info>, + pub srm_vault: Box>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_max_fill_reserve_fraction( - ctx: Context, - max_fill_reserve_fraction: u16, -) -> Result<()> { - validate!(max_fill_reserve_fraction > 0, ErrorCode::DefaultError)?; - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); +#[derive(Accounts)] +pub struct InitializePerpMarket<'info> { + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account(mut)] + pub state: Box>, + #[account( + init, + seeds = [b"perp_market", state.number_of_markets.to_le_bytes().as_ref()], + space = PerpMarket::SIZE, + bump, + payer = admin + )] + pub perp_market: AccountLoader<'info, PerpMarket>, + /// CHECK: checked in `initialize_perp_market` + pub oracle: AccountInfo<'info>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, +} - msg!( - "perp_market.amm.max_fill_reserve_fraction: {:?} -> {:?}", - perp_market.amm.max_fill_reserve_fraction, - max_fill_reserve_fraction - ); +#[derive(Accounts)] +pub struct DeleteInitializedPerpMarket<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + mut, + has_one = admin + )] + pub state: Box>, + #[account(mut, close = admin)] + pub perp_market: AccountLoader<'info, PerpMarket>, +} - perp_market.amm.max_fill_reserve_fraction = max_fill_reserve_fraction; - Ok(()) +#[derive(Accounts)] +pub struct AdminUpdatePerpMarket<'info> { + pub admin: Signer<'info>, + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_max_open_interest( - ctx: Context, - max_open_interest: u128, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); +#[derive(Accounts)] +pub struct HotAdminUpdatePerpMarket<'info> { + #[account( + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + pub state: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, +} - validate!( - is_multiple_of_step_size( - max_open_interest.cast::()?, - perp_market.amm.order_step_size - )?, - ErrorCode::DefaultError, - "max oi not a multiple of the step size" - )?; +#[derive(Accounts)] +pub struct AdminUpdatePerpMarketAmmSummaryStats<'info> { + #[account( + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + pub state: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, + #[account( + seeds = [b"spot_market", perp_market.load()?.quote_spot_market_index.to_le_bytes().as_ref()], + bump, + )] + pub spot_market: AccountLoader<'info, SpotMarket>, + /// CHECK: checked in `admin_update_perp_market_summary_stats` ix constraint + pub oracle: AccountInfo<'info>, +} - msg!( - "perp_market.amm.max_open_interest: {:?} -> {:?}", - perp_market.amm.max_open_interest, - max_open_interest - ); +#[derive(Accounts)] +pub struct SettleExpiredMarketPoolsToRevenuePool<'info> { + #[account( + has_one = admin + )] + pub state: Box>, + pub admin: Signer<'info>, + #[account( + seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], + bump, + mut + )] + pub spot_market: AccountLoader<'info, SpotMarket>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, +} - perp_market.amm.max_open_interest = max_open_interest; - Ok(()) +#[derive(Accounts)] +pub struct UpdatePerpMarketPnlPool<'info> { + #[account( + has_one = admin + )] + pub state: Box>, + pub admin: Signer<'info>, + #[account( + seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], + bump, + mut + )] + pub spot_market: AccountLoader<'info, SpotMarket>, + #[account( + mut, + seeds = [b"spot_market_vault".as_ref(), 0_u16.to_le_bytes().as_ref()], + bump, + )] + pub spot_market_vault: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_fee_adjustment( - ctx: Context, - fee_adjustment: i16, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); +#[derive(Accounts)] +pub struct DepositIntoMarketFeePool<'info> { + #[account( + mut, + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, + pub admin: Signer<'info>, + #[account( + mut, + token::authority = admin + )] + pub source_vault: Box>, + #[account( + constraint = state.signer.eq(&drift_signer.key()) + )] + /// CHECK: withdraw fails if this isn't vault owner + pub drift_signer: AccountInfo<'info>, + #[account( + mut, + seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], + bump, + )] + pub quote_spot_market: AccountLoader<'info, SpotMarket>, + #[account( + mut, + seeds = [b"spot_market_vault".as_ref(), 0_u16.to_le_bytes().as_ref()], + bump, + )] + pub spot_market_vault: Box>, + pub token_program: Interface<'info, TokenInterface>, +} - validate!( - fee_adjustment.unsigned_abs().cast::()? <= FEE_ADJUSTMENT_MAX, - ErrorCode::DefaultError, - "fee adjustment {} greater than max {}", - fee_adjustment, - FEE_ADJUSTMENT_MAX - )?; +#[derive(Accounts)] +pub struct DepositIntoSpotMarketVault<'info> { + pub state: Box>, + #[account(mut)] + pub spot_market: AccountLoader<'info, SpotMarket>, + #[account( + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account( + mut, + token::authority = admin + )] + pub source_vault: Box>, + #[account( + mut, + constraint = spot_market.load()?.vault == spot_market_vault.key() + )] + pub spot_market_vault: Box>, + pub token_program: Interface<'info, TokenInterface>, +} - msg!( - "perp_market.fee_adjustment: {:?} -> {:?}", - perp_market.fee_adjustment, - fee_adjustment - ); +#[derive(Accounts)] +pub struct RepegCurve<'info> { + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, + /// CHECK: checked in `repeg_curve` ix constraint + pub oracle: AccountInfo<'info>, + pub admin: Signer<'info>, +} - perp_market.fee_adjustment = fee_adjustment; - Ok(()) +#[derive(Accounts)] +pub struct AdminUpdateState<'info> { + pub admin: Signer<'info>, + #[account( + mut, + has_one = admin + )] + pub state: Box>, } -pub fn handle_update_perp_market_number_of_users( - ctx: Context, - number_of_users: Option, - number_of_users_with_base: Option, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); +#[derive(Accounts)] +pub struct HotAdminUpdateState<'info> { + #[account( + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account(mut)] + pub state: Box>, +} - if let Some(number_of_users) = number_of_users { - msg!( - "perp_market.number_of_users: {:?} -> {:?}", - perp_market.number_of_users, - number_of_users - ); - perp_market.number_of_users = number_of_users; - } else { - msg!("perp_market.number_of_users: unchanged"); - } - - if let Some(number_of_users_with_base) = number_of_users_with_base { - msg!( - "perp_market.number_of_users_with_base: {:?} -> {:?}", - perp_market.number_of_users_with_base, - number_of_users_with_base - ); - perp_market.number_of_users_with_base = number_of_users_with_base; - } else { - msg!("perp_market.number_of_users_with_base: unchanged"); - } - - validate!( - perp_market.number_of_users >= perp_market.number_of_users_with_base, - ErrorCode::DefaultError, - "number_of_users must be >= number_of_users_with_base " - )?; - - Ok(()) +#[derive(Accounts)] +pub struct AdminUpdateK<'info> { + pub admin: Signer<'info>, + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, + /// CHECK: checked in `admin_update_k` ix constraint + pub oracle: AccountInfo<'info>, } -pub fn handle_update_perp_market_fuel( - ctx: Context, - fuel_boost_taker: Option, - fuel_boost_maker: Option, - fuel_boost_position: Option, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - if let Some(fuel_boost_taker) = fuel_boost_taker { - msg!( - "perp_market.fuel_boost_taker: {:?} -> {:?}", - perp_market.fuel_boost_taker, - fuel_boost_taker - ); - perp_market.fuel_boost_taker = fuel_boost_taker; - } else { - msg!("perp_market.fuel_boost_taker: unchanged"); - } - - if let Some(fuel_boost_maker) = fuel_boost_maker { - msg!( - "perp_market.fuel_boost_maker: {:?} -> {:?}", - perp_market.fuel_boost_maker, - fuel_boost_maker - ); - perp_market.fuel_boost_maker = fuel_boost_maker; - } else { - msg!("perp_market.fuel_boost_maker: unchanged"); - } - - if let Some(fuel_boost_position) = fuel_boost_position { - msg!( - "perp_market.fuel_boost_position: {:?} -> {:?}", - perp_market.fuel_boost_position, - fuel_boost_position - ); - perp_market.fuel_boost_position = fuel_boost_position; - } else { - msg!("perp_market.fuel_boost_position: unchanged"); - } - - Ok(()) +#[derive(Accounts)] +pub struct AdminUpdateSpotMarket<'info> { + pub admin: Signer<'info>, + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub spot_market: AccountLoader<'info, SpotMarket>, } -pub fn handle_update_perp_market_protected_maker_params( - ctx: Context, - protected_maker_limit_price_divisor: Option, - protected_maker_dynamic_divisor: Option, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - if let Some(protected_maker_limit_price_divisor) = protected_maker_limit_price_divisor { - msg!( - "perp_market.protected_maker_limit_price_divisor: {:?} -> {:?}", - perp_market.protected_maker_limit_price_divisor, - protected_maker_limit_price_divisor - ); - perp_market.protected_maker_limit_price_divisor = protected_maker_limit_price_divisor; - } else { - msg!("perp_market.protected_maker_limit_price_divisor: unchanged"); - } - - if let Some(protected_maker_dynamic_divisor) = protected_maker_dynamic_divisor { - msg!( - "perp_market.protected_maker_dynamic_divisor: {:?} -> {:?}", - perp_market.protected_maker_dynamic_divisor, - protected_maker_dynamic_divisor - ); - perp_market.protected_maker_dynamic_divisor = protected_maker_dynamic_divisor; - } else { - msg!("perp_market.protected_maker_dynamic_divisor: unchanged"); - } - - Ok(()) +#[derive(Accounts)] +pub struct AdminUpdateSpotMarketFuel<'info> { + #[account( + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + pub state: Box>, + #[account(mut)] + pub spot_market: AccountLoader<'info, SpotMarket>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_taker_speed_bump_override( - ctx: Context, - taker_speed_bump_override: i8, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - msg!( - "perp_market.amm.taker_speed_bump_override: {:?} -> {:?}", - perp_market.amm.taker_speed_bump_override, - taker_speed_bump_override - ); - - perp_market.amm.taker_speed_bump_override = taker_speed_bump_override; - Ok(()) +#[derive(Accounts)] +pub struct AdminUpdateSpotMarketOracle<'info> { + pub admin: Signer<'info>, + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub spot_market: AccountLoader<'info, SpotMarket>, + /// CHECK: checked in `initialize_spot_market` + pub oracle: AccountInfo<'info>, + /// CHECK: checked in `admin_update_spot_market_oracle` ix constraint + pub old_oracle: AccountInfo<'info>, } -#[access_control( - perp_market_valid(&ctx.accounts.perp_market) -)] -pub fn handle_update_perp_market_amm_spread_adjustment( - ctx: Context, - amm_spread_adjustment: i8, - amm_inventory_spread_adjustment: i8, - reference_price_offset: i32, -) -> Result<()> { - let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; - msg!("perp market {}", perp_market.market_index); - - msg!( - "perp_market.amm.amm_spread_adjustment: {:?} -> {:?}", - perp_market.amm.amm_spread_adjustment, - amm_spread_adjustment - ); - - perp_market.amm.amm_spread_adjustment = amm_spread_adjustment; - - msg!( - "perp_market.amm.amm_inventory_spread_adjustment: {:?} -> {:?}", - perp_market.amm.amm_inventory_spread_adjustment, - amm_inventory_spread_adjustment - ); - - perp_market.amm.amm_inventory_spread_adjustment = amm_inventory_spread_adjustment; - - msg!( - "perp_market.amm.reference_price_offset: {:?} -> {:?}", - perp_market.amm.reference_price_offset, - reference_price_offset - ); - - perp_market.amm.reference_price_offset = reference_price_offset; - - Ok(()) +#[derive(Accounts)] +pub struct AdminUpdatePerpMarketOracle<'info> { + pub admin: Signer<'info>, + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub perp_market: AccountLoader<'info, PerpMarket>, + /// CHECK: checked in `admin_update_perp_market_oracle` ix constraint + pub oracle: AccountInfo<'info>, + /// CHECK: checked in `admin_update_perp_market_oracle` ix constraint + pub old_oracle: AccountInfo<'info>, } -#[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(()) +#[derive(Accounts)] +pub struct AdminDisableBidAskTwapUpdate<'info> { + #[account( + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + pub state: Box>, + #[account(mut)] + pub user_stats: AccountLoader<'info, UserStats>, } -#[access_control( - spot_market_valid(&ctx.accounts.spot_market) -)] -pub fn handle_update_spot_market_fee_adjustment( - ctx: Context, - fee_adjustment: i16, -) -> Result<()> { - let spot = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot.market_index); +#[derive(Accounts)] +pub struct InitUserFuel<'info> { + #[account( + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, // todo + pub state: Box>, + #[account(mut)] + pub user: AccountLoader<'info, User>, + #[account(mut)] + pub user_stats: AccountLoader<'info, UserStats>, +} - validate!( - fee_adjustment.unsigned_abs().cast::()? <= FEE_ADJUSTMENT_MAX, - ErrorCode::DefaultError, - "fee adjustment {} greater than max {}", - fee_adjustment, - FEE_ADJUSTMENT_MAX - )?; +#[derive(Accounts)] +pub struct InitializeProtocolIfSharesTransferConfig<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + init, + seeds = [b"if_shares_transfer_config".as_ref()], + space = ProtocolIfSharesTransferConfig::SIZE, + bump, + payer = admin + )] + pub protocol_if_shares_transfer_config: AccountLoader<'info, ProtocolIfSharesTransferConfig>, + #[account( + has_one = admin + )] + pub state: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, +} - msg!( - "spot_market.fee_adjustment: {:?} -> {:?}", - spot.fee_adjustment, - fee_adjustment - ); +#[derive(Accounts)] +pub struct UpdateProtocolIfSharesTransferConfig<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + mut, + seeds = [b"if_shares_transfer_config".as_ref()], + bump, + )] + pub protocol_if_shares_transfer_config: AccountLoader<'info, ProtocolIfSharesTransferConfig>, + #[account( + has_one = admin + )] + pub state: Box>, +} - spot.fee_adjustment = fee_adjustment; - Ok(()) +#[derive(Accounts)] +#[instruction(params: PrelaunchOracleParams,)] +pub struct InitializePrelaunchOracle<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + init, + seeds = [b"prelaunch_oracle".as_ref(), params.perp_market_index.to_le_bytes().as_ref()], + space = PrelaunchOracle::SIZE, + bump, + payer = admin + )] + pub prelaunch_oracle: AccountLoader<'info, PrelaunchOracle>, + #[account( + has_one = admin + )] + pub state: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } -pub fn handle_update_spot_market_fuel( - ctx: Context, - fuel_boost_deposits: Option, - fuel_boost_borrows: Option, - fuel_boost_taker: Option, - fuel_boost_maker: Option, - fuel_boost_insurance: Option, -) -> Result<()> { - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - msg!("spot market {}", spot_market.market_index); - - if let Some(fuel_boost_taker) = fuel_boost_taker { - msg!( - "spot_market.fuel_boost_taker: {:?} -> {:?}", - spot_market.fuel_boost_taker, - fuel_boost_taker - ); - spot_market.fuel_boost_taker = fuel_boost_taker; - } else { - msg!("spot_market.fuel_boost_taker: unchanged"); - } - - if let Some(fuel_boost_maker) = fuel_boost_maker { - msg!( - "spot_market.fuel_boost_maker: {:?} -> {:?}", - spot_market.fuel_boost_maker, - fuel_boost_maker - ); - spot_market.fuel_boost_maker = fuel_boost_maker; - } else { - msg!("spot_market.fuel_boost_maker: unchanged"); - } - - if let Some(fuel_boost_deposits) = fuel_boost_deposits { - msg!( - "spot_market.fuel_boost_deposits: {:?} -> {:?}", - spot_market.fuel_boost_deposits, - fuel_boost_deposits - ); - spot_market.fuel_boost_deposits = fuel_boost_deposits; - } else { - msg!("spot_market.fuel_boost_deposits: unchanged"); - } - - if let Some(fuel_boost_borrows) = fuel_boost_borrows { - msg!( - "spot_market.fuel_boost_borrows: {:?} -> {:?}", - spot_market.fuel_boost_borrows, - fuel_boost_borrows - ); - spot_market.fuel_boost_borrows = fuel_boost_borrows; - } else { - msg!("spot_market.fuel_boost_borrows: unchanged"); - } - - if let Some(fuel_boost_insurance) = fuel_boost_insurance { - msg!( - "spot_market.fuel_boost_insurance: {:?} -> {:?}", - spot_market.fuel_boost_insurance, - fuel_boost_insurance - ); - spot_market.fuel_boost_insurance = fuel_boost_insurance; - } else { - msg!("spot_market.fuel_boost_insurance: unchanged"); - } - - Ok(()) +#[derive(Accounts)] +#[instruction(params: PrelaunchOracleParams,)] +pub struct UpdatePrelaunchOracleParams<'info> { + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account( + mut, + seeds = [b"prelaunch_oracle".as_ref(), params.perp_market_index.to_le_bytes().as_ref()], + bump, + )] + pub prelaunch_oracle: AccountLoader<'info, PrelaunchOracle>, + #[account( + mut, + constraint = perp_market.load()?.market_index == params.perp_market_index + )] + pub perp_market: AccountLoader<'info, PerpMarket>, + pub state: Box>, } -pub fn handle_update_admin(ctx: Context, admin: Pubkey) -> Result<()> { - msg!("admin: {:?} -> {:?}", ctx.accounts.state.admin, admin); - ctx.accounts.state.admin = admin; - Ok(()) +#[derive(Accounts)] +#[instruction(perp_market_index: u16,)] +pub struct DeletePrelaunchOracle<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + mut, + seeds = [b"prelaunch_oracle".as_ref(), perp_market_index.to_le_bytes().as_ref()], + bump, + close = admin + )] + pub prelaunch_oracle: AccountLoader<'info, PrelaunchOracle>, + #[account( + constraint = perp_market.load()?.market_index == perp_market_index + )] + pub perp_market: AccountLoader<'info, PerpMarket>, + #[account( + has_one = admin + )] + pub state: Box>, } -pub fn handle_update_whitelist_mint( - ctx: Context, - whitelist_mint: Pubkey, -) -> Result<()> { - msg!( - "whitelist_mint: {:?} -> {:?}", - ctx.accounts.state.whitelist_mint, - whitelist_mint - ); - - ctx.accounts.state.whitelist_mint = whitelist_mint; - Ok(()) +#[derive(Accounts)] +#[instruction(market_index: u16)] +pub struct InitializeOpenbookV2FulfillmentConfig<'info> { + #[account( + seeds = [b"spot_market", market_index.to_le_bytes().as_ref()], + bump, + )] + pub base_spot_market: AccountLoader<'info, SpotMarket>, + #[account( + seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], + bump, + )] + pub quote_spot_market: AccountLoader<'info, SpotMarket>, + #[account( + mut, + has_one = admin + )] + pub state: Box>, + /// CHECK: checked in ix + pub openbook_v2_program: AccountInfo<'info>, + /// CHECK: checked in ix + pub openbook_v2_market: AccountInfo<'info>, + #[account( + constraint = state.signer.eq(&drift_signer.key()) + )] + /// CHECK: program signer + pub drift_signer: AccountInfo<'info>, + #[account( + init, + seeds = [b"openbook_v2_fulfillment_config".as_ref(), openbook_v2_market.key.as_ref()], + space = OpenbookV2FulfillmentConfig::SIZE, + bump, + payer = admin, + )] + pub openbook_v2_fulfillment_config: AccountLoader<'info, OpenbookV2FulfillmentConfig>, + #[account(mut)] + pub admin: Signer<'info>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } -pub fn handle_update_discount_mint( - ctx: Context, - discount_mint: Pubkey, -) -> Result<()> { - msg!( - "discount_mint: {:?} -> {:?}", - ctx.accounts.state.discount_mint, - discount_mint - ); - - ctx.accounts.state.discount_mint = discount_mint; - Ok(()) +#[derive(Accounts)] +pub struct UpdateOpenbookV2FulfillmentConfig<'info> { + #[account( + has_one = admin + )] + pub state: Box>, + #[account(mut)] + pub openbook_v2_fulfillment_config: AccountLoader<'info, OpenbookV2FulfillmentConfig>, + #[account(mut)] + pub admin: Signer<'info>, } -pub fn handle_update_exchange_status( - ctx: Context, - exchange_status: u8, -) -> Result<()> { - msg!( - "exchange_status: {:?} -> {:?}", - ctx.accounts.state.exchange_status, - exchange_status - ); - - ctx.accounts.state.exchange_status = exchange_status; - Ok(()) +#[derive(Accounts)] +#[instruction(feed_id : [u8; 32])] +pub struct InitPythPullPriceFeed<'info> { + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + pub pyth_solana_receiver: Program<'info, PythSolanaReceiver>, + /// CHECK: This account's seeds are checked + #[account(mut, seeds = [PTYH_PRICE_FEED_SEED_PREFIX, &feed_id], bump)] + pub price_feed: AccountInfo<'info>, + pub system_program: Program<'info, System>, + pub state: Box>, } -pub fn handle_update_perp_auction_duration( - ctx: Context, - min_perp_auction_duration: u8, -) -> Result<()> { - msg!( - "min_perp_auction_duration: {:?} -> {:?}", - ctx.accounts.state.min_perp_auction_duration, - min_perp_auction_duration - ); - - ctx.accounts.state.min_perp_auction_duration = min_perp_auction_duration; - Ok(()) +#[derive(Accounts)] +#[instruction(feed_id: u32)] +pub struct InitPythLazerOracle<'info> { + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account(init, seeds = [PYTH_LAZER_ORACLE_SEED, &feed_id.to_le_bytes()], + space=PythLazerOracle::SIZE, + bump, + payer=admin + )] + pub lazer_oracle: AccountLoader<'info, PythLazerOracle>, + pub state: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } -pub fn handle_update_spot_auction_duration( - ctx: Context, - default_spot_auction_duration: u8, -) -> Result<()> { - msg!( - "default_spot_auction_duration: {:?} -> {:?}", - ctx.accounts.state.default_spot_auction_duration, - default_spot_auction_duration - ); - - ctx.accounts.state.default_spot_auction_duration = default_spot_auction_duration; - Ok(()) +#[derive(Accounts)] +pub struct InitializeHighLeverageModeConfig<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + init, + seeds = [b"high_leverage_mode_config".as_ref()], + space = HighLeverageModeConfig::SIZE, + bump, + payer = admin + )] + pub high_leverage_mode_config: AccountLoader<'info, HighLeverageModeConfig>, + #[account( + has_one = admin + )] + pub state: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, } -pub fn handle_admin_disable_update_perp_bid_ask_twap( - ctx: Context, - disable: bool, -) -> Result<()> { - let mut user_stats = load_mut!(ctx.accounts.user_stats)?; - - msg!( - "disable_update_perp_bid_ask_twap: {:?} -> {:?}", - user_stats.disable_update_perp_bid_ask_twap, - disable - ); - - user_stats.disable_update_perp_bid_ask_twap = disable; - Ok(()) +#[derive(Accounts)] +pub struct UpdateHighLeverageModeConfig<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + mut, + seeds = [b"high_leverage_mode_config".as_ref()], + bump, + )] + pub high_leverage_mode_config: AccountLoader<'info, HighLeverageModeConfig>, + #[account( + has_one = admin + )] + pub state: Box>, } -pub fn handle_initialize_protocol_if_shares_transfer_config( - ctx: Context, -) -> Result<()> { - let mut config = ctx - .accounts - .protocol_if_shares_transfer_config - .load_init()?; +#[derive(Accounts)] +pub struct InitializeProtectedMakerModeConfig<'info> { + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account( + init, + seeds = [b"protected_maker_mode_config".as_ref()], + space = ProtectedMakerModeConfig::SIZE, + bump, + payer = admin + )] + pub protected_maker_mode_config: AccountLoader<'info, ProtectedMakerModeConfig>, + #[account( + has_one = admin + )] + pub state: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, +} - let now = Clock::get()?.unix_timestamp; - msg!( - "next_epoch_ts: {:?} -> {:?}", - config.next_epoch_ts, - now.safe_add(EPOCH_DURATION)? - ); - config.next_epoch_ts = now.safe_add(EPOCH_DURATION)?; +#[derive(Accounts)] +pub struct UpdateProtectedMakerModeConfig<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + mut, + seeds = [b"protected_maker_mode_config".as_ref()], + bump, + )] + pub protected_maker_mode_config: AccountLoader<'info, ProtectedMakerModeConfig>, + #[account( + has_one = admin + )] + pub state: Box>, +} - Ok(()) +#[derive(Accounts)] +#[instruction(market_index: u16,)] +pub struct AdminDeposit<'info> { + pub state: Box>, + #[account(mut)] + pub user: AccountLoader<'info, User>, + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account( + mut, + seeds = [b"spot_market_vault".as_ref(), market_index.to_le_bytes().as_ref()], + bump, + )] + pub spot_market_vault: Box>, + #[account( + mut, + constraint = &spot_market_vault.mint.eq(&admin_token_account.mint), + token::authority = admin.key() + )] + pub admin_token_account: Box>, + pub token_program: Interface<'info, TokenInterface>, } -pub fn handle_update_protocol_if_shares_transfer_config( - ctx: Context, - whitelisted_signers: Option<[Pubkey; 4]>, - max_transfer_per_epoch: Option, +#[derive(Accounts)] +#[instruction(params: IfRebalanceConfigParams)] +pub struct InitializeIfRebalanceConfig<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account( + init, + seeds = [b"if_rebalance_config".as_ref(), params.in_market_index.to_le_bytes().as_ref(), params.out_market_index.to_le_bytes().as_ref()], + space = IfRebalanceConfig::SIZE, + bump, + payer = admin + )] + pub if_rebalance_config: AccountLoader<'info, IfRebalanceConfig>, + #[account( + has_one = admin + )] + pub state: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct UpdateIfRebalanceConfig<'info> { + #[account(mut)] + pub admin: Signer<'info>, + #[account(mut)] + pub if_rebalance_config: AccountLoader<'info, IfRebalanceConfig>, + #[account( + has_one = admin + )] + pub state: Box>, +} + +#[derive(Accounts)] +pub struct UpdateDelegateUserGovTokenInsuranceStake<'info> { + #[account( + mut, + seeds = [b"spot_market", 15_u16.to_le_bytes().as_ref()], + bump + )] + pub spot_market: AccountLoader<'info, SpotMarket>, + pub insurance_fund_stake: AccountLoader<'info, InsuranceFundStake>, + #[account(mut)] + pub user_stats: AccountLoader<'info, UserStats>, + pub admin: Signer<'info>, + #[account( + mut, + seeds = [b"insurance_fund_vault".as_ref(), 15_u16.to_le_bytes().as_ref()], + bump, + )] + pub insurance_fund_vault: Box>, + #[account( + has_one = admin + )] + pub state: Box>, +} + +#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, PartialEq)] +pub struct SpotMarketUpdateParams { + pub name: Option<[u8; 32]>, + pub status: Option, + pub paused_operations: Option, + pub if_paused_operations: Option, + pub orders_enabled: Option, + pub asset_tier: Option, + pub initial_asset_weight: Option, + pub maintenance_asset_weight: Option, + pub initial_liability_weight: Option, + pub maintenance_liability_weight: Option, + pub imf_factor: Option, + pub optimal_utilization: Option, + pub optimal_borrow_rate: Option, + pub max_borrow_rate: Option, + pub min_borrow_rate: Option, + pub order_step_size: Option, + pub order_tick_size: Option, + pub min_order_size: Option, + pub max_token_deposits: Option, + pub max_token_borrows_fraction: Option, + pub scale_initial_asset_weight_start: Option, + pub fee_adjustment: Option, + pub revenue_settle_period: Option, + pub withdraw_guard_threshold: Option, + pub user_if_factor: Option, + pub total_if_factor: Option, + pub expiry_ts: Option, + pub pool_id: Option, + pub liquidator_fee: Option, + pub if_liquidation_fee: Option, +} + +pub fn handle_update_spot_market_params( + ctx: Context, + params: SpotMarketUpdateParams, ) -> Result<()> { - let mut config = ctx.accounts.protocol_if_shares_transfer_config.load_mut()?; + let clock = Clock::get()?; + let now = clock.unix_timestamp; + let mut spot_market = load_mut!(ctx.accounts.spot_market)?; - if let Some(whitelisted_signers) = whitelisted_signers { + msg!("spot market {}", spot_market.market_index); + + if let Some(name) = params.name { + msg!("spot_market.name: {:?} -> {:?}", spot_market.name, name); + spot_market.name = name; + } + + if let Some(status) = params.status { + status.validate_not_deprecated()?; msg!( - "whitelisted_signers: {:?} -> {:?}", - config.whitelisted_signers, - whitelisted_signers + "spot_market.status: {:?} -> {:?}", + spot_market.status, + status ); - config.whitelisted_signers = whitelisted_signers; - } else { - msg!("whitelisted_signers: unchanged"); + spot_market.status = status; } - if let Some(max_transfer_per_epoch) = max_transfer_per_epoch { + if let Some(po) = params.paused_operations { msg!( - "max_transfer_per_epoch: {:?} -> {:?}", - config.max_transfer_per_epoch, - max_transfer_per_epoch + "spot_market.paused_operations: {:?} -> {:?}", + spot_market.paused_operations, + po ); - config.max_transfer_per_epoch = max_transfer_per_epoch; - } else { - msg!("max_transfer_per_epoch: unchanged"); + spot_market.paused_operations = po; + SpotOperation::log_all_operations_paused(spot_market.paused_operations); } - Ok(()) -} - -pub fn handle_initialize_prelaunch_oracle( - ctx: Context, - params: PrelaunchOracleParams, -) -> Result<()> { - let mut oracle = ctx.accounts.prelaunch_oracle.load_init()?; - msg!("perp market {}", params.perp_market_index); + if let Some(po) = params.if_paused_operations { + msg!( + "spot_market.if_paused_operations: {:?} -> {:?}", + spot_market.if_paused_operations, + po + ); + spot_market.if_paused_operations = po; + InsuranceFundOperation::log_all_operations_paused(po); + } - oracle.perp_market_index = params.perp_market_index; - if let Some(price) = params.price { - oracle.price = price; + if let Some(orders_enabled) = params.orders_enabled { + msg!( + "spot_market.orders_enabled: {:?} -> {:?}", + spot_market.orders_enabled, + orders_enabled + ); + spot_market.orders_enabled = orders_enabled; } - if let Some(max_price) = params.max_price { - oracle.max_price = max_price; + + if let Some(asset_tier) = params.asset_tier { + if spot_market.initial_asset_weight > 0 { + validate!( + matches!(asset_tier, AssetTier::Collateral | AssetTier::Protected), + ErrorCode::DefaultError, + "initial_asset_weight > 0 so AssetTier must be collateral or protected" + )?; + } + msg!( + "spot_market.asset_tier: {:?} -> {:?}", + spot_market.asset_tier, + asset_tier + ); + spot_market.asset_tier = asset_tier; } - oracle.validate()?; + if params.initial_asset_weight.is_some() + || params.maintenance_asset_weight.is_some() + || params.initial_liability_weight.is_some() + || params.maintenance_liability_weight.is_some() + || params.imf_factor.is_some() + { + let initial_asset_weight = params + .initial_asset_weight + .unwrap_or(spot_market.initial_asset_weight); + let maintenance_asset_weight = params + .maintenance_asset_weight + .unwrap_or(spot_market.maintenance_asset_weight); + let initial_liability_weight = params + .initial_liability_weight + .unwrap_or(spot_market.initial_liability_weight); + let maintenance_liability_weight = params + .maintenance_liability_weight + .unwrap_or(spot_market.maintenance_liability_weight); + let imf_factor = params.imf_factor.unwrap_or(spot_market.imf_factor); + validate_margin_weights( + spot_market.market_index, + initial_asset_weight, + maintenance_asset_weight, + initial_liability_weight, + maintenance_liability_weight, + imf_factor, + )?; + msg!( + "spot_market.initial_asset_weight: {:?} -> {:?}", + spot_market.initial_asset_weight, + initial_asset_weight + ); - Ok(()) -} + msg!( + "spot_market.maintenance_asset_weight: {:?} -> {:?}", + spot_market.maintenance_asset_weight, + maintenance_asset_weight + ); -pub fn handle_update_prelaunch_oracle_params( - ctx: Context, - params: PrelaunchOracleParams, -) -> Result<()> { - let mut oracle = ctx.accounts.prelaunch_oracle.load_mut()?; - let mut perp_market = ctx.accounts.perp_market.load_mut()?; - msg!("perp market {}", perp_market.market_index); + msg!( + "spot_market.initial_liability_weight: {:?} -> {:?}", + spot_market.initial_liability_weight, + initial_liability_weight + ); - let now = Clock::get()?.unix_timestamp; + msg!( + "spot_market.maintenance_liability_weight: {:?} -> {:?}", + spot_market.maintenance_liability_weight, + maintenance_liability_weight + ); - if let Some(price) = params.price { - oracle.price = price; + msg!( + "spot_market.imf_factor: {:?} -> {:?}", + spot_market.imf_factor, + imf_factor + ); + spot_market.initial_asset_weight = initial_asset_weight; + spot_market.maintenance_asset_weight = maintenance_asset_weight; + spot_market.initial_liability_weight = initial_liability_weight; + spot_market.maintenance_liability_weight = maintenance_liability_weight; + spot_market.imf_factor = imf_factor; + } - msg!("before mark twap ts = {:?} mark twap = {:?} mark twap 5min = {:?} bid twap = {:?} ask twap {:?}", perp_market.amm.last_mark_price_twap_ts, perp_market.amm.last_mark_price_twap, perp_market.amm.last_mark_price_twap_5min, perp_market.amm.last_bid_price_twap, perp_market.amm.last_ask_price_twap); + if params.optimal_utilization.is_some() + || params.optimal_borrow_rate.is_some() + || params.max_borrow_rate.is_some() + || params.min_borrow_rate.is_some() + { + let optimal_utilization = params + .optimal_utilization + .unwrap_or(spot_market.optimal_utilization); + let optimal_borrow_rate = params + .optimal_borrow_rate + .unwrap_or(spot_market.optimal_borrow_rate); + let max_borrow_rate = params + .max_borrow_rate + .unwrap_or(spot_market.max_borrow_rate); + let min_borrow_rate = params + .min_borrow_rate + .unwrap_or(spot_market.min_borrow_rate); + validate_borrow_rate( + optimal_utilization, + optimal_borrow_rate, + max_borrow_rate, + min_borrow_rate.cast::()? * ((PERCENTAGE_PRECISION / 200) as u32), + )?; + msg!( + "spot_market.optimal_utilization: {:?} -> {:?}", + spot_market.optimal_utilization, + optimal_utilization + ); - perp_market.amm.last_mark_price_twap_ts = now; - perp_market.amm.last_mark_price_twap = price.cast()?; - perp_market.amm.last_mark_price_twap_5min = price.cast()?; - perp_market.amm.last_bid_price_twap = - perp_market.amm.last_bid_price_twap.min(price.cast()?); - perp_market.amm.last_ask_price_twap = - perp_market.amm.last_ask_price_twap.max(price.cast()?); + msg!( + "spot_market.optimal_borrow_rate: {:?} -> {:?}", + spot_market.optimal_borrow_rate, + optimal_borrow_rate + ); - msg!("after mark twap ts = {:?} mark twap = {:?} mark twap 5min = {:?} bid twap = {:?} ask twap {:?}", perp_market.amm.last_mark_price_twap_ts, perp_market.amm.last_mark_price_twap, perp_market.amm.last_mark_price_twap_5min, perp_market.amm.last_bid_price_twap, perp_market.amm.last_ask_price_twap); - } else { - msg!("mark twap ts, mark twap, mark twap 5min, bid twap, ask twap: unchanged"); - } + msg!( + "spot_market.max_borrow_rate: {:?} -> {:?}", + spot_market.max_borrow_rate, + max_borrow_rate + ); + msg!( + "spot_market.min_borrow_rate: {:?} -> {:?}", + spot_market.min_borrow_rate, + min_borrow_rate + ); - if let Some(max_price) = params.max_price { - msg!("max price: {:?} -> {:?}", oracle.max_price, max_price); - oracle.max_price = max_price; - } else { - msg!("max price: unchanged") + spot_market.optimal_utilization = optimal_utilization; + spot_market.optimal_borrow_rate = optimal_borrow_rate; + spot_market.max_borrow_rate = max_borrow_rate; + spot_market.min_borrow_rate = min_borrow_rate; } - oracle.validate()?; + if params.order_step_size.is_some() || params.order_tick_size.is_some() { + let step_size = params + .order_step_size + .unwrap_or(spot_market.order_step_size); + let tick_size = params + .order_tick_size + .unwrap_or(spot_market.order_tick_size); + validate!( + spot_market.market_index == 0 || step_size > 0 && tick_size > 0, + ErrorCode::DefaultError + )?; + msg!( + "spot_market.order_step_size: {:?} -> {:?}", + spot_market.order_step_size, + step_size + ); - Ok(()) -} + msg!( + "spot_market.order_tick_size: {:?} -> {:?}", + spot_market.order_tick_size, + tick_size + ); + spot_market.order_step_size = step_size; + spot_market.order_tick_size = tick_size; + } -pub fn handle_delete_prelaunch_oracle( - ctx: Context, - _perp_market_index: u16, -) -> Result<()> { - let perp_market = ctx.accounts.perp_market.load()?; - msg!("perp market {}", perp_market.market_index); - - validate!( - perp_market.amm.oracle != ctx.accounts.prelaunch_oracle.key(), - ErrorCode::DefaultError, - "prelaunch oracle currently in use" - )?; + if let Some(min_order_size) = params.min_order_size { + validate!( + spot_market.market_index == 0 || min_order_size > 0, + ErrorCode::DefaultError + )?; + msg!( + "spot_market.min_order_size: {:?} -> {:?}", + spot_market.min_order_size, + min_order_size + ); + spot_market.min_order_size = min_order_size; + } - Ok(()) -} + if let Some(max_token_deposits) = params.max_token_deposits { + msg!( + "spot_market.max_token_deposits: {:?} -> {:?}", + spot_market.max_token_deposits, + max_token_deposits + ); + spot_market.max_token_deposits = max_token_deposits; + } -pub fn handle_initialize_pyth_pull_oracle( - ctx: Context, - feed_id: [u8; 32], -) -> Result<()> { - let cpi_program = ctx.accounts.pyth_solana_receiver.to_account_info(); - let cpi_accounts = InitPriceUpdate { - payer: ctx.accounts.admin.to_account_info(), - price_update_account: ctx.accounts.price_feed.to_account_info(), - system_program: ctx.accounts.system_program.to_account_info(), - write_authority: ctx.accounts.price_feed.to_account_info(), - }; + if let Some(max_token_borrows_fraction) = params.max_token_borrows_fraction { + let current_spot_tokens_borrows: u64 = spot_market.get_borrows()?.cast()?; + let new_max_token_borrows = spot_market + .max_token_deposits + .safe_mul(max_token_borrows_fraction.cast()?)? + .safe_div(10000)?; + validate!( + current_spot_tokens_borrows <= new_max_token_borrows, + ErrorCode::InvalidSpotMarketInitialization, + "spot borrows {} > max_token_borrows {}", + current_spot_tokens_borrows, + max_token_borrows_fraction + )?; + msg!( + "spot_market.max_token_borrows_fraction: {:?} -> {:?}", + spot_market.max_token_borrows_fraction, + max_token_borrows_fraction + ); + spot_market.max_token_borrows_fraction = max_token_borrows_fraction; + } - let seeds = &[ - PTYH_PRICE_FEED_SEED_PREFIX, - feed_id.as_ref(), - &[ctx.bumps.price_feed], - ]; - let signer_seeds = &[&seeds[..]]; - let cpi_context = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds); + if let Some(scale) = params.scale_initial_asset_weight_start { + msg!( + "spot_market.scale_initial_asset_weight_start: {:?} -> {:?}", + spot_market.scale_initial_asset_weight_start, + scale + ); + spot_market.scale_initial_asset_weight_start = scale; + } - pyth_solana_receiver_sdk::cpi::init_price_update(cpi_context, feed_id)?; + if let Some(fee_adjustment) = params.fee_adjustment { + validate!( + fee_adjustment.unsigned_abs().cast::()? <= FEE_ADJUSTMENT_MAX, + ErrorCode::DefaultError, + "fee adjustment {} greater than max {}", + fee_adjustment, + FEE_ADJUSTMENT_MAX + )?; + msg!( + "spot_market.fee_adjustment: {:?} -> {:?}", + spot_market.fee_adjustment, + fee_adjustment + ); + spot_market.fee_adjustment = fee_adjustment; + } - Ok(()) -} + if let Some(period) = params.revenue_settle_period { + validate!(period > 0, ErrorCode::DefaultError)?; + msg!( + "spot_market.revenue_settle_period: {:?} -> {:?}", + spot_market.insurance_fund.revenue_settle_period, + period + ); + spot_market.insurance_fund.revenue_settle_period = period; + } -pub fn handle_initialize_pyth_lazer_oracle( - ctx: Context, - feed_id: u32, -) -> Result<()> { - let pubkey = ctx.accounts.lazer_oracle.to_account_info().key; - msg!( - "Lazer price feed initted {} with feed_id {}", - pubkey, - feed_id - ); - Ok(()) -} + if let Some(threshold) = params.withdraw_guard_threshold { + msg!( + "spot_market.withdraw_guard_threshold: {:?} -> {:?}", + spot_market.withdraw_guard_threshold, + threshold + ); + spot_market.withdraw_guard_threshold = threshold; + } -pub fn handle_settle_expired_market<'c: 'info, 'info>( - ctx: Context<'_, '_, 'c, 'info, AdminUpdatePerpMarket<'info>>, - market_index: u16, -) -> Result<()> { - let clock = Clock::get()?; - let _now = clock.unix_timestamp; - let state = &ctx.accounts.state; + if params.user_if_factor.is_some() || params.total_if_factor.is_some() { + let user_if_factor = params + .user_if_factor + .unwrap_or(spot_market.insurance_fund.user_factor); + let total_if_factor = params + .total_if_factor + .unwrap_or(spot_market.insurance_fund.total_factor); + validate!( + user_if_factor <= total_if_factor, + ErrorCode::DefaultError, + "user_if_factor must be <= total_if_factor" + )?; + validate!( + total_if_factor <= IF_FACTOR_PRECISION.cast()?, + ErrorCode::DefaultError, + "total_if_factor must be <= 100%" + )?; + msg!( + "spot_market.user_if_factor: {:?} -> {:?}", + spot_market.insurance_fund.user_factor, + user_if_factor + ); + msg!( + "spot_market.total_if_factor: {:?} -> {:?}", + spot_market.insurance_fund.total_factor, + total_if_factor + ); + spot_market.insurance_fund.user_factor = user_if_factor; + spot_market.insurance_fund.total_factor = total_if_factor; + } - let AccountMaps { - perp_market_map, - spot_market_map, - mut oracle_map, - } = load_maps( - &mut ctx.remaining_accounts.iter().peekable(), - &get_writable_perp_market_set(market_index), - &get_writable_spot_market_set(QUOTE_SPOT_MARKET_INDEX), - clock.slot, - Some(state.oracle_guard_rails), - )?; + if let Some(expiry_ts) = params.expiry_ts { + validate!( + now < expiry_ts, + ErrorCode::DefaultError, + "Market expiry ts must later than current clock timestamp" + )?; + msg!( + "spot_market.status {:?} -> {:?}", + spot_market.status, + MarketStatus::ReduceOnly + ); + msg!( + "spot_market.expiry_ts {} -> {}", + spot_market.expiry_ts, + expiry_ts + ); + spot_market.status = MarketStatus::ReduceOnly; + spot_market.expiry_ts = expiry_ts; + } - controller::repeg::update_amm( - market_index, - &perp_market_map, - &mut oracle_map, - state, - &clock, - )?; + if let Some(pool_id) = params.pool_id { + validate!( + spot_market.status == MarketStatus::Initialized, + ErrorCode::DefaultError, + "Market must be just initialized to update pool" + )?; + msg!( + "updating spot market {} pool id to {}", + spot_market.market_index, + pool_id + ); + spot_market.pool_id = pool_id; + } - controller::repeg::settle_expired_market( - market_index, - &perp_market_map, - &mut oracle_map, - &spot_market_map, - state, - &clock, - )?; + if params.liquidator_fee.is_some() || params.if_liquidation_fee.is_some() { + let liquidator_fee = params.liquidator_fee.unwrap_or(spot_market.liquidator_fee); + let if_liquidation_fee = params + .if_liquidation_fee + .unwrap_or(spot_market.if_liquidation_fee); + validate!( + liquidator_fee.safe_add(if_liquidation_fee)? < LIQUIDATION_FEE_PRECISION, + ErrorCode::DefaultError, + "Total liquidation fee must be less than 100%" + )?; + validate!( + if_liquidation_fee <= LIQUIDATION_FEE_PRECISION / 10, + ErrorCode::DefaultError, + "if_liquidation_fee must be <= 10%" + )?; + msg!( + "spot_market.liquidator_fee: {:?} -> {:?}", + spot_market.liquidator_fee, + liquidator_fee + ); + msg!( + "spot_market.if_liquidation_fee: {:?} -> {:?}", + spot_market.if_liquidation_fee, + if_liquidation_fee + ); + spot_market.liquidator_fee = liquidator_fee; + spot_market.if_liquidation_fee = if_liquidation_fee; + } Ok(()) } -pub fn handle_initialize_high_leverage_mode_config( - ctx: Context, - max_users: u32, +#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, PartialEq)] +pub struct PerpMarketUpdateParams { + pub name: Option<[u8; 32]>, + pub status: Option, + pub paused_operations: Option, + pub contract_tier: Option, + pub liquidator_fee: Option, + pub if_liquidation_fee: Option, + pub margin_ratio_initial: Option, + pub margin_ratio_maintenance: Option, + pub unrealized_initial_asset_weight: Option, + pub unrealized_maintenance_asset_weight: Option, + pub high_leverage_margin_ratio_initial: Option, + pub high_leverage_margin_ratio_maintenance: Option, + pub imf_factor: Option, + pub unrealized_pnl_imf_factor: Option, + pub funding_period: Option, + pub unrealized_max_imbalance: Option, + pub max_revenue_withdraw_per_period: Option, + pub quote_max_insurance: Option, + pub base_spread: Option, + pub max_spread: Option, + pub order_step_size: Option, + pub order_tick_size: Option, + pub min_order_size: Option, + pub max_slippage_ratio: Option, + pub max_fill_reserve_fraction: Option, + pub max_open_interest: Option, + pub fee_adjustment: Option, + pub number_of_users: Option, + pub number_of_users_with_base: Option, + pub protected_maker_limit_price_divisor: Option, + pub protected_maker_dynamic_divisor: Option, + pub fuel_boost_taker: Option, + pub fuel_boost_maker: Option, + pub fuel_boost_position: Option, + pub taker_speed_bump_override: Option, + pub oracle_slot_delay_override: Option, + pub amm_spread_adjustment: Option, + pub amm_inventory_spread_adjustment: Option, + pub reference_price_offset: Option, + pub zero_mm_oracle_fields: Option, + pub expiry_ts: Option, + pub concentration_scale: Option, + pub curve_update_intensity: Option, +} + +pub fn handle_update_perp_market_params( + ctx: Context, + params: PerpMarketUpdateParams, ) -> Result<()> { - let mut config = ctx.accounts.high_leverage_mode_config.load_init()?; + let clock = Clock::get()?; + let now = clock.unix_timestamp; + let mut perp_market = load_mut!(ctx.accounts.perp_market)?; - config.max_users = max_users; + msg!("perp market {}", perp_market.market_index); - config.validate()?; + if let Some(name) = params.name { + msg!("name: {:?} -> {:?}", perp_market.name, name); + perp_market.name = name; + } - Ok(()) -} + if let Some(status) = params.status { + msg!("status: {:?} -> {:?}", perp_market.status, status); + validate!( + !matches!(status, MarketStatus::Delisted | MarketStatus::Settlement), + ErrorCode::DefaultError, + "must set settlement/delist through another instruction", + )?; + status.validate_not_deprecated()?; + perp_market.status = status; + } -pub fn handle_update_high_leverage_mode_config( - ctx: Context, - max_users: u32, - reduce_only: bool, - current_users: Option, -) -> Result<()> { - let mut config = load_mut!(ctx.accounts.high_leverage_mode_config)?; + if let Some(po) = params.paused_operations { + msg!( + "paused operations: {:?} -> {:?}", + perp_market.paused_operations, + po + ); + perp_market.paused_operations = po; + if perp_market.is_prediction_market() { + validate!( + perp_market.is_operation_paused(PerpOperation::UpdateFunding), + ErrorCode::DefaultError, + "prediction market must have funding paused" + )?; + } + PerpOperation::log_all_operations_paused(perp_market.paused_operations); + } - config.max_users = max_users; + if let Some(ct) = params.contract_tier { + msg!( + "perp_market.contract_tier: {:?} -> {:?}", + perp_market.contract_tier, + ct + ); + perp_market.contract_tier = ct; + } - config.reduce_only = reduce_only as u8; + if params.liquidator_fee.is_some() || params.if_liquidation_fee.is_some() { + let liquidator_fee = params.liquidator_fee.unwrap_or(perp_market.liquidator_fee); + let if_liquidation_fee = params + .if_liquidation_fee + .unwrap_or(perp_market.if_liquidation_fee); - if let Some(current_users) = current_users { - config.current_users = current_users; + validate!( + liquidator_fee.safe_add(if_liquidation_fee)? < LIQUIDATION_FEE_PRECISION, + ErrorCode::DefaultError, + "Total liquidation fee must be less than 100%" + )?; + validate!( + if_liquidation_fee < LIQUIDATION_FEE_PRECISION, + ErrorCode::DefaultError, + "If liquidation fee must be less than 100%" + )?; + validate_margin( + perp_market.margin_ratio_initial, + perp_market.margin_ratio_maintenance, + perp_market.high_leverage_margin_ratio_initial.cast()?, + perp_market.high_leverage_margin_ratio_maintenance.cast()?, + liquidator_fee, + perp_market.amm.max_spread, + )?; + msg!( + "perp_market.liquidator_fee: {:?} -> {:?}", + perp_market.liquidator_fee, + liquidator_fee + ); + msg!( + "perp_market.if_liquidation_fee: {:?} -> {:?}", + perp_market.if_liquidation_fee, + if_liquidation_fee + ); + perp_market.liquidator_fee = liquidator_fee; + perp_market.if_liquidation_fee = if_liquidation_fee; } - config.validate()?; + if params.unrealized_initial_asset_weight.is_some() + || params.unrealized_maintenance_asset_weight.is_some() + { + let unrealized_initial_asset_weight = params + .unrealized_initial_asset_weight + .unwrap_or(perp_market.unrealized_pnl_initial_asset_weight); + let unrealized_maintenance_asset_weight = params + .unrealized_maintenance_asset_weight + .unwrap_or(perp_market.unrealized_pnl_maintenance_asset_weight); - Ok(()) -} + validate!( + unrealized_initial_asset_weight <= SPOT_WEIGHT_PRECISION.cast()?, + ErrorCode::DefaultError, + "invalid unrealized_initial_asset_weight", + )?; + validate!( + unrealized_maintenance_asset_weight <= SPOT_WEIGHT_PRECISION.cast()?, + ErrorCode::DefaultError, + "invalid unrealized_maintenance_asset_weight", + )?; + validate!( + unrealized_initial_asset_weight <= unrealized_maintenance_asset_weight, + ErrorCode::DefaultError, + "must enforce unrealized_initial_asset_weight <= unrealized_maintenance_asset_weight", + )?; + msg!( + "perp_market.unrealized_pnl_initial_asset_weight: {:?} -> {:?}", + perp_market.unrealized_pnl_initial_asset_weight, + unrealized_initial_asset_weight + ); + msg!( + "perp_market.unrealized_pnl_maintenance_asset_weight: {:?} -> {:?}", + perp_market.unrealized_pnl_maintenance_asset_weight, + unrealized_maintenance_asset_weight + ); + perp_market.unrealized_pnl_initial_asset_weight = unrealized_initial_asset_weight; + perp_market.unrealized_pnl_maintenance_asset_weight = unrealized_maintenance_asset_weight; + } -pub fn handle_initialize_protected_maker_mode_config( - ctx: Context, - max_users: u32, -) -> Result<()> { - let mut config = ctx.accounts.protected_maker_mode_config.load_init()?; + if params.margin_ratio_initial.is_some() || params.margin_ratio_maintenance.is_some() { + let margin_ratio_initial = params + .margin_ratio_initial + .unwrap_or(perp_market.margin_ratio_initial); + let margin_ratio_maintenance = params + .margin_ratio_maintenance + .unwrap_or(perp_market.margin_ratio_maintenance); + + validate_margin( + margin_ratio_initial, + margin_ratio_maintenance, + perp_market.high_leverage_margin_ratio_initial.cast()?, + perp_market.high_leverage_margin_ratio_maintenance.cast()?, + perp_market.liquidator_fee, + perp_market.amm.max_spread, + )?; + msg!( + "perp_market.margin_ratio_initial: {:?} -> {:?}", + perp_market.margin_ratio_initial, + margin_ratio_initial + ); + msg!( + "perp_market.margin_ratio_maintenance: {:?} -> {:?}", + perp_market.margin_ratio_maintenance, + margin_ratio_maintenance + ); + perp_market.margin_ratio_initial = margin_ratio_initial; + perp_market.margin_ratio_maintenance = margin_ratio_maintenance; + } - config.max_users = max_users; + if params.high_leverage_margin_ratio_initial.is_some() + || params.high_leverage_margin_ratio_maintenance.is_some() + { + let margin_ratio_initial = params + .high_leverage_margin_ratio_initial + .unwrap_or(perp_market.high_leverage_margin_ratio_initial); + let margin_ratio_maintenance = params + .high_leverage_margin_ratio_maintenance + .unwrap_or(perp_market.high_leverage_margin_ratio_maintenance); + + validate_margin( + perp_market.margin_ratio_initial, + perp_market.margin_ratio_maintenance, + margin_ratio_initial.cast()?, + margin_ratio_maintenance.cast()?, + perp_market.liquidator_fee, + perp_market.amm.max_spread, + )?; + msg!( + "perp_market.high_leverage_margin_ratio_initial: {:?} -> {:?}", + perp_market.high_leverage_margin_ratio_initial, + margin_ratio_initial + ); + msg!( + "perp_market.high_leverage_margin_ratio_maintenance: {:?} -> {:?}", + perp_market.high_leverage_margin_ratio_maintenance, + margin_ratio_maintenance + ); + perp_market.high_leverage_margin_ratio_initial = margin_ratio_initial; + perp_market.high_leverage_margin_ratio_maintenance = margin_ratio_maintenance; + } - Ok(()) -} + if params.imf_factor.is_some() || params.unrealized_pnl_imf_factor.is_some() { + let imf_facdtor = params.imf_factor.unwrap_or(perp_market.imf_factor); + let unrealized_pnl_imf_factor = params + .unrealized_pnl_imf_factor + .unwrap_or(perp_market.unrealized_pnl_imf_factor); -pub fn handle_update_protected_maker_mode_config( - ctx: Context, - max_users: u32, - reduce_only: bool, - current_users: Option, -) -> Result<()> { - let mut config = load_mut!(ctx.accounts.protected_maker_mode_config)?; + validate!( + imf_facdtor <= SPOT_IMF_PRECISION, + ErrorCode::DefaultError, + "invalid imf factor" + )?; + validate!( + unrealized_pnl_imf_factor <= SPOT_IMF_PRECISION, + ErrorCode::DefaultError, + "invalid unrealized pnl imf factor" + )?; + msg!( + "perp_market.imf_factor: {:?} -> {:?}", + perp_market.imf_factor, + imf_facdtor + ); + msg!( + "perp_market.unrealized_pnl_imf_factor: {:?} -> {:?}", + perp_market.unrealized_pnl_imf_factor, + unrealized_pnl_imf_factor + ); + perp_market.imf_factor = imf_facdtor; + perp_market.unrealized_pnl_imf_factor = unrealized_pnl_imf_factor; + } - if current_users.is_some() { - config.current_users = current_users.unwrap(); + if let Some(funding_period) = params.funding_period { + validate!(funding_period >= 0, ErrorCode::DefaultError)?; + msg!( + "perp_market.amm.funding_period: {:?} -> {:?}", + perp_market.amm.funding_period, + funding_period + ); + perp_market.amm.funding_period = funding_period; } - config.max_users = max_users; - config.reduce_only = reduce_only as u8; - config.validate()?; + if params.unrealized_max_imbalance.is_some() + || params.max_revenue_withdraw_per_period.is_some() + || params.quote_max_insurance.is_some() + { + let unrealized_max_imbalance = params + .unrealized_max_imbalance + .unwrap_or(perp_market.unrealized_pnl_max_imbalance); + let max_revenue_withdraw_per_period = params + .max_revenue_withdraw_per_period + .unwrap_or(perp_market.insurance_claim.max_revenue_withdraw_per_period); + let quote_max_insurance = params + .quote_max_insurance + .unwrap_or(perp_market.insurance_claim.quote_max_insurance); + + let max_insurance_for_tier = match perp_market.contract_tier { + ContractTier::A => INSURANCE_A_MAX, + ContractTier::B => INSURANCE_B_MAX, + ContractTier::C => INSURANCE_C_MAX, + ContractTier::Speculative => INSURANCE_SPECULATIVE_MAX, + ContractTier::HighlySpeculative => INSURANCE_SPECULATIVE_MAX, + ContractTier::Isolated => INSURANCE_SPECULATIVE_MAX, + }; - Ok(()) -} - -#[access_control( - deposit_not_paused(&ctx.accounts.state) -)] -pub fn handle_admin_deposit<'c: 'info, 'info>( - ctx: Context<'_, '_, 'c, 'info, AdminDeposit<'info>>, - market_index: u16, - amount: u64, -) -> Result<()> { - let user_key = ctx.accounts.user.key(); - let user = &mut load_mut!(ctx.accounts.user)?; - - let state = &ctx.accounts.state; - let clock = Clock::get()?; - let now = clock.unix_timestamp; - let slot = clock.slot; - - let remaining_accounts_iter = &mut ctx.remaining_accounts.iter().peekable(); - let AccountMaps { - perp_market_map: _, - spot_market_map, - mut oracle_map, - } = load_maps( - remaining_accounts_iter, - &MarketSet::new(), - &get_writable_spot_market_set(market_index), - clock.slot, - Some(state.oracle_guard_rails), - )?; - - let mint = get_token_mint(remaining_accounts_iter)?; + validate!( + max_revenue_withdraw_per_period + <= max_insurance_for_tier.max(FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()?) + && unrealized_max_imbalance <= max_insurance_for_tier + 1 + && quote_max_insurance <= max_insurance_for_tier, + ErrorCode::DefaultError, + "all maxs must be less than max_insurance for ContractTier ={}", + max_insurance_for_tier + )?; + validate!( + perp_market.insurance_claim.quote_settled_insurance <= quote_max_insurance, + ErrorCode::DefaultError, + "quote_max_insurance must be above market.insurance_claim.quote_settled_insurance={}", + perp_market.insurance_claim.quote_settled_insurance + )?; + msg!( + "market.max_revenue_withdraw_per_period: {:?} -> {:?}", + perp_market.insurance_claim.max_revenue_withdraw_per_period, + max_revenue_withdraw_per_period + ); + msg!( + "market.unrealized_max_imbalance: {:?} -> {:?}", + perp_market.unrealized_pnl_max_imbalance, + unrealized_max_imbalance + ); + msg!( + "market.quote_max_insurance: {:?} -> {:?}", + perp_market.insurance_claim.quote_max_insurance, + quote_max_insurance + ); + perp_market.insurance_claim.max_revenue_withdraw_per_period = + max_revenue_withdraw_per_period; + perp_market.unrealized_pnl_max_imbalance = unrealized_max_imbalance; + perp_market.insurance_claim.quote_max_insurance = quote_max_insurance; - if amount == 0 { - return Err(ErrorCode::InsufficientDeposit.into()); + // ensure altered max_revenue_withdraw_per_period doesn't break invariant check + crate::validation::perp_market::validate_perp_market(&perp_market)?; } - validate!(!user.is_bankrupt(), ErrorCode::UserBankrupt)?; - - let mut spot_market = spot_market_map.get_ref_mut(&market_index)?; - let oracle_price_data = *oracle_map.get_price_data(&spot_market.oracle_id())?; - - validate!( - user.pool_id == spot_market.pool_id, - ErrorCode::InvalidPoolId, - "user pool id ({}) != market pool id ({})", - user.pool_id, - spot_market.pool_id - )?; - - validate!( - !matches!(spot_market.status, MarketStatus::Initialized), - ErrorCode::MarketBeingInitialized, - "Market is being initialized" - )?; + if let Some(base_spread) = params.base_spread { + msg!( + "perp_market.amm.base_spread: {:?} -> {:?}", + perp_market.amm.base_spread, + base_spread + ); + msg!( + "perp_market.amm.long_spread: {:?} -> {:?}", + perp_market.amm.long_spread, + base_spread / 2 + ); + msg!( + "perp_market.amm.short_spread: {:?} -> {:?}", + perp_market.amm.short_spread, + base_spread / 2 + ); + perp_market.amm.base_spread = base_spread; + perp_market.amm.long_spread = base_spread / 2; + perp_market.amm.short_spread = base_spread / 2; + } - controller::spot_balance::update_spot_market_cumulative_interest( - &mut spot_market, - Some(&oracle_price_data), - now, - )?; + if let Some(max_spread) = params.max_spread { + validate!( + max_spread >= perp_market.amm.base_spread, + ErrorCode::DefaultError, + "invalid max_spread < base_spread", + )?; + validate!( + max_spread <= perp_market.margin_ratio_initial * 100, + ErrorCode::DefaultError, + "invalid max_spread > market.margin_ratio_initial * 100", + )?; + msg!( + "perp_market.amm.max_spread: {:?} -> {:?}", + perp_market.amm.max_spread, + max_spread + ); + perp_market.amm.max_spread = max_spread; + } - let position_index = user.force_get_spot_position_index(spot_market.market_index)?; + if params.order_step_size.is_some() || params.order_tick_size.is_some() { + let step = params + .order_step_size + .unwrap_or(perp_market.amm.order_step_size); + let tick = params + .order_tick_size + .unwrap_or(perp_market.amm.order_tick_size); + validate!(step > 0 && tick > 0, ErrorCode::DefaultError)?; + validate!(step <= 2000000000, ErrorCode::DefaultError)?; + msg!( + "perp_market.amm.order_step_size: {:?} -> {:?}", + perp_market.amm.order_step_size, + step + ); + msg!( + "perp_market.amm.order_tick_size: {:?} -> {:?}", + perp_market.amm.order_tick_size, + tick + ); + perp_market.amm.order_step_size = step; + perp_market.amm.order_tick_size = tick; + } - // if reduce only, have to compare ix amount to current borrow amount - let amount = if (spot_market.is_reduce_only()) - && user.spot_positions[position_index].balance_type == SpotBalanceType::Borrow - { - user.spot_positions[position_index] - .get_token_amount(&spot_market)? - .cast::()? - .min(amount) - } else { - amount - }; + if let Some(min_order_size) = params.min_order_size { + validate!(min_order_size > 0, ErrorCode::DefaultError)?; + msg!( + "perp_market.amm.min_order_size: {:?} -> {:?}", + perp_market.amm.min_order_size, + min_order_size + ); + perp_market.amm.min_order_size = min_order_size; + } - let total_deposits_after = user.total_deposits; - let total_withdraws_after = user.total_withdraws; + if let Some(v) = params.max_slippage_ratio { + validate!(v > 0, ErrorCode::DefaultError)?; + msg!( + "perp_market.amm.max_slippage_ratio: {:?} -> {:?}", + perp_market.amm.max_slippage_ratio, + v + ); + perp_market.amm.max_slippage_ratio = v; + } - let spot_position = &mut user.spot_positions[position_index]; - controller::spot_position::update_spot_balances_and_cumulative_deposits( - amount as u128, - &SpotBalanceType::Deposit, - &mut spot_market, - spot_position, - false, - None, - )?; + if let Some(v) = params.max_fill_reserve_fraction { + validate!(v > 0, ErrorCode::DefaultError)?; + msg!( + "perp_market.amm.max_fill_reserve_fraction: {:?} -> {:?}", + perp_market.amm.max_fill_reserve_fraction, + v + ); + perp_market.amm.max_fill_reserve_fraction = v; + } - let token_amount = spot_position.get_token_amount(&spot_market)?; - if token_amount == 0 { + if let Some(max_open_interest) = params.max_open_interest { validate!( - spot_position.scaled_balance == 0, - ErrorCode::InvalidSpotPosition, - "deposit left user with invalid position. scaled balance = {} token amount = {}", - spot_position.scaled_balance, - token_amount + is_multiple_of_step_size( + max_open_interest.cast::()?, + perp_market.amm.order_step_size + )?, + ErrorCode::DefaultError, + "max oi not a multiple of the step size" )?; + msg!( + "perp_market.amm.max_open_interest: {:?} -> {:?}", + perp_market.amm.max_open_interest, + max_open_interest + ); + perp_market.amm.max_open_interest = max_open_interest; } - if spot_position.balance_type == SpotBalanceType::Deposit && spot_position.scaled_balance > 0 { + if let Some(fee_adjustment) = params.fee_adjustment { validate!( - matches!(spot_market.status, MarketStatus::Active), - ErrorCode::MarketActionPaused, - "spot_market not active", + fee_adjustment.unsigned_abs().cast::()? <= FEE_ADJUSTMENT_MAX, + ErrorCode::DefaultError, + "fee adjustment {} greater than max {}", + fee_adjustment, + FEE_ADJUSTMENT_MAX )?; + msg!( + "perp_market.fee_adjustment: {:?} -> {:?}", + perp_market.fee_adjustment, + fee_adjustment + ); + perp_market.fee_adjustment = fee_adjustment; } - drop(spot_market); + if params.number_of_users.is_some() || params.number_of_users_with_base.is_some() { + if let Some(n) = params.number_of_users { + msg!( + "perp_market.number_of_users: {:?} -> {:?}", + perp_market.number_of_users, + n + ); + perp_market.number_of_users = n; + } + if let Some(nb) = params.number_of_users_with_base { + msg!( + "perp_market.number_of_users_with_base: {:?} -> {:?}", + perp_market.number_of_users_with_base, + nb + ); + perp_market.number_of_users_with_base = nb; + } + validate!( + perp_market.number_of_users >= perp_market.number_of_users_with_base, + ErrorCode::DefaultError, + "number_of_users must be >= number_of_users_with_base " + )?; + } - user.update_last_active_slot(slot); + if params.protected_maker_limit_price_divisor.is_some() + || params.protected_maker_dynamic_divisor.is_some() + { + if let Some(v) = params.protected_maker_limit_price_divisor { + msg!( + "perp_market.protected_maker_limit_price_divisor: {:?} -> {:?}", + perp_market.protected_maker_limit_price_divisor, + v + ); + perp_market.protected_maker_limit_price_divisor = v; + } + if let Some(v) = params.protected_maker_dynamic_divisor { + msg!( + "perp_market.protected_maker_dynamic_divisor: {:?} -> {:?}", + perp_market.protected_maker_dynamic_divisor, + v + ); + perp_market.protected_maker_dynamic_divisor = v; + } + } - let spot_market = &mut spot_market_map.get_ref_mut(&market_index)?; + if let Some(v) = params.fuel_boost_taker { + msg!( + "perp_market.fuel_boost_taker: {:?} -> {:?}", + perp_market.fuel_boost_taker, + v + ); + perp_market.fuel_boost_taker = v; + } + if let Some(v) = params.fuel_boost_maker { + msg!( + "perp_market.fuel_boost_maker: {:?} -> {:?}", + perp_market.fuel_boost_maker, + v + ); + perp_market.fuel_boost_maker = v; + } + if let Some(v) = params.fuel_boost_position { + msg!( + "perp_market.fuel_boost_position: {:?} -> {:?}", + perp_market.fuel_boost_position, + v + ); + perp_market.fuel_boost_position = v; + } - controller::token::receive( - &ctx.accounts.token_program, - &ctx.accounts.admin_token_account, - &ctx.accounts.spot_market_vault, - &ctx.accounts.admin, - amount, - &mint, - if spot_market.has_transfer_hook() { - Some(remaining_accounts_iter) - } else { - None - }, - )?; - ctx.accounts.spot_market_vault.reload()?; - validate_spot_market_vault_amount(spot_market, ctx.accounts.spot_market_vault.amount)?; + if let Some(v) = params.taker_speed_bump_override { + msg!( + "perp_market.amm.taker_speed_bump_override: {:?} -> {:?}", + perp_market.amm.taker_speed_bump_override, + v + ); + perp_market.amm.taker_speed_bump_override = v; + } - let deposit_record_id = get_then_update_id!(spot_market, next_deposit_record_id); - let oracle_price = oracle_price_data.price; - let deposit_record = DepositRecord { - ts: now, - deposit_record_id, - user_authority: user.authority, - user: user_key, - direction: DepositDirection::Deposit, - amount, - oracle_price, - market_deposit_balance: spot_market.deposit_balance, - market_withdraw_balance: spot_market.borrow_balance, - market_cumulative_deposit_interest: spot_market.cumulative_deposit_interest, - market_cumulative_borrow_interest: spot_market.cumulative_borrow_interest, - total_deposits_after, - total_withdraws_after, - market_index, - explanation: DepositExplanation::Reward, - transfer_user: None, - }; - emit!(deposit_record); + if let Some(v) = params.oracle_slot_delay_override { + msg!( + "perp_market.amm.oracle_slot_delay_override: {:?} -> {:?}", + perp_market.amm.oracle_slot_delay_override, + v + ); + perp_market.amm.oracle_slot_delay_override = v; + } - spot_market.validate_max_token_deposits_and_borrows(false)?; + if params.amm_spread_adjustment.is_some() + || params.amm_inventory_spread_adjustment.is_some() + || params.reference_price_offset.is_some() + { + if let Some(v) = params.amm_spread_adjustment { + msg!( + "perp_market.amm.amm_spread_adjustment: {:?} -> {:?}", + perp_market.amm.amm_spread_adjustment, + v + ); + perp_market.amm.amm_spread_adjustment = v; + } + if let Some(v) = params.amm_inventory_spread_adjustment { + msg!( + "perp_market.amm.amm_inventory_spread_adjustment: {:?} -> {:?}", + perp_market.amm.amm_inventory_spread_adjustment, + v + ); + perp_market.amm.amm_inventory_spread_adjustment = v; + } + if let Some(v) = params.reference_price_offset { + msg!( + "perp_market.amm.reference_price_offset: {:?} -> {:?}", + perp_market.amm.reference_price_offset, + v + ); + perp_market.amm.reference_price_offset = v; + } + } - Ok(()) -} + if params.zero_mm_oracle_fields.unwrap_or(false) { + msg!("zeroing mm oracle fields"); + perp_market.amm.mm_oracle_price = 0; + perp_market.amm.mm_oracle_sequence_id = 0; + perp_market.amm.mm_oracle_slot = 0; + } -pub fn handle_initialize_if_rebalance_config( - ctx: Context, - params: IfRebalanceConfigParams, -) -> Result<()> { - let pubkey = ctx.accounts.if_rebalance_config.to_account_info().key; - let mut config = ctx.accounts.if_rebalance_config.load_init()?; + if let Some(expiry_ts) = params.expiry_ts { + validate!( + now < expiry_ts, + ErrorCode::DefaultError, + "Market expiry ts must later than current clock timestamp" + )?; + msg!( + "perp_market.status {:?} -> {:?}", + perp_market.status, + MarketStatus::ReduceOnly + ); + msg!( + "perp_market.expiry_ts {} -> {}", + perp_market.expiry_ts, + expiry_ts + ); + perp_market.status = MarketStatus::ReduceOnly; + perp_market.expiry_ts = expiry_ts; + } - config.pubkey = *pubkey; - config.total_in_amount = params.total_in_amount; - config.current_in_amount = 0; - config.epoch_max_in_amount = params.epoch_max_in_amount; - config.epoch_duration = params.epoch_duration; - config.out_market_index = params.out_market_index; - config.in_market_index = params.in_market_index; - config.max_slippage_bps = params.max_slippage_bps; - config.swap_mode = params.swap_mode; - config.status = 0; - - config.validate()?; - - Ok(()) -} - -pub fn handle_update_if_rebalance_config( - ctx: Context, - params: IfRebalanceConfigParams, -) -> Result<()> { - let mut config = load_mut!(ctx.accounts.if_rebalance_config)?; - - config.total_in_amount = params.total_in_amount; - config.epoch_max_in_amount = params.epoch_max_in_amount; - config.epoch_duration = params.epoch_duration; - config.max_slippage_bps = params.max_slippage_bps; - - config.validate()?; - - Ok(()) -} - -pub fn handle_zero_mm_oracle_fields(ctx: Context) -> Result<()> { - let mut perp_market = load_mut!(ctx.accounts.perp_market)?; - perp_market.amm.mm_oracle_price = 0; - perp_market.amm.mm_oracle_sequence_id = 0; - perp_market.amm.mm_oracle_slot = 0; - Ok(()) -} - -pub fn handle_update_mm_oracle_native(accounts: &[AccountInfo], data: &[u8]) -> Result<()> { - // Verify this ix is allowed - let state = &accounts[3].data.borrow(); - assert!(state[982] & 1 > 0, "ix disabled by admin state"); - - let signer_account = &accounts[1]; - #[cfg(not(feature = "anchor-test"))] - assert!( - signer_account.is_signer && *signer_account.key == mm_oracle_crank_wallet::id(), - "signer must be mm oracle crank wallet, signer: {}, mm oracle crank wallet: {}", - signer_account.key, - mm_oracle_crank_wallet::id() - ); - - let mut perp_market = accounts[0].data.borrow_mut(); - let perp_market_sequence_id = u64::from_le_bytes(perp_market[936..944].try_into().unwrap()); - let incoming_sequence_id = u64::from_le_bytes(data[8..16].try_into().unwrap()); - - if incoming_sequence_id > perp_market_sequence_id { - let clock_account = &accounts[2]; - let clock_data = clock_account.data.borrow(); - - perp_market[832..840].copy_from_slice(&clock_data[0..8]); - perp_market[912..920].copy_from_slice(&data[0..8]); - perp_market[936..944].copy_from_slice(&data[8..16]); - } - - Ok(()) -} - -pub fn handle_update_amm_spread_adjustment_native( - accounts: &[AccountInfo], - data: &[u8], -) -> Result<()> { - let signer_account = &accounts[1]; - #[cfg(not(feature = "anchor-test"))] - assert!( - signer_account.is_signer && *signer_account.key == amm_spread_adjust_wallet::id(), - "signer must be amm spread adjust wallet, signer: {}, amm spread adjust wallet: {}", - signer_account.key, - amm_spread_adjust_wallet::id() - ); - let mut perp_market = accounts[0].data.borrow_mut(); - perp_market[934..935].copy_from_slice(&[data[0]]); - - Ok(()) -} - -pub fn handle_update_feature_bit_flags_mm_oracle( - ctx: Context, - enable: bool, -) -> Result<()> { - let state = &mut ctx.accounts.state; - if enable { - validate!( - ctx.accounts.admin.key().eq(&state.admin), - ErrorCode::DefaultError, - "Only state admin can re-enable after kill switch" - )?; - - msg!("Setting first bit to 1, enabling mm oracle update"); - state.feature_bit_flags = state.feature_bit_flags | (FeatureBitFlags::MmOracleUpdate as u8); - } else { - msg!("Setting first bit to 0, disabling mm oracle update"); - state.feature_bit_flags = - state.feature_bit_flags & !(FeatureBitFlags::MmOracleUpdate as u8); - } - Ok(()) -} - -pub fn handle_update_feature_bit_flags_median_trigger_price( - ctx: Context, - enable: bool, -) -> Result<()> { - let state = &mut ctx.accounts.state; - if enable { - validate!( - ctx.accounts.admin.key().eq(&state.admin), - ErrorCode::DefaultError, - "Only state admin can re-enable after kill switch" - )?; - - msg!("Setting second bit to 1, enabling median trigger price"); - state.feature_bit_flags = - state.feature_bit_flags | (FeatureBitFlags::MedianTriggerPrice as u8); - } else { - msg!("Setting second bit to 0, disabling median trigger price"); - state.feature_bit_flags = - state.feature_bit_flags & !(FeatureBitFlags::MedianTriggerPrice as u8); - } - Ok(()) -} - -pub fn handle_update_delegate_user_gov_token_insurance_stake( - ctx: Context, -) -> Result<()> { - let insurance_fund_stake = &mut load_mut!(ctx.accounts.insurance_fund_stake)?; - let user_stats = &mut load_mut!(ctx.accounts.user_stats)?; - let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; - - validate!( - insurance_fund_stake.market_index == GOV_SPOT_MARKET_INDEX, - ErrorCode::IncorrectSpotMarketAccountPassed, - "insurance_fund_stake is not for governance market index = {}", - GOV_SPOT_MARKET_INDEX - )?; - - if insurance_fund_stake.market_index == GOV_SPOT_MARKET_INDEX - && spot_market.market_index == GOV_SPOT_MARKET_INDEX - { - let clock = Clock::get()?; - let now = clock.unix_timestamp; - - crate::controller::insurance::update_user_stats_if_stake_amount( - 0, - ctx.accounts.insurance_fund_vault.amount, - insurance_fund_stake, - user_stats, - spot_market, - now, - )?; - } - - Ok(()) -} - -pub fn handle_update_feature_bit_flags_builder_codes( - ctx: Context, - enable: bool, -) -> Result<()> { - let state = &mut ctx.accounts.state; - if enable { + if let Some(concentration_scale) = params.concentration_scale { validate!( - ctx.accounts.admin.key().eq(&state.admin), - ErrorCode::DefaultError, - "Only state admin can enable feature bit flags" - )?; - - msg!("Setting 3rd bit to 1, enabling builder codes"); - state.feature_bit_flags = state.feature_bit_flags | (FeatureBitFlags::BuilderCodes as u8); - } else { - msg!("Setting 3rd bit to 0, disabling builder codes"); - state.feature_bit_flags = state.feature_bit_flags & !(FeatureBitFlags::BuilderCodes as u8); - } - Ok(()) -} - -pub fn handle_update_feature_bit_flags_builder_referral( - ctx: Context, - enable: bool, -) -> Result<()> { - let state = &mut ctx.accounts.state; - if enable { - validate!( - ctx.accounts.admin.key().eq(&state.admin), - ErrorCode::DefaultError, - "Only state admin can enable feature bit flags" - )?; - - msg!("Setting 4th bit to 1, enabling builder referral"); - state.feature_bit_flags = - state.feature_bit_flags | (FeatureBitFlags::BuilderReferral as u8); - } else { - msg!("Setting 4th bit to 0, disabling builder referral"); - state.feature_bit_flags = - state.feature_bit_flags & !(FeatureBitFlags::BuilderReferral as u8); - } - Ok(()) -} - -#[derive(Accounts)] -pub struct Initialize<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - init, - seeds = [b"drift_state".as_ref()], - space = State::SIZE, - bump, - payer = admin - )] - pub state: Box>, - pub quote_asset_mint: Box>, - /// CHECK: checked in `initialize` - pub drift_signer: AccountInfo<'info>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, - pub token_program: Interface<'info, TokenInterface>, -} - -#[derive(Accounts)] -pub struct InitializeSpotMarket<'info> { - #[account( - init, - seeds = [b"spot_market", state.number_of_spot_markets.to_le_bytes().as_ref()], - space = SpotMarket::SIZE, - bump, - payer = admin - )] - pub spot_market: AccountLoader<'info, SpotMarket>, - #[account( - mint::token_program = token_program, - )] - pub spot_market_mint: Box>, - #[account( - init, - seeds = [b"spot_market_vault".as_ref(), state.number_of_spot_markets.to_le_bytes().as_ref()], - bump, - payer = admin, - space = get_vault_len(&spot_market_mint)?, - owner = token_program.key() - )] - /// CHECK: checked in `initialize_spot_market` - pub spot_market_vault: AccountInfo<'info>, - #[account( - init, - seeds = [b"insurance_fund_vault".as_ref(), state.number_of_spot_markets.to_le_bytes().as_ref()], - bump, - payer = admin, - space = get_vault_len(&spot_market_mint)?, - owner = token_program.key() - )] - /// CHECK: checked in `initialize_spot_market` - pub insurance_fund_vault: AccountInfo<'info>, - #[account( - constraint = state.signer.eq(&drift_signer.key()) - )] - /// CHECK: program signer - pub drift_signer: AccountInfo<'info>, - #[account(mut)] - pub state: Box>, - /// CHECK: checked in `initialize_spot_market` - pub oracle: AccountInfo<'info>, - #[account( - mut, - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, - pub token_program: Interface<'info, TokenInterface>, -} - -#[derive(Accounts)] -#[instruction(market_index: u16)] -pub struct DeleteInitializedSpotMarket<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - mut, - has_one = admin - )] - pub state: Box>, - #[account(mut, close = admin)] - pub spot_market: AccountLoader<'info, SpotMarket>, - #[account( - mut, - seeds = [b"spot_market_vault".as_ref(), market_index.to_le_bytes().as_ref()], - bump, - )] - pub spot_market_vault: Box>, - #[account( - mut, - seeds = [b"insurance_fund_vault".as_ref(), market_index.to_le_bytes().as_ref()], - bump, - )] - pub insurance_fund_vault: Box>, - /// CHECK: program signer - pub drift_signer: AccountInfo<'info>, - pub token_program: Interface<'info, TokenInterface>, -} - -#[derive(Accounts)] -#[instruction(market_index: u16)] -pub struct InitializeSerumFulfillmentConfig<'info> { - #[account( - seeds = [b"spot_market", market_index.to_le_bytes().as_ref()], - bump, - )] - pub base_spot_market: AccountLoader<'info, SpotMarket>, - #[account( - seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], - bump, - )] - pub quote_spot_market: AccountLoader<'info, SpotMarket>, - #[account( - mut, - has_one = admin - )] - pub state: Box>, - /// CHECK: checked in ix - pub serum_program: AccountInfo<'info>, - /// CHECK: checked in ix - pub serum_market: AccountInfo<'info>, - #[account( - mut, - seeds = [b"serum_open_orders".as_ref(), serum_market.key.as_ref()], - bump, - )] - /// CHECK: checked in ix - pub serum_open_orders: AccountInfo<'info>, - #[account( - constraint = state.signer.eq(&drift_signer.key()) - )] - /// CHECK: program signer - pub drift_signer: AccountInfo<'info>, - #[account( - init, - seeds = [b"serum_fulfillment_config".as_ref(), serum_market.key.as_ref()], - space = SerumV3FulfillmentConfig::SIZE, - bump, - payer = admin, - )] - pub serum_fulfillment_config: AccountLoader<'info, SerumV3FulfillmentConfig>, - #[account(mut)] - pub admin: Signer<'info>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct UpdateSerumFulfillmentConfig<'info> { - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub serum_fulfillment_config: AccountLoader<'info, SerumV3FulfillmentConfig>, - #[account(mut)] - pub admin: Signer<'info>, -} - -#[derive(Accounts)] -#[instruction(market_index: u16)] -pub struct InitializePhoenixFulfillmentConfig<'info> { - #[account( - seeds = [b"spot_market", market_index.to_le_bytes().as_ref()], - bump, - )] - pub base_spot_market: AccountLoader<'info, SpotMarket>, - #[account( - seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], - bump, - )] - pub quote_spot_market: AccountLoader<'info, SpotMarket>, - #[account( - mut, - has_one = admin - )] - pub state: Box>, - /// CHECK: checked in ix - pub phoenix_program: AccountInfo<'info>, - /// CHECK: checked in ix - pub phoenix_market: AccountInfo<'info>, - #[account( - constraint = state.signer.eq(&drift_signer.key()) - )] - /// CHECK: program signer - pub drift_signer: AccountInfo<'info>, - #[account( - init, - seeds = [b"phoenix_fulfillment_config".as_ref(), phoenix_market.key.as_ref()], - space = PhoenixV1FulfillmentConfig::SIZE, - bump, - payer = admin, - )] - pub phoenix_fulfillment_config: AccountLoader<'info, PhoenixV1FulfillmentConfig>, - #[account(mut)] - pub admin: Signer<'info>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct UpdatePhoenixFulfillmentConfig<'info> { - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub phoenix_fulfillment_config: AccountLoader<'info, PhoenixV1FulfillmentConfig>, - #[account(mut)] - pub admin: Signer<'info>, -} - -#[derive(Accounts)] -pub struct UpdateSerumVault<'info> { - #[account( - mut, - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub admin: Signer<'info>, - pub srm_vault: Box>, -} - -#[derive(Accounts)] -pub struct InitializePerpMarket<'info> { - #[account( - mut, - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - #[account(mut)] - pub state: Box>, - #[account( - init, - seeds = [b"perp_market", state.number_of_markets.to_le_bytes().as_ref()], - space = PerpMarket::SIZE, - bump, - payer = admin - )] - pub perp_market: AccountLoader<'info, PerpMarket>, - /// CHECK: checked in `initialize_perp_market` - pub oracle: AccountInfo<'info>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct DeleteInitializedPerpMarket<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - mut, - has_one = admin - )] - pub state: Box>, - #[account(mut, close = admin)] - pub perp_market: AccountLoader<'info, PerpMarket>, -} - -#[derive(Accounts)] -pub struct AdminUpdatePerpMarket<'info> { - pub admin: Signer<'info>, - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, -} - -#[derive(Accounts)] -pub struct HotAdminUpdatePerpMarket<'info> { - #[account( - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - pub state: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, -} - -#[derive(Accounts)] -pub struct AdminUpdatePerpMarketAmmSummaryStats<'info> { - #[account( - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - pub state: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, - #[account( - seeds = [b"spot_market", perp_market.load()?.quote_spot_market_index.to_le_bytes().as_ref()], - bump, - )] - pub spot_market: AccountLoader<'info, SpotMarket>, - /// CHECK: checked in `admin_update_perp_market_summary_stats` ix constraint - pub oracle: AccountInfo<'info>, -} - -#[derive(Accounts)] -pub struct SettleExpiredMarketPoolsToRevenuePool<'info> { - #[account( - has_one = admin - )] - pub state: Box>, - pub admin: Signer<'info>, - #[account( - seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], - bump, - mut - )] - pub spot_market: AccountLoader<'info, SpotMarket>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, -} - -#[derive(Accounts)] -pub struct UpdatePerpMarketPnlPool<'info> { - #[account( - has_one = admin - )] - pub state: Box>, - pub admin: Signer<'info>, - #[account( - seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], - bump, - mut - )] - pub spot_market: AccountLoader<'info, SpotMarket>, - #[account( - mut, - seeds = [b"spot_market_vault".as_ref(), 0_u16.to_le_bytes().as_ref()], - bump, - )] - pub spot_market_vault: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, -} - -#[derive(Accounts)] -pub struct DepositIntoMarketFeePool<'info> { - #[account( - mut, - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, - pub admin: Signer<'info>, - #[account( - mut, - token::authority = admin - )] - pub source_vault: Box>, - #[account( - constraint = state.signer.eq(&drift_signer.key()) - )] - /// CHECK: withdraw fails if this isn't vault owner - pub drift_signer: AccountInfo<'info>, - #[account( - mut, - seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], - bump, - )] - pub quote_spot_market: AccountLoader<'info, SpotMarket>, - #[account( - mut, - seeds = [b"spot_market_vault".as_ref(), 0_u16.to_le_bytes().as_ref()], - bump, - )] - pub spot_market_vault: Box>, - pub token_program: Interface<'info, TokenInterface>, -} - -#[derive(Accounts)] -pub struct DepositIntoSpotMarketVault<'info> { - pub state: Box>, - #[account(mut)] - pub spot_market: AccountLoader<'info, SpotMarket>, - #[account( - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - #[account( - mut, - token::authority = admin - )] - pub source_vault: Box>, - #[account( - mut, - constraint = spot_market.load()?.vault == spot_market_vault.key() - )] - pub spot_market_vault: Box>, - pub token_program: Interface<'info, TokenInterface>, -} - -#[derive(Accounts)] -pub struct RepegCurve<'info> { - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, - /// CHECK: checked in `repeg_curve` ix constraint - pub oracle: AccountInfo<'info>, - pub admin: Signer<'info>, -} - -#[derive(Accounts)] -pub struct AdminUpdateState<'info> { - pub admin: Signer<'info>, - #[account( - mut, - has_one = admin - )] - pub state: Box>, -} - -#[derive(Accounts)] -pub struct HotAdminUpdateState<'info> { - #[account( - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - #[account(mut)] - pub state: Box>, -} - -#[derive(Accounts)] -pub struct AdminUpdateK<'info> { - pub admin: Signer<'info>, - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, - /// CHECK: checked in `admin_update_k` ix constraint - pub oracle: AccountInfo<'info>, -} - -#[derive(Accounts)] -pub struct AdminUpdateSpotMarket<'info> { - pub admin: Signer<'info>, - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub spot_market: AccountLoader<'info, SpotMarket>, -} - -#[derive(Accounts)] -pub struct AdminUpdateSpotMarketFuel<'info> { - #[account( - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - pub state: Box>, - #[account(mut)] - pub spot_market: AccountLoader<'info, SpotMarket>, -} - -#[derive(Accounts)] -pub struct AdminUpdateSpotMarketOracle<'info> { - pub admin: Signer<'info>, - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub spot_market: AccountLoader<'info, SpotMarket>, - /// CHECK: checked in `initialize_spot_market` - pub oracle: AccountInfo<'info>, - /// CHECK: checked in `admin_update_spot_market_oracle` ix constraint - pub old_oracle: AccountInfo<'info>, -} - -#[derive(Accounts)] -pub struct AdminUpdatePerpMarketOracle<'info> { - pub admin: Signer<'info>, - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub perp_market: AccountLoader<'info, PerpMarket>, - /// CHECK: checked in `admin_update_perp_market_oracle` ix constraint - pub oracle: AccountInfo<'info>, - /// CHECK: checked in `admin_update_perp_market_oracle` ix constraint - pub old_oracle: AccountInfo<'info>, -} - -#[derive(Accounts)] -pub struct AdminDisableBidAskTwapUpdate<'info> { - #[account( - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - pub state: Box>, - #[account(mut)] - pub user_stats: AccountLoader<'info, UserStats>, -} - -#[derive(Accounts)] -pub struct InitUserFuel<'info> { - #[account( - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, // todo - pub state: Box>, - #[account(mut)] - pub user: AccountLoader<'info, User>, - #[account(mut)] - pub user_stats: AccountLoader<'info, UserStats>, -} - -#[derive(Accounts)] -pub struct InitializeProtocolIfSharesTransferConfig<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - init, - seeds = [b"if_shares_transfer_config".as_ref()], - space = ProtocolIfSharesTransferConfig::SIZE, - bump, - payer = admin - )] - pub protocol_if_shares_transfer_config: AccountLoader<'info, ProtocolIfSharesTransferConfig>, - #[account( - has_one = admin - )] - pub state: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct UpdateProtocolIfSharesTransferConfig<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - mut, - seeds = [b"if_shares_transfer_config".as_ref()], - bump, - )] - pub protocol_if_shares_transfer_config: AccountLoader<'info, ProtocolIfSharesTransferConfig>, - #[account( - has_one = admin - )] - pub state: Box>, -} - -#[derive(Accounts)] -#[instruction(params: PrelaunchOracleParams,)] -pub struct InitializePrelaunchOracle<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - init, - seeds = [b"prelaunch_oracle".as_ref(), params.perp_market_index.to_le_bytes().as_ref()], - space = PrelaunchOracle::SIZE, - bump, - payer = admin - )] - pub prelaunch_oracle: AccountLoader<'info, PrelaunchOracle>, - #[account( - has_one = admin - )] - pub state: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -#[instruction(params: PrelaunchOracleParams,)] -pub struct UpdatePrelaunchOracleParams<'info> { - #[account( - mut, - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - #[account( - mut, - seeds = [b"prelaunch_oracle".as_ref(), params.perp_market_index.to_le_bytes().as_ref()], - bump, - )] - pub prelaunch_oracle: AccountLoader<'info, PrelaunchOracle>, - #[account( - mut, - constraint = perp_market.load()?.market_index == params.perp_market_index - )] - pub perp_market: AccountLoader<'info, PerpMarket>, - pub state: Box>, -} - -#[derive(Accounts)] -#[instruction(perp_market_index: u16,)] -pub struct DeletePrelaunchOracle<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - mut, - seeds = [b"prelaunch_oracle".as_ref(), perp_market_index.to_le_bytes().as_ref()], - bump, - close = admin - )] - pub prelaunch_oracle: AccountLoader<'info, PrelaunchOracle>, - #[account( - constraint = perp_market.load()?.market_index == perp_market_index - )] - pub perp_market: AccountLoader<'info, PerpMarket>, - #[account( - has_one = admin - )] - pub state: Box>, -} - -#[derive(Accounts)] -#[instruction(market_index: u16)] -pub struct InitializeOpenbookV2FulfillmentConfig<'info> { - #[account( - seeds = [b"spot_market", market_index.to_le_bytes().as_ref()], - bump, - )] - pub base_spot_market: AccountLoader<'info, SpotMarket>, - #[account( - seeds = [b"spot_market", 0_u16.to_le_bytes().as_ref()], - bump, - )] - pub quote_spot_market: AccountLoader<'info, SpotMarket>, - #[account( - mut, - has_one = admin - )] - pub state: Box>, - /// CHECK: checked in ix - pub openbook_v2_program: AccountInfo<'info>, - /// CHECK: checked in ix - pub openbook_v2_market: AccountInfo<'info>, - #[account( - constraint = state.signer.eq(&drift_signer.key()) - )] - /// CHECK: program signer - pub drift_signer: AccountInfo<'info>, - #[account( - init, - seeds = [b"openbook_v2_fulfillment_config".as_ref(), openbook_v2_market.key.as_ref()], - space = OpenbookV2FulfillmentConfig::SIZE, - bump, - payer = admin, - )] - pub openbook_v2_fulfillment_config: AccountLoader<'info, OpenbookV2FulfillmentConfig>, - #[account(mut)] - pub admin: Signer<'info>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} + concentration_scale > 0, + ErrorCode::DefaultError, + "invalid concentration_scale", + )?; -#[derive(Accounts)] -pub struct UpdateOpenbookV2FulfillmentConfig<'info> { - #[account( - has_one = admin - )] - pub state: Box>, - #[account(mut)] - pub openbook_v2_fulfillment_config: AccountLoader<'info, OpenbookV2FulfillmentConfig>, - #[account(mut)] - pub admin: Signer<'info>, -} + let prev_concentration_coef = perp_market.amm.concentration_coef; + controller::amm::update_concentration_coef(&mut perp_market, concentration_scale)?; + let new_concentration_coef = perp_market.amm.concentration_coef; -#[derive(Accounts)] -#[instruction(feed_id : [u8; 32])] -pub struct InitPythPullPriceFeed<'info> { - #[account( - mut, - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - pub pyth_solana_receiver: Program<'info, PythSolanaReceiver>, - /// CHECK: This account's seeds are checked - #[account(mut, seeds = [PTYH_PRICE_FEED_SEED_PREFIX, &feed_id], bump)] - pub price_feed: AccountInfo<'info>, - pub system_program: Program<'info, System>, - pub state: Box>, -} + msg!( + "perp_market.amm.concentration_coef: {} -> {}", + prev_concentration_coef, + new_concentration_coef + ); + } -#[derive(Accounts)] -#[instruction(feed_id: u32)] -pub struct InitPythLazerOracle<'info> { - #[account( - mut, - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - #[account(init, seeds = [PYTH_LAZER_ORACLE_SEED, &feed_id.to_le_bytes()], - space=PythLazerOracle::SIZE, - bump, - payer=admin - )] - pub lazer_oracle: AccountLoader<'info, PythLazerOracle>, - pub state: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} + if let Some(curve_update_intensity) = params.curve_update_intensity { + // (0, 100] is for repeg / formulaic k intensity + // (100, 200] is for reference price offset intensity + validate!( + curve_update_intensity <= 200, + ErrorCode::DefaultError, + "invalid curve_update_intensity", + )?; + let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; -#[derive(Accounts)] -pub struct InitializeHighLeverageModeConfig<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - init, - seeds = [b"high_leverage_mode_config".as_ref()], - space = HighLeverageModeConfig::SIZE, - bump, - payer = admin - )] - pub high_leverage_mode_config: AccountLoader<'info, HighLeverageModeConfig>, - #[account( - has_one = admin - )] - pub state: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} + msg!( + "perp_market.amm.curve_update_intensity: {} -> {}", + perp_market.amm.curve_update_intensity, + curve_update_intensity + ); -#[derive(Accounts)] -pub struct UpdateHighLeverageModeConfig<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - mut, - seeds = [b"high_leverage_mode_config".as_ref()], - bump, - )] - pub high_leverage_mode_config: AccountLoader<'info, HighLeverageModeConfig>, - #[account( - has_one = admin - )] - pub state: Box>, -} + perp_market.amm.curve_update_intensity = curve_update_intensity; + } -#[derive(Accounts)] -pub struct InitializeProtectedMakerModeConfig<'info> { - #[account( - mut, - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - #[account( - init, - seeds = [b"protected_maker_mode_config".as_ref()], - space = ProtectedMakerModeConfig::SIZE, - bump, - payer = admin - )] - pub protected_maker_mode_config: AccountLoader<'info, ProtectedMakerModeConfig>, - #[account( - has_one = admin - )] - pub state: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, + Ok(()) } -#[derive(Accounts)] -pub struct UpdateProtectedMakerModeConfig<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - mut, - seeds = [b"protected_maker_mode_config".as_ref()], - bump, - )] - pub protected_maker_mode_config: AccountLoader<'info, ProtectedMakerModeConfig>, - #[account( - has_one = admin - )] - pub state: Box>, -} +#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, PartialEq)] +pub struct StateUpdateParams { + pub lp_cooldown_time: Option, + pub initial_pct_to_liquidate: Option, + pub liquidation_duration: Option, + pub liquidation_margin_buffer_ratio: Option, + pub settlement_duration: Option, + pub max_number_of_sub_accounts: Option, + pub max_initialize_user_fee: Option, + pub admin: Option, + pub whitelist_mint: Option, + pub discount_mint: Option, + pub exchange_status: Option, + pub min_perp_auction_duration: Option, + pub default_spot_auction_duration: Option, +} + +pub fn handle_update_state_params( + ctx: Context, + params: StateUpdateParams, +) -> Result<()> { + let state = &mut ctx.accounts.state; -#[derive(Accounts)] -#[instruction(market_index: u16,)] -pub struct AdminDeposit<'info> { - pub state: Box>, - #[account(mut)] - pub user: AccountLoader<'info, User>, - #[account( - mut, - constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin - )] - pub admin: Signer<'info>, - #[account( - mut, - seeds = [b"spot_market_vault".as_ref(), market_index.to_le_bytes().as_ref()], - bump, - )] - pub spot_market_vault: Box>, - #[account( - mut, - constraint = &spot_market_vault.mint.eq(&admin_token_account.mint), - token::authority = admin.key() - )] - pub admin_token_account: Box>, - pub token_program: Interface<'info, TokenInterface>, -} + if let Some(v) = params.lp_cooldown_time { + msg!("lp_cooldown_time: {} -> {}", state.lp_cooldown_time, v); + state.lp_cooldown_time = v; + } -#[derive(Accounts)] -#[instruction(params: IfRebalanceConfigParams)] -pub struct InitializeIfRebalanceConfig<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account( - init, - seeds = [b"if_rebalance_config".as_ref(), params.in_market_index.to_le_bytes().as_ref(), params.out_market_index.to_le_bytes().as_ref()], - space = IfRebalanceConfig::SIZE, - bump, - payer = admin - )] - pub if_rebalance_config: AccountLoader<'info, IfRebalanceConfig>, - #[account( - has_one = admin - )] - pub state: Box>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} + if let Some(v) = params.initial_pct_to_liquidate { + msg!( + "initial_pct_to_liquidate: {} -> {}", + state.initial_pct_to_liquidate, + v + ); + state.initial_pct_to_liquidate = v; + } -#[derive(Accounts)] -pub struct UpdateIfRebalanceConfig<'info> { - #[account(mut)] - pub admin: Signer<'info>, - #[account(mut)] - pub if_rebalance_config: AccountLoader<'info, IfRebalanceConfig>, - #[account( - has_one = admin - )] - pub state: Box>, + if let Some(v) = params.liquidation_duration { + msg!( + "liquidation_duration: {} -> {}", + state.liquidation_duration, + v + ); + state.liquidation_duration = v; + } + + if let Some(v) = params.liquidation_margin_buffer_ratio { + msg!( + "liquidation_margin_buffer_ratio: {} -> {}", + state.liquidation_margin_buffer_ratio, + v + ); + state.liquidation_margin_buffer_ratio = v; + } + + if let Some(v) = params.settlement_duration { + msg!( + "settlement_duration: {} -> {}", + state.settlement_duration, + v + ); + state.settlement_duration = v; + } + + if let Some(v) = params.max_number_of_sub_accounts { + msg!( + "max_number_of_sub_accounts: {} -> {}", + state.max_number_of_sub_accounts, + v + ); + state.max_number_of_sub_accounts = v; + } + + if let Some(v) = params.max_initialize_user_fee { + msg!( + "max_initialize_user_fee: {} -> {}", + state.max_initialize_user_fee, + v + ); + state.max_initialize_user_fee = v; + } + + if let Some(v) = params.admin { + msg!("admin: {:?} -> {:?}", state.admin, v); + state.admin = v; + } + + if let Some(v) = params.whitelist_mint { + msg!("whitelist_mint: {:?} -> {:?}", state.whitelist_mint, v); + state.whitelist_mint = v; + } + + if let Some(v) = params.discount_mint { + msg!("discount_mint: {:?} -> {:?}", state.discount_mint, v); + state.discount_mint = v; + } + + if let Some(v) = params.exchange_status { + msg!("exchange_status: {:?} -> {:?}", state.exchange_status, v); + state.exchange_status = v; + } + + if let Some(v) = params.min_perp_auction_duration { + msg!( + "min_perp_auction_duration: {:?} -> {:?}", + state.min_perp_auction_duration, + v + ); + state.min_perp_auction_duration = v; + } + + if let Some(v) = params.default_spot_auction_duration { + msg!( + "default_spot_auction_duration: {:?} -> {:?}", + state.default_spot_auction_duration, + v + ); + state.default_spot_auction_duration = v; + } + + Ok(()) } -#[derive(Accounts)] -pub struct UpdateDelegateUserGovTokenInsuranceStake<'info> { - #[account( - mut, - seeds = [b"spot_market", 15_u16.to_le_bytes().as_ref()], - bump - )] - pub spot_market: AccountLoader<'info, SpotMarket>, - pub insurance_fund_stake: AccountLoader<'info, InsuranceFundStake>, - #[account(mut)] - pub user_stats: AccountLoader<'info, UserStats>, - pub admin: Signer<'info>, - #[account( - mut, - seeds = [b"insurance_fund_vault".as_ref(), 15_u16.to_le_bytes().as_ref()], - bump, - )] - pub insurance_fund_vault: Box>, - #[account( - has_one = admin - )] - pub state: Box>, +pub fn handle_update_feature_flags( + ctx: Context, + set_bits: u8, + clear_bits: u8, + require_state_admin: bool, +) -> Result<()> { + let state = &mut ctx.accounts.state; + if require_state_admin { + validate!( + ctx.accounts.admin.key().eq(&state.admin), + ErrorCode::DefaultError, + "Only state admin can update feature flags with require_state_admin=true" + )?; + } + let before = state.feature_bit_flags; + let after = (before | set_bits) & !clear_bits; + msg!("feature_bit_flags: {:?} -> {:?}", before, after); + state.feature_bit_flags = after; + Ok(()) } diff --git a/programs/drift/src/lib.rs b/programs/drift/src/lib.rs index eab5b09e25..ef6d6ca4e1 100644 --- a/programs/drift/src/lib.rs +++ b/programs/drift/src/lib.rs @@ -718,11 +718,11 @@ pub mod drift { handle_update_amms(ctx, market_indexes) } - pub fn update_spot_market_expiry( + pub fn update_spot_market_params( ctx: Context, - expiry_ts: i64, + params: SpotMarketUpdateParams, ) -> Result<()> { - handle_update_spot_market_expiry(ctx, expiry_ts) + handle_update_spot_market_params(ctx, params) } // IF stakers @@ -1048,11 +1048,11 @@ pub mod drift { handle_update_perp_market_amm_summary_stats(ctx, params) } - pub fn update_perp_market_expiry( + pub fn update_perp_market_params( ctx: Context, - expiry_ts: i64, + params: PerpMarketUpdateParams, ) -> Result<()> { - handle_update_perp_market_expiry(ctx, expiry_ts) + handle_update_perp_market_params(ctx, params) } pub fn settle_expired_market_pools_to_revenue_pool( @@ -1105,55 +1105,6 @@ pub mod drift { handle_update_k(ctx, sqrt_k) } - pub fn update_perp_market_margin_ratio( - ctx: Context, - margin_ratio_initial: u32, - margin_ratio_maintenance: u32, - ) -> Result<()> { - handle_update_perp_market_margin_ratio(ctx, margin_ratio_initial, margin_ratio_maintenance) - } - - pub fn update_perp_market_high_leverage_margin_ratio( - ctx: Context, - margin_ratio_initial: u16, - margin_ratio_maintenance: u16, - ) -> Result<()> { - handle_update_perp_market_high_leverage_margin_ratio( - ctx, - margin_ratio_initial, - margin_ratio_maintenance, - ) - } - - pub fn update_perp_market_funding_period( - ctx: Context, - funding_period: i64, - ) -> Result<()> { - handle_update_perp_market_funding_period(ctx, funding_period) - } - - pub fn update_perp_market_max_imbalances( - ctx: Context, - unrealized_max_imbalance: u64, - max_revenue_withdraw_per_period: u64, - quote_max_insurance: u64, - ) -> Result<()> { - handle_update_perp_market_max_imbalances( - ctx, - unrealized_max_imbalance, - max_revenue_withdraw_per_period, - quote_max_insurance, - ) - } - - pub fn update_perp_market_liquidation_fee( - ctx: Context, - liquidator_fee: u32, - if_liquidation_fee: u32, - ) -> Result<()> { - handle_update_perp_liquidation_fee(ctx, liquidator_fee, if_liquidation_fee) - } - pub fn update_insurance_fund_unstaking_period( ctx: Context, insurance_fund_unstaking_period: i64, @@ -1161,123 +1112,6 @@ pub mod drift { handle_update_insurance_fund_unstaking_period(ctx, insurance_fund_unstaking_period) } - pub fn update_spot_market_pool_id( - ctx: Context, - pool_id: u8, - ) -> Result<()> { - handle_update_spot_market_pool_id(ctx, pool_id) - } - - pub fn update_spot_market_liquidation_fee( - ctx: Context, - liquidator_fee: u32, - if_liquidation_fee: u32, - ) -> Result<()> { - handle_update_spot_market_liquidation_fee(ctx, liquidator_fee, if_liquidation_fee) - } - - pub fn update_withdraw_guard_threshold( - ctx: Context, - withdraw_guard_threshold: u64, - ) -> Result<()> { - handle_update_withdraw_guard_threshold(ctx, withdraw_guard_threshold) - } - - pub fn update_spot_market_if_factor( - ctx: Context, - spot_market_index: u16, - user_if_factor: u32, - total_if_factor: u32, - ) -> Result<()> { - handle_update_spot_market_if_factor(ctx, spot_market_index, user_if_factor, total_if_factor) - } - - pub fn update_spot_market_revenue_settle_period( - ctx: Context, - revenue_settle_period: i64, - ) -> Result<()> { - handle_update_spot_market_revenue_settle_period(ctx, revenue_settle_period) - } - - pub fn update_spot_market_status( - ctx: Context, - status: MarketStatus, - ) -> Result<()> { - handle_update_spot_market_status(ctx, status) - } - - pub fn update_spot_market_paused_operations( - ctx: Context, - paused_operations: u8, - ) -> Result<()> { - handle_update_spot_market_paused_operations(ctx, paused_operations) - } - - pub fn update_spot_market_asset_tier( - ctx: Context, - asset_tier: AssetTier, - ) -> Result<()> { - handle_update_spot_market_asset_tier(ctx, asset_tier) - } - - pub fn update_spot_market_margin_weights( - ctx: Context, - initial_asset_weight: u32, - maintenance_asset_weight: u32, - initial_liability_weight: u32, - maintenance_liability_weight: u32, - imf_factor: u32, - ) -> Result<()> { - handle_update_spot_market_margin_weights( - ctx, - initial_asset_weight, - maintenance_asset_weight, - initial_liability_weight, - maintenance_liability_weight, - imf_factor, - ) - } - - pub fn update_spot_market_borrow_rate( - ctx: Context, - optimal_utilization: u32, - optimal_borrow_rate: u32, - max_borrow_rate: u32, - min_borrow_rate: Option, - ) -> Result<()> { - handle_update_spot_market_borrow_rate( - ctx, - optimal_utilization, - optimal_borrow_rate, - max_borrow_rate, - min_borrow_rate, - ) - } - - pub fn update_spot_market_max_token_deposits( - ctx: Context, - max_token_deposits: u64, - ) -> Result<()> { - handle_update_spot_market_max_token_deposits(ctx, max_token_deposits) - } - - pub fn update_spot_market_max_token_borrows( - ctx: Context, - max_token_borrows_fraction: u16, - ) -> Result<()> { - handle_update_spot_market_max_token_borrows(ctx, max_token_borrows_fraction) - } - - pub fn update_spot_market_scale_initial_asset_weight_start( - ctx: Context, - scale_initial_asset_weight_start: u64, - ) -> Result<()> { - handle_update_spot_market_scale_initial_asset_weight_start( - ctx, - scale_initial_asset_weight_start, - ) - } - pub fn update_spot_market_oracle( ctx: Context, oracle: Pubkey, @@ -1287,104 +1121,6 @@ pub mod drift { handle_update_spot_market_oracle(ctx, oracle, oracle_source, skip_invariant_check) } - pub fn update_spot_market_step_size_and_tick_size( - ctx: Context, - step_size: u64, - tick_size: u64, - ) -> Result<()> { - handle_update_spot_market_step_size_and_tick_size(ctx, step_size, tick_size) - } - - pub fn update_spot_market_min_order_size( - ctx: Context, - order_size: u64, - ) -> Result<()> { - handle_update_spot_market_min_order_size(ctx, order_size) - } - - pub fn update_spot_market_orders_enabled( - ctx: Context, - orders_enabled: bool, - ) -> Result<()> { - handle_update_spot_market_orders_enabled(ctx, orders_enabled) - } - - pub fn update_spot_market_if_paused_operations( - ctx: Context, - paused_operations: u8, - ) -> Result<()> { - handle_update_spot_market_if_paused_operations(ctx, paused_operations) - } - - pub fn update_spot_market_name( - ctx: Context, - name: [u8; 32], - ) -> Result<()> { - handle_update_spot_market_name(ctx, name) - } - - pub fn update_perp_market_status( - ctx: Context, - status: MarketStatus, - ) -> Result<()> { - handle_update_perp_market_status(ctx, status) - } - - pub fn update_perp_market_paused_operations( - ctx: Context, - paused_operations: u8, - ) -> Result<()> { - handle_update_perp_market_paused_operations(ctx, paused_operations) - } - - pub fn update_perp_market_contract_tier( - ctx: Context, - contract_tier: ContractTier, - ) -> Result<()> { - handle_update_perp_market_contract_tier(ctx, contract_tier) - } - - pub fn update_perp_market_imf_factor( - ctx: Context, - imf_factor: u32, - unrealized_pnl_imf_factor: u32, - ) -> Result<()> { - handle_update_perp_market_imf_factor(ctx, imf_factor, unrealized_pnl_imf_factor) - } - - pub fn update_perp_market_unrealized_asset_weight( - ctx: Context, - unrealized_initial_asset_weight: u32, - unrealized_maintenance_asset_weight: u32, - ) -> Result<()> { - handle_update_perp_market_unrealized_asset_weight( - ctx, - unrealized_initial_asset_weight, - unrealized_maintenance_asset_weight, - ) - } - - pub fn update_perp_market_concentration_coef( - ctx: Context, - concentration_scale: u128, - ) -> Result<()> { - handle_update_perp_market_concentration_coef(ctx, concentration_scale) - } - - pub fn update_perp_market_curve_update_intensity( - ctx: Context, - curve_update_intensity: u8, - ) -> Result<()> { - handle_update_perp_market_curve_update_intensity(ctx, curve_update_intensity) - } - - pub fn update_lp_cooldown_time( - ctx: Context, - lp_cooldown_time: u64, - ) -> Result<()> { - handle_update_lp_cooldown_time(ctx, lp_cooldown_time) - } - pub fn update_perp_fee_structure( ctx: Context, fee_structure: FeeStructure, @@ -1399,25 +1135,11 @@ pub mod drift { handle_update_spot_fee_structure(ctx, fee_structure) } - pub fn update_initial_pct_to_liquidate( + pub fn update_state_all( ctx: Context, - initial_pct_to_liquidate: u16, + params: StateUpdateParams, ) -> Result<()> { - handle_update_initial_pct_to_liquidate(ctx, initial_pct_to_liquidate) - } - - pub fn update_liquidation_duration( - ctx: Context, - liquidation_duration: u8, - ) -> Result<()> { - handle_update_liquidation_duration(ctx, liquidation_duration) - } - - pub fn update_liquidation_margin_buffer_ratio( - ctx: Context, - liquidation_margin_buffer_ratio: u32, - ) -> Result<()> { - handle_update_liquidation_margin_buffer_ratio(ctx, liquidation_margin_buffer_ratio) + handle_update_state_params(ctx, params) } pub fn update_oracle_guard_rails( @@ -1427,27 +1149,6 @@ pub mod drift { handle_update_oracle_guard_rails(ctx, oracle_guard_rails) } - pub fn update_state_settlement_duration( - ctx: Context, - settlement_duration: u16, - ) -> Result<()> { - handle_update_state_settlement_duration(ctx, settlement_duration) - } - - pub fn update_state_max_number_of_sub_accounts( - ctx: Context, - max_number_of_sub_accounts: u16, - ) -> Result<()> { - handle_update_state_max_number_of_sub_accounts(ctx, max_number_of_sub_accounts) - } - - pub fn update_state_max_initialize_user_fee( - ctx: Context, - max_initialize_user_fee: u16, - ) -> Result<()> { - handle_update_state_max_initialize_user_fee(ctx, max_initialize_user_fee) - } - pub fn update_perp_market_oracle( ctx: Context, oracle: Pubkey, @@ -1457,13 +1158,6 @@ pub mod drift { handle_update_perp_market_oracle(ctx, oracle, oracle_source, skip_invariant_check) } - pub fn update_perp_market_base_spread( - ctx: Context, - base_spread: u32, - ) -> Result<()> { - handle_update_perp_market_base_spread(ctx, base_spread) - } - pub fn update_amm_jit_intensity( ctx: Context, amm_jit_intensity: u8, @@ -1471,127 +1165,6 @@ pub mod drift { handle_update_amm_jit_intensity(ctx, amm_jit_intensity) } - pub fn update_perp_market_max_spread( - ctx: Context, - max_spread: u32, - ) -> Result<()> { - handle_update_perp_market_max_spread(ctx, max_spread) - } - - pub fn update_perp_market_step_size_and_tick_size( - ctx: Context, - step_size: u64, - tick_size: u64, - ) -> Result<()> { - handle_update_perp_market_step_size_and_tick_size(ctx, step_size, tick_size) - } - - pub fn update_perp_market_name( - ctx: Context, - name: [u8; 32], - ) -> Result<()> { - handle_update_perp_market_name(ctx, name) - } - - pub fn update_perp_market_min_order_size( - ctx: Context, - order_size: u64, - ) -> Result<()> { - handle_update_perp_market_min_order_size(ctx, order_size) - } - - pub fn update_perp_market_max_slippage_ratio( - ctx: Context, - max_slippage_ratio: u16, - ) -> Result<()> { - handle_update_perp_market_max_slippage_ratio(ctx, max_slippage_ratio) - } - - pub fn update_perp_market_max_fill_reserve_fraction( - ctx: Context, - max_fill_reserve_fraction: u16, - ) -> Result<()> { - handle_update_perp_market_max_fill_reserve_fraction(ctx, max_fill_reserve_fraction) - } - - pub fn update_perp_market_max_open_interest( - ctx: Context, - max_open_interest: u128, - ) -> Result<()> { - handle_update_perp_market_max_open_interest(ctx, max_open_interest) - } - - pub fn update_perp_market_number_of_users( - ctx: Context, - number_of_users: Option, - number_of_users_with_base: Option, - ) -> Result<()> { - handle_update_perp_market_number_of_users(ctx, number_of_users, number_of_users_with_base) - } - - pub fn update_perp_market_fee_adjustment( - ctx: Context, - fee_adjustment: i16, - ) -> Result<()> { - handle_update_perp_market_fee_adjustment(ctx, fee_adjustment) - } - - pub fn update_spot_market_fee_adjustment( - ctx: Context, - fee_adjustment: i16, - ) -> Result<()> { - handle_update_spot_market_fee_adjustment(ctx, fee_adjustment) - } - - pub fn update_perp_market_fuel( - ctx: Context, - fuel_boost_taker: Option, - fuel_boost_maker: Option, - fuel_boost_position: Option, - ) -> Result<()> { - handle_update_perp_market_fuel(ctx, fuel_boost_taker, fuel_boost_maker, fuel_boost_position) - } - - pub fn update_perp_market_protected_maker_params( - ctx: Context, - protected_maker_limit_price_divisor: Option, - protected_maker_dynamic_divisor: Option, - ) -> Result<()> { - handle_update_perp_market_protected_maker_params( - ctx, - protected_maker_limit_price_divisor, - protected_maker_dynamic_divisor, - ) - } - - pub fn update_perp_market_taker_speed_bump_override( - ctx: Context, - taker_speed_bump_override: i8, - ) -> Result<()> { - handle_update_perp_market_taker_speed_bump_override(ctx, taker_speed_bump_override) - } - - pub fn update_perp_market_amm_spread_adjustment( - ctx: Context, - amm_spread_adjustment: i8, - amm_inventory_spread_adjustment: i8, - reference_price_offset: i32, - ) -> Result<()> { - handle_update_perp_market_amm_spread_adjustment( - ctx, - amm_spread_adjustment, - amm_inventory_spread_adjustment, - reference_price_offset, - ) - } - - 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, @@ -1628,45 +1201,6 @@ pub mod drift { ) } - pub fn update_admin(ctx: Context, admin: Pubkey) -> Result<()> { - handle_update_admin(ctx, admin) - } - - pub fn update_whitelist_mint( - ctx: Context, - whitelist_mint: Pubkey, - ) -> Result<()> { - handle_update_whitelist_mint(ctx, whitelist_mint) - } - - pub fn update_discount_mint( - ctx: Context, - discount_mint: Pubkey, - ) -> Result<()> { - handle_update_discount_mint(ctx, discount_mint) - } - - pub fn update_exchange_status( - ctx: Context, - exchange_status: u8, - ) -> Result<()> { - handle_update_exchange_status(ctx, exchange_status) - } - - pub fn update_perp_auction_duration( - ctx: Context, - min_perp_auction_duration: u8, - ) -> Result<()> { - handle_update_perp_auction_duration(ctx, min_perp_auction_duration) - } - - pub fn update_spot_auction_duration( - ctx: Context, - default_spot_auction_duration: u8, - ) -> Result<()> { - handle_update_spot_auction_duration(ctx, default_spot_auction_duration) - } - pub fn initialize_protocol_if_shares_transfer_config( ctx: Context, ) -> Result<()> { @@ -1781,24 +1315,6 @@ pub mod drift { handle_update_if_rebalance_config(ctx, params) } - pub fn update_feature_bit_flags_mm_oracle( - ctx: Context, - enable: bool, - ) -> Result<()> { - handle_update_feature_bit_flags_mm_oracle(ctx, enable) - } - - pub fn zero_mm_oracle_fields(ctx: Context) -> Result<()> { - handle_zero_mm_oracle_fields(ctx) - } - - pub fn update_feature_bit_flags_median_trigger_price( - ctx: Context, - enable: bool, - ) -> Result<()> { - handle_update_feature_bit_flags_median_trigger_price(ctx, enable) - } - // pub fn update_feature_bit_flags_builder_referral( // ctx: Context, // enable: bool, @@ -1806,11 +1322,13 @@ pub mod drift { // handle_update_feature_bit_flags_builder_referral(ctx, enable) // } - pub fn update_feature_bit_flags_builder_codes( + pub fn update_feature_flags( ctx: Context, - enable: bool, + set_bits: u8, + clear_bits: u8, + require_state_admin: bool, ) -> Result<()> { - handle_update_feature_bit_flags_builder_codes(ctx, enable) + handle_update_feature_flags(ctx, set_bits, clear_bits, require_state_admin) } pub fn initialize_revenue_share<'c: 'info, 'info>( diff --git a/sdk/src/adminClient.ts b/sdk/src/adminClient.ts index b16f672b89..d88d410dec 100644 --- a/sdk/src/adminClient.ts +++ b/sdk/src/adminClient.ts @@ -65,6 +65,192 @@ const OPENBOOK_PROGRAM_ID = new PublicKey( ); export class AdminClient extends DriftClient { + private buildSpotMarketUpdateParams(partial: any): any { + return { + name: null, + status: null, + pausedOperations: null, + ifPausedOperations: null, + ordersEnabled: null, + assetTier: null, + initialAssetWeight: null, + maintenanceAssetWeight: null, + initialLiabilityWeight: null, + maintenanceLiabilityWeight: null, + imfFactor: null, + optimalUtilization: null, + optimalBorrowRate: null, + maxBorrowRate: null, + minBorrowRate: null, + orderStepSize: null, + orderTickSize: null, + minOrderSize: null, + maxTokenDeposits: null, + maxTokenBorrowsFraction: null, + scaleInitialAssetWeightStart: null, + feeAdjustment: null, + revenueSettlePeriod: null, + withdrawGuardThreshold: null, + userIfFactor: null, + totalIfFactor: null, + expiryTs: null, + poolId: null, + liquidatorFee: null, + ifLiquidationFee: null, + ...partial, + }; + } + + private buildPerpMarketUpdateParams(partial: any): any { + return { + name: null, + status: null, + pausedOperations: null, + contractTier: null, + liquidatorFee: null, + ifLiquidationFee: null, + marginRatioInitial: null, + marginRatioMaintenance: null, + unrealizedInitialAssetWeight: null, + unrealizedMaintenanceAssetWeight: null, + highLeverageMarginRatioInitial: null, + highLeverageMarginRatioMaintenance: null, + imfFactor: null, + unrealizedPnlImfFactor: null, + fundingPeriod: null, + unrealizedMaxImbalance: null, + maxRevenueWithdrawPerPeriod: null, + quoteMaxInsurance: null, + baseSpread: null, + maxSpread: null, + orderStepSize: null, + orderTickSize: null, + minOrderSize: null, + maxSlippageRatio: null, + maxFillReserveFraction: null, + maxOpenInterest: null, + feeAdjustment: null, + numberOfUsers: null, + numberOfUsersWithBase: null, + protectedMakerLimitPriceDivisor: null, + protectedMakerDynamicDivisor: null, + fuelBoostTaker: null, + fuelBoostMaker: null, + fuelBoostPosition: null, + takerSpeedBumpOverride: null, + oracleSlotDelayOverride: null, + ammSpreadAdjustment: null, + ammInventorySpreadAdjustment: null, + referencePriceOffset: null, + zeroMmOracleFields: null, + expiryTs: null, + concentrationScale: null, + curveUpdateIntensity: null, + ...partial, + }; + } + + private buildStateUpdateParams(partial: any): any { + return { + lpCooldownTime: null, + initialPctToLiquidate: null, + liquidationDuration: null, + liquidationMarginBufferRatio: null, + settlementDuration: null, + maxNumberOfSubAccounts: null, + maxInitializeUserFee: null, + admin: null, + whitelistMint: null, + discountMint: null, + exchangeStatus: null, + minPerpAuctionDuration: null, + defaultSpotAuctionDuration: null, + ...partial, + }; + } + + public async updateSpotMarketParams( + spotMarketIndex: number, + partialParams: any + ): Promise { + const ix = await this.getUpdateSpotMarketParamsIx( + spotMarketIndex, + partialParams + ); + const tx = await this.buildTransaction(ix); + const { txSig } = await this.sendTransaction(tx, [], this.opts); + return txSig; + } + + public async getUpdateSpotMarketParamsIx( + spotMarketIndex: number, + partialParams: any + ): Promise { + const params = this.buildSpotMarketUpdateParams(partialParams); + return await this.program.instruction.updateSpotMarketParams(params, { + accounts: { + admin: this.isSubscribed + ? this.getStateAccount().admin + : this.wallet.publicKey, + state: await this.getStatePublicKey(), + spotMarket: await getSpotMarketPublicKey( + this.program.programId, + spotMarketIndex + ), + }, + }); + } + + public async updatePerpMarketParams( + perpMarketIndex: number, + partialParams: any + ): Promise { + const ix = await this.getUpdatePerpMarketParamsIx( + perpMarketIndex, + partialParams + ); + const tx = await this.buildTransaction(ix); + const { txSig } = await this.sendTransaction(tx, [], this.opts); + return txSig; + } + + public async getUpdatePerpMarketParamsIx( + perpMarketIndex: number, + partialParams: any + ): Promise { + const params = this.buildPerpMarketUpdateParams(partialParams); + return await this.program.instruction.updatePerpMarketParams(params, { + accounts: { + admin: this.isSubscribed + ? this.getStateAccount().admin + : this.wallet.publicKey, + state: await this.getStatePublicKey(), + perpMarket: await getPerpMarketPublicKey( + this.program.programId, + perpMarketIndex + ), + }, + }); + } + + public async updateStateAll(partialParams: any): Promise { + const ix = await this.getUpdateStateAllIx(partialParams); + const tx = await this.buildTransaction(ix); + const { txSig } = await this.sendTransaction(tx, [], this.opts); + return txSig; + } + + public async getUpdateStateAllIx(partialParams: any): Promise { + const params = this.buildStateUpdateParams(partialParams); + return await this.program.instruction.updateStateAll(params, { + accounts: { + admin: this.isSubscribed + ? this.getStateAccount().admin + : this.wallet.publicKey, + state: await this.getStatePublicKey(), + }, + }); + } public async initialize( usdcMint: PublicKey, _adminControlsPrices: boolean @@ -1214,21 +1400,9 @@ export class AdminClient extends DriftClient { perpMarketIndex: number, curveUpdateIntensity: number ): Promise { - return await this.program.instruction.updatePerpMarketCurveUpdateIntensity( + return await this.getUpdatePerpMarketParamsIx(perpMarketIndex, { curveUpdateIntensity, - { - accounts: { - admin: this.useHotWalletAdmin - ? this.wallet.publicKey - : this.getStateAccount().admin, - state: await this.getStatePublicKey(), - perpMarket: await getPerpMarketPublicKey( - this.program.programId, - perpMarketIndex - ), - }, - } - ); + }); } public async updatePerpMarketTargetBaseAssetAmountPerLp( @@ -1312,21 +1486,7 @@ export class AdminClient extends DriftClient { perpMarketIndex: number, targetBaseAssetAmountPerLP: number ): Promise { - return await this.program.instruction.updatePerpMarketTargetBaseAssetAmountPerLp( - targetBaseAssetAmountPerLP, - { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - perpMarket: await getPerpMarketPublicKey( - this.program.programId, - perpMarketIndex - ), - }, - } - ); + throw new Error('updatePerpMarketTargetBaseAssetAmountPerLp has been removed with no replacement'); } public async updatePerpMarketMarginRatio( @@ -1475,21 +1635,9 @@ export class AdminClient extends DriftClient { perpMarketIndex: number, baseSpread: number ): Promise { - return await this.program.instruction.updatePerpMarketBaseSpread( + return await this.getUpdatePerpMarketParamsIx(perpMarketIndex, { baseSpread, - { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - perpMarket: await getPerpMarketPublicKey( - this.program.programId, - perpMarketIndex - ), - }, - } - ); + }); } public async updateAmmJitIntensity( @@ -1550,17 +1698,8 @@ export class AdminClient extends DriftClient { name: string ): Promise { const nameBuffer = encodeName(name); - return await this.program.instruction.updatePerpMarketName(nameBuffer, { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - perpMarket: await getPerpMarketPublicKey( - this.program.programId, - perpMarketIndex - ), - }, + return await this.getUpdatePerpMarketParamsIx(perpMarketIndex, { + name: nameBuffer, }); } @@ -1585,17 +1724,8 @@ export class AdminClient extends DriftClient { name: string ): Promise { const nameBuffer = encodeName(name); - return await this.program.instruction.updateSpotMarketName(nameBuffer, { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - spotMarket: await getSpotMarketPublicKey( - this.program.programId, - spotMarketIndex - ), - }, + return await this.getUpdateSpotMarketParamsIx(spotMarketIndex, { + name: nameBuffer, }); } @@ -1619,18 +1749,7 @@ export class AdminClient extends DriftClient { spotMarketIndex: number, poolId: number ): Promise { - return await this.program.instruction.updateSpotMarketPoolId(poolId, { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - spotMarket: await getSpotMarketPublicKey( - this.program.programId, - spotMarketIndex - ), - }, - }); + return await this.getUpdateSpotMarketParamsIx(spotMarketIndex, { poolId }); } public async updatePerpMarketPerLpBase( @@ -1651,20 +1770,7 @@ export class AdminClient extends DriftClient { perpMarketIndex: number, perLpBase: number ): Promise { - const perpMarketPublicKey = await getPerpMarketPublicKey( - this.program.programId, - perpMarketIndex - ); - - return await this.program.instruction.updatePerpMarketPerLpBase(perLpBase, { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - perpMarket: perpMarketPublicKey, - }, - }); + throw new Error('updatePerpMarketPerLpBase has been removed with no replacement'); } public async updatePerpMarketMaxSpread( @@ -2465,21 +2571,9 @@ export class AdminClient extends DriftClient { spotMarketIndex: number, orderSize: BN ): Promise { - return await this.program.instruction.updateSpotMarketMinOrderSize( - orderSize, - { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - spotMarket: await getSpotMarketPublicKey( - this.program.programId, - spotMarketIndex - ), - }, - } - ); + return await this.getUpdateSpotMarketParamsIx(spotMarketIndex, { + minOrderSize: orderSize, + }); } public async updatePerpMarketExpiry( @@ -2583,21 +2677,9 @@ export class AdminClient extends DriftClient { spotMarketIndex: number, ordersEnabled: boolean ): Promise { - return await this.program.instruction.updateSpotMarketOrdersEnabled( + return await this.getUpdateSpotMarketParamsIx(spotMarketIndex, { ordersEnabled, - { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - spotMarket: await getSpotMarketPublicKey( - this.program.programId, - spotMarketIndex - ), - }, - } - ); + }); } public async updateSpotMarketIfPausedOperations( @@ -2621,21 +2703,9 @@ export class AdminClient extends DriftClient { spotMarketIndex: number, pausedOperations: number ): Promise { - return await this.program.instruction.updateSpotMarketIfPausedOperations( - pausedOperations, - { - accounts: { - admin: this.isSubscribed - ? this.getStateAccount().admin - : this.wallet.publicKey, - state: await this.getStatePublicKey(), - spotMarket: await getSpotMarketPublicKey( - this.program.programId, - spotMarketIndex - ), - }, - } - ); + return await this.getUpdateSpotMarketParamsIx(spotMarketIndex, { + ifPausedOperations: pausedOperations, + }); } public async updateSerumFulfillmentConfigStatus( diff --git a/sdk/src/idl/drift.json b/sdk/src/idl/drift.json index 76d8b07a00..43f74c4766 100644 --- a/sdk/src/idl/drift.json +++ b/sdk/src/idl/drift.json @@ -3044,7 +3044,7 @@ ] }, { - "name": "updateSpotMarketExpiry", + "name": "updateSpotMarketParams", "accounts": [ { "name": "admin", @@ -3064,8 +3064,10 @@ ], "args": [ { - "name": "expiryTs", - "type": "i64" + "name": "params", + "type": { + "defined": "SpotMarketUpdateParams" + } } ] }, @@ -3141,6 +3143,42 @@ ], "args": [] }, + { + "name": "updateDelegateUserGovTokenInsuranceStake", + "accounts": [ + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": false, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, { "name": "initializeInsuranceFundStake", "accounts": [ @@ -4627,7 +4665,7 @@ ] }, { - "name": "updatePerpMarketExpiry", + "name": "updatePerpMarketParams", "accounts": [ { "name": "admin", @@ -4647,8 +4685,10 @@ ], "args": [ { - "name": "expiryTs", - "type": "i64" + "name": "params", + "type": { + "defined": "PerpMarketUpdateParams" + } } ] }, @@ -4962,7 +5002,7 @@ ] }, { - "name": "updatePerpMarketMarginRatio", + "name": "updateInsuranceFundUnstakingPeriod", "accounts": [ { "name": "admin", @@ -4975,24 +5015,20 @@ "isSigner": false }, { - "name": "perpMarket", + "name": "spotMarket", "isMut": true, "isSigner": false } ], "args": [ { - "name": "marginRatioInitial", - "type": "u32" - }, - { - "name": "marginRatioMaintenance", - "type": "u32" + "name": "insuranceFundUnstakingPeriod", + "type": "i64" } ] }, { - "name": "updatePerpMarketHighLeverageMarginRatio", + "name": "updateSpotMarketOracle", "accounts": [ { "name": "admin", @@ -5005,84 +5041,40 @@ "isSigner": false }, { - "name": "perpMarket", + "name": "spotMarket", "isMut": true, "isSigner": false - } - ], - "args": [ - { - "name": "marginRatioInitial", - "type": "u16" - }, - { - "name": "marginRatioMaintenance", - "type": "u16" - } - ] - }, - { - "name": "updatePerpMarketFundingPeriod", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true }, { - "name": "state", + "name": "oracle", "isMut": false, "isSigner": false }, { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "fundingPeriod", - "type": "i64" - } - ] - }, - { - "name": "updatePerpMarketMaxImbalances", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", + "name": "oldOracle", "isMut": false, "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false } ], "args": [ { - "name": "unrealizedMaxImbalance", - "type": "u64" + "name": "oracle", + "type": "publicKey" }, { - "name": "maxRevenueWithdrawPerPeriod", - "type": "u64" + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } }, { - "name": "quoteMaxInsurance", - "type": "u64" + "name": "skipInvariantCheck", + "type": "bool" } ] }, { - "name": "updatePerpMarketLiquidationFee", + "name": "updatePerpFeeStructure", "accounts": [ { "name": "admin", @@ -5091,28 +5083,21 @@ }, { "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", "isMut": true, "isSigner": false } ], "args": [ { - "name": "liquidatorFee", - "type": "u32" - }, - { - "name": "ifLiquidationFee", - "type": "u32" + "name": "feeStructure", + "type": { + "defined": "FeeStructure" + } } ] }, { - "name": "updateInsuranceFundUnstakingPeriod", + "name": "updateSpotFeeStructure", "accounts": [ { "name": "admin", @@ -5121,24 +5106,21 @@ }, { "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "spotMarket", "isMut": true, "isSigner": false } ], "args": [ { - "name": "insuranceFundUnstakingPeriod", - "type": "i64" + "name": "feeStructure", + "type": { + "defined": "FeeStructure" + } } ] }, { - "name": "updateSpotMarketPoolId", + "name": "updateStateAll", "accounts": [ { "name": "admin", @@ -5147,24 +5129,21 @@ }, { "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "spotMarket", "isMut": true, "isSigner": false } ], "args": [ { - "name": "poolId", - "type": "u8" + "name": "params", + "type": { + "defined": "StateUpdateParams" + } } ] }, { - "name": "updateSpotMarketLiquidationFee", + "name": "updateOracleGuardRails", "accounts": [ { "name": "admin", @@ -5173,28 +5152,21 @@ }, { "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "spotMarket", "isMut": true, "isSigner": false } ], "args": [ { - "name": "liquidatorFee", - "type": "u32" - }, - { - "name": "ifLiquidationFee", - "type": "u32" + "name": "oracleGuardRails", + "type": { + "defined": "OracleGuardRails" + } } ] }, { - "name": "updateWithdrawGuardThreshold", + "name": "updatePerpMarketOracle", "accounts": [ { "name": "admin", @@ -5207,54 +5179,40 @@ "isSigner": false }, { - "name": "spotMarket", + "name": "perpMarket", "isMut": true, "isSigner": false - } - ], - "args": [ - { - "name": "withdrawGuardThreshold", - "type": "u64" - } - ] - }, - { - "name": "updateSpotMarketIfFactor", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true }, { - "name": "state", + "name": "oracle", "isMut": false, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "oldOracle", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "spotMarketIndex", - "type": "u16" + "name": "oracle", + "type": "publicKey" }, { - "name": "userIfFactor", - "type": "u32" + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } }, { - "name": "totalIfFactor", - "type": "u32" + "name": "skipInvariantCheck", + "type": "bool" } ] }, { - "name": "updateSpotMarketRevenueSettlePeriod", + "name": "updateAmmJitIntensity", "accounts": [ { "name": "admin", @@ -5267,20 +5225,20 @@ "isSigner": false }, { - "name": "spotMarket", + "name": "perpMarket", "isMut": true, "isSigner": false } ], "args": [ { - "name": "revenueSettlePeriod", - "type": "i64" + "name": "ammJitIntensity", + "type": "u8" } ] }, { - "name": "updateSpotMarketStatus", + "name": "updateSpotMarketFuel", "accounts": [ { "name": "admin", @@ -5300,15 +5258,39 @@ ], "args": [ { - "name": "status", + "name": "fuelBoostDeposits", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostBorrows", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostTaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostMaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostInsurance", "type": { - "defined": "MarketStatus" + "option": "u8" } } ] }, { - "name": "updateSpotMarketPausedOperations", + "name": "initUserFuel", "accounts": [ { "name": "admin", @@ -5321,505 +5303,581 @@ "isSigner": false }, { - "name": "spotMarket", + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", "isMut": true, "isSigner": false } ], "args": [ { - "name": "pausedOperations", - "type": "u8" - } - ] - }, - { - "name": "updateSpotMarketAssetTier", - "accounts": [ + "name": "fuelBoostDeposits", + "type": { + "option": "i32" + } + }, { - "name": "admin", - "isMut": false, - "isSigner": true + "name": "fuelBoostBorrows", + "type": { + "option": "u32" + } }, { - "name": "state", - "isMut": false, - "isSigner": false + "name": "fuelBoostTaker", + "type": { + "option": "u32" + } }, { - "name": "spotMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ + "name": "fuelBoostMaker", + "type": { + "option": "u32" + } + }, { - "name": "assetTier", + "name": "fuelBoostInsurance", "type": { - "defined": "AssetTier" + "option": "u32" } } ] }, { - "name": "updateSpotMarketMarginWeights", + "name": "initializeProtocolIfSharesTransferConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "spotMarket", + "name": "protocolIfSharesTransferConfig", "isMut": true, "isSigner": false - } - ], - "args": [ - { - "name": "initialAssetWeight", - "type": "u32" - }, - { - "name": "maintenanceAssetWeight", - "type": "u32" }, { - "name": "initialLiabilityWeight", - "type": "u32" + "name": "state", + "isMut": false, + "isSigner": false }, { - "name": "maintenanceLiabilityWeight", - "type": "u32" + "name": "rent", + "isMut": false, + "isSigner": false }, { - "name": "imfFactor", - "type": "u32" + "name": "systemProgram", + "isMut": false, + "isSigner": false } - ] + ], + "args": [] }, { - "name": "updateSpotMarketBorrowRate", + "name": "updateProtocolIfSharesTransferConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", - "isMut": false, + "name": "protocolIfSharesTransferConfig", + "isMut": true, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "state", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "optimalUtilization", - "type": "u32" - }, - { - "name": "optimalBorrowRate", - "type": "u32" - }, - { - "name": "maxBorrowRate", - "type": "u32" + "name": "whitelistedSigners", + "type": { + "option": { + "array": [ + "publicKey", + 4 + ] + } + } }, { - "name": "minBorrowRate", + "name": "maxTransferPerEpoch", "type": { - "option": "u8" + "option": "u128" } } ] }, { - "name": "updateSpotMarketMaxTokenDeposits", + "name": "initializePrelaunchOracle", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, + { + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, { "name": "state", "isMut": false, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "maxTokenDeposits", - "type": "u64" + "name": "params", + "type": { + "defined": "PrelaunchOracleParams" + } } ] }, { - "name": "updateSpotMarketMaxTokenBorrows", + "name": "updatePrelaunchOracleParams", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", - "isMut": false, + "name": "prelaunchOracle", + "isMut": true, "isSigner": false }, { - "name": "spotMarket", + "name": "perpMarket", "isMut": true, "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false } ], "args": [ { - "name": "maxTokenBorrowsFraction", - "type": "u16" + "name": "params", + "type": { + "defined": "PrelaunchOracleParams" + } } ] }, { - "name": "updateSpotMarketScaleInitialAssetWeightStart", + "name": "deletePrelaunchOracle", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", "isMut": false, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "state", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "scaleInitialAssetWeightStart", - "type": "u64" + "name": "perpMarketIndex", + "type": "u16" } ] }, { - "name": "updateSpotMarketOracle", + "name": "initializePythPullOracle", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", + "name": "pythSolanaReceiver", "isMut": false, "isSigner": false }, { - "name": "spotMarket", + "name": "priceFeed", "isMut": true, "isSigner": false }, { - "name": "oracle", + "name": "systemProgram", "isMut": false, "isSigner": false }, { - "name": "oldOracle", + "name": "state", "isMut": false, "isSigner": false } ], "args": [ { - "name": "oracle", - "type": "publicKey" - }, - { - "name": "oracleSource", + "name": "feedId", "type": { - "defined": "OracleSource" + "array": [ + "u8", + 32 + ] } - }, - { - "name": "skipInvariantCheck", - "type": "bool" } ] }, { - "name": "updateSpotMarketStepSizeAndTickSize", + "name": "initializePythLazerOracle", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, + { + "name": "lazerOracle", + "isMut": true, + "isSigner": false + }, { "name": "state", "isMut": false, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "stepSize", - "type": "u64" - }, - { - "name": "tickSize", - "type": "u64" + "name": "feedId", + "type": "u32" } ] }, { - "name": "updateSpotMarketMinOrderSize", + "name": "postPythLazerOracleUpdate", "accounts": [ { - "name": "admin", - "isMut": false, + "name": "keeper", + "isMut": true, "isSigner": true }, { - "name": "state", + "name": "pythLazerStorage", "isMut": false, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "ixSysvar", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "orderSize", - "type": "u64" + "name": "pythMessage", + "type": "bytes" } ] }, { - "name": "updateSpotMarketOrdersEnabled", + "name": "initializeHighLeverageModeConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, + { + "name": "highLeverageModeConfig", + "isMut": true, + "isSigner": false + }, { "name": "state", "isMut": false, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "ordersEnabled", - "type": "bool" + "name": "maxUsers", + "type": "u32" } ] }, { - "name": "updateSpotMarketIfPausedOperations", + "name": "updateHighLeverageModeConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", - "isMut": false, - "isSigner": false + "name": "highLeverageModeConfig", + "isMut": true, + "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "state", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "pausedOperations", - "type": "u8" + "name": "maxUsers", + "type": "u32" + }, + { + "name": "reduceOnly", + "type": "bool" + }, + { + "name": "currentUsers", + "type": { + "option": "u32" + } } ] }, { - "name": "updateSpotMarketName", + "name": "initializeProtectedMakerModeConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, + { + "name": "protectedMakerModeConfig", + "isMut": true, + "isSigner": false + }, { "name": "state", "isMut": false, "isSigner": false }, { - "name": "spotMarket", - "isMut": true, + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "name", - "type": { - "array": [ - "u8", - 32 - ] - } + "name": "maxUsers", + "type": "u32" } ] }, { - "name": "updatePerpMarketStatus", + "name": "updateProtectedMakerModeConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", - "isMut": false, + "name": "protectedMakerModeConfig", + "isMut": true, "isSigner": false }, { - "name": "perpMarket", - "isMut": true, + "name": "state", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "status", + "name": "maxUsers", + "type": "u32" + }, + { + "name": "reduceOnly", + "type": "bool" + }, + { + "name": "currentUsers", "type": { - "defined": "MarketStatus" + "option": "u32" } } ] }, { - "name": "updatePerpMarketPausedOperations", + "name": "adminDeposit", "accounts": [ { - "name": "admin", + "name": "state", "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, "isSigner": true }, { - "name": "state", - "isMut": false, + "name": "spotMarketVault", + "isMut": true, "isSigner": false }, { - "name": "perpMarket", + "name": "adminTokenAccount", "isMut": true, "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false } ], "args": [ { - "name": "pausedOperations", - "type": "u8" + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" } ] }, { - "name": "updatePerpMarketContractTier", + "name": "initializeIfRebalanceConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, + { + "name": "ifRebalanceConfig", + "isMut": true, + "isSigner": false + }, { "name": "state", "isMut": false, "isSigner": false }, { - "name": "perpMarket", - "isMut": true, + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "contractTier", + "name": "params", "type": { - "defined": "ContractTier" + "defined": "IfRebalanceConfigParams" } } ] }, { - "name": "updatePerpMarketImfFactor", + "name": "updateIfRebalanceConfig", "accounts": [ { "name": "admin", - "isMut": false, + "isMut": true, "isSigner": true }, { - "name": "state", - "isMut": false, + "name": "ifRebalanceConfig", + "isMut": true, "isSigner": false }, { - "name": "perpMarket", - "isMut": true, + "name": "state", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "imfFactor", - "type": "u32" - }, - { - "name": "unrealizedPnlImfFactor", - "type": "u32" + "name": "params", + "type": { + "defined": "IfRebalanceConfigParams" + } } ] }, { - "name": "updatePerpMarketUnrealizedAssetWeight", + "name": "updateFeatureFlags", "accounts": [ { "name": "admin", @@ -5828,59 +5886,73 @@ }, { "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", "isMut": true, "isSigner": false } ], "args": [ { - "name": "unrealizedInitialAssetWeight", - "type": "u32" + "name": "setBits", + "type": "u8" }, { - "name": "unrealizedMaintenanceAssetWeight", - "type": "u32" + "name": "clearBits", + "type": "u8" + }, + { + "name": "requireStateAdmin", + "type": "bool" } ] }, { - "name": "updatePerpMarketConcentrationCoef", + "name": "initializeRevenueShare", "accounts": [ { - "name": "admin", + "name": "revenueShare", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, "isSigner": true }, { - "name": "state", + "name": "rent", "isMut": false, "isSigner": false }, { - "name": "perpMarket", - "isMut": true, + "name": "systemProgram", + "isMut": false, "isSigner": false } ], - "args": [ - { - "name": "concentrationScale", - "type": "u128" - } - ] + "args": [] }, { - "name": "updatePerpMarketCurveUpdateIntensity", + "name": "initializeRevenueShareEscrow", "accounts": [ { - "name": "admin", + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", "isMut": false, - "isSigner": true + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false }, { "name": "state", @@ -5888,1964 +5960,877 @@ "isSigner": false }, { - "name": "perpMarket", + "name": "payer", "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "curveUpdateIntensity", - "type": "u8" + "name": "numOrders", + "type": "u16" } ] }, { - "name": "updateLpCooldownTime", + "name": "resizeRevenueShareEscrowOrders", "accounts": [ { - "name": "admin", + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", "isMut": false, - "isSigner": true + "isSigner": false }, { - "name": "state", + "name": "payer", "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "lpCooldownTime", - "type": "u64" + "name": "numOrders", + "type": "u16" } ] }, { - "name": "updatePerpFeeStructure", + "name": "changeApprovedBuilder", "accounts": [ { - "name": "admin", + "name": "escrow", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", "isMut": false, "isSigner": true }, { - "name": "state", + "name": "payer", "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, "isSigner": false } ], "args": [ { - "name": "feeStructure", - "type": { - "defined": "FeeStructure" - } - } - ] - }, - { - "name": "updateSpotFeeStructure", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "feeStructure", - "type": { - "defined": "FeeStructure" - } - } - ] - }, - { - "name": "updateInitialPctToLiquidate", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true + "name": "builder", + "type": "publicKey" }, { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "initialPctToLiquidate", + "name": "maxFeeBps", "type": "u16" - } - ] - }, - { - "name": "updateLiquidationDuration", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "liquidationDuration", - "type": "u8" - } - ] - }, - { - "name": "updateLiquidationMarginBufferRatio", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true }, { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "liquidationMarginBufferRatio", - "type": "u32" + "name": "add", + "type": "bool" } ] - }, + } + ], + "accounts": [ { - "name": "updateOracleGuardRails", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "oracleGuardRails", - "type": { - "defined": "OracleGuardRails" + "name": "OpenbookV2FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "openbookV2ProgramId", + "type": "publicKey" + }, + { + "name": "openbookV2Market", + "type": "publicKey" + }, + { + "name": "openbookV2MarketAuthority", + "type": "publicKey" + }, + { + "name": "openbookV2EventHeap", + "type": "publicKey" + }, + { + "name": "openbookV2Bids", + "type": "publicKey" + }, + { + "name": "openbookV2Asks", + "type": "publicKey" + }, + { + "name": "openbookV2BaseVault", + "type": "publicKey" + }, + { + "name": "openbookV2QuoteVault", + "type": "publicKey" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } } - } - ] - }, - { - "name": "updateStateSettlementDuration", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "settlementDuration", - "type": "u16" - } - ] + ] + } }, { - "name": "updateStateMaxNumberOfSubAccounts", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "maxNumberOfSubAccounts", - "type": "u16" - } - ] + "name": "PhoenixV1FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "phoenixProgramId", + "type": "publicKey" + }, + { + "name": "phoenixLogAuthority", + "type": "publicKey" + }, + { + "name": "phoenixMarket", + "type": "publicKey" + }, + { + "name": "phoenixBaseVault", + "type": "publicKey" + }, + { + "name": "phoenixQuoteVault", + "type": "publicKey" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } }, { - "name": "updateStateMaxInitializeUserFee", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "maxInitializeUserFee", - "type": "u16" - } - ] - }, - { - "name": "updatePerpMarketOracle", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - }, - { - "name": "oracle", - "isMut": false, - "isSigner": false - }, - { - "name": "oldOracle", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "oracle", - "type": "publicKey" - }, - { - "name": "oracleSource", - "type": { - "defined": "OracleSource" - } - }, - { - "name": "skipInvariantCheck", - "type": "bool" - } - ] - }, - { - "name": "updatePerpMarketBaseSpread", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "baseSpread", - "type": "u32" - } - ] - }, - { - "name": "updateAmmJitIntensity", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "ammJitIntensity", - "type": "u8" - } - ] - }, - { - "name": "updatePerpMarketMaxSpread", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "maxSpread", - "type": "u32" - } - ] - }, - { - "name": "updatePerpMarketStepSizeAndTickSize", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "stepSize", - "type": "u64" - }, - { - "name": "tickSize", - "type": "u64" - } - ] - }, - { - "name": "updatePerpMarketName", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "name", - "type": { - "array": [ - "u8", - 32 - ] - } - } - ] - }, - { - "name": "updatePerpMarketMinOrderSize", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "orderSize", - "type": "u64" - } - ] - }, - { - "name": "updatePerpMarketMaxSlippageRatio", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "maxSlippageRatio", - "type": "u16" - } - ] - }, - { - "name": "updatePerpMarketMaxFillReserveFraction", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "maxFillReserveFraction", - "type": "u16" - } - ] - }, - { - "name": "updatePerpMarketMaxOpenInterest", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "maxOpenInterest", - "type": "u128" - } - ] - }, - { - "name": "updatePerpMarketNumberOfUsers", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "numberOfUsers", - "type": { - "option": "u32" - } - }, - { - "name": "numberOfUsersWithBase", - "type": { - "option": "u32" - } - } - ] - }, - { - "name": "updatePerpMarketFeeAdjustment", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "feeAdjustment", - "type": "i16" - } - ] - }, - { - "name": "updateSpotMarketFeeAdjustment", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "spotMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "feeAdjustment", - "type": "i16" - } - ] - }, - { - "name": "updatePerpMarketFuel", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "fuelBoostTaker", - "type": { - "option": "u8" - } - }, - { - "name": "fuelBoostMaker", - "type": { - "option": "u8" - } - }, - { - "name": "fuelBoostPosition", - "type": { - "option": "u8" - } - } - ] - }, - { - "name": "updatePerpMarketProtectedMakerParams", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "protectedMakerLimitPriceDivisor", - "type": { - "option": "u8" - } - }, - { - "name": "protectedMakerDynamicDivisor", - "type": { - "option": "u8" - } - } - ] - }, - { - "name": "updatePerpMarketTakerSpeedBumpOverride", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "takerSpeedBumpOverride", - "type": "i8" - } - ] - }, - { - "name": "updatePerpMarketAmmSpreadAdjustment", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "ammSpreadAdjustment", - "type": "i8" - }, - { - "name": "ammInventorySpreadAdjustment", - "type": "i8" - }, - { - "name": "referencePriceOffset", - "type": "i32" - } - ] - }, - { - "name": "updatePerpMarketOracleSlotDelayOverride", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "oracleSlotDelayOverride", - "type": "i8" - } - ] - }, - { - "name": "updateSpotMarketFuel", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "spotMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "fuelBoostDeposits", - "type": { - "option": "u8" - } - }, - { - "name": "fuelBoostBorrows", - "type": { - "option": "u8" - } - }, - { - "name": "fuelBoostTaker", - "type": { - "option": "u8" - } - }, - { - "name": "fuelBoostMaker", - "type": { - "option": "u8" - } - }, - { - "name": "fuelBoostInsurance", - "type": { - "option": "u8" - } - } - ] - }, - { - "name": "initUserFuel", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "user", - "isMut": true, - "isSigner": false - }, - { - "name": "userStats", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "fuelBoostDeposits", - "type": { - "option": "i32" - } - }, - { - "name": "fuelBoostBorrows", - "type": { - "option": "u32" - } - }, - { - "name": "fuelBoostTaker", - "type": { - "option": "u32" - } - }, - { - "name": "fuelBoostMaker", - "type": { - "option": "u32" - } - }, - { - "name": "fuelBoostInsurance", - "type": { - "option": "u32" - } - } - ] - }, - { - "name": "updateAdmin", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "admin", - "type": "publicKey" - } - ] - }, - { - "name": "updateWhitelistMint", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "whitelistMint", - "type": "publicKey" - } - ] - }, - { - "name": "updateDiscountMint", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "discountMint", - "type": "publicKey" - } - ] - }, - { - "name": "updateExchangeStatus", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "exchangeStatus", - "type": "u8" - } - ] - }, - { - "name": "updatePerpAuctionDuration", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "minPerpAuctionDuration", - "type": "u8" - } - ] - }, - { - "name": "updateSpotAuctionDuration", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "defaultSpotAuctionDuration", - "type": "u8" - } - ] - }, - { - "name": "initializeProtocolIfSharesTransferConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "protocolIfSharesTransferConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [] - }, - { - "name": "updateProtocolIfSharesTransferConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "protocolIfSharesTransferConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "whitelistedSigners", - "type": { - "option": { - "array": [ - "publicKey", - 4 - ] - } - } - }, - { - "name": "maxTransferPerEpoch", - "type": { - "option": "u128" - } - } - ] - }, - { - "name": "initializePrelaunchOracle", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "prelaunchOracle", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "params", - "type": { - "defined": "PrelaunchOracleParams" - } - } - ] - }, - { - "name": "updatePrelaunchOracleParams", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "prelaunchOracle", - "isMut": true, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "params", - "type": { - "defined": "PrelaunchOracleParams" - } - } - ] - }, - { - "name": "deletePrelaunchOracle", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "prelaunchOracle", - "isMut": true, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": false, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "perpMarketIndex", - "type": "u16" - } - ] - }, - { - "name": "initializePythPullOracle", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "pythSolanaReceiver", - "isMut": false, - "isSigner": false - }, - { - "name": "priceFeed", - "isMut": true, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "feedId", - "type": { - "array": [ - "u8", - 32 - ] - } - } - ] - }, - { - "name": "initializePythLazerOracle", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "lazerOracle", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "feedId", - "type": "u32" - } - ] - }, - { - "name": "postPythLazerOracleUpdate", - "accounts": [ - { - "name": "keeper", - "isMut": true, - "isSigner": true - }, - { - "name": "pythLazerStorage", - "isMut": false, - "isSigner": false - }, - { - "name": "ixSysvar", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "pythMessage", - "type": "bytes" - } - ] - }, - { - "name": "initializeHighLeverageModeConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "highLeverageModeConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "maxUsers", - "type": "u32" - } - ] - }, - { - "name": "updateHighLeverageModeConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "highLeverageModeConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "maxUsers", - "type": "u32" - }, - { - "name": "reduceOnly", - "type": "bool" - }, - { - "name": "currentUsers", - "type": { - "option": "u32" - } - } - ] - }, - { - "name": "initializeProtectedMakerModeConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "protectedMakerModeConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "maxUsers", - "type": "u32" - } - ] - }, - { - "name": "updateProtectedMakerModeConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "protectedMakerModeConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "maxUsers", - "type": "u32" - }, - { - "name": "reduceOnly", - "type": "bool" - }, - { - "name": "currentUsers", - "type": { - "option": "u32" - } - } - ] - }, - { - "name": "adminDeposit", - "accounts": [ - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "user", - "isMut": true, - "isSigner": false - }, - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "spotMarketVault", - "isMut": true, - "isSigner": false - }, - { - "name": "adminTokenAccount", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "marketIndex", - "type": "u16" - }, - { - "name": "amount", - "type": "u64" - } - ] - }, - { - "name": "initializeIfRebalanceConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "ifRebalanceConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "params", - "type": { - "defined": "IfRebalanceConfigParams" - } - } - ] - }, - { - "name": "updateIfRebalanceConfig", - "accounts": [ - { - "name": "admin", - "isMut": true, - "isSigner": true - }, - { - "name": "ifRebalanceConfig", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "params", - "type": { - "defined": "IfRebalanceConfigParams" - } - } - ] - }, - { - "name": "updateFeatureBitFlagsMmOracle", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "enable", - "type": "bool" - } - ] - }, - { - "name": "zeroMmOracleFields", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "perpMarket", - "isMut": true, - "isSigner": false - } - ], - "args": [] + "name": "SerumV3FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "serumProgramId", + "type": "publicKey" + }, + { + "name": "serumMarket", + "type": "publicKey" + }, + { + "name": "serumRequestQueue", + "type": "publicKey" + }, + { + "name": "serumEventQueue", + "type": "publicKey" + }, + { + "name": "serumBids", + "type": "publicKey" + }, + { + "name": "serumAsks", + "type": "publicKey" + }, + { + "name": "serumBaseVault", + "type": "publicKey" + }, + { + "name": "serumQuoteVault", + "type": "publicKey" + }, + { + "name": "serumOpenOrders", + "type": "publicKey" + }, + { + "name": "serumSignerNonce", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } }, { - "name": "updateFeatureBitFlagsMedianTriggerPrice", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "enable", - "type": "bool" - } - ] + "name": "HighLeverageModeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxUsers", + "type": "u32" + }, + { + "name": "currentUsers", + "type": "u32" + }, + { + "name": "reduceOnly", + "type": "u8" + }, + { + "name": "padding1", + "type": { + "array": [ + "u8", + 3 + ] + } + }, + { + "name": "currentMaintenanceUsers", + "type": "u32" + }, + { + "name": "padding2", + "type": { + "array": [ + "u8", + 24 + ] + } + } + ] + } }, { - "name": "updateFeatureBitFlagsBuilderCodes", - "accounts": [ - { - "name": "admin", - "isMut": false, - "isSigner": true - }, - { - "name": "state", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "enable", - "type": "bool" - } - ] + "name": "IfRebalanceConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "totalInAmount", + "docs": [ + "total amount to be sold" + ], + "type": "u64" + }, + { + "name": "currentInAmount", + "docs": [ + "amount already sold" + ], + "type": "u64" + }, + { + "name": "currentOutAmount", + "docs": [ + "amount already bought" + ], + "type": "u64" + }, + { + "name": "currentOutAmountTransferred", + "docs": [ + "amount already transferred to revenue pool" + ], + "type": "u64" + }, + { + "name": "currentInAmountSinceLastTransfer", + "docs": [ + "amount already bought in epoch" + ], + "type": "u64" + }, + { + "name": "epochStartTs", + "docs": [ + "start time of epoch" + ], + "type": "i64" + }, + { + "name": "epochInAmount", + "docs": [ + "amount already bought in epoch" + ], + "type": "u64" + }, + { + "name": "epochMaxInAmount", + "docs": [ + "max amount to swap in epoch" + ], + "type": "u64" + }, + { + "name": "epochDuration", + "docs": [ + "duration of epoch" + ], + "type": "i64" + }, + { + "name": "outMarketIndex", + "docs": [ + "market index to sell" + ], + "type": "u16" + }, + { + "name": "inMarketIndex", + "docs": [ + "market index to buy" + ], + "type": "u16" + }, + { + "name": "maxSlippageBps", + "type": "u16" + }, + { + "name": "swapMode", + "type": "u8" + }, + { + "name": "status", + "type": "u8" + }, + { + "name": "padding2", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } }, { - "name": "initializeRevenueShare", - "accounts": [ - { - "name": "revenueShare", - "isMut": true, - "isSigner": false - }, - { - "name": "authority", - "isMut": false, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [] + "name": "InsuranceFundStake", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "ifShares", + "type": "u128" + }, + { + "name": "lastWithdrawRequestShares", + "type": "u128" + }, + { + "name": "ifBase", + "type": "u128" + }, + { + "name": "lastValidTs", + "type": "i64" + }, + { + "name": "lastWithdrawRequestValue", + "type": "u64" + }, + { + "name": "lastWithdrawRequestTs", + "type": "i64" + }, + { + "name": "costBasis", + "type": "i64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 14 + ] + } + } + ] + } }, { - "name": "initializeRevenueShareEscrow", - "accounts": [ - { - "name": "escrow", - "isMut": true, - "isSigner": false - }, - { - "name": "authority", - "isMut": false, - "isSigner": false - }, - { - "name": "userStats", - "isMut": true, - "isSigner": false - }, - { - "name": "state", - "isMut": false, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "numOrders", - "type": "u16" - } - ] + "name": "ProtocolIfSharesTransferConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "whitelistedSigners", + "type": { + "array": [ + "publicKey", + 4 + ] + } + }, + { + "name": "maxTransferPerEpoch", + "type": "u128" + }, + { + "name": "currentEpochTransfer", + "type": "u128" + }, + { + "name": "nextEpochTs", + "type": "i64" + }, + { + "name": "padding", + "type": { + "array": [ + "u128", + 8 + ] + } + } + ] + } }, { - "name": "resizeRevenueShareEscrowOrders", - "accounts": [ - { - "name": "escrow", - "isMut": true, - "isSigner": false - }, - { - "name": "authority", - "isMut": false, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "numOrders", - "type": "u16" - } - ] + "name": "PrelaunchOracle", + "type": { + "kind": "struct", + "fields": [ + { + "name": "price", + "type": "i64" + }, + { + "name": "maxPrice", + "type": "i64" + }, + { + "name": "confidence", + "type": "u64" + }, + { + "name": "lastUpdateSlot", + "type": "u64" + }, + { + "name": "ammLastUpdateSlot", + "type": "u64" + }, + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 70 + ] + } + } + ] + } }, { - "name": "changeApprovedBuilder", - "accounts": [ - { - "name": "escrow", - "isMut": true, - "isSigner": false - }, - { - "name": "authority", - "isMut": false, - "isSigner": true - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "builder", - "type": "publicKey" - }, - { - "name": "maxFeeBps", - "type": "u16" - }, - { - "name": "add", - "type": "bool" - } - ] - } - ], - "accounts": [ - { - "name": "OpenbookV2FulfillmentConfig", + "name": "PerpMarket", "type": { "kind": "struct", "fields": [ { "name": "pubkey", + "docs": [ + "The perp market's address. It is a pda of the market index" + ], "type": "publicKey" }, { - "name": "openbookV2ProgramId", - "type": "publicKey" + "name": "amm", + "docs": [ + "The automated market maker" + ], + "type": { + "defined": "AMM" + } }, { - "name": "openbookV2Market", - "type": "publicKey" + "name": "pnlPool", + "docs": [ + "The market's pnl pool. When users settle negative pnl, the balance increases.", + "When users settle positive pnl, the balance decreases. Can not go negative." + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "name", + "docs": [ + "Encoded display name for the perp market e.g. SOL-PERP" + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "insuranceClaim", + "docs": [ + "The perp market's claim on the insurance fund" + ], + "type": { + "defined": "InsuranceClaim" + } + }, + { + "name": "unrealizedPnlMaxImbalance", + "docs": [ + "The max pnl imbalance before positive pnl asset weight is discounted", + "pnl imbalance is the difference between long and short pnl. When it's greater than 0,", + "the amm has negative pnl and the initial asset weight for positive pnl is discounted", + "precision = QUOTE_PRECISION" + ], + "type": "u64" }, { - "name": "openbookV2MarketAuthority", - "type": "publicKey" + "name": "expiryTs", + "docs": [ + "The ts when the market will be expired. Only set if market is in reduce only mode" + ], + "type": "i64" }, { - "name": "openbookV2EventHeap", - "type": "publicKey" + "name": "expiryPrice", + "docs": [ + "The price at which positions will be settled. Only set if market is expired", + "precision = PRICE_PRECISION" + ], + "type": "i64" }, { - "name": "openbookV2Bids", - "type": "publicKey" + "name": "nextFillRecordId", + "docs": [ + "Every trade has a fill record id. This is the next id to be used" + ], + "type": "u64" }, { - "name": "openbookV2Asks", - "type": "publicKey" + "name": "nextFundingRateRecordId", + "docs": [ + "Every funding rate update has a record id. This is the next id to be used" + ], + "type": "u64" }, { - "name": "openbookV2BaseVault", - "type": "publicKey" + "name": "nextCurveRecordId", + "docs": [ + "Every amm k updated has a record id. This is the next id to be used" + ], + "type": "u64" }, { - "name": "openbookV2QuoteVault", - "type": "publicKey" + "name": "imfFactor", + "docs": [ + "The initial margin fraction factor. Used to increase margin ratio for large positions", + "precision: MARGIN_PRECISION" + ], + "type": "u32" }, { - "name": "marketIndex", - "type": "u16" + "name": "unrealizedPnlImfFactor", + "docs": [ + "The imf factor for unrealized pnl. Used to discount asset weight for large positive pnl", + "precision: MARGIN_PRECISION" + ], + "type": "u32" }, { - "name": "fulfillmentType", - "type": { - "defined": "SpotFulfillmentType" - } + "name": "liquidatorFee", + "docs": [ + "The fee the liquidator is paid for taking over perp position", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" }, { - "name": "status", - "type": { - "defined": "SpotFulfillmentConfigStatus" - } + "name": "ifLiquidationFee", + "docs": [ + "The fee the insurance fund receives from liquidation", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" }, { - "name": "padding", - "type": { - "array": [ - "u8", - 4 - ] - } - } - ] - } - }, - { - "name": "PhoenixV1FulfillmentConfig", - "type": { - "kind": "struct", - "fields": [ - { - "name": "pubkey", - "type": "publicKey" + "name": "marginRatioInitial", + "docs": [ + "The margin ratio which determines how much collateral is required to open a position", + "e.g. margin ratio of .1 means a user must have $100 of total collateral to open a $1000 position", + "precision: MARGIN_PRECISION" + ], + "type": "u32" }, { - "name": "phoenixProgramId", - "type": "publicKey" + "name": "marginRatioMaintenance", + "docs": [ + "The margin ratio which determines when a user will be liquidated", + "e.g. margin ratio of .05 means a user must have $50 of total collateral to maintain a $1000 position", + "else they will be liquidated", + "precision: MARGIN_PRECISION" + ], + "type": "u32" }, { - "name": "phoenixLogAuthority", - "type": "publicKey" + "name": "unrealizedPnlInitialAssetWeight", + "docs": [ + "The initial asset weight for positive pnl. Negative pnl always has an asset weight of 1", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" }, { - "name": "phoenixMarket", - "type": "publicKey" + "name": "unrealizedPnlMaintenanceAssetWeight", + "docs": [ + "The maintenance asset weight for positive pnl. Negative pnl always has an asset weight of 1", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" }, { - "name": "phoenixBaseVault", - "type": "publicKey" + "name": "numberOfUsersWithBase", + "docs": [ + "number of users in a position (base)" + ], + "type": "u32" }, { - "name": "phoenixQuoteVault", - "type": "publicKey" + "name": "numberOfUsers", + "docs": [ + "number of users in a position (pnl) or pnl (quote)" + ], + "type": "u32" }, { "name": "marketIndex", "type": "u16" }, { - "name": "fulfillmentType", + "name": "status", + "docs": [ + "Whether a market is active, reduce only, expired, etc", + "Affects whether users can open/close positions" + ], "type": { - "defined": "SpotFulfillmentType" + "defined": "MarketStatus" } }, { - "name": "status", + "name": "contractType", + "docs": [ + "Currently only Perpetual markets are supported" + ], "type": { - "defined": "SpotFulfillmentConfigStatus" + "defined": "ContractType" } }, { - "name": "padding", + "name": "contractTier", + "docs": [ + "The contract tier determines how much insurance a market can receive, with more speculative markets receiving less insurance", + "It also influences the order perp markets can be liquidated, with less speculative markets being liquidated first" + ], "type": { - "array": [ - "u8", - 4 - ] + "defined": "ContractTier" } - } - ] - } - }, - { - "name": "SerumV3FulfillmentConfig", - "type": { - "kind": "struct", - "fields": [ - { - "name": "pubkey", - "type": "publicKey" }, { - "name": "serumProgramId", - "type": "publicKey" + "name": "pausedOperations", + "type": "u8" }, { - "name": "serumMarket", - "type": "publicKey" + "name": "quoteSpotMarketIndex", + "docs": [ + "The spot market that pnl is settled in" + ], + "type": "u16" }, { - "name": "serumRequestQueue", - "type": "publicKey" + "name": "feeAdjustment", + "docs": [ + "Between -100 and 100, represents what % to increase/decrease the fee by", + "E.g. if this is -50 and the fee is 5bps, the new fee will be 2.5bps", + "if this is 50 and the fee is 5bps, the new fee will be 7.5bps" + ], + "type": "i16" }, { - "name": "serumEventQueue", - "type": "publicKey" + "name": "fuelBoostPosition", + "docs": [ + "fuel multiplier for perp funding", + "precision: 10" + ], + "type": "u8" }, { - "name": "serumBids", - "type": "publicKey" + "name": "fuelBoostTaker", + "docs": [ + "fuel multiplier for perp taker", + "precision: 10" + ], + "type": "u8" }, { - "name": "serumAsks", - "type": "publicKey" + "name": "fuelBoostMaker", + "docs": [ + "fuel multiplier for perp maker", + "precision: 10" + ], + "type": "u8" }, { - "name": "serumBaseVault", - "type": "publicKey" + "name": "poolId", + "type": "u8" }, { - "name": "serumQuoteVault", - "type": "publicKey" + "name": "highLeverageMarginRatioInitial", + "type": "u16" }, { - "name": "serumOpenOrders", - "type": "publicKey" + "name": "highLeverageMarginRatioMaintenance", + "type": "u16" }, { - "name": "serumSignerNonce", - "type": "u64" + "name": "protectedMakerLimitPriceDivisor", + "type": "u8" }, { - "name": "marketIndex", - "type": "u16" + "name": "protectedMakerDynamicDivisor", + "type": "u8" }, { - "name": "fulfillmentType", - "type": { - "defined": "SpotFulfillmentType" - } + "name": "padding1", + "type": "u32" }, { - "name": "status", - "type": { - "defined": "SpotFulfillmentConfigStatus" - } + "name": "lastFillPrice", + "type": "u64" }, { "name": "padding", "type": { "array": [ "u8", - 4 + 24 ] } } @@ -7853,7 +6838,7 @@ } }, { - "name": "HighLeverageModeConfig", + "name": "ProtectedMakerModeConfig", "type": { "kind": "struct", "fields": [ @@ -7870,382 +6855,496 @@ "type": "u8" }, { - "name": "padding1", + "name": "padding", "type": { "array": [ "u8", - 3 + 31 ] } + } + ] + } + }, + { + "name": "PythLazerOracle", + "type": { + "kind": "struct", + "fields": [ + { + "name": "price", + "type": "i64" }, { - "name": "currentMaintenanceUsers", - "type": "u32" + "name": "publishTime", + "type": "u64" }, { - "name": "padding2", + "name": "postedSlot", + "type": "u64" + }, + { + "name": "exponent", + "type": "i32" + }, + { + "name": "padding", "type": { "array": [ "u8", - 24 + 4 ] } + }, + { + "name": "conf", + "type": "u64" } ] } }, { - "name": "IfRebalanceConfig", + "name": "RevenueShare", "type": { "kind": "struct", "fields": [ { - "name": "pubkey", - "type": "publicKey" - }, - { - "name": "totalInAmount", + "name": "authority", "docs": [ - "total amount to be sold" + "the owner of this account, a builder or referrer" ], - "type": "u64" + "type": "publicKey" }, { - "name": "currentInAmount", - "docs": [ - "amount already sold" - ], + "name": "totalReferrerRewards", "type": "u64" }, { - "name": "currentOutAmount", - "docs": [ - "amount already bought" - ], + "name": "totalBuilderRewards", "type": "u64" }, { - "name": "currentOutAmountTransferred", - "docs": [ - "amount already transferred to revenue pool" - ], - "type": "u64" - }, + "name": "padding", + "type": { + "array": [ + "u8", + 18 + ] + } + } + ] + } + }, + { + "name": "RevenueShareEscrow", + "type": { + "kind": "struct", + "fields": [ { - "name": "currentInAmountSinceLastTransfer", + "name": "authority", "docs": [ - "amount already bought in epoch" + "the owner of this account, a user" ], - "type": "u64" + "type": "publicKey" }, { - "name": "epochStartTs", - "docs": [ - "start time of epoch" - ], - "type": "i64" + "name": "referrer", + "type": "publicKey" }, { - "name": "epochInAmount", - "docs": [ - "amount already bought in epoch" - ], - "type": "u64" + "name": "referrerBoostExpireTs", + "type": "u32" }, { - "name": "epochMaxInAmount", - "docs": [ - "max amount to swap in epoch" - ], - "type": "u64" + "name": "referrerRewardOffset", + "type": "i8" }, { - "name": "epochDuration", - "docs": [ - "duration of epoch" - ], - "type": "i64" + "name": "refereeFeeNumeratorOffset", + "type": "i8" }, { - "name": "outMarketIndex", - "docs": [ - "market index to sell" - ], - "type": "u16" + "name": "referrerBoostNumerator", + "type": "i8" }, { - "name": "inMarketIndex", - "docs": [ - "market index to buy" - ], - "type": "u16" + "name": "reservedFixed", + "type": { + "array": [ + "u8", + 17 + ] + } }, { - "name": "maxSlippageBps", - "type": "u16" + "name": "padding0", + "type": "u32" }, { - "name": "swapMode", - "type": "u8" + "name": "orders", + "type": { + "vec": { + "defined": "RevenueShareOrder" + } + } }, { - "name": "status", - "type": "u8" + "name": "padding1", + "type": "u32" }, { - "name": "padding2", + "name": "approvedBuilders", "type": { - "array": [ - "u8", - 32 - ] + "vec": { + "defined": "BuilderInfo" + } } } ] } }, { - "name": "InsuranceFundStake", + "name": "SignedMsgUserOrders", + "docs": [ + "* This struct is a duplicate of SignedMsgUserOrdersZeroCopy\n * It is used to give anchor an struct to generate the idl for clients\n * The struct SignedMsgUserOrdersZeroCopy is used to load the data in efficiently" + ], "type": { "kind": "struct", "fields": [ { - "name": "authority", + "name": "authorityPubkey", "type": "publicKey" }, { - "name": "ifShares", - "type": "u128" + "name": "padding", + "type": "u32" }, { - "name": "lastWithdrawRequestShares", - "type": "u128" + "name": "signedMsgOrderData", + "type": { + "vec": { + "defined": "SignedMsgOrderId" + } + } + } + ] + } + }, + { + "name": "SignedMsgWsDelegates", + "docs": [ + "* Used to store authenticated delegates for swift-like ws connections" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "delegates", + "type": { + "vec": "publicKey" + } + } + ] + } + }, + { + "name": "SpotMarket", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "docs": [ + "The address of the spot market. It is a pda of the market index" + ], + "type": "publicKey" }, { - "name": "ifBase", - "type": "u128" + "name": "oracle", + "docs": [ + "The oracle used to price the markets deposits/borrows" + ], + "type": "publicKey" }, { - "name": "lastValidTs", - "type": "i64" + "name": "mint", + "docs": [ + "The token mint of the market" + ], + "type": "publicKey" }, { - "name": "lastWithdrawRequestValue", - "type": "u64" + "name": "vault", + "docs": [ + "The vault used to store the market's deposits", + "The amount in the vault should be equal to or greater than deposits - borrows" + ], + "type": "publicKey" }, { - "name": "lastWithdrawRequestTs", - "type": "i64" + "name": "name", + "docs": [ + "The encoded display name for the market e.g. SOL" + ], + "type": { + "array": [ + "u8", + 32 + ] + } }, { - "name": "costBasis", - "type": "i64" + "name": "historicalOracleData", + "type": { + "defined": "HistoricalOracleData" + } + }, + { + "name": "historicalIndexData", + "type": { + "defined": "HistoricalIndexData" + } }, { - "name": "marketIndex", - "type": "u16" + "name": "revenuePool", + "docs": [ + "Revenue the protocol has collected in this markets token", + "e.g. for SOL-PERP, funds can be settled in usdc and will flow into the USDC revenue pool" + ], + "type": { + "defined": "PoolBalance" + } }, { - "name": "padding", + "name": "spotFeePool", + "docs": [ + "The fees collected from swaps between this market and the quote market", + "Is settled to the quote markets revenue pool" + ], "type": { - "array": [ - "u8", - 14 - ] + "defined": "PoolBalance" } - } - ] - } - }, - { - "name": "ProtocolIfSharesTransferConfig", - "type": { - "kind": "struct", - "fields": [ + }, { - "name": "whitelistedSigners", + "name": "insuranceFund", + "docs": [ + "Details on the insurance fund covering bankruptcies in this markets token", + "Covers bankruptcies for borrows with this markets token and perps settling in this markets token" + ], "type": { - "array": [ - "publicKey", - 4 - ] + "defined": "InsuranceFund" } }, { - "name": "maxTransferPerEpoch", + "name": "totalSpotFee", + "docs": [ + "The total spot fees collected for this market", + "precision: QUOTE_PRECISION" + ], "type": "u128" }, { - "name": "currentEpochTransfer", + "name": "depositBalance", + "docs": [ + "The sum of the scaled balances for deposits across users and pool balances", + "To convert to the deposit token amount, multiply by the cumulative deposit interest", + "precision: SPOT_BALANCE_PRECISION" + ], "type": "u128" }, { - "name": "nextEpochTs", - "type": "i64" + "name": "borrowBalance", + "docs": [ + "The sum of the scaled balances for borrows across users and pool balances", + "To convert to the borrow token amount, multiply by the cumulative borrow interest", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u128" }, { - "name": "padding", - "type": { - "array": [ - "u128", - 8 - ] - } - } - ] - } - }, - { - "name": "PrelaunchOracle", - "type": { - "kind": "struct", - "fields": [ + "name": "cumulativeDepositInterest", + "docs": [ + "The cumulative interest earned by depositors", + "Used to calculate the deposit token amount from the deposit balance", + "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + ], + "type": "u128" + }, { - "name": "price", - "type": "i64" + "name": "cumulativeBorrowInterest", + "docs": [ + "The cumulative interest earned by borrowers", + "Used to calculate the borrow token amount from the borrow balance", + "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + ], + "type": "u128" }, { - "name": "maxPrice", - "type": "i64" + "name": "totalSocialLoss", + "docs": [ + "The total socialized loss from borrows, in the mint's token", + "precision: token mint precision" + ], + "type": "u128" }, { - "name": "confidence", - "type": "u64" + "name": "totalQuoteSocialLoss", + "docs": [ + "The total socialized loss from borrows, in the quote market's token", + "preicision: QUOTE_PRECISION" + ], + "type": "u128" }, { - "name": "lastUpdateSlot", + "name": "withdrawGuardThreshold", + "docs": [ + "no withdraw limits/guards when deposits below this threshold", + "precision: token mint precision" + ], "type": "u64" }, { - "name": "ammLastUpdateSlot", + "name": "maxTokenDeposits", + "docs": [ + "The max amount of token deposits in this market", + "0 if there is no limit", + "precision: token mint precision" + ], "type": "u64" }, { - "name": "perpMarketIndex", - "type": "u16" + "name": "depositTokenTwap", + "docs": [ + "24hr average of deposit token amount", + "precision: token mint precision" + ], + "type": "u64" }, { - "name": "padding", - "type": { - "array": [ - "u8", - 70 - ] - } - } - ] - } - }, - { - "name": "PerpMarket", - "type": { - "kind": "struct", - "fields": [ + "name": "borrowTokenTwap", + "docs": [ + "24hr average of borrow token amount", + "precision: token mint precision" + ], + "type": "u64" + }, { - "name": "pubkey", + "name": "utilizationTwap", "docs": [ - "The perp market's address. It is a pda of the market index" + "24hr average of utilization", + "which is borrow amount over token amount", + "precision: SPOT_UTILIZATION_PRECISION" ], - "type": "publicKey" + "type": "u64" }, { - "name": "amm", + "name": "lastInterestTs", "docs": [ - "The automated market maker" + "Last time the cumulative deposit and borrow interest was updated" ], - "type": { - "defined": "AMM" - } + "type": "u64" }, { - "name": "pnlPool", + "name": "lastTwapTs", "docs": [ - "The market's pnl pool. When users settle negative pnl, the balance increases.", - "When users settle positive pnl, the balance decreases. Can not go negative." + "Last time the deposit/borrow/utilization averages were updated" ], - "type": { - "defined": "PoolBalance" - } + "type": "u64" }, { - "name": "name", + "name": "expiryTs", "docs": [ - "Encoded display name for the perp market e.g. SOL-PERP" + "The time the market is set to expire. Only set if market is in reduce only mode" ], - "type": { - "array": [ - "u8", - 32 - ] - } + "type": "i64" }, { - "name": "insuranceClaim", + "name": "orderStepSize", "docs": [ - "The perp market's claim on the insurance fund" + "Spot orders must be a multiple of the step size", + "precision: token mint precision" ], - "type": { - "defined": "InsuranceClaim" - } + "type": "u64" }, { - "name": "unrealizedPnlMaxImbalance", + "name": "orderTickSize", "docs": [ - "The max pnl imbalance before positive pnl asset weight is discounted", - "pnl imbalance is the difference between long and short pnl. When it's greater than 0,", - "the amm has negative pnl and the initial asset weight for positive pnl is discounted", - "precision = QUOTE_PRECISION" + "Spot orders must be a multiple of the tick size", + "precision: PRICE_PRECISION" ], "type": "u64" }, { - "name": "expiryTs", + "name": "minOrderSize", "docs": [ - "The ts when the market will be expired. Only set if market is in reduce only mode" + "The minimum order size", + "precision: token mint precision" ], - "type": "i64" + "type": "u64" }, { - "name": "expiryPrice", + "name": "maxPositionSize", "docs": [ - "The price at which positions will be settled. Only set if market is expired", - "precision = PRICE_PRECISION" + "The maximum spot position size", + "if the limit is 0, there is no limit", + "precision: token mint precision" ], - "type": "i64" + "type": "u64" }, { "name": "nextFillRecordId", "docs": [ - "Every trade has a fill record id. This is the next id to be used" + "Every spot trade has a fill record id. This is the next id to use" ], "type": "u64" }, { - "name": "nextFundingRateRecordId", + "name": "nextDepositRecordId", "docs": [ - "Every funding rate update has a record id. This is the next id to be used" + "Every deposit has a deposit record id. This is the next id to use" ], "type": "u64" }, { - "name": "nextCurveRecordId", + "name": "initialAssetWeight", "docs": [ - "Every amm k updated has a record id. This is the next id to be used" + "The initial asset weight used to calculate a deposits contribution to a users initial total collateral", + "e.g. if the asset weight is .8, $100 of deposits contributes $80 to the users initial total collateral", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "maintenanceAssetWeight", + "docs": [ + "The maintenance asset weight used to calculate a deposits contribution to a users maintenance total collateral", + "e.g. if the asset weight is .9, $100 of deposits contributes $90 to the users maintenance total collateral", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "initialLiabilityWeight", + "docs": [ + "The initial liability weight used to calculate a borrows contribution to a users initial margin requirement", + "e.g. if the liability weight is .9, $100 of borrows contributes $90 to the users initial margin requirement", + "precision: SPOT_WEIGHT_PRECISION" ], - "type": "u64" + "type": "u32" }, { - "name": "imfFactor", + "name": "maintenanceLiabilityWeight", "docs": [ - "The initial margin fraction factor. Used to increase margin ratio for large positions", - "precision: MARGIN_PRECISION" + "The maintenance liability weight used to calculate a borrows contribution to a users maintenance margin requirement", + "e.g. if the liability weight is .8, $100 of borrows contributes $80 to the users maintenance margin requirement", + "precision: SPOT_WEIGHT_PRECISION" ], "type": "u32" }, { - "name": "unrealizedPnlImfFactor", + "name": "imfFactor", "docs": [ - "The imf factor for unrealized pnl. Used to discount asset weight for large positive pnl", + "The initial margin fraction factor. Used to increase liability weight/decrease asset weight for large positions", "precision: MARGIN_PRECISION" ], "type": "u32" @@ -8253,7 +7352,7 @@ { "name": "liquidatorFee", "docs": [ - "The fee the liquidator is paid for taking over perp position", + "The fee the liquidator is paid for taking over borrow/deposit", "precision: LIQUIDATOR_FEE_PRECISION" ], "type": "u32" @@ -8267,263 +7366,187 @@ "type": "u32" }, { - "name": "marginRatioInitial", + "name": "optimalUtilization", "docs": [ - "The margin ratio which determines how much collateral is required to open a position", - "e.g. margin ratio of .1 means a user must have $100 of total collateral to open a $1000 position", - "precision: MARGIN_PRECISION" + "The optimal utilization rate for this market.", + "Used to determine the markets borrow rate", + "precision: SPOT_UTILIZATION_PRECISION" ], "type": "u32" }, { - "name": "marginRatioMaintenance", + "name": "optimalBorrowRate", "docs": [ - "The margin ratio which determines when a user will be liquidated", - "e.g. margin ratio of .05 means a user must have $50 of total collateral to maintain a $1000 position", - "else they will be liquidated", - "precision: MARGIN_PRECISION" + "The borrow rate for this market when the market has optimal utilization", + "precision: SPOT_RATE_PRECISION" ], "type": "u32" }, { - "name": "unrealizedPnlInitialAssetWeight", + "name": "maxBorrowRate", "docs": [ - "The initial asset weight for positive pnl. Negative pnl always has an asset weight of 1", - "precision: SPOT_WEIGHT_PRECISION" + "The borrow rate for this market when the market has 1000 utilization", + "precision: SPOT_RATE_PRECISION" ], "type": "u32" }, { - "name": "unrealizedPnlMaintenanceAssetWeight", + "name": "decimals", "docs": [ - "The maintenance asset weight for positive pnl. Negative pnl always has an asset weight of 1", - "precision: SPOT_WEIGHT_PRECISION" + "The market's token mint's decimals. To from decimals to a precision, 10^decimals" ], "type": "u32" }, { - "name": "numberOfUsersWithBase", - "docs": [ - "number of users in a position (base)" - ], - "type": "u32" + "name": "marketIndex", + "type": "u16" }, { - "name": "numberOfUsers", + "name": "ordersEnabled", "docs": [ - "number of users in a position (pnl) or pnl (quote)" + "Whether or not spot trading is enabled" ], - "type": "u32" + "type": "bool" }, { - "name": "marketIndex", - "type": "u16" + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } }, { "name": "status", - "docs": [ - "Whether a market is active, reduce only, expired, etc", - "Affects whether users can open/close positions" - ], "type": { "defined": "MarketStatus" } }, { - "name": "contractType", + "name": "assetTier", "docs": [ - "Currently only Perpetual markets are supported" + "The asset tier affects how a deposit can be used as collateral and the priority for a borrow being liquidated" ], "type": { - "defined": "ContractType" + "defined": "AssetTier" } }, { - "name": "contractTier", - "docs": [ - "The contract tier determines how much insurance a market can receive, with more speculative markets receiving less insurance", - "It also influences the order perp markets can be liquidated, with less speculative markets being liquidated first" - ], - "type": { - "defined": "ContractTier" - } + "name": "pausedOperations", + "type": "u8" }, { - "name": "pausedOperations", + "name": "ifPausedOperations", "type": "u8" }, { - "name": "quoteSpotMarketIndex", + "name": "feeAdjustment", + "type": "i16" + }, + { + "name": "maxTokenBorrowsFraction", "docs": [ - "The spot market that pnl is settled in" + "What fraction of max_token_deposits", + "disabled when 0, 1 => 1/10000 => .01% of max_token_deposits", + "precision: X/10000" ], "type": "u16" }, { - "name": "feeAdjustment", + "name": "flashLoanAmount", "docs": [ - "Between -100 and 100, represents what % to increase/decrease the fee by", - "E.g. if this is -50 and the fee is 5bps, the new fee will be 2.5bps", - "if this is 50 and the fee is 5bps, the new fee will be 7.5bps" + "For swaps, the amount of token loaned out in the begin_swap ix", + "precision: token mint precision" ], - "type": "i16" + "type": "u64" }, { - "name": "fuelBoostPosition", + "name": "flashLoanInitialTokenAmount", "docs": [ - "fuel multiplier for perp funding", - "precision: 10" + "For swaps, the amount in the users token account in the begin_swap ix", + "Used to calculate how much of the token left the system in end_swap ix", + "precision: token mint precision" ], - "type": "u8" + "type": "u64" }, { - "name": "fuelBoostTaker", + "name": "totalSwapFee", "docs": [ - "fuel multiplier for perp taker", - "precision: 10" + "The total fees received from swaps", + "precision: token mint precision" ], - "type": "u8" + "type": "u64" }, { - "name": "fuelBoostMaker", + "name": "scaleInitialAssetWeightStart", "docs": [ - "fuel multiplier for perp maker", - "precision: 10" + "When to begin scaling down the initial asset weight", + "disabled when 0", + "precision: QUOTE_PRECISION" ], - "type": "u8" + "type": "u64" }, { - "name": "poolId", + "name": "minBorrowRate", + "docs": [ + "The min borrow rate for this market when the market regardless of utilization", + "1 => 1/200 => .5%", + "precision: X/200" + ], "type": "u8" }, { - "name": "highLeverageMarginRatioInitial", - "type": "u16" - }, - { - "name": "highLeverageMarginRatioMaintenance", - "type": "u16" - }, - { - "name": "protectedMakerLimitPriceDivisor", + "name": "fuelBoostDeposits", + "docs": [ + "fuel multiplier for spot deposits", + "precision: 10" + ], "type": "u8" }, { - "name": "protectedMakerDynamicDivisor", + "name": "fuelBoostBorrows", + "docs": [ + "fuel multiplier for spot borrows", + "precision: 10" + ], "type": "u8" }, { - "name": "padding1", - "type": "u32" - }, - { - "name": "lastFillPrice", - "type": "u64" - }, - { - "name": "padding", - "type": { - "array": [ - "u8", - 24 - ] - } - } - ] - } - }, - { - "name": "ProtectedMakerModeConfig", - "type": { - "kind": "struct", - "fields": [ - { - "name": "maxUsers", - "type": "u32" - }, - { - "name": "currentUsers", - "type": "u32" - }, - { - "name": "reduceOnly", + "name": "fuelBoostTaker", + "docs": [ + "fuel multiplier for spot taker", + "precision: 10" + ], "type": "u8" }, { - "name": "padding", - "type": { - "array": [ - "u8", - 31 - ] - } - } - ] - } - }, - { - "name": "PythLazerOracle", - "type": { - "kind": "struct", - "fields": [ - { - "name": "price", - "type": "i64" - }, - { - "name": "publishTime", - "type": "u64" - }, - { - "name": "postedSlot", - "type": "u64" - }, - { - "name": "exponent", - "type": "i32" - }, - { - "name": "padding", - "type": { - "array": [ - "u8", - 4 - ] - } + "name": "fuelBoostMaker", + "docs": [ + "fuel multiplier for spot maker", + "precision: 10" + ], + "type": "u8" }, { - "name": "conf", - "type": "u64" - } - ] - } - }, - { - "name": "RevenueShare", - "type": { - "kind": "struct", - "fields": [ - { - "name": "authority", + "name": "fuelBoostInsurance", "docs": [ - "the owner of this account, a builder or referrer" + "fuel multiplier for spot insurance stake", + "precision: 10" ], - "type": "publicKey" + "type": "u8" }, { - "name": "totalReferrerRewards", - "type": "u64" + "name": "tokenProgramFlag", + "type": "u8" }, { - "name": "totalBuilderRewards", - "type": "u64" + "name": "poolId", + "type": "u8" }, { "name": "padding", "type": { "array": [ "u8", - 18 + 40 ] } } @@ -8531,1317 +7554,1257 @@ } }, { - "name": "RevenueShareEscrow", + "name": "State", "type": { "kind": "struct", "fields": [ { - "name": "authority", - "docs": [ - "the owner of this account, a user" - ], + "name": "admin", "type": "publicKey" }, { - "name": "referrer", + "name": "whitelistMint", "type": "publicKey" }, { - "name": "referrerBoostExpireTs", - "type": "u32" - }, - { - "name": "referrerRewardOffset", - "type": "i8" + "name": "discountMint", + "type": "publicKey" }, { - "name": "refereeFeeNumeratorOffset", - "type": "i8" + "name": "signer", + "type": "publicKey" }, { - "name": "referrerBoostNumerator", - "type": "i8" + "name": "srmVault", + "type": "publicKey" }, { - "name": "reservedFixed", + "name": "perpFeeStructure", "type": { - "array": [ - "u8", - 17 - ] + "defined": "FeeStructure" } }, { - "name": "padding0", - "type": "u32" + "name": "spotFeeStructure", + "type": { + "defined": "FeeStructure" + } }, { - "name": "orders", + "name": "oracleGuardRails", "type": { - "vec": { - "defined": "RevenueShareOrder" - } + "defined": "OracleGuardRails" } }, { - "name": "padding1", - "type": "u32" + "name": "numberOfAuthorities", + "type": "u64" }, { - "name": "approvedBuilders", - "type": { - "vec": { - "defined": "BuilderInfo" - } - } - } - ] - } - }, - { - "name": "SignedMsgUserOrders", - "docs": [ - "* This struct is a duplicate of SignedMsgUserOrdersZeroCopy\n * It is used to give anchor an struct to generate the idl for clients\n * The struct SignedMsgUserOrdersZeroCopy is used to load the data in efficiently" - ], - "type": { - "kind": "struct", - "fields": [ + "name": "numberOfSubAccounts", + "type": "u64" + }, { - "name": "authorityPubkey", - "type": "publicKey" + "name": "lpCooldownTime", + "type": "u64" }, { - "name": "padding", + "name": "liquidationMarginBufferRatio", "type": "u32" }, { - "name": "signedMsgOrderData", - "type": { - "vec": { - "defined": "SignedMsgOrderId" - } - } - } - ] - } - }, - { - "name": "SignedMsgWsDelegates", - "docs": [ - "* Used to store authenticated delegates for swift-like ws connections" - ], - "type": { - "kind": "struct", - "fields": [ + "name": "settlementDuration", + "type": "u16" + }, { - "name": "delegates", + "name": "numberOfMarkets", + "type": "u16" + }, + { + "name": "numberOfSpotMarkets", + "type": "u16" + }, + { + "name": "signerNonce", + "type": "u8" + }, + { + "name": "minPerpAuctionDuration", + "type": "u8" + }, + { + "name": "defaultMarketOrderTimeInForce", + "type": "u8" + }, + { + "name": "defaultSpotAuctionDuration", + "type": "u8" + }, + { + "name": "exchangeStatus", + "type": "u8" + }, + { + "name": "liquidationDuration", + "type": "u8" + }, + { + "name": "initialPctToLiquidate", + "type": "u16" + }, + { + "name": "maxNumberOfSubAccounts", + "type": "u16" + }, + { + "name": "maxInitializeUserFee", + "type": "u16" + }, + { + "name": "featureBitFlags", + "type": "u8" + }, + { + "name": "padding", "type": { - "vec": "publicKey" + "array": [ + "u8", + 9 + ] } } ] } }, { - "name": "SpotMarket", + "name": "User", "type": { "kind": "struct", "fields": [ { - "name": "pubkey", + "name": "authority", "docs": [ - "The address of the spot market. It is a pda of the market index" + "The owner/authority of the account" ], "type": "publicKey" }, { - "name": "oracle", + "name": "delegate", "docs": [ - "The oracle used to price the markets deposits/borrows" + "An addresses that can control the account on the authority's behalf. Has limited power, cant withdraw" ], "type": "publicKey" }, { - "name": "mint", + "name": "name", "docs": [ - "The token mint of the market" + "Encoded display name e.g. \"toly\"" ], - "type": "publicKey" + "type": { + "array": [ + "u8", + 32 + ] + } }, { - "name": "vault", + "name": "spotPositions", "docs": [ - "The vault used to store the market's deposits", - "The amount in the vault should be equal to or greater than deposits - borrows" + "The user's spot positions" ], - "type": "publicKey" + "type": { + "array": [ + { + "defined": "SpotPosition" + }, + 8 + ] + } }, { - "name": "name", + "name": "perpPositions", "docs": [ - "The encoded display name for the market e.g. SOL" + "The user's perp positions" ], "type": { "array": [ - "u8", - 32 + { + "defined": "PerpPosition" + }, + 8 ] } }, { - "name": "historicalOracleData", + "name": "orders", + "docs": [ + "The user's orders" + ], "type": { - "defined": "HistoricalOracleData" + "array": [ + { + "defined": "Order" + }, + 32 + ] } }, { - "name": "historicalIndexData", - "type": { - "defined": "HistoricalIndexData" - } + "name": "lastAddPerpLpSharesTs", + "docs": [ + "The last time the user added perp lp positions" + ], + "type": "i64" + }, + { + "name": "totalDeposits", + "docs": [ + "The total values of deposits the user has made", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalWithdraws", + "docs": [ + "The total values of withdrawals the user has made", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalSocialLoss", + "docs": [ + "The total socialized loss the users has incurred upon the protocol", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "settledPerpPnl", + "docs": [ + "Fees (taker fees, maker rebate, referrer reward, filler reward) and pnl for perps", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "cumulativeSpotFees", + "docs": [ + "Fees (taker fees, maker rebate, filler reward) for spot", + "precision: QUOTE_PRECISION" + ], + "type": "i64" }, { - "name": "revenuePool", + "name": "cumulativePerpFunding", "docs": [ - "Revenue the protocol has collected in this markets token", - "e.g. for SOL-PERP, funds can be settled in usdc and will flow into the USDC revenue pool" + "Cumulative funding paid/received for perps", + "precision: QUOTE_PRECISION" ], - "type": { - "defined": "PoolBalance" - } + "type": "i64" }, { - "name": "spotFeePool", + "name": "liquidationMarginFreed", "docs": [ - "The fees collected from swaps between this market and the quote market", - "Is settled to the quote markets revenue pool" + "The amount of margin freed during liquidation. Used to force the liquidation to occur over a period of time", + "Defaults to zero when not being liquidated", + "precision: QUOTE_PRECISION" ], - "type": { - "defined": "PoolBalance" - } + "type": "u64" }, { - "name": "insuranceFund", + "name": "lastActiveSlot", "docs": [ - "Details on the insurance fund covering bankruptcies in this markets token", - "Covers bankruptcies for borrows with this markets token and perps settling in this markets token" + "The last slot a user was active. Used to determine if a user is idle" ], - "type": { - "defined": "InsuranceFund" - } + "type": "u64" }, { - "name": "totalSpotFee", + "name": "nextOrderId", "docs": [ - "The total spot fees collected for this market", - "precision: QUOTE_PRECISION" + "Every user order has an order id. This is the next order id to be used" ], - "type": "u128" + "type": "u32" }, { - "name": "depositBalance", + "name": "maxMarginRatio", "docs": [ - "The sum of the scaled balances for deposits across users and pool balances", - "To convert to the deposit token amount, multiply by the cumulative deposit interest", - "precision: SPOT_BALANCE_PRECISION" + "Custom max initial margin ratio for the user" ], - "type": "u128" + "type": "u32" }, { - "name": "borrowBalance", + "name": "nextLiquidationId", "docs": [ - "The sum of the scaled balances for borrows across users and pool balances", - "To convert to the borrow token amount, multiply by the cumulative borrow interest", - "precision: SPOT_BALANCE_PRECISION" + "The next liquidation id to be used for user" ], - "type": "u128" + "type": "u16" }, { - "name": "cumulativeDepositInterest", + "name": "subAccountId", "docs": [ - "The cumulative interest earned by depositors", - "Used to calculate the deposit token amount from the deposit balance", - "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + "The sub account id for this user" ], - "type": "u128" + "type": "u16" }, { - "name": "cumulativeBorrowInterest", + "name": "status", "docs": [ - "The cumulative interest earned by borrowers", - "Used to calculate the borrow token amount from the borrow balance", - "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + "Whether the user is active, being liquidated or bankrupt" ], - "type": "u128" + "type": "u8" }, { - "name": "totalSocialLoss", + "name": "isMarginTradingEnabled", "docs": [ - "The total socialized loss from borrows, in the mint's token", - "precision: token mint precision" + "Whether the user has enabled margin trading" ], - "type": "u128" + "type": "bool" }, { - "name": "totalQuoteSocialLoss", + "name": "idle", "docs": [ - "The total socialized loss from borrows, in the quote market's token", - "preicision: QUOTE_PRECISION" + "User is idle if they haven't interacted with the protocol in 1 week and they have no orders, perp positions or borrows", + "Off-chain keeper bots can ignore users that are idle" ], - "type": "u128" + "type": "bool" }, { - "name": "withdrawGuardThreshold", + "name": "openOrders", "docs": [ - "no withdraw limits/guards when deposits below this threshold", - "precision: token mint precision" + "number of open orders" ], - "type": "u64" + "type": "u8" }, { - "name": "maxTokenDeposits", + "name": "hasOpenOrder", "docs": [ - "The max amount of token deposits in this market", - "0 if there is no limit", - "precision: token mint precision" + "Whether or not user has open order" ], - "type": "u64" + "type": "bool" }, { - "name": "depositTokenTwap", + "name": "openAuctions", "docs": [ - "24hr average of deposit token amount", - "precision: token mint precision" + "number of open orders with auction" ], - "type": "u64" + "type": "u8" }, { - "name": "borrowTokenTwap", + "name": "hasOpenAuction", "docs": [ - "24hr average of borrow token amount", - "precision: token mint precision" + "Whether or not user has open order with auction" ], - "type": "u64" + "type": "bool" }, { - "name": "utilizationTwap", + "name": "marginMode", + "type": { + "defined": "MarginMode" + } + }, + { + "name": "poolId", + "type": "u8" + }, + { + "name": "padding1", + "type": { + "array": [ + "u8", + 3 + ] + } + }, + { + "name": "lastFuelBonusUpdateTs", + "type": "u32" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 12 + ] + } + } + ] + } + }, + { + "name": "UserStats", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", "docs": [ - "24hr average of utilization", - "which is borrow amount over token amount", - "precision: SPOT_UTILIZATION_PRECISION" + "The authority for all of a users sub accounts" ], - "type": "u64" + "type": "publicKey" }, { - "name": "lastInterestTs", + "name": "referrer", "docs": [ - "Last time the cumulative deposit and borrow interest was updated" + "The address that referred this user" ], - "type": "u64" + "type": "publicKey" }, { - "name": "lastTwapTs", + "name": "fees", "docs": [ - "Last time the deposit/borrow/utilization averages were updated" + "Stats on the fees paid by the user" ], - "type": "u64" + "type": { + "defined": "UserFees" + } }, { - "name": "expiryTs", + "name": "nextEpochTs", "docs": [ - "The time the market is set to expire. Only set if market is in reduce only mode" + "The timestamp of the next epoch", + "Epoch is used to limit referrer rewards earned in single epoch" ], "type": "i64" }, { - "name": "orderStepSize", + "name": "makerVolume30d", "docs": [ - "Spot orders must be a multiple of the step size", - "precision: token mint precision" + "Rolling 30day maker volume for user", + "precision: QUOTE_PRECISION" ], "type": "u64" }, { - "name": "orderTickSize", + "name": "takerVolume30d", "docs": [ - "Spot orders must be a multiple of the tick size", - "precision: PRICE_PRECISION" + "Rolling 30day taker volume for user", + "precision: QUOTE_PRECISION" ], "type": "u64" }, { - "name": "minOrderSize", + "name": "fillerVolume30d", "docs": [ - "The minimum order size", - "precision: token mint precision" + "Rolling 30day filler volume for user", + "precision: QUOTE_PRECISION" ], "type": "u64" }, { - "name": "maxPositionSize", + "name": "lastMakerVolume30dTs", "docs": [ - "The maximum spot position size", - "if the limit is 0, there is no limit", - "precision: token mint precision" + "last time the maker volume was updated" ], - "type": "u64" + "type": "i64" }, { - "name": "nextFillRecordId", + "name": "lastTakerVolume30dTs", "docs": [ - "Every spot trade has a fill record id. This is the next id to use" + "last time the taker volume was updated" ], - "type": "u64" + "type": "i64" }, { - "name": "nextDepositRecordId", + "name": "lastFillerVolume30dTs", "docs": [ - "Every deposit has a deposit record id. This is the next id to use" + "last time the filler volume was updated" ], - "type": "u64" + "type": "i64" }, { - "name": "initialAssetWeight", + "name": "ifStakedQuoteAssetAmount", "docs": [ - "The initial asset weight used to calculate a deposits contribution to a users initial total collateral", - "e.g. if the asset weight is .8, $100 of deposits contributes $80 to the users initial total collateral", - "precision: SPOT_WEIGHT_PRECISION" + "The amount of tokens staked in the quote spot markets if" ], - "type": "u32" + "type": "u64" }, { - "name": "maintenanceAssetWeight", + "name": "numberOfSubAccounts", "docs": [ - "The maintenance asset weight used to calculate a deposits contribution to a users maintenance total collateral", - "e.g. if the asset weight is .9, $100 of deposits contributes $90 to the users maintenance total collateral", - "precision: SPOT_WEIGHT_PRECISION" + "The current number of sub accounts" ], - "type": "u32" + "type": "u16" }, { - "name": "initialLiabilityWeight", + "name": "numberOfSubAccountsCreated", "docs": [ - "The initial liability weight used to calculate a borrows contribution to a users initial margin requirement", - "e.g. if the liability weight is .9, $100 of borrows contributes $90 to the users initial margin requirement", - "precision: SPOT_WEIGHT_PRECISION" + "The number of sub accounts created. Can be greater than the number of sub accounts if user", + "has deleted sub accounts" ], - "type": "u32" + "type": "u16" }, { - "name": "maintenanceLiabilityWeight", + "name": "referrerStatus", "docs": [ - "The maintenance liability weight used to calculate a borrows contribution to a users maintenance margin requirement", - "e.g. if the liability weight is .8, $100 of borrows contributes $80 to the users maintenance margin requirement", - "precision: SPOT_WEIGHT_PRECISION" + "Flags for referrer status:", + "First bit (LSB): 1 if user is a referrer, 0 otherwise", + "Second bit: 1 if user was referred, 0 otherwise" ], - "type": "u32" + "type": "u8" }, { - "name": "imfFactor", + "name": "disableUpdatePerpBidAskTwap", + "type": "bool" + }, + { + "name": "padding1", + "type": { + "array": [ + "u8", + 1 + ] + } + }, + { + "name": "fuelOverflowStatus", "docs": [ - "The initial margin fraction factor. Used to increase liability weight/decrease asset weight for large positions", - "precision: MARGIN_PRECISION" + "whether the user has a FuelOverflow account" ], - "type": "u32" + "type": "u8" }, { - "name": "liquidatorFee", + "name": "fuelInsurance", "docs": [ - "The fee the liquidator is paid for taking over borrow/deposit", - "precision: LIQUIDATOR_FEE_PRECISION" + "accumulated fuel for token amounts of insurance" ], "type": "u32" }, { - "name": "ifLiquidationFee", + "name": "fuelDeposits", "docs": [ - "The fee the insurance fund receives from liquidation", - "precision: LIQUIDATOR_FEE_PRECISION" + "accumulated fuel for notional of deposits" ], "type": "u32" }, { - "name": "optimalUtilization", + "name": "fuelBorrows", "docs": [ - "The optimal utilization rate for this market.", - "Used to determine the markets borrow rate", - "precision: SPOT_UTILIZATION_PRECISION" + "accumulate fuel bonus for notional of borrows" ], "type": "u32" }, { - "name": "optimalBorrowRate", + "name": "fuelPositions", "docs": [ - "The borrow rate for this market when the market has optimal utilization", - "precision: SPOT_RATE_PRECISION" + "accumulated fuel for perp open interest" ], "type": "u32" }, { - "name": "maxBorrowRate", + "name": "fuelTaker", "docs": [ - "The borrow rate for this market when the market has 1000 utilization", - "precision: SPOT_RATE_PRECISION" + "accumulate fuel bonus for taker volume" ], "type": "u32" }, { - "name": "decimals", + "name": "fuelMaker", "docs": [ - "The market's token mint's decimals. To from decimals to a precision, 10^decimals" + "accumulate fuel bonus for maker volume" ], "type": "u32" }, { - "name": "marketIndex", - "type": "u16" - }, - { - "name": "ordersEnabled", + "name": "ifStakedGovTokenAmount", "docs": [ - "Whether or not spot trading is enabled" + "The amount of tokens staked in the governance spot markets if" ], - "type": "bool" + "type": "u64" }, { - "name": "oracleSource", - "type": { - "defined": "OracleSource" - } + "name": "lastFuelIfBonusUpdateTs", + "docs": [ + "last unix ts user stats data was used to update if fuel (u32 to save space)" + ], + "type": "u32" }, { - "name": "status", + "name": "padding", "type": { - "defined": "MarketStatus" + "array": [ + "u8", + 12 + ] } - }, + } + ] + } + }, + { + "name": "ReferrerName", + "type": { + "kind": "struct", + "fields": [ { - "name": "assetTier", - "docs": [ - "The asset tier affects how a deposit can be used as collateral and the priority for a borrow being liquidated" - ], - "type": { - "defined": "AssetTier" - } + "name": "authority", + "type": "publicKey" }, { - "name": "pausedOperations", - "type": "u8" + "name": "user", + "type": "publicKey" }, { - "name": "ifPausedOperations", - "type": "u8" + "name": "userStats", + "type": "publicKey" }, { - "name": "feeAdjustment", - "type": "i16" - }, + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "FuelOverflow", + "type": { + "kind": "struct", + "fields": [ { - "name": "maxTokenBorrowsFraction", + "name": "authority", "docs": [ - "What fraction of max_token_deposits", - "disabled when 0, 1 => 1/10000 => .01% of max_token_deposits", - "precision: X/10000" + "The authority of this overflow account" ], - "type": "u16" + "type": "publicKey" }, { - "name": "flashLoanAmount", - "docs": [ - "For swaps, the amount of token loaned out in the begin_swap ix", - "precision: token mint precision" - ], - "type": "u64" + "name": "fuelInsurance", + "type": "u128" }, { - "name": "flashLoanInitialTokenAmount", - "docs": [ - "For swaps, the amount in the users token account in the begin_swap ix", - "Used to calculate how much of the token left the system in end_swap ix", - "precision: token mint precision" - ], - "type": "u64" + "name": "fuelDeposits", + "type": "u128" }, { - "name": "totalSwapFee", - "docs": [ - "The total fees received from swaps", - "precision: token mint precision" - ], - "type": "u64" + "name": "fuelBorrows", + "type": "u128" }, { - "name": "scaleInitialAssetWeightStart", - "docs": [ - "When to begin scaling down the initial asset weight", - "disabled when 0", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "fuelPositions", + "type": "u128" }, { - "name": "minBorrowRate", - "docs": [ - "The min borrow rate for this market when the market regardless of utilization", - "1 => 1/200 => .5%", - "precision: X/200" - ], - "type": "u8" + "name": "fuelTaker", + "type": "u128" }, { - "name": "fuelBoostDeposits", - "docs": [ - "fuel multiplier for spot deposits", - "precision: 10" - ], - "type": "u8" + "name": "fuelMaker", + "type": "u128" }, { - "name": "fuelBoostBorrows", - "docs": [ - "fuel multiplier for spot borrows", - "precision: 10" - ], - "type": "u8" + "name": "lastFuelSweepTs", + "type": "u32" }, { - "name": "fuelBoostTaker", - "docs": [ - "fuel multiplier for spot taker", - "precision: 10" - ], - "type": "u8" + "name": "lastResetTs", + "type": "u32" }, { - "name": "fuelBoostMaker", - "docs": [ - "fuel multiplier for spot maker", - "precision: 10" - ], - "type": "u8" - }, + "name": "padding", + "type": { + "array": [ + "u128", + 6 + ] + } + } + ] + } + } + ], + "types": [ + { + "name": "UpdatePerpMarketSummaryStatsParams", + "type": { + "kind": "struct", + "fields": [ { - "name": "fuelBoostInsurance", - "docs": [ - "fuel multiplier for spot insurance stake", - "precision: 10" - ], - "type": "u8" + "name": "quoteAssetAmountWithUnsettledLp", + "type": { + "option": "i64" + } }, { - "name": "tokenProgramFlag", - "type": "u8" + "name": "netUnsettledFundingPnl", + "type": { + "option": "i64" + } }, { - "name": "poolId", - "type": "u8" + "name": "updateAmmSummaryStats", + "type": { + "option": "bool" + } }, { - "name": "padding", + "name": "excludeTotalLiqFee", "type": { - "array": [ - "u8", - 40 - ] + "option": "bool" } } ] } }, { - "name": "State", + "name": "SpotMarketUpdateParams", "type": { "kind": "struct", "fields": [ { - "name": "admin", - "type": "publicKey" - }, - { - "name": "whitelistMint", - "type": "publicKey" - }, - { - "name": "discountMint", - "type": "publicKey" - }, - { - "name": "signer", - "type": "publicKey" - }, - { - "name": "srmVault", - "type": "publicKey" - }, - { - "name": "perpFeeStructure", + "name": "name", "type": { - "defined": "FeeStructure" + "option": { + "array": [ + "u8", + 32 + ] + } } }, { - "name": "spotFeeStructure", + "name": "status", "type": { - "defined": "FeeStructure" + "option": { + "defined": "MarketStatus" + } } }, { - "name": "oracleGuardRails", + "name": "pausedOperations", "type": { - "defined": "OracleGuardRails" + "option": "u8" } }, { - "name": "numberOfAuthorities", - "type": "u64" - }, - { - "name": "numberOfSubAccounts", - "type": "u64" - }, - { - "name": "lpCooldownTime", - "type": "u64" - }, - { - "name": "liquidationMarginBufferRatio", - "type": "u32" - }, - { - "name": "settlementDuration", - "type": "u16" - }, - { - "name": "numberOfMarkets", - "type": "u16" - }, - { - "name": "numberOfSpotMarkets", - "type": "u16" - }, - { - "name": "signerNonce", - "type": "u8" - }, - { - "name": "minPerpAuctionDuration", - "type": "u8" + "name": "ifPausedOperations", + "type": { + "option": "u8" + } }, { - "name": "defaultMarketOrderTimeInForce", - "type": "u8" + "name": "ordersEnabled", + "type": { + "option": "bool" + } }, { - "name": "defaultSpotAuctionDuration", - "type": "u8" + "name": "assetTier", + "type": { + "option": { + "defined": "AssetTier" + } + } }, { - "name": "exchangeStatus", - "type": "u8" + "name": "initialAssetWeight", + "type": { + "option": "u32" + } }, { - "name": "liquidationDuration", - "type": "u8" + "name": "maintenanceAssetWeight", + "type": { + "option": "u32" + } }, { - "name": "initialPctToLiquidate", - "type": "u16" + "name": "initialLiabilityWeight", + "type": { + "option": "u32" + } }, { - "name": "maxNumberOfSubAccounts", - "type": "u16" + "name": "maintenanceLiabilityWeight", + "type": { + "option": "u32" + } }, { - "name": "maxInitializeUserFee", - "type": "u16" + "name": "imfFactor", + "type": { + "option": "u32" + } }, { - "name": "featureBitFlags", - "type": "u8" + "name": "optimalUtilization", + "type": { + "option": "u32" + } }, { - "name": "padding", + "name": "optimalBorrowRate", "type": { - "array": [ - "u8", - 9 - ] + "option": "u32" } - } - ] - } - }, - { - "name": "User", - "type": { - "kind": "struct", - "fields": [ - { - "name": "authority", - "docs": [ - "The owner/authority of the account" - ], - "type": "publicKey" }, { - "name": "delegate", - "docs": [ - "An addresses that can control the account on the authority's behalf. Has limited power, cant withdraw" - ], - "type": "publicKey" + "name": "maxBorrowRate", + "type": { + "option": "u32" + } }, { - "name": "name", - "docs": [ - "Encoded display name e.g. \"toly\"" - ], + "name": "minBorrowRate", "type": { - "array": [ - "u8", - 32 - ] + "option": "u8" } }, { - "name": "spotPositions", - "docs": [ - "The user's spot positions" - ], + "name": "orderStepSize", "type": { - "array": [ - { - "defined": "SpotPosition" - }, - 8 - ] + "option": "u64" } }, { - "name": "perpPositions", - "docs": [ - "The user's perp positions" - ], + "name": "orderTickSize", "type": { - "array": [ - { - "defined": "PerpPosition" - }, - 8 - ] + "option": "u64" } }, { - "name": "orders", - "docs": [ - "The user's orders" - ], + "name": "minOrderSize", "type": { - "array": [ - { - "defined": "Order" - }, - 32 - ] + "option": "u64" } }, { - "name": "lastAddPerpLpSharesTs", - "docs": [ - "The last time the user added perp lp positions" - ], - "type": "i64" + "name": "maxTokenDeposits", + "type": { + "option": "u64" + } }, { - "name": "totalDeposits", - "docs": [ - "The total values of deposits the user has made", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "maxTokenBorrowsFraction", + "type": { + "option": "u16" + } }, { - "name": "totalWithdraws", - "docs": [ - "The total values of withdrawals the user has made", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "scaleInitialAssetWeightStart", + "type": { + "option": "u64" + } }, { - "name": "totalSocialLoss", - "docs": [ - "The total socialized loss the users has incurred upon the protocol", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "feeAdjustment", + "type": { + "option": "i16" + } }, { - "name": "settledPerpPnl", - "docs": [ - "Fees (taker fees, maker rebate, referrer reward, filler reward) and pnl for perps", - "precision: QUOTE_PRECISION" - ], - "type": "i64" + "name": "revenueSettlePeriod", + "type": { + "option": "i64" + } }, { - "name": "cumulativeSpotFees", - "docs": [ - "Fees (taker fees, maker rebate, filler reward) for spot", - "precision: QUOTE_PRECISION" - ], - "type": "i64" + "name": "withdrawGuardThreshold", + "type": { + "option": "u64" + } }, { - "name": "cumulativePerpFunding", - "docs": [ - "Cumulative funding paid/received for perps", - "precision: QUOTE_PRECISION" - ], - "type": "i64" + "name": "userIfFactor", + "type": { + "option": "u32" + } }, { - "name": "liquidationMarginFreed", - "docs": [ - "The amount of margin freed during liquidation. Used to force the liquidation to occur over a period of time", - "Defaults to zero when not being liquidated", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "totalIfFactor", + "type": { + "option": "u32" + } }, { - "name": "lastActiveSlot", - "docs": [ - "The last slot a user was active. Used to determine if a user is idle" - ], - "type": "u64" + "name": "expiryTs", + "type": { + "option": "i64" + } }, { - "name": "nextOrderId", - "docs": [ - "Every user order has an order id. This is the next order id to be used" - ], - "type": "u32" + "name": "poolId", + "type": { + "option": "u8" + } }, { - "name": "maxMarginRatio", - "docs": [ - "Custom max initial margin ratio for the user" - ], - "type": "u32" + "name": "liquidatorFee", + "type": { + "option": "u32" + } }, { - "name": "nextLiquidationId", - "docs": [ - "The next liquidation id to be used for user" - ], - "type": "u16" - }, + "name": "ifLiquidationFee", + "type": { + "option": "u32" + } + } + ] + } + }, + { + "name": "PerpMarketUpdateParams", + "type": { + "kind": "struct", + "fields": [ { - "name": "subAccountId", - "docs": [ - "The sub account id for this user" - ], - "type": "u16" + "name": "name", + "type": { + "option": { + "array": [ + "u8", + 32 + ] + } + } }, { "name": "status", - "docs": [ - "Whether the user is active, being liquidated or bankrupt" - ], - "type": "u8" + "type": { + "option": { + "defined": "MarketStatus" + } + } }, { - "name": "isMarginTradingEnabled", - "docs": [ - "Whether the user has enabled margin trading" - ], - "type": "bool" + "name": "pausedOperations", + "type": { + "option": "u8" + } }, { - "name": "idle", - "docs": [ - "User is idle if they haven't interacted with the protocol in 1 week and they have no orders, perp positions or borrows", - "Off-chain keeper bots can ignore users that are idle" - ], - "type": "bool" + "name": "contractTier", + "type": { + "option": { + "defined": "ContractTier" + } + } }, { - "name": "openOrders", - "docs": [ - "number of open orders" - ], - "type": "u8" + "name": "liquidatorFee", + "type": { + "option": "u32" + } }, { - "name": "hasOpenOrder", - "docs": [ - "Whether or not user has open order" - ], - "type": "bool" + "name": "ifLiquidationFee", + "type": { + "option": "u32" + } }, { - "name": "openAuctions", - "docs": [ - "number of open orders with auction" - ], - "type": "u8" + "name": "marginRatioInitial", + "type": { + "option": "u32" + } }, { - "name": "hasOpenAuction", - "docs": [ - "Whether or not user has open order with auction" - ], - "type": "bool" + "name": "marginRatioMaintenance", + "type": { + "option": "u32" + } }, { - "name": "marginMode", + "name": "unrealizedInitialAssetWeight", "type": { - "defined": "MarginMode" + "option": "u32" } }, { - "name": "poolId", - "type": "u8" + "name": "unrealizedMaintenanceAssetWeight", + "type": { + "option": "u32" + } }, { - "name": "padding1", + "name": "highLeverageMarginRatioInitial", "type": { - "array": [ - "u8", - 3 - ] + "option": "u16" } }, { - "name": "lastFuelBonusUpdateTs", - "type": "u32" + "name": "highLeverageMarginRatioMaintenance", + "type": { + "option": "u16" + } }, { - "name": "padding", + "name": "imfFactor", "type": { - "array": [ - "u8", - 12 - ] + "option": "u32" } - } - ] - } - }, - { - "name": "UserStats", - "type": { - "kind": "struct", - "fields": [ + }, { - "name": "authority", - "docs": [ - "The authority for all of a users sub accounts" - ], - "type": "publicKey" + "name": "unrealizedPnlImfFactor", + "type": { + "option": "u32" + } }, { - "name": "referrer", - "docs": [ - "The address that referred this user" - ], - "type": "publicKey" + "name": "fundingPeriod", + "type": { + "option": "i64" + } }, { - "name": "fees", - "docs": [ - "Stats on the fees paid by the user" - ], + "name": "unrealizedMaxImbalance", "type": { - "defined": "UserFees" + "option": "u64" } }, { - "name": "nextEpochTs", - "docs": [ - "The timestamp of the next epoch", - "Epoch is used to limit referrer rewards earned in single epoch" - ], - "type": "i64" + "name": "maxRevenueWithdrawPerPeriod", + "type": { + "option": "u64" + } }, { - "name": "makerVolume30d", - "docs": [ - "Rolling 30day maker volume for user", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "quoteMaxInsurance", + "type": { + "option": "u64" + } }, { - "name": "takerVolume30d", - "docs": [ - "Rolling 30day taker volume for user", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "baseSpread", + "type": { + "option": "u32" + } }, { - "name": "fillerVolume30d", - "docs": [ - "Rolling 30day filler volume for user", - "precision: QUOTE_PRECISION" - ], - "type": "u64" + "name": "maxSpread", + "type": { + "option": "u32" + } }, { - "name": "lastMakerVolume30dTs", - "docs": [ - "last time the maker volume was updated" - ], - "type": "i64" + "name": "orderStepSize", + "type": { + "option": "u64" + } }, { - "name": "lastTakerVolume30dTs", - "docs": [ - "last time the taker volume was updated" - ], - "type": "i64" + "name": "orderTickSize", + "type": { + "option": "u64" + } }, { - "name": "lastFillerVolume30dTs", - "docs": [ - "last time the filler volume was updated" - ], - "type": "i64" + "name": "minOrderSize", + "type": { + "option": "u64" + } + }, + { + "name": "maxSlippageRatio", + "type": { + "option": "u16" + } }, { - "name": "ifStakedQuoteAssetAmount", - "docs": [ - "The amount of tokens staked in the quote spot markets if" - ], - "type": "u64" + "name": "maxFillReserveFraction", + "type": { + "option": "u16" + } }, { - "name": "numberOfSubAccounts", - "docs": [ - "The current number of sub accounts" - ], - "type": "u16" + "name": "maxOpenInterest", + "type": { + "option": "u128" + } }, { - "name": "numberOfSubAccountsCreated", - "docs": [ - "The number of sub accounts created. Can be greater than the number of sub accounts if user", - "has deleted sub accounts" - ], - "type": "u16" + "name": "feeAdjustment", + "type": { + "option": "i16" + } }, { - "name": "referrerStatus", - "docs": [ - "Flags for referrer status:", - "First bit (LSB): 1 if user is a referrer, 0 otherwise", - "Second bit: 1 if user was referred, 0 otherwise" - ], - "type": "u8" + "name": "numberOfUsers", + "type": { + "option": "u32" + } }, { - "name": "disableUpdatePerpBidAskTwap", - "type": "bool" + "name": "numberOfUsersWithBase", + "type": { + "option": "u32" + } }, { - "name": "padding1", + "name": "protectedMakerLimitPriceDivisor", "type": { - "array": [ - "u8", - 1 - ] + "option": "u8" } }, { - "name": "fuelOverflowStatus", - "docs": [ - "whether the user has a FuelOverflow account" - ], - "type": "u8" + "name": "protectedMakerDynamicDivisor", + "type": { + "option": "u8" + } }, { - "name": "fuelInsurance", - "docs": [ - "accumulated fuel for token amounts of insurance" - ], - "type": "u32" + "name": "fuelBoostTaker", + "type": { + "option": "u8" + } }, { - "name": "fuelDeposits", - "docs": [ - "accumulated fuel for notional of deposits" - ], - "type": "u32" + "name": "fuelBoostMaker", + "type": { + "option": "u8" + } }, { - "name": "fuelBorrows", - "docs": [ - "accumulate fuel bonus for notional of borrows" - ], - "type": "u32" + "name": "fuelBoostPosition", + "type": { + "option": "u8" + } }, { - "name": "fuelPositions", - "docs": [ - "accumulated fuel for perp open interest" - ], - "type": "u32" + "name": "takerSpeedBumpOverride", + "type": { + "option": "i8" + } }, { - "name": "fuelTaker", - "docs": [ - "accumulate fuel bonus for taker volume" - ], - "type": "u32" + "name": "oracleSlotDelayOverride", + "type": { + "option": "i8" + } }, { - "name": "fuelMaker", - "docs": [ - "accumulate fuel bonus for maker volume" - ], - "type": "u32" + "name": "ammSpreadAdjustment", + "type": { + "option": "i8" + } }, { - "name": "ifStakedGovTokenAmount", - "docs": [ - "The amount of tokens staked in the governance spot markets if" - ], - "type": "u64" + "name": "ammInventorySpreadAdjustment", + "type": { + "option": "i8" + } }, { - "name": "lastFuelIfBonusUpdateTs", - "docs": [ - "last unix ts user stats data was used to update if fuel (u32 to save space)" - ], - "type": "u32" + "name": "referencePriceOffset", + "type": { + "option": "i32" + } }, { - "name": "padding", + "name": "zeroMmOracleFields", "type": { - "array": [ - "u8", - 12 - ] + "option": "bool" } - } - ] - } - }, - { - "name": "ReferrerName", - "type": { - "kind": "struct", - "fields": [ - { - "name": "authority", - "type": "publicKey" }, { - "name": "user", - "type": "publicKey" + "name": "expiryTs", + "type": { + "option": "i64" + } }, { - "name": "userStats", - "type": "publicKey" + "name": "concentrationScale", + "type": { + "option": "u128" + } }, { - "name": "name", + "name": "curveUpdateIntensity", "type": { - "array": [ - "u8", - 32 - ] + "option": "u8" } } ] } }, { - "name": "FuelOverflow", + "name": "StateUpdateParams", "type": { "kind": "struct", "fields": [ { - "name": "authority", - "docs": [ - "The authority of this overflow account" - ], - "type": "publicKey" - }, - { - "name": "fuelInsurance", - "type": "u128" + "name": "lpCooldownTime", + "type": { + "option": "u64" + } }, { - "name": "fuelDeposits", - "type": "u128" + "name": "initialPctToLiquidate", + "type": { + "option": "u16" + } }, { - "name": "fuelBorrows", - "type": "u128" + "name": "liquidationDuration", + "type": { + "option": "u8" + } }, { - "name": "fuelPositions", - "type": "u128" + "name": "liquidationMarginBufferRatio", + "type": { + "option": "u32" + } }, { - "name": "fuelTaker", - "type": "u128" + "name": "settlementDuration", + "type": { + "option": "u16" + } }, { - "name": "fuelMaker", - "type": "u128" + "name": "maxNumberOfSubAccounts", + "type": { + "option": "u16" + } }, { - "name": "lastFuelSweepTs", - "type": "u32" + "name": "maxInitializeUserFee", + "type": { + "option": "u16" + } }, { - "name": "lastResetTs", - "type": "u32" + "name": "admin", + "type": { + "option": "publicKey" + } }, { - "name": "padding", + "name": "whitelistMint", "type": { - "array": [ - "u128", - 6 - ] + "option": "publicKey" } - } - ] - } - } - ], - "types": [ - { - "name": "UpdatePerpMarketSummaryStatsParams", - "type": { - "kind": "struct", - "fields": [ + }, { - "name": "quoteAssetAmountWithUnsettledLp", + "name": "discountMint", "type": { - "option": "i64" + "option": "publicKey" } }, { - "name": "netUnsettledFundingPnl", + "name": "exchangeStatus", "type": { - "option": "i64" + "option": "u8" } }, { - "name": "updateAmmSummaryStats", + "name": "minPerpAuctionDuration", "type": { - "option": "bool" + "option": "u8" } }, { - "name": "excludeTotalLiqFee", + "name": "defaultSpotAuctionDuration", "type": { - "option": "bool" + "option": "u8" } } ] @@ -16806,8 +15769,5 @@ "name": "RevenueShareOrderNotFound", "msg": "RevenueShare order not found" } - ], - "metadata": { - "address": "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH" - } + ] } \ No newline at end of file