Skip to content

Commit

Permalink
program: add post only slide for perps (#541)
Browse files Browse the repository at this point in the history
* program: add post only slide for perps

* tests

* add to ts types

* CHANGELOG
  • Loading branch information
crispheaney authored and 0xbigz committed Jul 21, 2023
1 parent dfddf20 commit 21570f3
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 17 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- program: add post only slide for perps ([#541](https://github.com/drift-labs/protocol-v2/pull/541))
- program: allow up to 10000 users

### Fixes
- program: if taker increases free colalteral, check maintenance health ([#538](https://github.com/drift-labs/protocol-v2/pull/345))
- program: improve bid/ask twap update for infrequent trading ([#529](https://github.com/drift-labs/protocol-v2/pull/345))
- program: if taker increases free colalteral, check maintenance health ([#538](https://github.com/drift-labs/protocol-v2/pull/538))
- program: improve bid/ask twap update for infrequent trading ([#529](https://github.com/drift-labs/protocol-v2/pull/529))
- sdk: simplify, mirror contract, and write tests for predicting funding rate function ([#529](https://github.com/drift-labs/protocol-v2/pull/529))

### Breaking
Expand Down
7 changes: 6 additions & 1 deletion programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,12 @@ pub fn place_perp_order(
order_id: get_then_update_id!(user, next_order_id),
user_order_id: params.user_order_id,
market_index: params.market_index,
price: standardize_price(params.price, market.amm.order_tick_size, params.direction)?,
price: get_price_for_perp_order(
params.price,
params.direction,
params.post_only,
&market.amm,
)?,
existing_position_direction,
base_asset_amount: order_base_asset_amount,
base_asset_amount_filled: 0,
Expand Down
1 change: 1 addition & 0 deletions programs/drift/src/instructions/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ 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 {
Expand Down
42 changes: 28 additions & 14 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::math::amm::calculate_amm_available_liquidity;
use crate::math::auction::is_auction_complete;
use crate::math::casting::Cast;
use crate::{
math, BASE_PRECISION_I128, OPEN_ORDER_MARGIN_REQUIREMENT, PERCENTAGE_PRECISION,
math, PostOnlyParam, BASE_PRECISION_I128, OPEN_ORDER_MARGIN_REQUIREMENT, PERCENTAGE_PRECISION,
PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, QUOTE_PRECISION_I128, SPOT_WEIGHT_PRECISION,
};

Expand All @@ -25,7 +25,7 @@ use crate::math::spot_withdraw::get_max_withdraw_for_market_with_token_amount;
use crate::math_error;
use crate::print_error;
use crate::state::oracle_map::OracleMap;
use crate::state::perp_market::PerpMarket;
use crate::state::perp_market::{PerpMarket, AMM};
use crate::state::perp_market_map::PerpMarketMap;
use crate::state::spot_market::{SpotBalanceType, SpotMarket};
use crate::state::spot_market_map::SpotMarketMap;
Expand Down Expand Up @@ -255,19 +255,33 @@ pub fn standardize_price_i64(
}
}

#[cfg(test)]
mod test2 {
use crate::controller::position::PositionDirection;
use crate::math::orders::standardize_price_i64;

#[test]
fn test() {
let price = -1001_i64;

let result = standardize_price_i64(price, 100, PositionDirection::Long).unwrap();

println!("result {}", result);
pub fn get_price_for_perp_order(
price: u64,
direction: PositionDirection,
post_only: PostOnlyParam,
amm: &AMM,
) -> DriftResult<u64> {
let mut limit_price = standardize_price(price, amm.order_tick_size, direction)?;

if post_only == PostOnlyParam::Slide {
let reserve_price = amm.reserve_price()?;
match direction {
PositionDirection::Long => {
let amm_ask = amm.ask_price(reserve_price)?;
if limit_price >= amm_ask {
limit_price = amm_ask.safe_sub(amm.order_tick_size)?;
}
}
PositionDirection::Short => {
let amm_bid = amm.bid_price(reserve_price)?;
if limit_price <= amm_bid {
limit_price = amm_bid.safe_add(amm.order_tick_size)?;
}
}
}
}

Ok(limit_price)
}

pub fn get_position_delta_for_fill(
Expand Down
120 changes: 120 additions & 0 deletions programs/drift/src/math/orders/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2511,3 +2511,123 @@ pub mod is_oracle_too_divergent_with_twap_5min {
assert!(is_oracle_too_divergent_with_twap_5min(oracle_price, twap, max_divergence).unwrap())
}
}

pub mod get_price_for_perp_order {
use crate::math::orders::get_price_for_perp_order;

use crate::state::perp_market::AMM;
use crate::{PositionDirection, PostOnlyParam, BID_ASK_SPREAD_PRECISION_U128};
use crate::{AMM_RESERVE_PRECISION, PEG_PRECISION};

#[test]
fn bid_crosses_vamm_ask() {
let amm = AMM {
base_asset_reserve: 100 * AMM_RESERVE_PRECISION,
quote_asset_reserve: 100 * AMM_RESERVE_PRECISION,
peg_multiplier: 100 * PEG_PRECISION,
order_tick_size: 100000,
short_spread: BID_ASK_SPREAD_PRECISION_U128 as u32 / 100,
..AMM::default()
};

let amm_reserve_price = amm.reserve_price().unwrap();
let amm_bid_price = amm.bid_price(amm_reserve_price).unwrap();

assert_eq!(amm_bid_price, 99000000); // $99

let ask = 98900000; // $98.9
let direction = PositionDirection::Short;

let limit_price =
get_price_for_perp_order(ask, direction, PostOnlyParam::Slide, &amm).unwrap();

assert_eq!(limit_price, 99100000); // $99.1

let ask = amm_bid_price;
let limit_price =
get_price_for_perp_order(ask, direction, PostOnlyParam::Slide, &amm).unwrap();

assert_eq!(limit_price, 99100000); // $99.1
}

#[test]
fn bid_doesnt_cross_vamm_ask() {
let amm = AMM {
base_asset_reserve: 100 * AMM_RESERVE_PRECISION,
quote_asset_reserve: 100 * AMM_RESERVE_PRECISION,
peg_multiplier: 100 * PEG_PRECISION,
order_tick_size: 100000,
short_spread: BID_ASK_SPREAD_PRECISION_U128 as u32 / 100,
..AMM::default()
};

let amm_reserve_price = amm.reserve_price().unwrap();
let amm_bid_price = amm.bid_price(amm_reserve_price).unwrap();

assert_eq!(amm_bid_price, 99000000); // $99

let ask = 99900000; // $99.9
let direction = PositionDirection::Short;

let limit_price =
get_price_for_perp_order(ask, direction, PostOnlyParam::Slide, &amm).unwrap();

assert_eq!(limit_price, ask); // $99.1
}

#[test]
fn ask_crosses_vamm_ask() {
let amm = AMM {
base_asset_reserve: 100 * AMM_RESERVE_PRECISION,
quote_asset_reserve: 100 * AMM_RESERVE_PRECISION,
peg_multiplier: 100 * PEG_PRECISION,
order_tick_size: 100000,
long_spread: BID_ASK_SPREAD_PRECISION_U128 as u32 / 100,
..AMM::default()
};

let amm_reserve_price = amm.reserve_price().unwrap();
let amm_ask_price = amm.ask_price(amm_reserve_price).unwrap();

assert_eq!(amm_ask_price, 101000000); // $101

let bid = 101100000; // $101.1
let direction = PositionDirection::Long;

let limit_price =
get_price_for_perp_order(bid, direction, PostOnlyParam::Slide, &amm).unwrap();

assert_eq!(limit_price, 100900000); // $100.9

let bid = amm_ask_price;
let limit_price =
get_price_for_perp_order(bid, direction, PostOnlyParam::Slide, &amm).unwrap();

assert_eq!(limit_price, 100900000); // $100.9
}

#[test]
fn ask_doesnt_cross_vamm_ask() {
let amm = AMM {
base_asset_reserve: 100 * AMM_RESERVE_PRECISION,
quote_asset_reserve: 100 * AMM_RESERVE_PRECISION,
peg_multiplier: 100 * PEG_PRECISION,
order_tick_size: 100000,
long_spread: BID_ASK_SPREAD_PRECISION_U128 as u32 / 100,
..AMM::default()
};

let amm_reserve_price = amm.reserve_price().unwrap();
let amm_ask_price = amm.ask_price(amm_reserve_price).unwrap();

assert_eq!(amm_ask_price, 101000000); // $101

let bid = 100100000; // $100.1
let direction = PositionDirection::Long;

let limit_price =
get_price_for_perp_order(bid, direction, PostOnlyParam::Slide, &amm).unwrap();

assert_eq!(limit_price, bid); // $100.1
}
}
1 change: 1 addition & 0 deletions sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ export class PostOnlyParams {
static readonly NONE = { none: {} };
static readonly MUST_POST_ONLY = { mustPostOnly: {} }; // Tx fails if order can't be post only
static readonly TRY_POST_ONLY = { tryPostOnly: {} }; // Tx succeeds and order not placed if can't be post only
static readonly SLIDE = { slide: {} }; // Modify price to be post only if can't be post only
}

export type NecessaryOrderParams = {
Expand Down

0 comments on commit 21570f3

Please sign in to comment.