Skip to content

Commit

Permalink
program: allow duplicate reduce only orders (#293)
Browse files Browse the repository at this point in the history
* program: place order does not alter users order base asset amount

* fix race condition in serumTests

* update CHANGELOG.md
  • Loading branch information
crispheaney committed Dec 15, 2022
1 parent 32464ad commit a25cea6
Show file tree
Hide file tree
Showing 5 changed files with 4 additions and 279 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixes

- program: allow duplicative reduce only orders ([#293](https://github.com/drift-labs/protocol-v2/pull/293))
- program: fix should_cancel_reduce_only_order
- ts-sdk: add Oracle OrderType to dlob idl

Expand Down
28 changes: 2 additions & 26 deletions programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,21 +170,9 @@ pub fn place_perp_order(
market.amm.order_step_size
)?;

let standardized_base_asset_amount =
let base_asset_amount =
standardize_base_asset_amount(params.base_asset_amount, market.amm.order_step_size)?;

let base_asset_amount = if params.reduce_only || force_reduce_only {
calculate_base_asset_amount_for_reduce_only_order(
standardized_base_asset_amount,
params.direction,
market_position.base_asset_amount,
market_position.open_bids,
market_position.open_asks,
)?
} else {
standardized_base_asset_amount
};

if !matches!(
&params.order_type,
OrderType::TriggerMarket | OrderType::TriggerLimit
Expand Down Expand Up @@ -2519,21 +2507,9 @@ pub fn place_spot_order(
spot_market.order_step_size
)?;

let standardized_base_asset_amount =
let base_asset_amount =
standardize_base_asset_amount(params.base_asset_amount, spot_market.order_step_size)?;

let base_asset_amount = if params.reduce_only || force_reduce_only {
calculate_base_asset_amount_for_reduce_only_order(
standardized_base_asset_amount,
params.direction,
signed_token_amount,
spot_position.open_bids,
spot_position.open_asks,
)?
} else {
standardized_base_asset_amount
};

validate!(
is_multiple_of_step_size(base_asset_amount, spot_market.order_step_size)?,
ErrorCode::InvalidOrderNotStepSizeMultiple,
Expand Down
38 changes: 0 additions & 38 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,44 +144,6 @@ pub fn calculate_quote_asset_amount_for_maker_order(
}
}

pub fn calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount: u64,
order_direction: PositionDirection,
existing_position: i64,
open_bids: i64,
open_asks: i64,
) -> DriftResult<u64> {
let position_plus_open_orders = if existing_position > 0 {
existing_position.safe_add(open_asks)?
} else if existing_position < 0 {
existing_position.safe_add(open_bids)?
} else {
0
};

let signed_order_base_asset_amount: i64 = match order_direction {
PositionDirection::Long => order_base_asset_amount.cast()?,
PositionDirection::Short => -order_base_asset_amount.cast()?,
};

if position_plus_open_orders == 0
|| position_plus_open_orders.signum() == signed_order_base_asset_amount.signum()
{
msg!("Reduce Only Order must decrease existing position size");
msg!(
"position_plus_open_orders = {} signed_order_base_asset_amount = {}",
position_plus_open_orders,
signed_order_base_asset_amount
);
return Err(ErrorCode::InvalidOrderNotRiskReducing);
}

Ok(min(
position_plus_open_orders.unsigned_abs(),
signed_order_base_asset_amount.unsigned_abs(),
))
}

pub fn standardize_base_asset_amount_with_remainder_i128(
base_asset_amount: i128,
step_size: u128,
Expand Down
215 changes: 0 additions & 215 deletions programs/drift/src/math/orders/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,221 +522,6 @@ mod should_expire_order {
}
}

mod calculate_base_asset_amount_for_reduce_only_order {
use crate::controller::position::PositionDirection;
use crate::error::ErrorCode;
use crate::math::orders::calculate_base_asset_amount_for_reduce_only_order;

#[test]
pub fn zero_position() {
let order_base_asset_amount = 1;
let order_direction = PositionDirection::Long;
let existing_position = 0;
let open_bids = 0;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Err(ErrorCode::InvalidOrderNotRiskReducing))
}

#[test]
pub fn long_position_with_equal_asks() {
let order_base_asset_amount = 1;
let order_direction = PositionDirection::Long;
let existing_position = 1;
let open_bids = 0;
let open_asks = -1;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Err(ErrorCode::InvalidOrderNotRiskReducing))
}

#[test]
pub fn short_position_with_equal_bids() {
let order_base_asset_amount = 1;
let order_direction = PositionDirection::Long;
let existing_position = -1;
let open_bids = 1;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Err(ErrorCode::InvalidOrderNotRiskReducing))
}

#[test]
pub fn long_position_with_long_order() {
let order_base_asset_amount = 1;
let order_direction = PositionDirection::Long;
let existing_position = 1;
let open_bids = 0;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Err(ErrorCode::InvalidOrderNotRiskReducing))
}

#[test]
pub fn short_position_with_long_order() {
let order_base_asset_amount = 1;
let order_direction = PositionDirection::Short;
let existing_position = -1;
let open_bids = 0;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Err(ErrorCode::InvalidOrderNotRiskReducing))
}

#[test]
pub fn long_position_with_bigger_short_order() {
let order_base_asset_amount = 5;
let order_direction = PositionDirection::Short;
let existing_position = 1;
let open_bids = 0;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Ok(1))
}

#[test]
pub fn long_position_with_smaller_short_order() {
let order_base_asset_amount = 1;
let order_direction = PositionDirection::Short;
let existing_position = 5;
let open_bids = 0;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Ok(1))
}

#[test]
pub fn long_position_with_asks_and_short_order() {
let order_base_asset_amount = 2;
let order_direction = PositionDirection::Short;
let existing_position = 5;
let open_bids = 0;
let open_asks = -4;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Ok(1))
}

#[test]
pub fn short_position_with_bigger_long_order() {
let order_base_asset_amount = 5;
let order_direction = PositionDirection::Long;
let existing_position = -1;
let open_bids = 0;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Ok(1))
}

#[test]
pub fn short_position_with_smaller_long_order() {
let order_base_asset_amount = 1;
let order_direction = PositionDirection::Long;
let existing_position = -5;
let open_bids = 0;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Ok(1))
}

#[test]
pub fn short_position_with_bids_and_long_order() {
let order_base_asset_amount = 2;
let order_direction = PositionDirection::Long;
let existing_position = -5;
let open_bids = 4;
let open_asks = 0;

let result = calculate_base_asset_amount_for_reduce_only_order(
order_base_asset_amount,
order_direction,
existing_position,
open_bids,
open_asks,
);

assert_eq!(result, Ok(1))
}
}

mod get_max_fill_amounts {
use crate::controller::position::PositionDirection;
use crate::math::constants::{
Expand Down
1 change: 1 addition & 0 deletions tests/serumTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ describe('serum spot market', () => {
assert(orderActionRecord.quoteAssetAmountFilled.eq(new BN(100000000)));
assert(orderActionRecord.takerFee.eq(new BN(100000)));

await makerDriftClient.fetchAccounts();
assert(makerDriftClient.getQuoteAssetTokenAmount().eq(new BN(11800)));

const solSpotMarket =
Expand Down

0 comments on commit a25cea6

Please sign in to comment.