Skip to content

Commit

Permalink
Added cancel limit
Browse files Browse the repository at this point in the history
  • Loading branch information
crnbarr93 committed Feb 18, 2024
1 parent f529ca1 commit db8e5f1
Show file tree
Hide file tree
Showing 9 changed files with 361 additions and 24 deletions.
15 changes: 12 additions & 3 deletions contracts/orderbook/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ pub fn execute(
} => 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 {
book_id,
tick_id,
order_id,
} => order::cancel_limit(deps, env, info, book_id, tick_id, order_id),

// Places a market order on the passed in market
ExecuteMsg::PlaceMarket => order::place_market(deps, env, info),
Expand All @@ -93,9 +97,14 @@ pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
/// Handling submessage reply.
/// For more info on submessage and reply, see https://github.com/CosmWasm/cosmwasm/blob/main/SEMANTICS.md#submessages
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn reply(_deps: DepsMut, _env: Env, _msg: Reply) -> Result<Response, ContractError> {
pub fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
// With `Response` type, it is still possible to dispatch message to invoke external logic.
// See: https://github.com/CosmWasm/cosmwasm/blob/main/SEMANTICS.md#dispatching-messages

if msg.result.is_err() {
return Err(ContractError::ReplyError {
id: msg.id,
error: msg.result.unwrap_err(),
});
}
todo!()
}
15 changes: 14 additions & 1 deletion contracts/orderbook/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cosmwasm_std::{CoinsError, StdError, Uint128};
use cosmwasm_std::{CoinsError, OverflowError, StdError, Uint128};
use cw_utils::PaymentError;
use thiserror::Error;

Expand All @@ -7,6 +7,9 @@ pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),

#[error("{0}")]
Overflow(#[from] OverflowError),

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

Expand All @@ -27,4 +30,14 @@ pub enum ContractError {

#[error(transparent)]
PaymentError(#[from] PaymentError),

#[error("Order not found: {book_id:?}, {tick_id:?}, {order_id:?}")]
OrderNotFound {
book_id: u64,
tick_id: i64,
order_id: u64,
},

#[error("Reply error: {id:?}, {error:?}")]
ReplyError { id: u64, error: String },
}
6 changes: 5 additions & 1 deletion contracts/orderbook/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ pub enum ExecuteMsg {
order_direction: OrderDirection,
quantity: Uint128,
},
CancelLimit,
CancelLimit {
book_id: u64,
tick_id: i64,
order_id: u64,
},
PlaceMarket,
}

Expand Down
75 changes: 63 additions & 12 deletions contracts/orderbook/src/order.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
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;
use crate::types::{LimitOrder, OrderDirection, REPLY_ID_REFUND};
use cosmwasm_std::{
coin, ensure, ensure_eq, BankMsg, DepsMut, Env, MessageInfo, Response, SubMsg, Uint128,
};
use cw_utils::{must_pay, nonpayable};

#[allow(clippy::manual_range_contains)]
pub fn place_limit(
Expand Down Expand Up @@ -33,16 +35,14 @@ pub fn place_limit(
);

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

// 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,
ensure_eq!(
received,
quantity,
ContractError::InsufficientFunds {
sent: received,
required: quantity,
Expand All @@ -65,6 +65,11 @@ pub fn place_limit(
// Save the order to the orderbook
orders().save(deps.storage, &(book_id, tick_id, order_id), &limit_order)?;

// Update tick liquidity
TICK_LIQUIDITY.update(deps.storage, &(book_id, tick_id), |liquidity| {
Ok::<Uint128, ContractError>(liquidity.unwrap_or_default().checked_add(quantity)?)
})?;

Ok(Response::new()
.add_message(BankMsg::Send {
to_address: env.contract.address.to_string(),
Expand All @@ -80,15 +85,61 @@ pub fn place_limit(
}

pub fn cancel_limit(
_deps: DepsMut,
deps: DepsMut,
_env: Env,
info: MessageInfo,
book_id: u64,
tick_id: i64,
order_id: u64,
) -> Result<Response, ContractError> {
// TODO: Implement cancel_limit
nonpayable(&info)?;
let key = (book_id, tick_id, order_id);
// Check for the order, error if not found
let order = orders()
.may_load(deps.storage, &key)?
.ok_or(ContractError::OrderNotFound {
book_id,
tick_id,
order_id,
})?;

// Ensure the sender is the order owner
ensure_eq!(info.sender, order.owner, ContractError::Unauthorized {});

// Remove order
orders().remove(deps.storage, &key)?;

// Update tick liquidity
TICK_LIQUIDITY.update(deps.storage, &(book_id, tick_id), |liquidity| {
Ok::<Uint128, ContractError>(liquidity.unwrap_or_default().checked_sub(order.quantity)?)
})?;

// Get orderbook info for correct denomination
let orderbook =
ORDERBOOKS
.may_load(deps.storage, &order.book_id)?
.ok_or(ContractError::InvalidBookId {
book_id: order.book_id,
})?;

// Generate refund
let expected_denom = orderbook.get_expected_denom_for_direction(&order.order_direction);
let coin_to_send = coin(order.quantity.u128(), expected_denom);
let refund_msg = SubMsg::reply_on_error(
BankMsg::Send {
to_address: order.owner.to_string(),
amount: vec![coin_to_send],
},
REPLY_ID_REFUND,
);

Ok(Response::new()
.add_attribute("method", "cancelLimit")
.add_attribute("owner", info.sender))
.add_attribute("owner", info.sender)
.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_submessage(refund_msg))
}

pub fn place_market(
Expand Down
Loading

0 comments on commit db8e5f1

Please sign in to comment.