Skip to content

Commit

Permalink
Merge pull request #34 from osmosis-labs/alpo/limit-placement
Browse files Browse the repository at this point in the history
[Orderbook]: Limit order placement logic
  • Loading branch information
crnbarr93 authored Feb 18, 2024
2 parents 3fc8189 + 47f0ae4 commit f529ca1
Show file tree
Hide file tree
Showing 8 changed files with 394 additions and 19 deletions.
1 change: 1 addition & 0 deletions contracts/orderbook/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ cosmwasm-std = {version = "1.5.0", features = [
"cosmwasm_1_3", # "cosmwasm_1_4" # <- Enable this if you only deploy to chains that have CosmWasm 1.4 or higher
]}
cw-storage-plus = "1.1.0"
cw-utils = "1.0.3"
cw2 = "1.1.1"
schemars = "0.8.15"
serde = {version = "1.0.189", default-features = false, features = ["derive"]}
Expand Down
19 changes: 12 additions & 7 deletions contracts/orderbook/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ pub fn migrate(_deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, C
/// Handling contract execution
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
Expand All @@ -60,16 +60,21 @@ pub fn execute(
ExecuteMsg::CreateOrderbook {
quote_denom,
base_denom,
} => orderbook::create_orderbook(_deps, _env, _info, quote_denom, base_denom),
} => orderbook::create_orderbook(deps, env, info, quote_denom, base_denom),

// Places limit order on given market
ExecuteMsg::PlaceLimit => order::place_limit(_deps, _env, _info),
ExecuteMsg::PlaceLimit {
book_id,
tick_id,
order_direction,
quantity,
} => order::place_limit(deps, env, info, book_id, tick_id, order_direction, quantity),

// Cancels limit order with given ID
ExecuteMsg::CancelLimit => order::cancel_limit(_deps, _env, _info),
ExecuteMsg::CancelLimit => order::cancel_limit(deps, env, info),

// Places a market order on the passed in market
ExecuteMsg::PlaceMarket => order::place_market(_deps, _env, _info),
ExecuteMsg::PlaceMarket => order::place_market(deps, env, info),
}
}

Expand Down
23 changes: 21 additions & 2 deletions contracts/orderbook/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
use cosmwasm_std::StdError;
use cosmwasm_std::{CoinsError, StdError, Uint128};
use cw_utils::PaymentError;
use thiserror::Error;

#[derive(Error, Debug)]
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),

#[error("Unauthorized")]
Unauthorized {},

#[error("Invalid tick ID: {tick_id:?}")]
InvalidTickId { tick_id: i64 },

#[error("Invalid quantity: {quantity:?}")]
InvalidQuantity { quantity: Uint128 },

#[error("Insufficient funds. Sent: {sent:?}, Required: {required:?}")]
InsufficientFunds { sent: Uint128, required: Uint128 },

#[error("Invalid book ID: {book_id:?}")]
InvalidBookId { book_id: u64 },

#[error(transparent)]
Coins(#[from] CoinsError),

#[error(transparent)]
PaymentError(#[from] PaymentError),
}
13 changes: 9 additions & 4 deletions contracts/orderbook/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::types::OrderDirection;
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::Uint128;

/// Message type for `instantiate` entry_point
#[cw_serde]
Expand All @@ -7,14 +9,17 @@ pub struct InstantiateMsg {}
/// Message type for `execute` entry_point
#[cw_serde]
pub enum ExecuteMsg {

// === Orderbook ===

CreateOrderbook{
CreateOrderbook {
quote_denom: String,
base_denom: String,
},
PlaceLimit,
PlaceLimit {
book_id: u64,
tick_id: i64,
order_direction: OrderDirection,
quantity: Uint128,
},
CancelLimit,
PlaceMarket,
}
Expand Down
78 changes: 72 additions & 6 deletions contracts/orderbook/src/order.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,82 @@
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
use crate::error::ContractError;
use crate::state::*;
use crate::state::{MAX_TICK, MIN_TICK, ORDERBOOKS};
use crate::types::{LimitOrder, OrderDirection};
use cosmwasm_std::{coin, ensure, BankMsg, DepsMut, Env, MessageInfo, Response, Uint128};
use cw_utils::must_pay;

#[allow(clippy::manual_range_contains)]
pub fn place_limit(
_deps: DepsMut,
_env: Env,
deps: DepsMut,
env: Env,
info: MessageInfo,
book_id: u64,
tick_id: i64,
order_direction: OrderDirection,
quantity: Uint128,
) -> Result<Response, ContractError> {
// TODO: Implement place_limit
// Validate book_id exists
let orderbook = ORDERBOOKS
.load(deps.storage, &book_id)
.map_err(|_| ContractError::InvalidBookId { book_id })?;

// Validate tick_id is within valid range
ensure!(
tick_id >= MIN_TICK && tick_id <= MAX_TICK,
ContractError::InvalidTickId { tick_id }
);

// Ensure order_quantity is positive
ensure!(
quantity > Uint128::zero(),
ContractError::InvalidQuantity { quantity }
);

// Determine the correct denom based on order direction
let expected_denom = match order_direction {
OrderDirection::Bid => orderbook.quote_denom,
OrderDirection::Ask => orderbook.base_denom,
};

// Verify the funds sent with the message match the `quantity` for the correct denom
// We reject any quantity that is not exactly equal to the amount in the limit order being placed
let received = must_pay(&info, &expected_denom)?;
ensure!(
received == quantity,
ContractError::InsufficientFunds {
sent: received,
required: quantity,
}
);

// Generate a new order ID
let order_id = new_order_id(deps.storage)?;

// Build limit order
let limit_order = LimitOrder::new(
book_id,
tick_id,
order_id,
order_direction,
info.sender.clone(),
quantity,
);

// Save the order to the orderbook
orders().save(deps.storage, &(book_id, tick_id, order_id), &limit_order)?;

Ok(Response::new()
.add_message(BankMsg::Send {
to_address: env.contract.address.to_string(),
amount: vec![coin(quantity.u128(), expected_denom)],
})
.add_attribute("method", "placeLimit")
.add_attribute("owner", info.sender))
.add_attribute("owner", info.sender.to_string())
.add_attribute("book_id", book_id.to_string())
.add_attribute("tick_id", tick_id.to_string())
.add_attribute("order_id", order_id.to_string())
.add_attribute("order_direction", format!("{order_direction:?}"))
.add_attribute("quantity", quantity.to_string()))
}

pub fn cancel_limit(
Expand All @@ -35,4 +101,4 @@ pub fn place_market(
Ok(Response::new()
.add_attribute("method", "placeMarket")
.add_attribute("owner", info.sender))
}
}
1 change: 1 addition & 0 deletions contracts/orderbook/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod test_order;
pub mod test_orderbook;
pub mod test_state;
Loading

0 comments on commit f529ca1

Please sign in to comment.