Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

program: maker trigger market oracle offset and fill with amm faster #1564

Merged
merged 8 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: maker trigger market oracle offset and fill with amm faster ([#1564](https://github.com/drift-labs/protocol-v2/pull/1564))
- program: sanitize signed msg orders with wider thresholds ([#1554](https://github.com/drift-labs/protocol-v2/pull/1554))

### Fixes
Expand Down
25 changes: 11 additions & 14 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ use crate::state::state::FeeStructure;
use crate::state::state::*;
use crate::state::traits::Size;
use crate::state::user::{
AssetType, Order, OrderStatus, OrderTriggerCondition, OrderType, UserStats,
AssetType, Order, OrderBitFlag, OrderStatus, OrderTriggerCondition, OrderType, UserStats,
};
use crate::state::user::{MarketType, User};
use crate::state::user_map::{UserMap, UserStatsMap};
Expand Down Expand Up @@ -951,7 +951,6 @@ pub fn fill_perp_order(
order_oracle_price_offset,
order_direction,
order_auction_duration,
order_posted_slot_tail,
) = get_struct_values!(
user.orders[order_index],
status,
Expand All @@ -960,8 +959,7 @@ pub fn fill_perp_order(
price,
oracle_price_offset,
direction,
auction_duration,
posted_slot_tail
auction_duration
);

validate!(
Expand Down Expand Up @@ -1235,17 +1233,9 @@ pub fn fill_perp_order(
return Ok((0, 0));
}

let clock_slot_tail = get_posted_slot_from_clock_slot(slot);

let amm_availability = if amm_is_available {
if amm_can_skip_duration && user_can_skip_duration {
AMMAvailability::Immediate
} else if !user_can_skip_duration
&& (clock_slot_tail.wrapping_sub(order_posted_slot_tail)
< state.min_perp_auction_duration)
{
msg!("Overriding amm to unavailable for user atomic fill");
AMMAvailability::Unavailable
} else {
AMMAvailability::AfterMinDuration
}
Expand Down Expand Up @@ -1671,6 +1661,7 @@ fn get_referrer_info(
if referrer.pool_id != 0 {
return Ok(None);
}

referrer.update_last_active_slot(slot);
referrer_user_key = *referrer_key;
break;
Expand Down Expand Up @@ -2959,7 +2950,7 @@ pub fn trigger_order(
&mut user.orders[order_index],
oracle_price_data,
slot,
30,
20,
Some(&perp_market),
)?;

Expand Down Expand Up @@ -3064,6 +3055,10 @@ fn update_trigger_order_params(
}
};

if slot.saturating_sub(order.slot) > 150 && order.reduce_only {
order.add_bit_flag(OrderBitFlag::SafeTriggerOrder);
}

order.slot = slot;

let (auction_duration, auction_start_price, auction_end_price) =
Expand All @@ -3085,6 +3080,8 @@ fn update_trigger_order_params(
order.auction_start_price = auction_start_price;
order.auction_end_price = auction_end_price;

order.add_bit_flag(OrderBitFlag::OracleTriggerMarket);

Ok(())
}

Expand Down Expand Up @@ -5305,7 +5302,7 @@ pub fn trigger_spot_order(
&mut user.orders[order_index],
oracle_price_data,
slot,
30,
20,
None,
)?;

Expand Down
2 changes: 1 addition & 1 deletion programs/drift/src/instructions/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use crate::state::fulfillment_params::serum::SerumFulfillmentParams;
use crate::state::high_leverage_mode_config::HighLeverageModeConfig;
use crate::state::insurance_fund_stake::InsuranceFundStake;
use crate::state::oracle_map::OracleMap;
use crate::state::order_params::{OrderParams, PlaceOrderOptions, SignedMsgOrderParamsMessage};
use crate::state::order_params::{OrderParams, PlaceOrderOptions};
use crate::state::paused_operations::{PerpOperation, SpotOperation};
use crate::state::perp_market::{ContractType, MarketStatus, PerpMarket};
use crate::state::perp_market_map::{
Expand Down
45 changes: 40 additions & 5 deletions programs/drift/src/math/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ use crate::math::orders::standardize_price;
use crate::math::safe_math::SafeMath;
use crate::msg;
use crate::state::oracle::OraclePriceData;
use crate::state::user::{Order, OrderType};
use crate::state::perp_market::ContractTier;
use crate::state::user::{Order, OrderBitFlag, OrderType};

use crate::state::fill_mode::FillMode;
use crate::state::perp_market::{AMMAvailability, PerpMarket};
use crate::{OrderParams, MAX_PREDICTION_MARKET_PRICE};
use std::cmp::min;

use super::orders::get_posted_slot_from_clock_slot;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -89,6 +92,15 @@ pub fn calculate_auction_price(
is_prediction_market: bool,
) -> DriftResult<u64> {
match order.order_type {
OrderType::TriggerMarket if order.is_bit_flag_set(OrderBitFlag::OracleTriggerMarket) => {
calculate_auction_price_for_oracle_offset_auction(
order,
slot,
tick_size,
valid_oracle_price,
is_prediction_market,
)
}
OrderType::Market | OrderType::TriggerMarket | OrderType::TriggerLimit => {
calculate_auction_price_for_fixed_auction(order, slot, tick_size)
}
Expand Down Expand Up @@ -242,7 +254,20 @@ pub fn is_amm_available_liquidity_source(
slot: u64,
fill_mode: FillMode,
) -> DriftResult<bool> {
Ok(is_auction_complete(order.slot, min_auction_duration, slot)? || fill_mode.is_liquidation())
if fill_mode.is_liquidation() {
return Ok(true);
}

if order.is_bit_flag_set(OrderBitFlag::SafeTriggerOrder) {
return Ok(true);
}

if order.is_signed_msg() {
let clock_slot_tail = get_posted_slot_from_clock_slot(slot);
return Ok(clock_slot_tail.wrapping_sub(order.posted_slot_tail) >= min_auction_duration);
}

Ok(is_auction_complete(order.slot, min_auction_duration, slot)?)
}

pub fn calculate_auction_params_for_trigger_order(
Expand All @@ -254,13 +279,23 @@ pub fn calculate_auction_params_for_trigger_order(
let auction_duration = min_auction_duration;

if let Some(perp_market) = perp_market {
// negative buffer is crossing
let auction_start_buffer = if perp_market
.contract_tier
.is_as_safe_as_contract(&ContractTier::B)
{
-500
} else {
-3_500
};

let (auction_start_price, auction_end_price, derived_auction_duration) =
OrderParams::derive_market_order_auction_params(
OrderParams::derive_oracle_order_auction_params(
perp_market,
order.direction,
oracle_price_data.price,
order.price,
0,
None,
auction_start_buffer,
)?;

let auction_duration = auction_duration.max(derived_auction_duration);
Expand Down
6 changes: 3 additions & 3 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::math::auction::is_amm_available_liquidity_source;
use crate::math::casting::Cast;
use crate::state::fill_mode::FillMode;
use crate::state::protected_maker_mode_config::ProtectedMakerParams;
use crate::state::user::OrderBitFlag;
use crate::{
load, math, FeeTier, State, BASE_PRECISION_I128, FEE_ADJUSTMENT_MAX,
MAX_PREDICTION_MARKET_PRICE, MAX_PREDICTION_MARKET_PRICE_I64, OPEN_ORDER_MARGIN_REQUIREMENT,
Expand Down Expand Up @@ -1398,12 +1399,11 @@ pub fn get_posted_slot_from_clock_slot(slot: u64) -> u8 {
}

// Bit flag operators
pub const FLAG_IS_SIGNED_MSG: u8 = 0x01;
pub fn set_is_signed_msg_flag(mut flags: u8, value: bool) -> u8 {
if value {
flags |= FLAG_IS_SIGNED_MSG;
flags |= OrderBitFlag::SignedMessage as u8;
} else {
flags &= !FLAG_IS_SIGNED_MSG;
flags &= !(OrderBitFlag::SignedMessage as u8);
}
flags
}
23 changes: 16 additions & 7 deletions programs/drift/src/state/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ use crate::math::constants::{
use crate::math::lp::{calculate_lp_open_bids_asks, calculate_settle_lp_metrics};
use crate::math::margin::MarginRequirementType;
use crate::math::orders::{
apply_protected_maker_limit_price_offset, set_is_signed_msg_flag,
standardize_base_asset_amount, standardize_price, FLAG_IS_SIGNED_MSG,
apply_protected_maker_limit_price_offset, standardize_base_asset_amount, standardize_price,
};
use crate::math::position::{
calculate_base_asset_value_and_pnl_with_oracle_price,
Expand Down Expand Up @@ -1602,13 +1601,16 @@ impl Order {
Ok(self.post_only || self.is_auction_complete(slot)?)
}

// Bit flags here
pub fn set_signed_msg(&mut self, value: bool) {
self.bit_flags = set_is_signed_msg_flag(self.bit_flags, value)
pub fn is_signed_msg(&self) -> bool {
self.is_bit_flag_set(OrderBitFlag::SignedMessage)
}

pub fn is_signed_msg(&self) -> bool {
(self.bit_flags & FLAG_IS_SIGNED_MSG) != 0
pub fn add_bit_flag(&mut self, flag: OrderBitFlag) {
self.bit_flags |= flag as u8;
}

pub fn is_bit_flag_set(&self, flag: OrderBitFlag) -> bool {
(self.bit_flags & flag as u8) != 0
}

pub fn is_available(&self) -> bool {
Expand Down Expand Up @@ -1697,6 +1699,13 @@ impl fmt::Display for MarketType {
}
}

#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, PartialEq, Debug, Eq)]
pub enum OrderBitFlag {
SignedMessage = 0b00000001,
OracleTriggerMarket = 0b00000010,
SafeTriggerOrder = 0b00000100,
}

#[account(zero_copy(unsafe))]
#[derive(Eq, PartialEq, Debug)]
#[repr(C)]
Expand Down
1 change: 0 additions & 1 deletion programs/drift/src/validation/sig_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use solana_program::instruction::Instruction;
use solana_program::program_memory::sol_memcmp;
use solana_program::sysvar;
use std::convert::TryInto;
use std::f32::consts::E;

const ED25519_PROGRAM_INPUT_HEADER_LEN: usize = 2;

Expand Down
2 changes: 1 addition & 1 deletion programs/drift/src/validation/user.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::{DriftResult, ErrorCode};
use crate::msg;
use crate::state::spot_market::SpotBalanceType;
use crate::state::user::{OrderStatus, User, UserStats};
use crate::state::user::{User, UserStats};
use crate::{validate, State, THIRTEEN_DAY};

pub fn validate_user_deletion(
Expand Down
12 changes: 9 additions & 3 deletions sdk/src/math/auction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isOneOfVariant, isVariant, Order, PositionDirection } from '../types';
import { BN, getVariant, ONE, ZERO } from '../.';
import { BN, getVariant, ONE, OrderBitFlag, ZERO } from '../.';

export function isAuctionComplete(order: Order, slot: number): boolean {
if (order.auctionDuration === 0) {
Expand Down Expand Up @@ -27,7 +27,9 @@ export function getAuctionPrice(
oraclePrice: BN
): BN {
if (
isOneOfVariant(order.orderType, ['market', 'triggerMarket', 'triggerLimit'])
isOneOfVariant(order.orderType, ['market', 'triggerLimit']) ||
(isVariant(order.orderType, 'triggerMarket') &&
(order.bitFlags & OrderBitFlag.OracleTriggerMarket) === 0)
) {
return getAuctionPriceForFixedAuction(order, slot);
} else if (isVariant(order.orderType, 'limit')) {
Expand All @@ -36,7 +38,11 @@ export function getAuctionPrice(
} else {
return getAuctionPriceForFixedAuction(order, slot);
}
} else if (isVariant(order.orderType, 'oracle')) {
} else if (
isVariant(order.orderType, 'oracle') ||
(isVariant(order.orderType, 'triggerMarket') &&
(order.bitFlags & OrderBitFlag.OracleTriggerMarket) !== 0)
) {
return getAuctionPriceForOracleOffsetAuction(order, slot, oraclePrice);
} else {
throw Error(
Expand Down
6 changes: 6 additions & 0 deletions sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ export class OrderStatus {
static readonly CANCELED = { canceled: {} };
}

export class OrderBitFlag {
static readonly SignedMessage = 1;
static readonly OracleTriggerMarket = 2;
static readonly SafeTriggerOrder = 4;
}

export class OrderAction {
static readonly PLACE = { place: {} };
static readonly CANCEL = { cancel: {} };
Expand Down
Loading