Skip to content

Commit

Permalink
program: reduce cu's in place_spot_order (#662)
Browse files Browse the repository at this point in the history
* program: add get_worst_case_base_asset_amount for spot

* update

* remove unused code

* add better validate for force only orders

* CHANGELOG
  • Loading branch information
crispheaney authored Oct 24, 2023
1 parent 9cfe390 commit f2b7d2e
Show file tree
Hide file tree
Showing 12 changed files with 384 additions and 262 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- program: reduce cus for place_spot_order ([#662](https://github.com/drift-labs/protocol-v2/pull/662))
- program: bump max sub accounts to 15k
- program: user custom margin ratio works with spot ([#633](https://github.com/drift-labs/protocol-v2/pull/633))
- program: add swap price bands ([#611](https://github.com/drift-labs/protocol-v2/pull/611))
Expand Down
81 changes: 35 additions & 46 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::u64;
use anchor_lang::prelude::*;
use solana_program::msg;

use crate::controller;
use crate::controller::funding::settle_funding_payment;
use crate::controller::position;
use crate::controller::position::{
Expand All @@ -23,7 +24,8 @@ use crate::controller::spot_position::{
};
use crate::error::DriftResult;
use crate::error::ErrorCode;
use crate::instructions::{OrderParams, PlaceOrderOptions};
use crate::get_struct_values;
use crate::get_then_update_id;
use crate::load_mut;
use crate::math::amm_jit::calculate_amm_jit_liquidity;
use crate::math::auction::calculate_auction_prices;
Expand All @@ -47,9 +49,9 @@ use crate::math::safe_math::SafeMath;
use crate::math::spot_balance::{get_signed_token_amount, get_token_amount};
use crate::math::stats::calculate_new_twap;
use crate::math::{amm, fees, margin::*, orders::*};
use crate::{controller, PostOnlyParam};
use crate::{get_struct_values, ModifyOrderParams};
use crate::{get_then_update_id, ModifyOrderPolicy};
use crate::state::order_params::{
ModifyOrderParams, ModifyOrderPolicy, OrderParams, PlaceOrderOptions, PostOnlyParam,
};

use crate::math::amm::calculate_amm_available_liquidity;
use crate::math::safe_unwrap::SafeUnwrap;
Expand All @@ -76,7 +78,9 @@ use crate::state::user::{MarketType, User};
use crate::state::user_map::{UserMap, UserStatsMap};
use crate::validate;
use crate::validation;
use crate::validation::order::{validate_order, validate_spot_order};
use crate::validation::order::{
validate_order, validate_order_for_force_reduce_only, validate_spot_order,
};

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -181,9 +185,6 @@ pub fn place_perp_order(
let position_index = get_position_index(&user.perp_positions, market_index)
.or_else(|_| add_new_position(&mut user.perp_positions, market_index))?;

let worst_case_base_asset_amount_before =
user.perp_positions[position_index].worst_case_base_asset_amount()?;

// Increment open orders for existing position
let (existing_position_direction, order_base_asset_amount) = {
validate!(
Expand Down Expand Up @@ -279,6 +280,13 @@ pub fn place_perp_order(
Err(err) => return Err(err),
};

let risk_increasing = is_new_order_risk_increasing(
&new_order,
user.perp_positions[position_index].base_asset_amount,
user.perp_positions[position_index].open_bids,
user.perp_positions[position_index].open_asks,
)?;

user.increment_open_orders(new_order.has_auction());
user.orders[new_order_index] = new_order;
user.perp_positions[position_index].open_orders += 1;
Expand All @@ -290,12 +298,6 @@ pub fn place_perp_order(
)?;
}

let worst_case_base_asset_amount_after =
user.perp_positions[position_index].worst_case_base_asset_amount()?;

let risk_increasing = worst_case_base_asset_amount_after.unsigned_abs()
> worst_case_base_asset_amount_before.unsigned_abs();

options.update_risk_increasing(risk_increasing);

// when orders are placed in bulk, only need to check margin on last place
Expand All @@ -309,8 +311,11 @@ pub fn place_perp_order(
)?;
}

if force_reduce_only && risk_increasing {
return Err(ErrorCode::InvalidOrderNotRiskReducing);
if force_reduce_only {
validate_order_for_force_reduce_only(
&user.orders[new_order_index],
user.perp_positions[position_index].base_asset_amount,
)?;
}

let max_oi = market.amm.max_open_interest;
Expand Down Expand Up @@ -2856,21 +2861,6 @@ pub fn place_spot_order(
let signed_token_amount = get_signed_token_amount(token_amount, &balance_type)?;

let oracle_price_data = *oracle_map.get_price_data(&spot_market.oracle)?;
let strict_oracle_price = StrictOraclePrice::new(
oracle_price_data.price,
spot_market
.historical_oracle_data
.last_oracle_price_twap_5min,
true,
);

let worst_case_simulation_before = user.spot_positions[spot_position_index]
.get_worst_case_token_amount(
spot_market,
&strict_oracle_price,
Some(signed_token_amount),
MarginRequirementType::Initial,
)?;

// Increment open orders for existing position
let (existing_position_direction, order_base_asset_amount) = {
Expand Down Expand Up @@ -2972,6 +2962,13 @@ pub fn place_spot_order(
spot_market.min_order_size,
)?;

let risk_increasing = is_new_order_risk_increasing(
&new_order,
signed_token_amount.cast()?,
user.spot_positions[spot_position_index].open_bids,
user.spot_positions[spot_position_index].open_asks,
)?;

user.increment_open_orders(new_order.has_auction());
user.orders[new_order_index] = new_order;
user.spot_positions[spot_position_index].open_orders += 1;
Expand All @@ -2983,17 +2980,6 @@ pub fn place_spot_order(
)?;
}

let worst_case_simulation_after = user.spot_positions[spot_position_index]
.get_worst_case_token_amount(
spot_market,
&strict_oracle_price,
Some(signed_token_amount),
MarginRequirementType::Initial,
)?;

// Order fails if it's risk increasing and it brings the user collateral below the margin requirement
let risk_increasing = worst_case_simulation_before.risk_increasing(worst_case_simulation_after);

options.update_risk_increasing(risk_increasing);

if options.enforce_margin_check {
Expand All @@ -3008,8 +2994,11 @@ pub fn place_spot_order(

validate_spot_margin_trading(user, spot_market_map, oracle_map)?;

if force_reduce_only && risk_increasing {
return Err(ErrorCode::InvalidOrderNotRiskReducing);
if force_reduce_only {
validate_order_for_force_reduce_only(
&user.orders[new_order_index],
signed_token_amount.cast()?,
)?;
}

let (taker, taker_order, maker, maker_order) =
Expand Down Expand Up @@ -4445,7 +4434,7 @@ pub fn trigger_spot_order(
user.spot_positions[position_index].get_signed_token_amount(&spot_market)?;

let worst_case_simulation_before = user.spot_positions[position_index]
.get_worst_case_token_amount(
.get_worst_case_fill_simulation(
&spot_market,
&strict_oracle_price,
Some(signed_token_amount),
Expand Down Expand Up @@ -4519,7 +4508,7 @@ pub fn trigger_spot_order(

let worst_case_simulation_after = user
.get_spot_position(market_index)?
.get_worst_case_token_amount(
.get_worst_case_fill_simulation(
&spot_market,
&strict_oracle_price,
Some(signed_token_amount),
Expand Down
96 changes: 5 additions & 91 deletions programs/drift/src/instructions/user.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anchor_lang::prelude::*;
use anchor_lang::Discriminator;
use anchor_lang::{prelude::*, AnchorDeserialize, AnchorSerialize};
use anchor_spl::token::{Token, TokenAccount};

use crate::controller::orders::{cancel_orders, ModifyOrderId};
Expand Down Expand Up @@ -43,6 +43,9 @@ use crate::state::fulfillment_params::drift::MatchFulfillmentParams;
use crate::state::fulfillment_params::phoenix::PhoenixFulfillmentParams;
use crate::state::fulfillment_params::serum::SerumFulfillmentParams;
use crate::state::oracle::StrictOraclePrice;
use crate::state::order_params::{
ModifyOrderParams, OrderParams, PlaceOrderOptions, PostOnlyParam,
};
use crate::state::perp_market::MarketStatus;
use crate::state::perp_market_map::{get_writable_perp_market_set, MarketSet};
use crate::state::spot_fulfillment_params::SpotFulfillmentParams;
Expand All @@ -53,9 +56,7 @@ use crate::state::spot_market_map::{
};
use crate::state::state::State;
use crate::state::traits::Size;
use crate::state::user::{
MarketType, OrderTriggerCondition, OrderType, ReferrerName, User, UserStats, UserStatus,
};
use crate::state::user::{MarketType, OrderType, ReferrerName, User, UserStats, UserStatus};
use crate::state::user_map::load_user_maps;
use crate::validate;
use crate::validation::user::validate_user_deletion;
Expand Down Expand Up @@ -738,63 +739,6 @@ pub fn handle_transfer_deposit(
Ok(())
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default, Copy)]
pub struct OrderParams {
pub order_type: OrderType,
pub market_type: MarketType,
pub direction: PositionDirection,
pub user_order_id: u8,
pub base_asset_amount: u64,
pub price: u64,
pub market_index: u16,
pub reduce_only: bool,
pub post_only: PostOnlyParam,
pub immediate_or_cancel: bool,
pub max_ts: Option<i64>,
pub trigger_price: Option<u64>,
pub trigger_condition: OrderTriggerCondition,
pub oracle_price_offset: Option<i32>,
pub auction_duration: Option<u8>,
pub auction_start_price: Option<i64>,
pub auction_end_price: Option<i64>,
}

#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, PartialEq, Debug, Eq)]
pub enum PostOnlyParam {
None,
MustPostOnly, // Tx fails if order can't be post only
TryPostOnly, // Tx succeeds and order not placed if can't be post only
Slide, // Modify price to be post only if can't be post only
}

impl Default for PostOnlyParam {
fn default() -> Self {
PostOnlyParam::None
}
}

pub struct PlaceOrderOptions {
pub try_expire_orders: bool,
pub enforce_margin_check: bool,
pub risk_increasing: bool,
}

impl Default for PlaceOrderOptions {
fn default() -> Self {
Self {
try_expire_orders: true,
enforce_margin_check: true,
risk_increasing: false,
}
}
}

impl PlaceOrderOptions {
pub fn update_risk_increasing(&mut self, risk_increasing: bool) {
self.risk_increasing = self.risk_increasing || risk_increasing;
}
}

#[access_control(
exchange_not_paused(&ctx.accounts.state)
)]
Expand Down Expand Up @@ -978,36 +922,6 @@ pub fn handle_cancel_orders(
Ok(())
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
pub struct ModifyOrderParams {
pub direction: Option<PositionDirection>,
pub base_asset_amount: Option<u64>,
pub price: Option<u64>,
pub reduce_only: Option<bool>,
pub post_only: Option<PostOnlyParam>,
pub immediate_or_cancel: Option<bool>,
pub max_ts: Option<i64>,
pub trigger_price: Option<u64>,
pub trigger_condition: Option<OrderTriggerCondition>,
pub oracle_price_offset: Option<i32>,
pub auction_duration: Option<u8>,
pub auction_start_price: Option<i64>,
pub auction_end_price: Option<i64>,
pub policy: Option<ModifyOrderPolicy>,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Eq, PartialEq)]
pub enum ModifyOrderPolicy {
TryModify,
MustModify,
}

impl Default for ModifyOrderPolicy {
fn default() -> Self {
Self::TryModify
}
}

#[access_control(
exchange_not_paused(&ctx.accounts.state)
)]
Expand Down
1 change: 1 addition & 0 deletions programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use math::{bn, constants::*};
use state::oracle::OracleSource;

use crate::controller::position::PositionDirection;
use crate::state::order_params::{ModifyOrderParams, OrderParams};
use crate::state::perp_market::{ContractTier, MarketStatus};
use crate::state::spot_market::AssetTier;
use crate::state::spot_market::SpotFulfillmentConfigStatus;
Expand Down
2 changes: 1 addition & 1 deletion programs/drift/src/math/margin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info(
weighted_token_value: worst_case_weighted_token_value,
..
} = spot_position
.get_worst_case_token_amount(
.get_worst_case_fill_simulation(
&spot_market,
&strict_oracle_price,
Some(signed_token_amount),
Expand Down
44 changes: 32 additions & 12 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use crate::math::amm::calculate_amm_available_liquidity;
use crate::math::auction::{is_amm_available_liquidity_source, is_auction_complete};
use crate::math::casting::Cast;
use crate::{
load, math, PostOnlyParam, State, BASE_PRECISION_I128, OPEN_ORDER_MARGIN_REQUIREMENT,
PERCENTAGE_PRECISION, PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, QUOTE_PRECISION_I128,
SPOT_WEIGHT_PRECISION, SPOT_WEIGHT_PRECISION_I128,
load, math, State, BASE_PRECISION_I128, OPEN_ORDER_MARGIN_REQUIREMENT, PERCENTAGE_PRECISION,
PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, QUOTE_PRECISION_I128, SPOT_WEIGHT_PRECISION,
SPOT_WEIGHT_PRECISION_I128,
};

use crate::math::constants::MARGIN_PRECISION_U128;
Expand All @@ -28,6 +28,7 @@ use crate::print_error;
use crate::state::margin_calculation::{MarginCalculation, MarginContext};
use crate::state::oracle::{OraclePriceData, StrictOraclePrice};
use crate::state::oracle_map::OracleMap;
use crate::state::order_params::PostOnlyParam;
use crate::state::perp_market::{PerpMarket, AMM};
use crate::state::perp_market_map::PerpMarketMap;
use crate::state::spot_market::SpotMarket;
Expand Down Expand Up @@ -602,17 +603,36 @@ pub fn is_order_risk_decreasing(
})
}

pub fn is_order_risk_increasing(
order_direction: &PositionDirection,
order_base_asset_amount: u64,
pub fn is_new_order_risk_increasing(
order: &Order,
position_base_asset_amount: i64,
position_bids: i64,
position_asks: i64,
) -> DriftResult<bool> {
is_order_risk_decreasing(
order_direction,
order_base_asset_amount,
position_base_asset_amount,
)
.map(|risk_decreasing| !risk_decreasing)
if order.reduce_only {
return Ok(false);
}

match order.direction {
PositionDirection::Long => {
if position_base_asset_amount >= 0 {
return Ok(true);
}

Ok(position_bids.safe_add(order.base_asset_amount.cast()?)?
> position_base_asset_amount.abs())
}
PositionDirection::Short => {
if position_base_asset_amount <= 0 {
return Ok(true);
}

Ok(position_asks
.safe_sub(order.base_asset_amount.cast()?)?
.abs()
> position_base_asset_amount)
}
}
}

pub fn is_order_position_reducing(
Expand Down
Loading

0 comments on commit f2b7d2e

Please sign in to comment.