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: order params utilize post only enum #361

Merged
merged 3 commits into from
Feb 17, 2023
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
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
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