Skip to content

Commit

Permalink
program: limit order auctions (#355)
Browse files Browse the repository at this point in the history
* new is_amm_available_liquidity_source

* tweak how trigger orders work

* tweak get_limit_price to allow limit orders to have auction price

* allow limit order to pass auction params

* do order validation

* make the resting limit order logic based on auction being complete

* dlob trigger order matches on chain

* ts client reflects price changes

* fix ts dlob tests

* add rust tests

* add failing test

* prototype of updateRestingLimitOrders

* address pr feedback

* program: tweak calculate_size_premium_liability_weight to have smaller effect on initial margin (#350)

* bigz/improve-calculate_size_premium_liability_weight

* fmt fix

* margin.ts: sync w/ contract

* CHANGELOG

---------

Co-authored-by: Chris Heaney <chrisheaney30@gmail.com>

* v2.16.0-beta.2

* sdk: fix borrow limit calc (#356)

* update CHANGELOG.md

* sdk: new squareRootBN implementation using bit shifting

* sdk: change modify order params to be object (#353)

* sdk: change modify order params to be object

* Update CHANGELOG.md

* sdk: DLOB matching logic accounts for zero-price spot market orders not matching resting limit orders

* v2.16.0-beta.3

* sdk: add market lookup table (#359)

* sdk: add look up table to config

* add ability to send version tx with retry sender

* tweak LOOK UP to LOOKUP

* add fetchMarketLookupTableAccount to driftClient

* CHANGELOG

* v2.16.0

* getMarketBids/Asks becomes getTakingBids/Asks

* remove updateRestingLimitOrder from getbestNode

* tests working

* update isFallbackAvailableLiquiditySource

* tweak is_maker_for_taker

* tweaks

* fix updateRestingLimitOrders

* add test for updating resting limit ordres

* add tests for is_maker_for_taker

* fix broken ts test

* tweak some syntax choices

* simplify is_maker_for_taker

* dont let auction prices be zero for market or limit orders

* tweak findJitAuctionNodesToFill

* CHANGELOG

---------

Co-authored-by: bigzPubkey <zane@lunoho.company>
Co-authored-by: wphan <william@drift.trade>
Co-authored-by: Evan Pipta <3pipta@gmail.com>
Co-authored-by: 0xbigz <83473873+0xbigz@users.noreply.github.com>
  • Loading branch information
5 people authored Feb 20, 2023
1 parent b0a6250 commit 0c4a4ba
Show file tree
Hide file tree
Showing 18 changed files with 1,674 additions and 331 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Features

- program: allow limit orders to go through auction ([#355](https://github.com/drift-labs/protocol-v2/pull/355))
- program: improve conditions for withdraw/borrow guard ([#354](https://github.com/drift-labs/protocol-v2/pull/354))

### Fixes
Expand Down
95 changes: 52 additions & 43 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::cell::RefMut;
use std::cmp::max;
use std::num::NonZeroU64;
use std::ops::DerefMut;

Expand Down Expand Up @@ -29,7 +28,7 @@ use crate::get_struct_values;
use crate::get_then_update_id;
use crate::instructions::OrderParams;
use crate::load_mut;
use crate::math::auction::{calculate_auction_prices, is_auction_complete};
use crate::math::auction::{calculate_auction_prices, is_amm_available_liquidity_source};
use crate::math::casting::Cast;
use crate::math::constants::{
BASE_PRECISION_U64, FEE_POOL_TO_REVENUE_POOL_THRESHOLD, FIVE_MINUTE, ONE_HOUR, PERP_DECIMALS,
Expand Down Expand Up @@ -207,20 +206,19 @@ pub fn place_perp_order(
};

let oracle_price_data = oracle_map.get_price_data(&market.amm.oracle)?;
let (auction_start_price, auction_end_price) =
get_auction_prices(&params, oracle_price_data, market.amm.order_tick_size)?;
let (auction_start_price, auction_end_price, auction_duration) = get_auction_params(
&params,
oracle_price_data,
market.amm.order_tick_size,
state.min_perp_auction_duration,
)?;

validate!(
params.market_type == MarketType::Perp,
ErrorCode::InvalidOrderMarketType,
"must be perp order"
)?;

let auction_duration = max(
params.auction_duration.unwrap_or(0),
state.min_perp_auction_duration,
);

let new_order = Order {
status: OrderStatus::Open,
order_type: params.order_type,
Expand Down Expand Up @@ -371,13 +369,31 @@ pub fn place_perp_order(
Ok(())
}

fn get_auction_prices(
fn get_auction_params(
params: &OrderParams,
oracle_price_data: &OraclePriceData,
tick_size: u64,
) -> DriftResult<(i64, i64)> {
if !matches!(params.order_type, OrderType::Market | OrderType::Oracle) {
return Ok((0_i64, 0_i64));
min_auction_duration: u8,
) -> DriftResult<(i64, i64, u8)> {
if !matches!(
params.order_type,
OrderType::Market | OrderType::Oracle | OrderType::Limit
) {
return Ok((0_i64, 0_i64, 0_u8));
}

let auction_duration = params
.auction_duration
.unwrap_or(0)
.max(min_auction_duration);

if params.order_type == OrderType::Limit {
return match (params.auction_start_price, params.auction_end_price) {
(Some(auction_start_price), Some(auction_end_price)) => {
Ok((auction_start_price, auction_end_price, auction_duration))
}
_ => Ok((0_i64, 0_i64, 0_u8)),
};
}

let (auction_start_price, auction_end_price) =
Expand All @@ -395,6 +411,7 @@ fn get_auction_prices(
Ok((
standardize_price_i64(auction_start_price, tick_size.cast()?, params.direction)?,
standardize_price_i64(auction_end_price, tick_size.cast()?, params.direction)?,
auction_duration,
))
}

Expand Down Expand Up @@ -856,6 +873,7 @@ pub fn fill_perp_order(
valid_oracle_price,
now,
slot,
state.min_perp_auction_duration,
amm_is_available,
)?;

Expand Down Expand Up @@ -1076,11 +1094,12 @@ fn sanitize_maker_order<'a>(
let maker_order_price = *maker_order_price;

let maker_order = &maker.orders[maker_order_index];
if !is_maker_for_taker(maker_order, taker_order)? {
if !is_maker_for_taker(maker_order, taker_order, slot)? {
continue;
}

if !maker_order.is_resting_limit_order(slot)? || maker_order.is_jit_maker() {
// dont use maker if order is < 45 slots old and cross amm
if slot.safe_sub(maker_order.slot)? < 45 {
match maker_direction {
PositionDirection::Long => {
if maker_order_price >= amm_ask_price {
Expand Down Expand Up @@ -1258,6 +1277,7 @@ fn fulfill_perp_order(
valid_oracle_price: Option<i64>,
now: i64,
slot: u64,
min_auction_duration: u8,
amm_is_available: bool,
) -> DriftResult<(u64, bool, bool)> {
let market_index = user.orders[user_order_index].market_index;
Expand Down Expand Up @@ -1287,6 +1307,7 @@ fn fulfill_perp_order(
Some(oracle_price),
amm_is_available,
slot,
min_auction_duration,
)?
};

Expand Down Expand Up @@ -1347,6 +1368,7 @@ fn fulfill_perp_order(
valid_oracle_price,
now,
slot,
min_auction_duration,
fee_structure,
oracle_map,
&mut order_records,
Expand Down Expand Up @@ -1764,6 +1786,7 @@ pub fn fulfill_perp_order_with_match(
valid_oracle_price: Option<i64>,
now: i64,
slot: u64,
min_auction_duration: u8,
fee_structure: &FeeStructure,
oracle_map: &mut OracleMap,
order_records: &mut Vec<OrderActionRecord>,
Expand Down Expand Up @@ -1816,7 +1839,11 @@ pub fn fulfill_perp_order_with_match(
// if the auction isn't complete, cant fill against vamm yet
// use the vamm price to guard against bad fill for taker
if taker.orders[taker_order_index].is_limit_order()
&& !taker.orders[taker_order_index].is_auction_complete(slot)?
&& !is_amm_available_liquidity_source(
&taker.orders[taker_order_index],
min_auction_duration,
slot,
)?
{
taker_price = match taker_direction {
PositionDirection::Long => {
Expand Down Expand Up @@ -2298,14 +2325,6 @@ pub fn trigger_order(

let oracle_price = oracle_price_data.price;

let order_slot = user.orders[order_index].slot;
let auction_duration = user.orders[order_index].auction_duration;
validate!(
is_auction_complete(order_slot, auction_duration, slot)?,
ErrorCode::OrderDidNotSatisfyTriggerCondition,
"Auction duration must elapse before triggering"
)?;

let can_trigger = order_satisfies_trigger_condition(
&user.orders[order_index],
oracle_price.unsigned_abs().cast()?,
Expand All @@ -2328,6 +2347,7 @@ pub fn trigger_order(
user.orders[order_index].slot = slot;
let order_type = user.orders[order_index].order_type;
if let OrderType::TriggerMarket = order_type {
user.orders[order_index].auction_duration = state.min_perp_auction_duration;
let (auction_start_price, auction_end_price) =
calculate_auction_prices(oracle_price_data, direction, 0)?;
user.orders[order_index].auction_start_price = auction_start_price;
Expand Down Expand Up @@ -2712,8 +2732,12 @@ pub fn place_spot_order(
)
};

let (auction_start_price, auction_end_price) =
get_auction_prices(&params, &oracle_price_data, spot_market.order_tick_size)?;
let (auction_start_price, auction_end_price, auction_duration) = get_auction_params(
&params,
&oracle_price_data,
spot_market.order_tick_size,
state.default_spot_auction_duration,
)?;

validate!(spot_market.orders_enabled, ErrorCode::SpotOrdersDisabled)?;

Expand All @@ -2729,10 +2753,6 @@ pub fn place_spot_order(
"must be spot order"
)?;

let auction_duration = params
.auction_duration
.unwrap_or(state.default_spot_auction_duration);

let new_order = Order {
status: OrderStatus::Open,
order_type: params.order_type,
Expand Down Expand Up @@ -3153,11 +3173,7 @@ fn sanitize_spot_maker_order<'a>(

{
let maker_order = &maker.orders[maker_order_index];
if !is_maker_for_taker(maker_order, taker_order)? {
return Ok((None, None, None, None));
}

if !maker_order.is_resting_limit_order(slot)? {
if !is_maker_for_taker(maker_order, taker_order, slot)? {
return Ok((None, None, None, None));
}

Expand Down Expand Up @@ -4282,14 +4298,6 @@ pub fn trigger_spot_order(

let oracle_price = oracle_price_data.price;

let order_slot = user.orders[order_index].slot;
let auction_duration = user.orders[order_index].auction_duration;
validate!(
is_auction_complete(order_slot, auction_duration, slot)?,
ErrorCode::OrderDidNotSatisfyTriggerCondition,
"Auction duration must elapse before triggering"
)?;

let can_trigger = order_satisfies_trigger_condition(
&user.orders[order_index],
oracle_price.unsigned_abs().cast()?,
Expand All @@ -4311,6 +4319,7 @@ pub fn trigger_spot_order(
user.orders[order_index].slot = slot;
let order_type = user.orders[order_index].order_type;
if let OrderType::TriggerMarket = order_type {
user.orders[order_index].auction_duration = state.default_spot_auction_duration;
let (auction_start_price, auction_end_price) =
calculate_auction_prices(oracle_price_data, direction, 0)?;
user.orders[order_index].auction_start_price = auction_start_price;
Expand Down
12 changes: 12 additions & 0 deletions programs/drift/src/controller/orders/amm_jit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ pub mod amm_jit {
Some(market.amm.historical_oracle_data.last_oracle_price),
now,
slot,
0,
true,
)
.unwrap();
Expand Down Expand Up @@ -469,6 +470,7 @@ pub mod amm_jit {
Some(PRICE_PRECISION_I64),
now,
slot,
10,
true,
)
.unwrap();
Expand Down Expand Up @@ -651,6 +653,7 @@ pub mod amm_jit {
Some(PRICE_PRECISION_I64),
now,
slot,
10,
true,
)
.unwrap();
Expand Down Expand Up @@ -833,6 +836,7 @@ pub mod amm_jit {
Some(200 * PRICE_PRECISION_I64),
now,
slot,
10,
true,
)
.unwrap();
Expand Down Expand Up @@ -1023,6 +1027,7 @@ pub mod amm_jit {
Some(market.amm.historical_oracle_data.last_oracle_price),
now,
slot,
0,
true,
)
.unwrap();
Expand Down Expand Up @@ -1221,6 +1226,7 @@ pub mod amm_jit {
Some(market.amm.historical_oracle_data.last_oracle_price),
now,
slot,
0,
true,
)
.unwrap();
Expand Down Expand Up @@ -1419,6 +1425,7 @@ pub mod amm_jit {
Some(market.amm.historical_oracle_data.last_oracle_price),
now,
slot,
0,
true,
)
.unwrap();
Expand Down Expand Up @@ -1593,6 +1600,7 @@ pub mod amm_jit {
Some(1),
now,
slot,
10,
true,
)
.unwrap();
Expand Down Expand Up @@ -1778,6 +1786,7 @@ pub mod amm_jit {
Some(200 * PRICE_PRECISION_I64),
now,
slot,
10,
true,
)
.unwrap();
Expand Down Expand Up @@ -2014,6 +2023,7 @@ pub mod amm_jit {
Some(1),
now,
slot,
auction_duration,
true,
)
.unwrap();
Expand Down Expand Up @@ -2284,6 +2294,7 @@ pub mod amm_jit {
Some(200 * PRICE_PRECISION_I64),
now,
slot,
10,
true,
)
.unwrap();
Expand Down Expand Up @@ -2496,6 +2507,7 @@ pub mod amm_jit {
Some(1),
now,
slot,
0,
true,
)
.unwrap();
Expand Down
Loading

0 comments on commit 0c4a4ba

Please sign in to comment.