Skip to content

Commit

Permalink
program: order params utilize post only enum (#361)
Browse files Browse the repository at this point in the history
* program: order params utilize post only enum

* tweaks

* CHANGELOG.md
  • Loading branch information
crispheaney committed Feb 17, 2023
1 parent f8af4db commit efb7f5f
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 46 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- program: order params utilize post only enum ([#361](https://github.com/drift-labs/protocol-v2/pull/361))

### Fixes

### Breaking
Expand Down
54 changes: 30 additions & 24 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use serum_dex::instruction::{NewOrderInstructionV3, SelfTradeBehavior};
use serum_dex::matching::Side;
use solana_program::msg;

use crate::controller;
use crate::controller::funding::settle_funding_payment;
use crate::controller::position;
use crate::controller::position::{
Expand Down Expand Up @@ -55,6 +54,7 @@ use crate::math::serum::{
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::math::amm::calculate_amm_available_liquidity;
use crate::math::safe_unwrap::SafeUnwrap;
Expand Down Expand Up @@ -197,16 +197,7 @@ pub fn place_perp_order(
standardize_base_asset_amount(params.base_asset_amount, market.amm.order_step_size)?
};

let market_position = &mut user.perp_positions[position_index];
market_position.open_orders += 1;

if !matches!(
&params.order_type,
OrderType::TriggerMarket | OrderType::TriggerLimit
) {
increase_open_bids_and_asks(market_position, &params.direction, base_asset_amount)?;
}

let market_position = &user.perp_positions[position_index];
let existing_position_direction = if market_position.base_asset_amount >= 0 {
PositionDirection::Long
} else {
Expand Down Expand Up @@ -251,7 +242,7 @@ pub fn place_perp_order(
params.direction,
)?,
trigger_condition: params.trigger_condition,
post_only: params.post_only,
post_only: params.post_only != PostOnlyParam::None,
oracle_price_offset: params.oracle_price_offset.unwrap_or(0),
immediate_or_cancel: params.immediate_or_cancel,
auction_start_price,
Expand All @@ -268,9 +259,26 @@ pub fn place_perp_order(
&state.oracle_guard_rails.validity,
)?;

validate_order(&new_order, market, valid_oracle_price, slot)?;
match validate_order(&new_order, market, valid_oracle_price, slot) {
Ok(()) => {}
Err(ErrorCode::PlacePostOnlyLimitFailure)
if params.post_only == PostOnlyParam::TryPostOnly =>
{
// just want place to succeeds without error if TryPostOnly

This comment has been minimized.

Copy link
@SpaceMonkeyForever
return Ok(());
}
Err(err) => return Err(err),
};

user.orders[new_order_index] = new_order;
user.perp_positions[position_index].open_orders += 1;
if !new_order.must_be_triggered() {
increase_open_bids_and_asks(
&mut user.perp_positions[position_index],
&params.direction,
order_base_asset_amount,
)?;
}

let worst_case_base_asset_amount_after =
user.perp_positions[position_index].worst_case_base_asset_amount()?;
Expand Down Expand Up @@ -2693,16 +2701,6 @@ pub fn place_spot_order(
step_size
)?;

let spot_position = &mut user.spot_positions[spot_position_index];
spot_position.open_orders += 1;

if !matches!(
&params.order_type,
OrderType::TriggerMarket | OrderType::TriggerLimit
) {
increase_spot_open_bids_and_asks(spot_position, &params.direction, base_asset_amount)?;
}

let existing_position_direction = if signed_token_amount >= 0 {
PositionDirection::Long
} else {
Expand Down Expand Up @@ -2756,7 +2754,7 @@ pub fn place_spot_order(
params.direction,
)?,
trigger_condition: params.trigger_condition,
post_only: params.post_only,
post_only: params.post_only != PostOnlyParam::None,
oracle_price_offset: params.oracle_price_offset.unwrap_or(0),
immediate_or_cancel: params.immediate_or_cancel,
auction_start_price,
Expand All @@ -2779,6 +2777,14 @@ pub fn place_spot_order(
)?;

user.orders[new_order_index] = new_order;
user.spot_positions[spot_position_index].open_orders += 1;
if !new_order.must_be_triggered() {
increase_spot_open_bids_and_asks(
&mut user.spot_positions[spot_position_index],
&params.direction,
order_base_asset_amount,
)?;
}

let (worst_case_token_amount_after, _) = user.spot_positions[spot_position_index]
.get_worst_case_token_amounts(spot_market, &oracle_price_data, None, None)?;
Expand Down
30 changes: 25 additions & 5 deletions programs/drift/src/instructions/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use crate::validate;
use crate::validation::user::validate_user_deletion;
use crate::validation::whitelist::validate_whitelist_token;
use crate::{controller, math};
use borsh::{BorshDeserialize, BorshSerialize};

pub fn handle_initialize_user(
ctx: Context<InitializeUser>,
Expand Down Expand Up @@ -685,7 +686,7 @@ pub struct OrderParams {
pub price: u64,
pub market_index: u16,
pub reduce_only: bool,
pub post_only: bool,
pub post_only: PostOnlyParam,
pub immediate_or_cancel: bool,
pub max_ts: Option<i64>,
pub trigger_price: Option<u64>,
Expand All @@ -696,6 +697,19 @@ pub struct OrderParams {
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
}

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

#[access_control(
exchange_not_paused(&ctx.accounts.state)
)]
Expand Down Expand Up @@ -869,7 +883,7 @@ pub fn handle_place_and_take_perp_order<'info>(
Some(state.oracle_guard_rails),
)?;

if params.post_only {
if params.post_only != PostOnlyParam::None {
msg!("post_only cant be used in place_and_take");
return Err(print_error!(ErrorCode::InvalidOrderPostOnly)().into());
}
Expand Down Expand Up @@ -970,7 +984,10 @@ pub fn handle_place_and_make_perp_order<'info>(

let (referrer, referrer_stats) = get_referrer_and_referrer_stats(remaining_accounts_iter)?;

if !params.immediate_or_cancel || !params.post_only || params.order_type != OrderType::Limit {
if !params.immediate_or_cancel
|| params.post_only == PostOnlyParam::None
|| params.order_type != OrderType::Limit
{
msg!("place_and_make must use IOC post only limit order");
return Err(print_error!(ErrorCode::InvalidOrderIOCPostOnly)().into());
}
Expand Down Expand Up @@ -1088,7 +1105,7 @@ pub fn handle_place_and_take_spot_order<'info>(
None,
)?;

if params.post_only {
if params.post_only != PostOnlyParam::None {
msg!("post_only cant be used in place_and_take");
return Err(print_error!(ErrorCode::InvalidOrderPostOnly)().into());
}
Expand Down Expand Up @@ -1218,7 +1235,10 @@ pub fn handle_place_and_make_spot_order<'info>(

let (_referrer, _referrer_stats) = get_referrer_and_referrer_stats(remaining_accounts_iter)?;

if !params.immediate_or_cancel || !params.post_only || params.order_type != OrderType::Limit {
if !params.immediate_or_cancel
|| params.post_only == PostOnlyParam::None
|| params.order_type != OrderType::Limit
{
msg!("place_and_make must use IOC post only limit order");
return Err(print_error!(ErrorCode::InvalidOrderIOCPostOnly)().into());
}
Expand Down
9 changes: 7 additions & 2 deletions sdk/src/driftClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
isVariant,
OrderTriggerCondition,
isOneOfVariant,
PostOnlyParams,
} from './types';
import * as anchor from '@project-serum/anchor';
import driftIDL from './idl/drift.json';
Expand Down Expand Up @@ -3150,7 +3151,9 @@ export class DriftClient {
: undefined,
marketIndex: openOrder.marketIndex,
reduceOnly: openOrder.reduceOnly,
postOnly: openOrder.postOnly,
postOnly: openOrder.postOnly
? PostOnlyParams.MUST_POST_ONLY
: PostOnlyParams.NONE,
immediateOrCancel: openOrder.immediateOrCancel,
triggerPrice: orderTypeHasTrigger
? newTriggerPrice || openOrder.triggerPrice
Expand Down Expand Up @@ -3260,7 +3263,9 @@ export class DriftClient {
: undefined,
marketIndex: openOrder.marketIndex,
reduceOnly: openOrder.reduceOnly,
postOnly: openOrder.postOnly,
postOnly: openOrder.postOnly
? PostOnlyParams.MUST_POST_ONLY
: PostOnlyParams.NONE,
immediateOrCancel: openOrder.immediateOrCancel,
triggerPrice: orderTypeHasTrigger
? newTriggerPrice || openOrder.triggerPrice
Expand Down
21 changes: 20 additions & 1 deletion sdk/src/idl/drift.json
Original file line number Diff line number Diff line change
Expand Up @@ -4655,7 +4655,9 @@
},
{
"name": "postOnly",
"type": "bool"
"type": {
"defined": "PostOnlyParam"
}
},
{
"name": "immediateOrCancel",
Expand Down Expand Up @@ -5862,6 +5864,23 @@
]
}
},
{
"name": "PostOnlyParam",
"type": {
"kind": "enum",
"variants": [
{
"name": "None"
},
{
"name": "MustPostOnly"
},
{
"name": "TryPostOnly"
}
]
}
},
{
"name": "TwapPeriod",
"type": {
Expand Down
10 changes: 8 additions & 2 deletions sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ export type OrderParams = {
price: BN;
marketIndex: number;
reduceOnly: boolean;
postOnly: boolean;
postOnly: PostOnlyParams;
immediateOrCancel: boolean;
triggerPrice: BN | null;
triggerCondition: OrderTriggerCondition;
Expand All @@ -858,6 +858,12 @@ export type OrderParams = {
auctionEndPrice: BN | null;
};

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
}

export type NecessaryOrderParams = {
orderType: OrderType;
marketIndex: number;
Expand All @@ -878,7 +884,7 @@ export const DefaultOrderParams: OrderParams = {
price: ZERO,
marketIndex: 0,
reduceOnly: false,
postOnly: false,
postOnly: PostOnlyParams.NONE,
immediateOrCancel: false,
triggerPrice: null,
triggerCondition: OrderTriggerCondition.ABOVE,
Expand Down
10 changes: 5 additions & 5 deletions tests/oracleOffsetOrders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
setFeedPrice,
initializeQuoteSpotMarket,
} from './testHelpers';
import { BulkAccountLoader, calculateEntryPrice } from '../sdk';
import { BulkAccountLoader, calculateEntryPrice, PostOnlyParams } from '../sdk';

describe('oracle offset', () => {
const provider = anchor.AnchorProvider.local(undefined, {
Expand Down Expand Up @@ -262,7 +262,7 @@ describe('oracle offset', () => {
baseAssetAmount,
reduceOnly,
userOrderId: 1,
postOnly: true,
postOnly: PostOnlyParams.MUST_POST_ONLY,
oraclePriceOffset: priceOffset.toNumber(),
});

Expand Down Expand Up @@ -429,7 +429,7 @@ describe('oracle offset', () => {
reduceOnly,
price,
userOrderId: 1,
postOnly: true,
postOnly: PostOnlyParams.MUST_POST_ONLY,
oraclePriceOffset: priceOffset.toNumber(),
});
await driftClient.placePerpOrder(orderParams);
Expand Down Expand Up @@ -510,7 +510,7 @@ describe('oracle offset', () => {
baseAssetAmount,
price,
reduceOnly,
postOnly: true,
postOnly: PostOnlyParams.MUST_POST_ONLY,
oraclePriceOffset: priceOffset.toNumber(),
});
await driftClient.placePerpOrder(orderParams);
Expand Down Expand Up @@ -572,7 +572,7 @@ describe('oracle offset', () => {
baseAssetAmount,
price,
reduceOnly,
postOnly: true,
postOnly: PostOnlyParams.MUST_POST_ONLY,
userOrderId: 1,
oraclePriceOffset: priceOffset.toNumber(),
});
Expand Down
6 changes: 3 additions & 3 deletions tests/placeAndMakeSpotOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
printTxLogs,
sleep,
} from './testHelpers';
import { BulkAccountLoader } from '../sdk';
import { BulkAccountLoader, PostOnlyParams } from '../sdk';

describe('place and make spot order', () => {
const provider = anchor.AnchorProvider.local(undefined, {
Expand Down Expand Up @@ -158,7 +158,7 @@ describe('place and make spot order', () => {
baseAssetAmount,
price: new BN(40).mul(PRICE_PRECISION),
userOrderId: 1,
postOnly: false,
postOnly: PostOnlyParams.NONE,
});
await takerDriftClient.placeSpotOrder(takerOrderParams);
await takerDriftClientUser.fetchAccounts();
Expand All @@ -171,7 +171,7 @@ describe('place and make spot order', () => {
baseAssetAmount,
price: new BN(40).mul(PRICE_PRECISION),
userOrderId: 1,
postOnly: true,
postOnly: PostOnlyParams.MUST_POST_ONLY,
immediateOrCancel: true,
});

Expand Down
5 changes: 3 additions & 2 deletions tests/postOnly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
getLimitOrderParams,
isVariant,
OracleSource,
PostOnlyParams,
ZERO,
} from '../sdk';

Expand Down Expand Up @@ -191,7 +192,7 @@ describe('post only', () => {
baseAssetAmount,
price: reservePrice,
userOrderId: 1,
postOnly: true,
postOnly: PostOnlyParams.MUST_POST_ONLY,
});
await driftClient.placePerpOrder(makerOrderParams);
await driftClientUser.fetchAccounts();
Expand Down Expand Up @@ -280,7 +281,7 @@ describe('post only', () => {
baseAssetAmount,
price: reservePrice,
userOrderId: 1,
postOnly: true,
postOnly: PostOnlyParams.MUST_POST_ONLY,
});
await driftClient.placePerpOrder(makerOrderParams);
await driftClientUser.fetchAccounts();
Expand Down
Loading

0 comments on commit efb7f5f

Please sign in to comment.