Skip to content

Commit

Permalink
Duplicated tick state for order direction
Browse files Browse the repository at this point in the history
  • Loading branch information
crnbarr93 committed Apr 1, 2024
1 parent 67189f4 commit 80f66c3
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 22 deletions.
28 changes: 17 additions & 11 deletions contracts/sumtree-orderbook/src/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pub fn place_limit(
let mut tick_state = TICK_STATE
.load(deps.storage, &(book_id, tick_id))
.unwrap_or_default();
let mut tick_values = tick_state.get_values(order_direction);

// Build limit order
let limit_order = LimitOrder::new(
Expand All @@ -86,7 +87,7 @@ pub fn place_limit(
order_direction,
info.sender.clone(),
quantity,
tick_state.cumulative_total_value,
tick_values.cumulative_total_value,
);

// Determine if the order needs to be filled
Expand All @@ -108,7 +109,7 @@ pub fn place_limit(
// Save the order to the orderbook
orders().save(deps.storage, &(book_id, tick_id, order_id), &limit_order)?;

tick_state.total_amount_of_liquidity = tick_state
tick_values.total_amount_of_liquidity = tick_values
.total_amount_of_liquidity
.checked_add(Decimal256::from_ratio(
limit_order.quantity.u128(),
Expand All @@ -117,10 +118,11 @@ pub fn place_limit(
.unwrap();
}

tick_state.cumulative_total_value = tick_state
tick_values.cumulative_total_value = tick_values
.cumulative_total_value
.checked_add(Decimal256::from_ratio(quantity, Uint256::one()))?;

tick_state.set_values(order_direction, tick_values);
TICK_STATE.save(deps.storage, &(book_id, tick_id), &tick_state)?;

Ok(response
Expand Down Expand Up @@ -162,8 +164,9 @@ pub fn cancel_limit(
let tick_state = TICK_STATE
.load(deps.storage, &(book_id, tick_id))
.unwrap_or_default();
let tick_values = tick_state.get_values(order.order_direction);
ensure!(
tick_state.effective_total_amount_swapped <= order.etas,
tick_values.effective_total_amount_swapped <= order.etas,
ContractError::CancelFilledOrder
);

Expand All @@ -189,6 +192,7 @@ pub fn cancel_limit(
.ok_or(ContractError::InvalidTickId {
tick_id: order.tick_id,
})?;
let mut curr_tick_values = curr_tick_state.get_values(order.order_direction);

let mut new_node = TreeNode::new(
order.book_id,
Expand Down Expand Up @@ -226,10 +230,10 @@ pub fn cancel_limit(
&(order.book_id, order.tick_id, order.order_id),
)?;

curr_tick_state.total_amount_of_liquidity = curr_tick_state
curr_tick_values.total_amount_of_liquidity = curr_tick_values
.total_amount_of_liquidity
.checked_sub(Decimal256::from_ratio(order.quantity, Uint256::one()))?;

curr_tick_state.set_values(order.order_direction, curr_tick_values);
TICK_STATE.save(
deps.storage,
&(order.book_id, order.tick_id),
Expand Down Expand Up @@ -337,27 +341,28 @@ pub fn run_market_order(
let mut tick_updates: Vec<(i64, TickState)> = Vec::new();
for maybe_current_tick in ticks {
let (current_tick_id, mut current_tick) = maybe_current_tick?;
let mut current_tick_values = current_tick.get_values(order.order_direction.opposite());
let tick_price = tick_to_price(current_tick_id)?;

let output_quantity = amount_to_value(order.order_direction, order.quantity, tick_price)?;

let output_quantity_dec =
Decimal256::from_ratio(Uint256::from_uint128(output_quantity), Uint256::one());

// If order quantity is less than the current tick's liquidity, fill the whole order.
// Otherwise, fill the whole tick.
let fill_amount_dec = if output_quantity_dec < current_tick.total_amount_of_liquidity {
let fill_amount_dec = if output_quantity_dec < current_tick_values.total_amount_of_liquidity
{
output_quantity_dec
} else {
current_tick.total_amount_of_liquidity
current_tick_values.total_amount_of_liquidity
};

// Update tick and order state to process the fill
current_tick.total_amount_of_liquidity = current_tick
current_tick_values.total_amount_of_liquidity = current_tick_values
.total_amount_of_liquidity
.checked_sub(fill_amount_dec)?;

current_tick.effective_total_amount_swapped = current_tick
current_tick_values.effective_total_amount_swapped = current_tick_values
.effective_total_amount_swapped
.checked_add(fill_amount_dec)?;

Expand All @@ -371,6 +376,7 @@ pub fn run_market_order(
amount_to_value(order.order_direction.opposite(), fill_amount, tick_price)?;
order.quantity = order.quantity.checked_sub(input_filled)?;

current_tick.set_values(order.order_direction.opposite(), current_tick_values);
// Add the updated tick state to the vector
tick_updates.push((current_tick_id, current_tick));

Expand Down
15 changes: 10 additions & 5 deletions contracts/sumtree-orderbook/src/tests/test_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,9 @@ fn test_place_limit() {
let state = TICK_STATE
.load(&deps.storage, &(test.book_id, test.tick_id))
.unwrap_or_default();
let values = state.get_values(test.order_direction);
assert!(
state.total_amount_of_liquidity.is_zero(),
values.total_amount_of_liquidity.is_zero(),
"{}",
format_test_name(test.name)
);
Expand Down Expand Up @@ -305,7 +306,8 @@ fn test_place_limit() {
// Validate liquidity updated as intended
let state = TICK_STATE
.load(&deps.storage, &(test.book_id, test.tick_id))
.unwrap();
.unwrap()
.get_values(test.order_direction);
assert_eq!(
state.total_amount_of_liquidity,
Decimal256::from_ratio(test.quantity, Uint256::one()),
Expand Down Expand Up @@ -476,7 +478,8 @@ fn test_cancel_limit() {
// Verify Liqudity was updated as intended
let state = TICK_STATE
.load(deps.as_ref().storage, &(test.book_id, test.tick_id))
.unwrap_or_default();
.unwrap_or_default()
.get_values(test.order_direction);
if test.place_order {
assert_eq!(
state.total_amount_of_liquidity,
Expand Down Expand Up @@ -567,7 +570,8 @@ fn test_cancel_limit() {
// Validate liquidity updated as intended
let state = TICK_STATE
.load(deps.as_ref().storage, &(test.book_id, test.tick_id))
.unwrap_or_default();
.unwrap_or_default()
.get_values(test.order_direction);

assert!(
state.total_amount_of_liquidity.is_zero(),
Expand Down Expand Up @@ -1041,7 +1045,8 @@ fn test_run_market_order() {
for (tick_id, expected_etas) in test.expected_tick_etas {
let tick_state = TICK_STATE
.load(&deps.storage, &(valid_book_id, tick_id))
.unwrap();
.unwrap()
.get_values(test.placed_order.order_direction.opposite());
assert_eq!(
expected_etas,
tick_state.effective_total_amount_swapped,
Expand Down
4 changes: 2 additions & 2 deletions contracts/sumtree-orderbook/src/types/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use cosmwasm_std::{Addr, Decimal256, Uint128};
#[cw_serde]
#[derive(Copy)]
pub enum OrderDirection {
Bid,
Ask,
Bid = 0,
Ask = 1,
}

impl OrderDirection {
Expand Down
39 changes: 35 additions & 4 deletions contracts/sumtree-orderbook/src/types/tick.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Decimal256;

/// Represents the state of a specific price tick in a liquidity pool.
use super::OrderDirection;

#[cw_serde]
pub struct TickState {
pub struct TickValues {
/// Total Amount of Liquidity at tick (TAL)
/// - Every limit order placement increments this value.
/// - Every swap at this tick decrements this value.
Expand All @@ -21,12 +22,42 @@ pub struct TickState {
pub effective_total_amount_swapped: Decimal256,
}

impl Default for TickState {
impl Default for TickValues {
fn default() -> Self {
TickState {
TickValues {
total_amount_of_liquidity: Decimal256::zero(),
cumulative_total_value: Decimal256::zero(),
effective_total_amount_swapped: Decimal256::zero(),
}
}
}

/// Represents the state of a specific price tick in a liquidity pool.
///
/// The state is split into two parts for the ask and bid directions.
#[cw_serde]
#[derive(Default)]
pub struct TickState {
/// Values for the ask direction of the tick
pub ask_values: TickValues,
/// Values for the bid direction of the tick
pub bid_values: TickValues,
}

impl TickState {
pub fn get_values(&self, direction: OrderDirection) -> TickValues {
if direction == OrderDirection::Ask {
self.ask_values.clone()
} else {
self.bid_values.clone()
}
}

pub fn set_values(&mut self, direction: OrderDirection, values: TickValues) {
if direction == OrderDirection::Ask {
self.ask_values = values;
} else {
self.bid_values = values;
}
}
}

0 comments on commit 80f66c3

Please sign in to comment.