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

[Sumtree]: Initialization and Insertion for Sumtree #56

Merged
merged 23 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
3 changes: 3 additions & 0 deletions contracts/orderbook/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ pub enum ContractError {

#[error("Mismatched order direction")]
MismatchedOrderDirection {},

#[error("Invalid Node Type")]
InvalidNodeType,
}

pub type ContractResult<T> = Result<T, ContractError>;
24 changes: 13 additions & 11 deletions contracts/orderbook/src/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use crate::constants::{MAX_TICK, MIN_TICK};
use crate::error::ContractError;
use crate::state::ORDERBOOKS;
use crate::state::*;
use crate::tick_math::{amount_to_value, tick_to_price};
use crate::types::{Fulfillment, LimitOrder, MarketOrder, OrderDirection, REPLY_ID_REFUND};
use cosmwasm_std::{
coin, ensure, ensure_eq, ensure_ne, BankMsg, Decimal, DepsMut, Env, MessageInfo, Order,
coin, ensure, ensure_eq, ensure_ne, BankMsg, Decimal256, DepsMut, Env, MessageInfo, Order,
Response, Storage, SubMsg, Uint128,
};
use cw_storage_plus::Bound;
Expand Down Expand Up @@ -193,6 +194,7 @@ pub fn run_market_order(
) -> Result<(Vec<Fulfillment>, BankMsg), ContractError> {
let mut fulfillments: Vec<Fulfillment> = vec![];
let mut amount_fulfilled: Uint128 = Uint128::zero();
let mut amount_to_send: Uint128 = Uint128::zero();
let orderbook = ORDERBOOKS.load(storage, &order.book_id)?;
let placed_order_fulfilled_denom = orderbook.get_opposite_denom(&order.order_direction);

Expand Down Expand Up @@ -235,7 +237,7 @@ pub fn run_market_order(

for maybe_current_tick in ticks {
let current_tick = maybe_current_tick?.0;

let tick_price: Decimal256 = tick_to_price(current_tick)?;
// Create orders iterator for all orders on current tick
let tick_orders = orders().prefix((order.book_id, current_tick)).range(
storage,
Expand All @@ -254,42 +256,44 @@ pub fn run_market_order(
let fill_quantity = order.quantity.min(current_order.quantity);
// Add to total amount fulfilled from placed order
amount_fulfilled = amount_fulfilled.checked_add(fill_quantity)?;
amount_to_send = amount_to_send.checked_add(amount_to_value(
order.order_direction,
fill_quantity,
tick_price,
)?)?;
// Generate fulfillment for current order
let fulfillment = Fulfillment::new(current_order, fill_quantity);
fulfillments.push(fulfillment);

// Update remaining order quantity
order.quantity = order.quantity.checked_sub(fill_quantity)?;
// TODO: Price detection
if order.quantity.is_zero() {
return Ok((
fulfillments,
BankMsg::Send {
to_address: order.owner.to_string(),
amount: vec![coin(amount_fulfilled.u128(), placed_order_fulfilled_denom)],
amount: vec![coin(amount_to_send.u128(), placed_order_fulfilled_denom)],
},
));
}
}

// TODO: Price detection
if order.quantity.is_zero() {
return Ok((
fulfillments,
BankMsg::Send {
to_address: order.owner.to_string(),
amount: vec![coin(amount_fulfilled.u128(), placed_order_fulfilled_denom)],
amount: vec![coin(amount_to_send.u128(), placed_order_fulfilled_denom)],
},
));
}
}

// TODO: Price detection
Ok((
fulfillments,
BankMsg::Send {
to_address: order.owner.to_string(),
amount: vec![coin(amount_fulfilled.u128(), placed_order_fulfilled_denom)],
amount: vec![coin(amount_to_send.u128(), placed_order_fulfilled_denom)],
},
))
}
Expand All @@ -314,9 +318,7 @@ pub fn resolve_fulfillments(
);
let denom = orderbook.get_opposite_denom(&fulfillment.order.order_direction);
// TODO: Add price detection for tick
let msg = fulfillment
.order
.fill(&denom, fulfillment.amount, Decimal::one())?;
let msg = fulfillment.order.fill(&denom, fulfillment.amount)?;
msgs.push(msg);
if fulfillment.order.quantity.is_zero() {
orders().remove(
Expand Down
143 changes: 97 additions & 46 deletions contracts/orderbook/src/tests/test_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use crate::{
order::*,
orderbook::*,
state::*,
tick_math::{divide_by_price, multiply_by_price, tick_to_price},
types::{Fulfillment, LimitOrder, MarketOrder, OrderDirection, REPLY_ID_REFUND},
};
use cosmwasm_std::{coin, Addr, BankMsg, Coin, CosmosMsg, Decimal, Empty, SubMsg, Uint128};
use cosmwasm_std::{coin, Addr, BankMsg, Coin, CosmosMsg, Empty, SubMsg, Uint128};
use cosmwasm_std::{
testing::{mock_dependencies_with_balances, mock_env, mock_info},
ReplyOn,
Expand Down Expand Up @@ -321,36 +322,6 @@ fn test_place_limit_fill() {
let base_denom = "base".to_string();

let test_cases: Vec<FillLimitOrderTestCase> = vec![
FillLimitOrderTestCase {
name: "standard fulfilled order BID",
tick_id: 2,
order_direction: OrderDirection::Bid,
quantity: Uint128::from(100u128),
expected_fulfillments: vec![Fulfillment::new(
LimitOrder::new(
valid_book_id,
1,
0,
OrderDirection::Ask,
Addr::unchecked("maker1"),
Uint128::from(100u128),
),
Uint128::zero(),
)],
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker1".to_string(),
amount: vec![coin(100u128, quote_denom.clone())],
},
BankMsg::Send {
to_address: creator.to_string(),
amount: vec![coin(100u128, base_denom.clone())],
},
],
expected_liquidity: vec![(1, Uint128::zero())],
expected_remainder: Uint128::zero(),
expected_error: None,
},
FillLimitOrderTestCase {
name: "run limit order with single fulfillment ASK",
tick_id: -1,
Expand Down Expand Up @@ -428,6 +399,46 @@ fn test_place_limit_fill() {
expected_remainder: Uint128::zero(),
expected_error: None,
},
FillLimitOrderTestCase {
name: "standard fulfilled order higher tick ASK",
tick_id: -100000,
order_direction: OrderDirection::Ask,
quantity: Uint128::from(100u128),
expected_fulfillments: vec![Fulfillment::new(
LimitOrder::new(
valid_book_id,
-100000,
0,
OrderDirection::Bid,
Addr::unchecked("maker1"),
Uint128::from(100u128),
),
Uint128::zero(),
)],
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker1".to_string(),
amount: vec![coin(
multiply_by_price(Uint128::from(100u128), tick_to_price(-100000).unwrap())
.unwrap()
.u128(),
base_denom.clone(),
)],
},
BankMsg::Send {
to_address: creator.to_string(),
amount: vec![coin(
divide_by_price(Uint128::from(100u128), tick_to_price(-100000).unwrap())
.unwrap()
.u128(),
quote_denom.clone(),
)],
},
],
expected_liquidity: vec![(1, Uint128::zero())],
expected_remainder: Uint128::zero(),
expected_error: None,
},
FillLimitOrderTestCase {
name: "run limit order with multiple fulfillments across multiple ticks ASK",
tick_id: -3,
Expand Down Expand Up @@ -588,11 +599,51 @@ fn test_place_limit_fill() {
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker".to_string(),
amount: vec![coin(50, "quote")],
amount: vec![coin(49, "quote")],
},
BankMsg::Send {
to_address: "creator".to_string(),
amount: vec![coin(50, "base")],
amount: vec![coin(51, "base")],
},
],
expected_liquidity: vec![(1, Uint128::zero())],
expected_remainder: Uint128::zero(),
expected_error: None,
},
FillLimitOrderTestCase {
name: "standard fulfilled order higher tick BID",
tick_id: 100000,
order_direction: OrderDirection::Bid,
quantity: Uint128::from(100u128),
expected_fulfillments: vec![Fulfillment::new(
LimitOrder::new(
valid_book_id,
100000,
0,
OrderDirection::Ask,
Addr::unchecked("maker1"),
Uint128::from(100u128),
),
Uint128::zero(),
)],
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker1".to_string(),
amount: vec![coin(
divide_by_price(Uint128::from(100u128), tick_to_price(100000).unwrap())
.unwrap()
.u128(),
quote_denom.clone(),
)],
},
BankMsg::Send {
to_address: creator.to_string(),
amount: vec![coin(
multiply_by_price(Uint128::from(100u128), tick_to_price(100000).unwrap())
.unwrap()
.u128(),
base_denom.clone(),
)],
},
],
expected_liquidity: vec![(1, Uint128::zero())],
Expand Down Expand Up @@ -631,15 +682,15 @@ fn test_place_limit_fill() {
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker1".to_string(),
amount: vec![coin(25, "quote")],
amount: vec![coin(24, "quote")],
},
BankMsg::Send {
to_address: "maker2".to_string(),
amount: vec![coin(75, "quote")],
amount: vec![coin(74, "quote")],
},
BankMsg::Send {
to_address: "creator".to_string(),
amount: vec![coin(100, "base")],
amount: vec![coin(102, "base")],
},
],
expected_liquidity: vec![(1, Uint128::zero())],
Expand Down Expand Up @@ -678,15 +729,15 @@ fn test_place_limit_fill() {
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker1".to_string(),
amount: vec![coin(25, "quote")],
amount: vec![coin(24, "quote")],
},
BankMsg::Send {
to_address: "maker2".to_string(),
amount: vec![coin(75, "quote")],
amount: vec![coin(74, "quote")],
},
BankMsg::Send {
to_address: "creator".to_string(),
amount: vec![coin(100, "base")],
amount: vec![coin(102, "base")],
},
],
expected_liquidity: vec![(1, Uint128::zero()), (2, Uint128::zero())],
Expand Down Expand Up @@ -725,15 +776,15 @@ fn test_place_limit_fill() {
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker1".to_string(),
amount: vec![coin(25, "quote")],
amount: vec![coin(24, "quote")],
},
BankMsg::Send {
to_address: "maker2".to_string(),
amount: vec![coin(75, "quote")],
amount: vec![coin(74, "quote")],
},
BankMsg::Send {
to_address: "creator".to_string(),
amount: vec![coin(100, "base")],
amount: vec![coin(102, "base")],
},
],
expected_liquidity: vec![(1, Uint128::from(75u128))],
Expand Down Expand Up @@ -772,15 +823,15 @@ fn test_place_limit_fill() {
expected_bank_msgs: vec![
BankMsg::Send {
to_address: "maker1".to_string(),
amount: vec![coin(25, "quote")],
amount: vec![coin(24, "quote")],
},
BankMsg::Send {
to_address: "maker2".to_string(),
amount: vec![coin(150, "quote")],
amount: vec![coin(149, "quote")],
},
BankMsg::Send {
to_address: "creator".to_string(),
amount: vec![coin(175, "base")],
amount: vec![coin(177, "base")],
},
],
expected_liquidity: vec![(1, Uint128::zero()), (2, Uint128::from(825u128))],
Expand Down Expand Up @@ -1574,7 +1625,7 @@ fn test_resolve_fulfillments() {
// Check message is generated as expected
let mut order = order.clone();
let denom = orderbook.get_opposite_denom(&order.order_direction);
let msg = order.fill(denom, *amount, Decimal::one()).unwrap();
let msg = order.fill(denom, *amount).unwrap();

assert_eq!(response[idx], msg, "{}", format_test_name(test.name));
}
Expand Down
Loading
Loading