From 975a08fc7253f660c9ca0ec56074eee6d5ad6a68 Mon Sep 17 00:00:00 2001 From: politeWall <138504353+politeWall@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:07:15 +0100 Subject: [PATCH 1/5] save --- Cargo.toml | 6 +- README.md | 10 ++- src/action/execute/cancel_margin_order.rs | 34 +++----- src/action/execute/cancel_spot_orders.rs | 4 +- src/action/execute/create_margin_order.rs | 85 +++++++++++++------ src/action/execute/create_spot_order.rs | 8 +- src/action/execute/process_spot_orders.rs | 16 ++-- src/action/query/get_spot_orders.rs | 2 +- src/entry_point/execute.rs | 3 + src/entry_point/reply.rs | 6 +- src/msg/execute_msg.rs | 7 +- src/msg/query_msg.rs | 4 +- src/msg/reply_type.rs | 2 + .../process_spot_order_processing.rs | 2 +- ...cessful_cancel_order_with_created_order.rs | 2 +- .../successfully_cancel_orders.rs | 8 +- .../successfully_cancel_orders_id.rs | 8 +- .../successfully_cancel_orders_type.rs | 10 +-- src/tests/create_spot_order/coin_number.rs | 2 +- .../create_spot_order/not_enough_fund.rs | 2 +- .../create_spot_order/order_price_denom.rs | 2 +- .../create_spot_order/order_same_denom.rs | 2 +- .../create_spot_order/order_wrong_fund.rs | 2 +- .../successful_create_limit_buy_order.rs | 2 +- .../successful_create_limit_sell_order.rs | 2 +- .../successful_create_market_order.rs | 2 +- .../successful_create_stop_loss_order.rs | 2 +- src/tests/get_spot_orders/get_spot_orders.rs | 10 +-- .../succesful_process_limit_buy_order.rs | 2 +- .../successful_process_5_of_10_orders.rs | 20 ++--- .../successful_process_limit_sell_order.rs | 2 +- .../successful_process_stop_loss_order.rs | 2 +- src/types/margin_order.rs | 48 +++++++++++ src/types/mod.rs | 6 +- .../{spot_order_type.rs => order_type.rs} | 2 +- src/types/spot_order/impls/new.rs | 2 +- src/types/spot_order/impls/new_dummy.rs | 2 +- src/types/spot_order/spot_order.rs | 4 +- 38 files changed, 207 insertions(+), 128 deletions(-) create mode 100644 src/types/margin_order.rs rename src/types/{spot_order_type.rs => order_type.rs} (80%) diff --git a/Cargo.toml b/Cargo.toml index c26d8d8..12e5b6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,13 +14,13 @@ thiserror = "1" schemars = "0.8.1" cosmwasm-schema = "1.1.4" cw-utils = "0.13" -elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "main" } +elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "fix-margin" } [dev-dependencies] cw-multi-test = "0.13.4" serde_json = "1.0.107" -elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "main", features = [ +elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "fix-margin", features = [ "testing", ] } -elys-bindings-test = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "main" } +elys-bindings-test = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "fix-margin" } diff --git a/README.md b/README.md index bb35d67..668a7db 100644 --- a/README.md +++ b/README.md @@ -18,15 +18,17 @@ A spot order is fulfilled when the specified price set by the trader aligns with - **Stop Loss Functionality**: Enable users to set automated orders that trigger when the asset's price reaches a specified lower limit, minimizing potential losses. - **Limit Sell Functionality**: Allow users to set automated orders that execute when the asset's price reaches a specified upper limit, securing profits. -- **Limit Buy Fuctionality**: Allow user to set automated orders that execute when the limit price is reaches, securing profits. +- **Limit Buy Fuctionality**: Allow users to set automated orders that execute when the limit price is reaches, securing profits. +- **Market Buy Fuctionality**: Allow users to set automated orders that will execute at market price ### Margin Order A margin order involves trading an asset using funds provided by a third party. It allows users to trade larger positions with a smaller initial capital outlay. -- **Long Position Functionality**: Allows users to borrow an asset to sell it, hoping to repurchase it later at a lower price, thus profiting from the difference. -- **Short Position Functionality**: Allows users to borrow an asset, selling it with the expectation of buying it back at a lower price to repay the loan and pocket the difference. -- **Unspecified Position Functionality**: A neutral or unspecified position in a margin order, potentially indicating no active trading or a position that isn't explicitly long or short. +- **Stop Loss Functionality**: Enable users to set automated orders that trigger when the asset's price reaches a specified lower limit, minimizing potential losses. +- **Limit Sell Functionality**: Allow users to set automated orders that execute when the asset's price reaches a specified upper limit, securing profits. +- **Limit Buy Fuctionality**: Allow users to set automated orders that execute when the limit price is reaches, securing profits. +- **Market Buy Fuctionality**: Allow users to set automated orders that will execute at market price ## Getting Started diff --git a/src/action/execute/cancel_margin_order.rs b/src/action/execute/cancel_margin_order.rs index 358f2ea..022aa11 100644 --- a/src/action/execute/cancel_margin_order.rs +++ b/src/action/execute/cancel_margin_order.rs @@ -16,34 +16,26 @@ pub fn cancel_margin_order( None => return Err(ContractError::OrderNotFound { order_id }), }; - if order.creator == info.sender.to_string() { + if order.owner == info.sender.to_string() { return Err(ContractError::Unauthorized { sender: info.sender, }); } - let meta_data = Some(to_json_binary(&order_id)?); + let orders: Vec = orders + .iter() + .filter(|order| order.order_id != order_id) + .cloned() + .collect(); - let cancel_msg = ElysMsg::margin_close_position(order.creator, order_id); - - let mut reply_infos = REPLY_INFO.load(deps.storage)?; - - let reply_info_id = - if let Some(reply_info) = reply_infos.iter().max_by_key(|reply_info| reply_info.id) { - reply_info.id + 1 - } else { - 0 - }; - - let reply_info = ReplyInfo { - id: reply_info_id, - reply_type: ReplyType::MarginClosePosition, - data: meta_data, + let return_msg = BankMsg::Send { + to_address: order.owner, + amount: vec![order.collateral], }; - reply_infos.push(reply_info); - - let resp = Response::new().add_submessage(SubMsg::reply_always(cancel_msg, reply_info_id)); + MARGIN_ORDER.save(deps.storage, &orders)?; - Ok(resp) + Ok(Response::new() + .add_message(return_msg) + .add_attribute("order_id", order.order_id.to_string())) } diff --git a/src/action/execute/cancel_spot_orders.rs b/src/action/execute/cancel_spot_orders.rs index 5d34ae7..3381d84 100644 --- a/src/action/execute/cancel_spot_orders.rs +++ b/src/action/execute/cancel_spot_orders.rs @@ -7,7 +7,7 @@ pub fn cancel_spot_orders( deps: DepsMut, order_ids: Option>, owner_address: String, - order_type: Option, + order_type: Option, ) -> Result, ContractError> { if info.sender.as_str() != owner_address { return Err(ContractError::Unauthorized { @@ -95,7 +95,7 @@ fn filter_order_by_id( fn filter_order_by_type( orders: Vec, - order_type: Option, + order_type: Option, ) -> Result, ContractError> { let order_type = match order_type { Some(order_type) => order_type, diff --git a/src/action/execute/create_margin_order.rs b/src/action/execute/create_margin_order.rs index 0c03648..f8801ea 100644 --- a/src/action/execute/create_margin_order.rs +++ b/src/action/execute/create_margin_order.rs @@ -1,17 +1,17 @@ -use cosmwasm_std::{to_json_binary, Coin, Decimal, Int128, StdError, SubMsg}; - -use crate::msg::ReplyType; - use super::*; +use crate::msg::ReplyType; +use cosmwasm_std::{to_json_binary, Coin, Decimal, Int128, StdError, StdResult, Storage, SubMsg}; pub fn create_margin_order( info: MessageInfo, deps: DepsMut, + env: Env, position: MarginPosition, collateral: Coin, leverage: Decimal, borrow_asset: String, take_profit_price: Decimal, + order_type: OrderType, ) -> Result, ContractError> { if info.funds.len() != 1 { return Err(ContractError::CoinNumber); @@ -34,39 +34,68 @@ pub fn create_margin_order( amount: (leverage - Decimal::one()) * collateral.amount, }; - let meta_data = to_json_binary(&MarginOrder::new( - position.clone(), - &info.sender, - collateral.clone(), - leverage, - borrow_token, - take_profit_price, - ))?; + let mut order_vec = MARGIN_ORDER.load(deps.storage)?; - let sub_msg = ElysMsg::margin_open_position( + let order = MarginOrder::new( + &position, + &collateral, + borrow_asset, &info.sender, - &collateral.denom, - Int128::from(collateral.amount.u128() as i128), - &borrow_asset, - position, - leverage, - take_profit_price, + &leverage, + &take_profit_price, + &order_type, + &order_vec, ); - let mut reply_info = REPLY_INFO.load(deps.storage)?; + let resp = create_response(deps.storage, &order, env.contract.address)?; + + order_vec.push(order); + + MARGIN_ORDER.save(deps.storage, &order_vec)?; + + Ok(resp) +} + +fn create_response( + storage: &mut dyn Storage, + order: &MarginOrder, + contract_addr: impl Into, +) -> StdResult> { + let mut resp: Response = + Response::new().add_attribute("order_id", order.order_id.to_string()); + + if order.order_type == OrderType::MarketBuy { + return Ok(resp); + } - let new_info_id = match reply_info.iter().max_by_key(|info| info.id) { - Some(max_info) => max_info.id + 1, + let mut reply_infos = REPLY_INFO.load(storage)?; + + let reply_info_id = match reply_infos.iter().max_by_key(|info| info.id) { + Some(info) => info.id + 1, None => 0, }; - reply_info.push(ReplyInfo { - id: new_info_id, + let reply_info = ReplyInfo { + id: reply_info_id, reply_type: ReplyType::MarginOpenPosition, - data: Some(meta_data), - }); + data: Some(to_json_binary(&order.order_id)?), + }; - REPLY_INFO.save(deps.storage, &reply_info)?; + reply_infos.push(reply_info); + + let submsg: SubMsg = SubMsg::reply_always( + ElysMsg::margin_broker_open_position( + contract_addr, + &order.collateral.denom, + Int128::new(order.collateral.amount.u128() as i128), + &order.borrow_asset, + order.position.clone() as i32, + order.leverage, + order.take_profit_price, + &order.owner, + ), + reply_info_id, + ); - Ok(Response::new().add_submessage(SubMsg::reply_always(sub_msg, new_info_id))) + Ok(resp) } diff --git a/src/action/execute/create_spot_order.rs b/src/action/execute/create_spot_order.rs index b0dd739..14c1395 100644 --- a/src/action/execute/create_spot_order.rs +++ b/src/action/execute/create_spot_order.rs @@ -8,7 +8,7 @@ pub fn create_spot_order( env: Env, deps: DepsMut, info: MessageInfo, - order_type: SpotOrderType, + order_type: OrderType, order_source_denom: String, order_target_denom: String, order_price: SpotOrderPrice, @@ -62,7 +62,7 @@ fn check_denom_error( order_source_denom: &str, order_target_denom: &str, order_price: &SpotOrderPrice, - order_type: &SpotOrderType, + order_type: &OrderType, funds_send_denom: &str, ) -> Result<(), ContractError> { if order_source_denom != funds_send_denom { @@ -73,7 +73,7 @@ fn check_denom_error( return Err(ContractError::SpotOrderSameDenom); } - if order_type == &SpotOrderType::MarketBuy { + if order_type == &OrderType::MarketBuy { return Ok(()); } @@ -98,7 +98,7 @@ fn create_resp( .add_attribute("order_id", new_order.order_id.to_string()) .add_message(bank_msg); // information message - if new_order.order_type != SpotOrderType::MarketBuy { + if new_order.order_type != OrderType::MarketBuy { return Ok(resp); } diff --git a/src/action/execute/process_spot_orders.rs b/src/action/execute/process_spot_orders.rs index 67c9c9b..cd56175 100644 --- a/src/action/execute/process_spot_orders.rs +++ b/src/action/execute/process_spot_orders.rs @@ -70,7 +70,7 @@ fn send_token( } fn check_order(order: &SpotOrder, querier: &ElysQuerier) -> bool { - if order.order_type == SpotOrderType::MarketBuy { + if order.order_type == OrderType::MarketBuy { return true; } @@ -88,11 +88,11 @@ fn check_order(order: &SpotOrder, querier: &ElysQuerier) -> bool { let order_token_out = order_spot_price * order.order_amount.amount; match order.order_type { - SpotOrderType::LimitBuy => order_token_out <= amm_swap_estimation.token_out.amount, + OrderType::LimitBuy => order_token_out <= amm_swap_estimation.token_out.amount, - SpotOrderType::LimitSell => order_token_out <= amm_swap_estimation.token_out.amount, + OrderType::LimitSell => order_token_out <= amm_swap_estimation.token_out.amount, - SpotOrderType::StopLoss => order_token_out >= amm_swap_estimation.token_out.amount, + OrderType::StopLoss => order_token_out >= amm_swap_estimation.token_out.amount, _ => false, } } @@ -104,10 +104,10 @@ fn process_order( reply_infos: &mut Vec, ) -> StdResult<()> { let token_out_min_amount: Int128 = match order.order_type { - SpotOrderType::LimitBuy => calculate_token_out_min_amount(order), - SpotOrderType::LimitSell => calculate_token_out_min_amount(order), - SpotOrderType::StopLoss => Int128::zero(), - SpotOrderType::MarketBuy => Int128::zero(), + OrderType::LimitBuy => calculate_token_out_min_amount(order), + OrderType::LimitSell => calculate_token_out_min_amount(order), + OrderType::StopLoss => Int128::zero(), + OrderType::MarketBuy => Int128::zero(), }; let msg = ElysMsg::amm_swap_exact_amount_in( diff --git a/src/action/query/get_spot_orders.rs b/src/action/query/get_spot_orders.rs index 8d832c4..758d162 100644 --- a/src/action/query/get_spot_orders.rs +++ b/src/action/query/get_spot_orders.rs @@ -4,7 +4,7 @@ pub fn get_spot_orders( deps: Deps, pagination: PageRequest, order_owner: Option, - order_type: Option, + order_type: Option, ) -> Result { let orders = SPOT_ORDER.load(deps.storage)?; diff --git a/src/entry_point/execute.rs b/src/entry_point/execute.rs index 55e95b0..c66fc4f 100644 --- a/src/entry_point/execute.rs +++ b/src/entry_point/execute.rs @@ -43,14 +43,17 @@ pub fn execute( leverage, borrow_asset, take_profit_price, + order_type, } => create_margin_order( info, deps, + env, position, collateral, leverage, borrow_asset, take_profit_price, + order_type, ), CancelMarginOrder { order_id } => cancel_margin_order(info, deps, order_id), } diff --git a/src/entry_point/reply.rs b/src/entry_point/reply.rs index d74f841..cd5aa00 100644 --- a/src/entry_point/reply.rs +++ b/src/entry_point/reply.rs @@ -1,6 +1,6 @@ use super::*; use crate::{action::reply::*, states::REPLY_INFO, types::ReplyInfo}; -use cosmwasm_std::Reply; +use cosmwasm_std::{Reply, StdError}; use msg::ReplyType; #[cfg_attr(not(feature = "library"), entry_point)] @@ -30,7 +30,7 @@ pub fn reply( match info.reply_type { ReplyType::SpotOrder => reply_to_spot_order(deps, info.data, module_resp), - ReplyType::MarginOpenPosition => reply_to_create_margin_order(deps, info.data, module_resp), - ReplyType::MarginClosePosition => reply_to_close_margin_order(deps, module_resp), + ReplyType::MarginBrokerOpen => reply_to_create_margin_order(deps, info.data, module_resp), + _ => return Err(StdError::generic_err("submsg unimplemented").into()), } } diff --git a/src/msg/execute_msg.rs b/src/msg/execute_msg.rs index 4dcfde1..f12428d 100644 --- a/src/msg/execute_msg.rs +++ b/src/msg/execute_msg.rs @@ -1,11 +1,11 @@ -use crate::types::{MarginPosition, SpotOrderPrice, SpotOrderType, SwapAmountInRoute}; +use crate::types::{MarginPosition, OrderType, SpotOrderPrice, SwapAmountInRoute}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{Coin, Decimal}; #[cw_serde] pub enum ExecuteMsg { CreateSpotOrder { - order_type: SpotOrderType, + order_type: OrderType, order_source_denom: String, order_target_denom: String, order_price: SpotOrderPrice, @@ -18,7 +18,7 @@ pub enum ExecuteMsg { CancelSpotOrders { order_ids: Option>, owner_address: String, - order_type: Option, + order_type: Option, }, ProcessSpotOrders {}, @@ -29,6 +29,7 @@ pub enum ExecuteMsg { leverage: Decimal, borrow_asset: String, take_profit_price: Decimal, + order_type: OrderType, }, CancelMarginOrder { diff --git a/src/msg/query_msg.rs b/src/msg/query_msg.rs index 2174b75..29f6dd9 100644 --- a/src/msg/query_msg.rs +++ b/src/msg/query_msg.rs @@ -1,6 +1,6 @@ #[allow(unused_imports)] use super::query_resp::*; -use crate::types::SpotOrderType; +use crate::types::OrderType; use cosmwasm_schema::{cw_serde, QueryResponses}; #[allow(unused_imports)] use elys_bindings::query_resp::*; @@ -23,6 +23,6 @@ pub enum QueryMsg { GetSpotOrders { pagination: PageRequest, order_owner: Option, - order_type: Option, + order_type: Option, }, } diff --git a/src/msg/reply_type.rs b/src/msg/reply_type.rs index b787a58..2541718 100644 --- a/src/msg/reply_type.rs +++ b/src/msg/reply_type.rs @@ -5,4 +5,6 @@ pub enum ReplyType { SpotOrder, MarginOpenPosition, MarginClosePosition, + MarginBrokerOpen, + MarginBrokerClose, } diff --git a/src/tests/cancel_spot_order/process_spot_order_processing.rs b/src/tests/cancel_spot_order/process_spot_order_processing.rs index 5f36602..cc54d1f 100644 --- a/src/tests/cancel_spot_order/process_spot_order_processing.rs +++ b/src/tests/cancel_spot_order/process_spot_order_processing.rs @@ -22,7 +22,7 @@ fn process_spot_order_processing() { // Create a "limit buy" order (dummy order) with a specific rate and balance. let dummy_order = SpotOrder::new( - SpotOrderType::LimitBuy, + OrderType::LimitBuy, SpotOrderPrice { base_denom: "ubtc".to_string(), quote_denom: "usdc".to_string(), diff --git a/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs b/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs index e3c2137..d266e82 100644 --- a/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs +++ b/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs @@ -38,7 +38,7 @@ fn successful_cancel_order_with_created_order() { Addr::unchecked("user"), addr.clone(), &ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_price: SpotOrderPrice { rate: Decimal::from_atomics(Uint128::new(18), 0).unwrap(), base_denom: "btc".to_string(), diff --git a/src/tests/cancel_spot_orders/successfully_cancel_orders.rs b/src/tests/cancel_spot_orders/successfully_cancel_orders.rs index 9f1f797..ab11b47 100644 --- a/src/tests/cancel_spot_orders/successfully_cancel_orders.rs +++ b/src/tests/cancel_spot_orders/successfully_cancel_orders.rs @@ -11,7 +11,7 @@ fn successfully_cancel_orders() { let orders = vec![ SpotOrder { - order_type: SpotOrderType::LimitBuy, + order_type: OrderType::LimitBuy, order_id: 0, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -24,7 +24,7 @@ fn successfully_cancel_orders() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 1, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -37,7 +37,7 @@ fn successfully_cancel_orders() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 2, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -50,7 +50,7 @@ fn successfully_cancel_orders() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 3, order_price: SpotOrderPrice { base_denom: "".to_string(), diff --git a/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs b/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs index 7b60ce2..347e4ce 100644 --- a/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs +++ b/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs @@ -11,7 +11,7 @@ fn successfully_cancel_orders_ids() { let orders = vec![ SpotOrder { - order_type: SpotOrderType::LimitBuy, + order_type: OrderType::LimitBuy, order_id: 0, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -24,7 +24,7 @@ fn successfully_cancel_orders_ids() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 1, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -37,7 +37,7 @@ fn successfully_cancel_orders_ids() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 2, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -50,7 +50,7 @@ fn successfully_cancel_orders_ids() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 3, order_price: SpotOrderPrice { base_denom: "".to_string(), diff --git a/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs b/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs index b871365..bf58fbd 100644 --- a/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs +++ b/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs @@ -11,7 +11,7 @@ fn successfully_cancel_orders_type() { let orders = vec![ SpotOrder { - order_type: SpotOrderType::LimitBuy, + order_type: OrderType::LimitBuy, order_id: 0, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -24,7 +24,7 @@ fn successfully_cancel_orders_type() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 1, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -37,7 +37,7 @@ fn successfully_cancel_orders_type() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 2, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -50,7 +50,7 @@ fn successfully_cancel_orders_type() { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 3, order_price: SpotOrderPrice { base_denom: "".to_string(), @@ -121,7 +121,7 @@ fn successfully_cancel_orders_type() { &&ExecuteMsg::CancelSpotOrders { order_ids: None, owner_address: "user".to_string(), - order_type: Some(SpotOrderType::LimitBuy), + order_type: Some(OrderType::LimitBuy), }, &[], ) diff --git a/src/tests/create_spot_order/coin_number.rs b/src/tests/create_spot_order/coin_number.rs index c6d3177..1b38afc 100644 --- a/src/tests/create_spot_order/coin_number.rs +++ b/src/tests/create_spot_order/coin_number.rs @@ -35,7 +35,7 @@ fn coin_number() { Addr::unchecked("user"), addr, &ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_price: SpotOrderPrice { rate: Decimal::from_atomics(Uint128::new(17), 0).unwrap(), base_denom: "btc".to_string(), diff --git a/src/tests/create_spot_order/not_enough_fund.rs b/src/tests/create_spot_order/not_enough_fund.rs index 8508c3d..5255c64 100644 --- a/src/tests/create_spot_order/not_enough_fund.rs +++ b/src/tests/create_spot_order/not_enough_fund.rs @@ -19,7 +19,7 @@ fn not_enough_fund() { // Define the parameters for creating an order with insufficient funds. let create_order_msg = ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_price: SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "eth".to_string(), diff --git a/src/tests/create_spot_order/order_price_denom.rs b/src/tests/create_spot_order/order_price_denom.rs index 9d2dfba..d8f4908 100644 --- a/src/tests/create_spot_order/order_price_denom.rs +++ b/src/tests/create_spot_order/order_price_denom.rs @@ -16,7 +16,7 @@ fn order_price_denom() { }; let create_order_msg = ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_price: SpotOrderPrice { base_denom: "eth".to_string(), quote_denom: "usdc".to_string(), // Invalid pair. diff --git a/src/tests/create_spot_order/order_same_denom.rs b/src/tests/create_spot_order/order_same_denom.rs index bd58a8d..e36d671 100644 --- a/src/tests/create_spot_order/order_same_denom.rs +++ b/src/tests/create_spot_order/order_same_denom.rs @@ -14,7 +14,7 @@ fn order_same_denom() { }; let create_order_msg = ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_price: SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "eth".to_string(), diff --git a/src/tests/create_spot_order/order_wrong_fund.rs b/src/tests/create_spot_order/order_wrong_fund.rs index 355ade8..27c10a9 100644 --- a/src/tests/create_spot_order/order_wrong_fund.rs +++ b/src/tests/create_spot_order/order_wrong_fund.rs @@ -15,7 +15,7 @@ fn order_wrong_fund() { }; let create_order_msg = ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_price: SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "eth".to_string(), diff --git a/src/tests/create_spot_order/successful_create_limit_buy_order.rs b/src/tests/create_spot_order/successful_create_limit_buy_order.rs index 2c9df11..82f0fb4 100644 --- a/src/tests/create_spot_order/successful_create_limit_buy_order.rs +++ b/src/tests/create_spot_order/successful_create_limit_buy_order.rs @@ -40,7 +40,7 @@ fn successful_create_limit_buy_order() { Addr::unchecked("user"), addr.clone(), &ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::LimitBuy, + order_type: OrderType::LimitBuy, order_price: SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), diff --git a/src/tests/create_spot_order/successful_create_limit_sell_order.rs b/src/tests/create_spot_order/successful_create_limit_sell_order.rs index 17430c8..e332d61 100644 --- a/src/tests/create_spot_order/successful_create_limit_sell_order.rs +++ b/src/tests/create_spot_order/successful_create_limit_sell_order.rs @@ -40,7 +40,7 @@ fn successful_create_limit_sell_order() { Addr::unchecked("user"), addr.clone(), &ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_price: SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), diff --git a/src/tests/create_spot_order/successful_create_market_order.rs b/src/tests/create_spot_order/successful_create_market_order.rs index 8e42e91..82fc8f2 100644 --- a/src/tests/create_spot_order/successful_create_market_order.rs +++ b/src/tests/create_spot_order/successful_create_market_order.rs @@ -52,7 +52,7 @@ fn successful_create_stop_loss_order() { Addr::unchecked("user"), addr.clone(), &ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::MarketBuy, + order_type: OrderType::MarketBuy, // Empty order price - not utilized in market orders order_price: SpotOrderPrice { base_denom: "".to_string(), diff --git a/src/tests/create_spot_order/successful_create_stop_loss_order.rs b/src/tests/create_spot_order/successful_create_stop_loss_order.rs index e5ee29c..ffeebd3 100644 --- a/src/tests/create_spot_order/successful_create_stop_loss_order.rs +++ b/src/tests/create_spot_order/successful_create_stop_loss_order.rs @@ -41,7 +41,7 @@ fn successful_create_stop_loss_order() { Addr::unchecked("user"), addr.clone(), &ExecuteMsg::CreateSpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_price: SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), diff --git a/src/tests/get_spot_orders/get_spot_orders.rs b/src/tests/get_spot_orders/get_spot_orders.rs index eb2cdd6..f08f503 100644 --- a/src/tests/get_spot_orders/get_spot_orders.rs +++ b/src/tests/get_spot_orders/get_spot_orders.rs @@ -82,7 +82,7 @@ fn get_spot_orders() { fn create_orders() -> Vec { vec![ SpotOrder { - order_type: SpotOrderType::LimitBuy, + order_type: OrderType::LimitBuy, order_id: 0, order_price: SpotOrderPrice { base_denom: "btc".to_owned(), @@ -95,7 +95,7 @@ fn create_orders() -> Vec { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 1, order_price: SpotOrderPrice { base_denom: "eth".to_owned(), @@ -108,7 +108,7 @@ fn create_orders() -> Vec { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 2, order_price: SpotOrderPrice { base_denom: "xrp".to_owned(), @@ -121,7 +121,7 @@ fn create_orders() -> Vec { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 3, order_price: SpotOrderPrice { base_denom: "ltc".to_owned(), @@ -134,7 +134,7 @@ fn create_orders() -> Vec { order_amm_routes: vec![], }, SpotOrder { - order_type: SpotOrderType::LimitBuy, + order_type: OrderType::LimitBuy, order_id: 4, order_price: SpotOrderPrice { base_denom: "ada".to_owned(), diff --git a/src/tests/process_spot_order/succesful_process_limit_buy_order.rs b/src/tests/process_spot_order/succesful_process_limit_buy_order.rs index ee3bc62..ff92837 100644 --- a/src/tests/process_spot_order/succesful_process_limit_buy_order.rs +++ b/src/tests/process_spot_order/succesful_process_limit_buy_order.rs @@ -32,7 +32,7 @@ fn successful_process_limit_buy_order() { // Create a "limit buy" order (dummy order) with a specific rate and balance. let dummy_order = SpotOrder::new( - SpotOrderType::LimitBuy, + OrderType::LimitBuy, SpotOrderPrice { base_denom: "ubtc".to_string(), quote_denom: "usdc".to_string(), diff --git a/src/tests/process_spot_order/successful_process_5_of_10_orders.rs b/src/tests/process_spot_order/successful_process_5_of_10_orders.rs index 52c63aa..d3f1ec3 100644 --- a/src/tests/process_spot_order/successful_process_5_of_10_orders.rs +++ b/src/tests/process_spot_order/successful_process_5_of_10_orders.rs @@ -238,7 +238,7 @@ fn successful_process_5_of_10_orders() { fn create_dummy_orders() -> Vec { vec![ SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 0, order_target_denom: "usdc".to_string(), order_amount: coin(1, "eth"), @@ -251,7 +251,7 @@ fn create_dummy_orders() -> Vec { }, }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 1, order_amount: coin(2, "btc"), owner_address: Addr::unchecked("user"), @@ -264,7 +264,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 2, order_amount: coin(3, "btc"), owner_address: Addr::unchecked("user"), @@ -277,7 +277,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 3, order_amount: coin(5, "eth"), owner_address: Addr::unchecked("user"), @@ -290,7 +290,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_id: 4, order_amount: coin(1, "eth"), owner_address: Addr::unchecked("user"), @@ -303,7 +303,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 5, order_amount: coin(1, "eth"), owner_address: Addr::unchecked("user"), @@ -316,7 +316,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 6, order_amount: coin(3, "btc"), owner_address: Addr::unchecked("user"), @@ -329,7 +329,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 7, order_amount: coin(2, "btc"), owner_address: Addr::unchecked("user"), @@ -342,7 +342,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 8, order_amount: coin(1, "btc"), owner_address: Addr::unchecked("user"), @@ -355,7 +355,7 @@ fn create_dummy_orders() -> Vec { order_target_denom: "usdc".to_string(), }, SpotOrder { - order_type: SpotOrderType::LimitSell, + order_type: OrderType::LimitSell, order_id: 9, order_amount: coin(1, "eth"), owner_address: Addr::unchecked("user"), diff --git a/src/tests/process_spot_order/successful_process_limit_sell_order.rs b/src/tests/process_spot_order/successful_process_limit_sell_order.rs index 679d5ee..970ba5d 100644 --- a/src/tests/process_spot_order/successful_process_limit_sell_order.rs +++ b/src/tests/process_spot_order/successful_process_limit_sell_order.rs @@ -35,7 +35,7 @@ fn successful_process_limit_sell_order() { // Create a "limit sell" order (dummy order) with a specific rate and balance. let dummy_order = SpotOrder::new( - SpotOrderType::LimitSell, + OrderType::LimitSell, SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), diff --git a/src/tests/process_spot_order/successful_process_stop_loss_order.rs b/src/tests/process_spot_order/successful_process_stop_loss_order.rs index 95d0c43..6ff4ae7 100644 --- a/src/tests/process_spot_order/successful_process_stop_loss_order.rs +++ b/src/tests/process_spot_order/successful_process_stop_loss_order.rs @@ -36,7 +36,7 @@ fn successful_process_stop_loss_order() { // Create a "stop-loss" order (dummy order) with trigger price and balance. let dummy_order = SpotOrder::new( - SpotOrderType::StopLoss, + OrderType::StopLoss, SpotOrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), diff --git a/src/types/margin_order.rs b/src/types/margin_order.rs new file mode 100644 index 0000000..73081e4 --- /dev/null +++ b/src/types/margin_order.rs @@ -0,0 +1,48 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{Coin, Decimal}; +use elys_bindings::types::MarginPosition; + +use super::OrderType; + +#[cw_serde] +pub struct MarginOrder { + pub order_id: u64, + pub position: MarginPosition, + pub collateral: Coin, + pub borrow_asset: String, + pub owner: String, + pub leverage: Decimal, + pub take_profit_price: Decimal, + pub order_type: OrderType, + pub position_id: Option, +} + +impl MarginOrder { + pub fn new( + position: &MarginPosition, + collateral: &Coin, + borrow_asset: impl Into, + owner: impl Into, + leverage: &Decimal, + take_profit_price: &Decimal, + order_type: &OrderType, + order_vec: &Vec, + ) -> Self { + let order_id: u64 = match order_vec.iter().max_by_key(|s| s.order_id) { + Some(x) => x.order_id + 1, + None => 0, + }; + + Self { + order_id, + position: position.to_owned(), + collateral: collateral.to_owned(), + borrow_asset: borrow_asset.into(), + owner: owner.into(), + leverage: leverage.to_owned(), + take_profit_price: take_profit_price.to_owned(), + order_type: order_type.to_owned(), + position_id: None, + } + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index 279d399..42ded31 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,5 +1,5 @@ +mod order_type; mod spot_order_price; -mod spot_order_type; mod spot_order { pub mod spot_order; mod impls { @@ -8,10 +8,12 @@ mod spot_order { mod new_dummy; } } +mod margin_order; mod reply_info; pub use elys_bindings::types::*; +pub use margin_order::MarginOrder; +pub use order_type::OrderType; pub use reply_info::ReplyInfo; pub use spot_order::spot_order::SpotOrder; pub use spot_order_price::SpotOrderPrice; -pub use spot_order_type::SpotOrderType; diff --git a/src/types/spot_order_type.rs b/src/types/order_type.rs similarity index 80% rename from src/types/spot_order_type.rs rename to src/types/order_type.rs index c18ec7c..97bb98a 100644 --- a/src/types/spot_order_type.rs +++ b/src/types/order_type.rs @@ -1,7 +1,7 @@ use cosmwasm_schema::cw_serde; #[cw_serde] -pub enum SpotOrderType { +pub enum OrderType { StopLoss, LimitSell, LimitBuy, diff --git a/src/types/spot_order/impls/new.rs b/src/types/spot_order/impls/new.rs index 2f7cc71..a68a15d 100644 --- a/src/types/spot_order/impls/new.rs +++ b/src/types/spot_order/impls/new.rs @@ -3,7 +3,7 @@ use cosmwasm_std::{Addr, Coin}; impl SpotOrder { pub fn new( - order_type: SpotOrderType, + order_type: OrderType, order_price: SpotOrderPrice, order_amount: Coin, owner_address: Addr, diff --git a/src/types/spot_order/impls/new_dummy.rs b/src/types/spot_order/impls/new_dummy.rs index ad68a09..258a125 100644 --- a/src/types/spot_order/impls/new_dummy.rs +++ b/src/types/spot_order/impls/new_dummy.rs @@ -5,7 +5,7 @@ impl SpotOrder { pub fn new_dummy() -> SpotOrder { SpotOrder { order_id: 777, - order_type: SpotOrderType::StopLoss, + order_type: OrderType::StopLoss, order_amount: coin(1000, "btc"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![], diff --git a/src/types/spot_order/spot_order.rs b/src/types/spot_order/spot_order.rs index caada60..0d07bba 100644 --- a/src/types/spot_order/spot_order.rs +++ b/src/types/spot_order/spot_order.rs @@ -1,10 +1,10 @@ -use crate::types::{spot_order_type::SpotOrderType, SpotOrderPrice, SwapAmountInRoute}; +use crate::types::{order_type::OrderType, SpotOrderPrice, SwapAmountInRoute}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{Addr, Coin}; #[cw_serde] pub struct SpotOrder { - pub order_type: SpotOrderType, + pub order_type: OrderType, pub order_id: u64, pub order_price: SpotOrderPrice, pub order_amount: Coin, From 12a13a0edba5c3cc324b9f193291c8318cba22e7 Mon Sep 17 00:00:00 2001 From: politeWall <138504353+politeWall@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:39:32 +0100 Subject: [PATCH 2/5] feat: fix margin order and impl market buy to margin order --- front_end_script/README.md | 10 ++- src/action/execute/cancel_margin_order.rs | 16 ++-- src/action/execute/create_margin_order.rs | 30 +++---- src/action/execute/create_spot_order.rs | 6 +- src/action/mod.rs | 6 +- src/action/query/get_margin_order.rs | 16 ++-- src/action/query/get_margin_position.rs | 19 ++++ ...rgin_orders.rs => get_margin_positions.rs} | 2 +- src/action/reply/close_margin_position.rs | 27 +++--- src/action/reply/create_margin_order.rs | 29 +++--- src/entry_point/execute.rs | 2 + src/entry_point/query.rs | 5 +- src/entry_point/reply.rs | 3 +- src/error.rs | 4 +- src/msg/execute_msg.rs | 5 +- src/msg/mod.rs | 3 + src/msg/query_msg.rs | 10 ++- src/msg/query_resp/get_margin_order_resp.rs | 7 ++ src/msg/reply_type.rs | 3 +- src/tests/cancel_margin_order/not_found.rs | 44 +++++++++ .../succesful_cancel_an_order.rs | 83 +++++++++++++++++ src/tests/cancel_margin_order/unauthorize.rs | 90 +++++++++++++++++++ src/tests/cancel_spot_order/not_found.rs | 3 +- .../process_spot_order_processing.rs | 5 +- ...cessful_cancel_order_with_created_order.rs | 5 +- ...uccessful_cancel_order_with_dummy_order.rs | 3 +- src/tests/cancel_spot_order/unauthorized.rs | 5 +- .../successfully_cancel_orders.rs | 13 +-- .../successfully_cancel_orders_id.rs | 13 +-- .../successfully_cancel_orders_type.rs | 13 +-- src/tests/cancel_spot_orders/unauthorize.rs | 3 +- src/tests/create_margin_order/coin_number.rs | 13 ++- .../create_margin_order/collateral_amount.rs | 11 ++- ...er.rs => non_usdc_collateral_for_short.rs} | 47 +++++----- .../successful_create_margin_market_order.rs | 82 +++++++++++++++++ ...r.rs => successful_create_margin_order.rs} | 19 ++-- src/tests/create_spot_order/coin_number.rs | 5 +- .../create_spot_order/not_enough_fund.rs | 5 +- .../create_spot_order/order_price_denom.rs | 7 +- .../create_spot_order/order_same_denom.rs | 5 +- .../create_spot_order/order_wrong_fund.rs | 5 +- .../successful_create_limit_buy_order.rs | 5 +- .../successful_create_limit_sell_order.rs | 5 +- .../successful_create_market_order.rs | 5 +- .../successful_create_stop_loss_order.rs | 5 +- src/tests/get_margin_order/not_found.rs | 55 ++++++++++++ .../successful_query_message.rs | 60 +++++++++++++ src/tests/get_spot_order/not_found.rs | 3 +- .../successful_query_message.rs | 5 +- src/tests/get_spot_orders/get_spot_orders.rs | 17 ++-- src/tests/mock/instantiate.rs | 12 ++- src/tests/mod.rs | 19 +++- .../succesful_process_limit_buy_order.rs | 5 +- .../successful_process_5_of_10_orders.rs | 35 ++++---- .../successful_process_limit_sell_order.rs | 5 +- .../successful_process_stop_loss_order.rs | 5 +- src/tests/process_spot_order/unauthorize.rs | 3 +- src/types/margin_order.rs | 7 +- src/types/mod.rs | 2 +- src/types/spot_order/impls/new.rs | 2 +- src/types/spot_order/impls/new_dummy.rs | 2 +- src/types/spot_order/spot_order.rs | 4 +- src/types/spot_order_price.rs | 2 +- 63 files changed, 725 insertions(+), 220 deletions(-) create mode 100644 src/action/query/get_margin_position.rs rename src/action/query/{get_margin_orders.rs => get_margin_positions.rs} (90%) create mode 100644 src/msg/query_resp/get_margin_order_resp.rs create mode 100644 src/tests/cancel_margin_order/not_found.rs create mode 100644 src/tests/cancel_margin_order/succesful_cancel_an_order.rs create mode 100644 src/tests/cancel_margin_order/unauthorize.rs rename src/tests/create_margin_order/{succsessful_create_short_order.rs => non_usdc_collateral_for_short.rs} (63%) create mode 100644 src/tests/create_margin_order/successful_create_margin_market_order.rs rename src/tests/create_margin_order/{successful_create_long_order.rs => successful_create_margin_order.rs} (79%) create mode 100644 src/tests/get_margin_order/not_found.rs create mode 100644 src/tests/get_margin_order/successful_query_message.rs diff --git a/front_end_script/README.md b/front_end_script/README.md index b1b02ce..271ac46 100644 --- a/front_end_script/README.md +++ b/front_end_script/README.md @@ -134,7 +134,7 @@ getSpotOrders( ); ``` -### 6. createMarginOrder(position, collateral, leverage, borrow_asset, take_profit_price) +### 6. createMarginOrder(position, collateral, leverage, borrow_asset, take_profit_price, order_type, trigger_price) This function allows you to create a margin order by sending a transaction to the CosmWasm contract. @@ -145,6 +145,8 @@ This function allows you to create a margin order by sending a transaction to th - `leverage` (String): The leverage for the margin order. - `borrow_asset` (String): The asset to borrow for the margin order. - `take_profit_price` (String): The price at which the order will take profit. +- `order_type` (String): The type of the order (e.g., "stop_loss", "limit_sell", "limit_buy"). +- `trigger_price` ({`base_denom`:String, `quote_denom`:String, `rate` :String}): Price relates two assets exchange rate that the user should define #### Usage @@ -154,7 +156,9 @@ createMarginOrder( "collateral", "leverage_value", "borrow_asset", - "take_profit_price" + "take_profit_price", + "order_type", + "trigger_price" ); ``` @@ -167,6 +171,8 @@ createMarginOrder( "4.3", "ueth", "2.2" + "limit_buy", + { base_denom: "ueth", quote_denom: "uusdc", rate: "2076.5" } ); ``` diff --git a/src/action/execute/cancel_margin_order.rs b/src/action/execute/cancel_margin_order.rs index 022aa11..76399fc 100644 --- a/src/action/execute/cancel_margin_order.rs +++ b/src/action/execute/cancel_margin_order.rs @@ -1,7 +1,3 @@ -use cosmwasm_std::{to_json_binary, SubMsg}; - -use crate::msg::ReplyType; - use super::*; pub fn cancel_margin_order( @@ -16,7 +12,7 @@ pub fn cancel_margin_order( None => return Err(ContractError::OrderNotFound { order_id }), }; - if order.owner == info.sender.to_string() { + if order.owner != info.sender.to_string() { return Err(ContractError::Unauthorized { sender: info.sender, }); @@ -28,14 +24,16 @@ pub fn cancel_margin_order( .cloned() .collect(); - let return_msg = BankMsg::Send { + let refund_msg = BankMsg::Send { to_address: order.owner, amount: vec![order.collateral], }; + let resp = Response::new() + .add_message(CosmosMsg::Bank(refund_msg)) + .add_attribute("order_id", order.order_id.to_string()); + MARGIN_ORDER.save(deps.storage, &orders)?; - Ok(Response::new() - .add_message(return_msg) - .add_attribute("order_id", order.order_id.to_string())) + Ok(resp) } diff --git a/src/action/execute/create_margin_order.rs b/src/action/execute/create_margin_order.rs index f8801ea..247168f 100644 --- a/src/action/execute/create_margin_order.rs +++ b/src/action/execute/create_margin_order.rs @@ -12,6 +12,7 @@ pub fn create_margin_order( borrow_asset: String, take_profit_price: Decimal, order_type: OrderType, + trigger_price: OrderPrice, ) -> Result, ContractError> { if info.funds.len() != 1 { return Err(ContractError::CoinNumber); @@ -21,19 +22,14 @@ pub fn create_margin_order( return Err(ContractError::CollateralAmount); } - if position == MarginPosition::Short && collateral.denom == "uusdc" { + if position == MarginPosition::Short && collateral.denom != "uusdc" { return Err( - StdError::generic_err("the collateral asset for a short can only be USDC").into(), + StdError::generic_err("the collateral asset for a short can only be UUSDC").into(), ); } cw_utils::must_pay(&info, &info.funds[0].denom)?; - let borrow_token = Coin { - denom: borrow_asset.clone(), - amount: (leverage - Decimal::one()) * collateral.amount, - }; - let mut order_vec = MARGIN_ORDER.load(deps.storage)?; let order = MarginOrder::new( @@ -44,14 +40,17 @@ pub fn create_margin_order( &leverage, &take_profit_price, &order_type, + &trigger_price, &order_vec, ); let resp = create_response(deps.storage, &order, env.contract.address)?; - order_vec.push(order); + if order.order_type != OrderType::MarketBuy { + order_vec.push(order); - MARGIN_ORDER.save(deps.storage, &order_vec)?; + MARGIN_ORDER.save(deps.storage, &order_vec)?; + } Ok(resp) } @@ -61,11 +60,8 @@ fn create_response( order: &MarginOrder, contract_addr: impl Into, ) -> StdResult> { - let mut resp: Response = - Response::new().add_attribute("order_id", order.order_id.to_string()); - - if order.order_type == OrderType::MarketBuy { - return Ok(resp); + if order.order_type != OrderType::MarketBuy { + return Ok(Response::new().add_attribute("order_id", order.order_id.to_string())); } let mut reply_infos = REPLY_INFO.load(storage)?; @@ -77,8 +73,8 @@ fn create_response( let reply_info = ReplyInfo { id: reply_info_id, - reply_type: ReplyType::MarginOpenPosition, - data: Some(to_json_binary(&order.order_id)?), + reply_type: ReplyType::MarginBrokerOpenMarketBuy, + data: None, }; reply_infos.push(reply_info); @@ -97,5 +93,5 @@ fn create_response( reply_info_id, ); - Ok(resp) + Ok(Response::new().add_submessage(submsg)) } diff --git a/src/action/execute/create_spot_order.rs b/src/action/execute/create_spot_order.rs index 14c1395..8d43d7e 100644 --- a/src/action/execute/create_spot_order.rs +++ b/src/action/execute/create_spot_order.rs @@ -11,7 +11,7 @@ pub fn create_spot_order( order_type: OrderType, order_source_denom: String, order_target_denom: String, - order_price: SpotOrderPrice, + order_price: OrderPrice, order_amm_routes: Vec, ) -> Result, ContractError> { if info.funds.len() != 1 { @@ -61,7 +61,7 @@ pub fn create_spot_order( fn check_denom_error( order_source_denom: &str, order_target_denom: &str, - order_price: &SpotOrderPrice, + order_price: &OrderPrice, order_type: &OrderType, funds_send_denom: &str, ) -> Result<(), ContractError> { @@ -82,7 +82,7 @@ fn check_denom_error( || (order_price.quote_denom != order_source_denom && order_price.quote_denom != order_target_denom) { - return Err(ContractError::SpotOrderPriceDenom); + return Err(ContractError::OrderPriceDenom); } Ok(()) diff --git a/src/action/mod.rs b/src/action/mod.rs index ac2df9b..5445236 100644 --- a/src/action/mod.rs +++ b/src/action/mod.rs @@ -6,7 +6,8 @@ pub mod query { mod asset_info; mod get_all_price; mod get_margin_order; - mod get_margin_orders; + mod get_margin_position; + mod get_margin_positions; mod get_spot_order; mod get_spot_orders; @@ -19,7 +20,8 @@ pub mod query { pub use asset_info::asset_info; pub use get_all_price::get_all_prices; pub use get_margin_order::get_margin_order; - pub use get_margin_orders::get_margin_orders; + pub use get_margin_position::get_margin_position; + pub use get_margin_positions::get_margin_positions; pub use get_spot_order::get_spot_order; pub use get_spot_orders::get_spot_orders; } diff --git a/src/action/query/get_margin_order.rs b/src/action/query/get_margin_order.rs index 960840b..db6a091 100644 --- a/src/action/query/get_margin_order.rs +++ b/src/action/query/get_margin_order.rs @@ -1,19 +1,13 @@ -use cosmwasm_std::StdError; - use super::*; pub fn get_margin_order( deps: Deps, - address: String, id: u64, -) -> Result { - let querier = ElysQuerier::new(&deps.querier); - - let resp: MarginMtpResponse = querier.mtp(address, id)?; +) -> Result { + let orders = MARGIN_ORDER.load(deps.storage)?; - if let Some(mtp) = resp.mtp { - Ok(mtp) - } else { - Err(StdError::not_found("margin trading prosition").into()) + match orders.iter().find(|order| order.order_id == id).cloned() { + Some(order) => Ok(GetMarginOrderResp { order }), + None => Err(ContractError::OrderNotFound { order_id: id }), } } diff --git a/src/action/query/get_margin_position.rs b/src/action/query/get_margin_position.rs new file mode 100644 index 0000000..4f96fff --- /dev/null +++ b/src/action/query/get_margin_position.rs @@ -0,0 +1,19 @@ +use cosmwasm_std::StdError; + +use super::*; + +pub fn get_margin_position( + deps: Deps, + address: String, + id: u64, +) -> Result { + let querier = ElysQuerier::new(&deps.querier); + + let resp: MarginMtpResponse = querier.mtp(address, id)?; + + if let Some(_) = &resp.mtp { + Ok(resp) + } else { + Err(StdError::not_found("margin trading prosition").into()) + } +} diff --git a/src/action/query/get_margin_orders.rs b/src/action/query/get_margin_positions.rs similarity index 90% rename from src/action/query/get_margin_orders.rs rename to src/action/query/get_margin_positions.rs index 9764298..2c9a188 100644 --- a/src/action/query/get_margin_orders.rs +++ b/src/action/query/get_margin_positions.rs @@ -1,6 +1,6 @@ use super::*; -pub fn get_margin_orders( +pub fn get_margin_positions( deps: Deps, pagination: PageRequest, ) -> Result { diff --git a/src/action/reply/close_margin_position.rs b/src/action/reply/close_margin_position.rs index 69cb164..e084974 100644 --- a/src/action/reply/close_margin_position.rs +++ b/src/action/reply/close_margin_position.rs @@ -1,27 +1,24 @@ -use cosmwasm_std::SubMsgResult; - -use crate::helper::get_response_from_reply; +use cosmwasm_std::{from_json, StdError, SubMsgResult}; use super::*; pub fn reply_to_close_margin_order( - deps: DepsMut, module_resp: SubMsgResult, ) -> Result, ContractError> { - let close_resp: MarginCloseResponse = match get_response_from_reply(module_resp) { - Ok(close_resp) => close_resp, - Err(err) => return Ok(err), + let response = match module_resp.into_result() { + Ok(response) => response, + Err(err) => return Err(StdError::generic_err(err).into()), }; - let orders: Vec = MARGIN_ORDER.load(deps.storage)?; - - let orders: Vec = orders - .iter() - .filter(|order| order.order_id != close_resp.id) - .cloned() - .collect(); + let data = match response.data { + Some(data) => data, + None => return Err(StdError::generic_err("No Data").into()), + }; - MARGIN_ORDER.save(deps.storage, &orders)?; + let close_resp: MarginBrokerCloseResResponse = match from_json(&data) { + Ok(resp) => resp, + Err(err) => return Err(err.into()), + }; let resp = Response::new().add_attribute("order_id", close_resp.id.to_string()); diff --git a/src/action/reply/create_margin_order.rs b/src/action/reply/create_margin_order.rs index 1ac1acf..b807c8e 100644 --- a/src/action/reply/create_margin_order.rs +++ b/src/action/reply/create_margin_order.rs @@ -1,29 +1,26 @@ -use crate::helper::get_response_from_reply; - use super::*; -use cosmwasm_std::{from_json, Binary, SubMsgResult}; +use cosmwasm_std::{from_json, StdError, SubMsgResult}; pub fn reply_to_create_margin_order( - deps: DepsMut, - data: Option, module_resp: SubMsgResult, ) -> Result, ContractError> { - let open_resp: MarginOpenResponse = match get_response_from_reply(module_resp) { - Ok(open_resp) => open_resp, - Err(err) => return Ok(err), + let response = match module_resp.into_result() { + Ok(response) => response, + Err(err) => return Err(StdError::generic_err(err).into()), }; - let mut order: MarginOrder = match data { - Some(ref data) => from_json(data)?, - None => return Ok(Response::new().add_attribute("error", "no meta_data".to_string())), + let data = match response.data { + Some(data) => data, + None => return Err(StdError::generic_err("No Data").into()), }; - order.order_id = open_resp.id; - - let mut orders = MARGIN_ORDER.load(deps.storage)?; - orders.push(order); + let margin_resp: MarginBrokerOpenResResponse = match from_json(&data) { + Ok(resp) => resp, + Err(err) => return Err(err.into()), + }; - let resp = Response::new().add_attribute("order_id", open_resp.id.to_string()); + let resp = + Response::new().add_attribute("margin_trading_position_id", margin_resp.id.to_string()); Ok(resp) } diff --git a/src/entry_point/execute.rs b/src/entry_point/execute.rs index c66fc4f..3732dcc 100644 --- a/src/entry_point/execute.rs +++ b/src/entry_point/execute.rs @@ -44,6 +44,7 @@ pub fn execute( borrow_asset, take_profit_price, order_type, + trigger_price, } => create_margin_order( info, deps, @@ -54,6 +55,7 @@ pub fn execute( borrow_asset, take_profit_price, order_type, + trigger_price, ), CancelMarginOrder { order_id } => cancel_margin_order(info, deps, order_id), } diff --git a/src/entry_point/query.rs b/src/entry_point/query.rs index 01562fb..960b8af 100644 --- a/src/entry_point/query.rs +++ b/src/entry_point/query.rs @@ -10,10 +10,10 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&query::get_spot_order(deps, order_id)?)?), GetAllPrices {} => Ok(to_json_binary(&query::get_all_prices(deps)?)?), AssetInfo { denom } => Ok(to_json_binary(&query::asset_info(deps, denom)?)?), - GetMarginOrder { address, id } => Ok(to_json_binary(&query::get_margin_order( + GetMarginPosition { address, id } => Ok(to_json_binary(&query::get_margin_position( deps, address, id, )?)?), - GetMarginOrders { pagination } => Ok(to_json_binary(&query::get_margin_orders( + GetMarginPositions { pagination } => Ok(to_json_binary(&query::get_margin_positions( deps, pagination, )?)?), GetSpotOrders { @@ -26,5 +26,6 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&query::get_margin_order(deps, id)?)?), } } diff --git a/src/entry_point/reply.rs b/src/entry_point/reply.rs index cd5aa00..5932966 100644 --- a/src/entry_point/reply.rs +++ b/src/entry_point/reply.rs @@ -30,7 +30,8 @@ pub fn reply( match info.reply_type { ReplyType::SpotOrder => reply_to_spot_order(deps, info.data, module_resp), - ReplyType::MarginBrokerOpen => reply_to_create_margin_order(deps, info.data, module_resp), + ReplyType::MarginBrokerOpenMarketBuy => reply_to_create_margin_order(module_resp), + ReplyType::MarginBrokerClose => reply_to_close_margin_order(module_resp), _ => return Err(StdError::generic_err("submsg unimplemented").into()), } } diff --git a/src/error.rs b/src/error.rs index 7e36099..2586371 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,11 +17,11 @@ pub enum ContractError { #[error("Incorrect number of funds. Only one fund is allowed.")] CoinNumber, #[error("order price already been reached")] - SpotOrderPriceReached, + OrderPriceReached, #[error("order_source_denom and order_target_denom cannot be the same")] SpotOrderSameDenom, #[error("denom in order_price not used")] - SpotOrderPriceDenom, + OrderPriceDenom, #[error("fund not used by the order")] SpotOrderWrongFund, #[error("{sender} is no autorized to use the process_orders endpoint")] diff --git a/src/msg/execute_msg.rs b/src/msg/execute_msg.rs index f12428d..a40cd3d 100644 --- a/src/msg/execute_msg.rs +++ b/src/msg/execute_msg.rs @@ -1,4 +1,4 @@ -use crate::types::{MarginPosition, OrderType, SpotOrderPrice, SwapAmountInRoute}; +use crate::types::{MarginPosition, OrderPrice, OrderType, SwapAmountInRoute}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{Coin, Decimal}; @@ -8,7 +8,7 @@ pub enum ExecuteMsg { order_type: OrderType, order_source_denom: String, order_target_denom: String, - order_price: SpotOrderPrice, + order_price: OrderPrice, order_amm_routes: Vec, }, CancelSpotOrder { @@ -30,6 +30,7 @@ pub enum ExecuteMsg { borrow_asset: String, take_profit_price: Decimal, order_type: OrderType, + trigger_price: OrderPrice, }, CancelMarginOrder { diff --git a/src/msg/mod.rs b/src/msg/mod.rs index 67acdf7..e720f19 100644 --- a/src/msg/mod.rs +++ b/src/msg/mod.rs @@ -10,9 +10,12 @@ pub use reply_type::ReplyType; pub mod query_resp { mod get_all_prices_resp; + mod get_margin_order_resp; mod get_spot_order_resp; mod get_spot_orders_resp; + pub use get_all_prices_resp::GetAllPricesResponse; + pub use get_margin_order_resp::GetMarginOrderResp; pub use get_spot_order_resp::GetSpotOrderResp; pub use get_spot_orders_resp::GetSpotOrdersResp; } diff --git a/src/msg/query_msg.rs b/src/msg/query_msg.rs index 29f6dd9..ed566e3 100644 --- a/src/msg/query_msg.rs +++ b/src/msg/query_msg.rs @@ -15,14 +15,16 @@ pub enum QueryMsg { GetAllPrices {}, #[returns(OracleAssetInfoResponse)] AssetInfo { denom: String }, - #[returns(MarginMtpResponse)] - GetMarginOrder { address: String, id: u64 }, - #[returns(MarginQueryPositionsResponse)] - GetMarginOrders { pagination: PageRequest }, + #[returns(GetMarginOrderResp)] + GetMarginOrder { id: u64 }, #[returns(GetSpotOrdersResp)] GetSpotOrders { pagination: PageRequest, order_owner: Option, order_type: Option, }, + #[returns(MarginMtpResponse)] + GetMarginPosition { id: u64, address: String }, + #[returns(MarginQueryPositionsResponse)] + GetMarginPositions { pagination: PageRequest }, } diff --git a/src/msg/query_resp/get_margin_order_resp.rs b/src/msg/query_resp/get_margin_order_resp.rs new file mode 100644 index 0000000..62abe6c --- /dev/null +++ b/src/msg/query_resp/get_margin_order_resp.rs @@ -0,0 +1,7 @@ +use crate::types::MarginOrder; +use cosmwasm_schema::cw_serde; + +#[cw_serde] +pub struct GetMarginOrderResp { + pub order: MarginOrder, +} diff --git a/src/msg/reply_type.rs b/src/msg/reply_type.rs index 2541718..a8458d3 100644 --- a/src/msg/reply_type.rs +++ b/src/msg/reply_type.rs @@ -3,8 +3,7 @@ use cosmwasm_schema::cw_serde; #[cw_serde] pub enum ReplyType { SpotOrder, - MarginOpenPosition, - MarginClosePosition, MarginBrokerOpen, MarginBrokerClose, + MarginBrokerOpenMarketBuy, } diff --git a/src/tests/cancel_margin_order/not_found.rs b/src/tests/cancel_margin_order/not_found.rs new file mode 100644 index 0000000..6f0b105 --- /dev/null +++ b/src/tests/cancel_margin_order/not_found.rs @@ -0,0 +1,44 @@ +use super::*; + +#[test] +fn not_found() { + // Initialize the ElysApp. + let mut app = ElysApp::new(); + + // Create a mock message to instantiate the contract with no initial orders. + let instantiate_msg = InstantiateMockMsg { + process_order_executor: "owner".to_string(), + spot_orders: vec![], + margin_orders: vec![], + }; + + // Create a contract wrapper and store its code. + let code = ContractWrapper::new(execute, instantiate, query).with_reply(reply); + let code_id = app.store_code(Box::new(code)); + + // Instantiate the contract with "owner" as the deployer. + let addr = app + .instantiate_contract( + code_id, + Addr::unchecked("owner"), + &instantiate_msg, + &[], + "Contract", + None, + ) + .unwrap(); + + let err = app + .execute_contract( + Addr::unchecked("user"), + addr.clone(), + &ExecuteMsg::CancelMarginOrder { order_id: 0 }, + &[], + ) + .unwrap_err(); + + assert_eq!( + ContractError::OrderNotFound { order_id: 0 }, + err.downcast().unwrap() + ); +} diff --git a/src/tests/cancel_margin_order/succesful_cancel_an_order.rs b/src/tests/cancel_margin_order/succesful_cancel_an_order.rs new file mode 100644 index 0000000..d458a5f --- /dev/null +++ b/src/tests/cancel_margin_order/succesful_cancel_an_order.rs @@ -0,0 +1,83 @@ +use super::*; +use cw_multi_test::BankSudo; + +#[test] +fn succesful_cancel_an_order() { + // Initialize the ElysApp. + let mut app = ElysApp::new(); + + // Create a mock message to instantiate the contract with no initial orders. + let instantiate_msg = InstantiateMockMsg { + process_order_executor: "owner".to_string(), + spot_orders: vec![], + margin_orders: vec![MarginOrder::new( + &MarginPosition::Long, + &coin(255, "usdc"), + "btc", + "user", + &Decimal::one(), + &Decimal::one(), + &OrderType::LimitBuy, + &OrderPrice { + base_denom: "btc".to_string(), + quote_denom: "usdc".to_string(), + rate: Decimal::one(), + }, + &vec![], + )], + }; + + // Create a contract wrapper and store its code. + let code = ContractWrapper::new(execute, instantiate, query).with_reply(reply); + let code_id = app.store_code(Box::new(code)); + + // Instantiate the contract with "owner" as the deployer. + let addr = app + .instantiate_contract( + code_id, + Addr::unchecked("owner"), + &instantiate_msg, + &[], + "Contract", + None, + ) + .unwrap(); + + // Mint the token from the order to simulate that the tokens are already locked. + + app.sudo( + BankSudo::Mint { + to_address: addr.to_string(), + amount: coins(255, "usdc"), + } + .into(), + ) + .unwrap(); + + let resp = app + .execute_contract( + Addr::unchecked("user"), + addr.clone(), + &ExecuteMsg::CancelMarginOrder { order_id: 0 }, + &[], + ) + .unwrap(); + + assert_eq!( + app.wrap() + .query_balance(&addr, "usdc") + .unwrap() + .amount + .u128(), + 0 + ); + + assert_eq!( + app.wrap() + .query_balance("user", "usdc") + .unwrap() + .amount + .u128(), + 255 + ); +} diff --git a/src/tests/cancel_margin_order/unauthorize.rs b/src/tests/cancel_margin_order/unauthorize.rs new file mode 100644 index 0000000..2d4bbb0 --- /dev/null +++ b/src/tests/cancel_margin_order/unauthorize.rs @@ -0,0 +1,90 @@ +use super::*; +use cw_multi_test::BankSudo; + +#[test] +fn unauthorize() { + // Initialize the ElysApp. + let mut app = ElysApp::new(); + + // Create a mock message to instantiate the contract with no initial orders. + let instantiate_msg = InstantiateMockMsg { + process_order_executor: "owner".to_string(), + spot_orders: vec![], + margin_orders: vec![MarginOrder::new( + &MarginPosition::Long, + &coin(255, "usdc"), + "btc", + "user", + &Decimal::one(), + &Decimal::one(), + &OrderType::LimitBuy, + &OrderPrice { + base_denom: "btc".to_string(), + quote_denom: "usdc".to_string(), + rate: Decimal::one(), + }, + &vec![], + )], + }; + + // Create a contract wrapper and store its code. + let code = ContractWrapper::new(execute, instantiate, query).with_reply(reply); + let code_id = app.store_code(Box::new(code)); + + // Instantiate the contract with "owner" as the deployer. + let addr = app + .instantiate_contract( + code_id, + Addr::unchecked("owner"), + &instantiate_msg, + &[], + "Contract", + None, + ) + .unwrap(); + + // Mint the token from the order to simulate that the tokens are already locked. + + app.sudo( + BankSudo::Mint { + to_address: addr.to_string(), + amount: coins(255, "usdc"), + } + .into(), + ) + .unwrap(); + + let err = app + .execute_contract( + Addr::unchecked("not-user"), + addr.clone(), + &ExecuteMsg::CancelMarginOrder { order_id: 0 }, + &[], + ) + .unwrap_err(); + + assert_eq!( + app.wrap() + .query_balance(&addr, "usdc") + .unwrap() + .amount + .u128(), + 255 + ); + + assert_eq!( + app.wrap() + .query_balance("not-user", "usdc") + .unwrap() + .amount + .u128(), + 0 + ); + + assert_eq!( + ContractError::Unauthorized { + sender: Addr::unchecked("not-user") + }, + err.downcast().unwrap() + ); +} diff --git a/src/tests/cancel_spot_order/not_found.rs b/src/tests/cancel_spot_order/not_found.rs index ae710e0..13ab82b 100644 --- a/src/tests/cancel_spot_order/not_found.rs +++ b/src/tests/cancel_spot_order/not_found.rs @@ -7,7 +7,8 @@ fn not_found() { // Create a mock message to instantiate the contract with an empty list of orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Specify the order ID that the user wants to cancel. diff --git a/src/tests/cancel_spot_order/process_spot_order_processing.rs b/src/tests/cancel_spot_order/process_spot_order_processing.rs index cc54d1f..38db088 100644 --- a/src/tests/cancel_spot_order/process_spot_order_processing.rs +++ b/src/tests/cancel_spot_order/process_spot_order_processing.rs @@ -23,7 +23,7 @@ fn process_spot_order_processing() { // Create a "limit buy" order (dummy order) with a specific rate and balance. let dummy_order = SpotOrder::new( OrderType::LimitBuy, - SpotOrderPrice { + OrderPrice { base_denom: "ubtc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(38), 0).unwrap(), // Rate at which ubtc will be bought (38 USDC per ubtc). @@ -38,7 +38,8 @@ fn process_spot_order_processing() { // Create a mock message to instantiate the contract with the dummy order. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![dummy_order], + spot_orders: vec![dummy_order], + margin_orders: vec![], }; // Create an execution message to process orders. diff --git a/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs b/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs index d266e82..5f7334e 100644 --- a/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs +++ b/src/tests/cancel_spot_order/successful_cancel_order_with_created_order.rs @@ -13,7 +13,8 @@ fn successful_cancel_order_with_created_order() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -39,7 +40,7 @@ fn successful_cancel_order_with_created_order() { addr.clone(), &ExecuteMsg::CreateSpotOrder { order_type: OrderType::StopLoss, - order_price: SpotOrderPrice { + order_price: OrderPrice { rate: Decimal::from_atomics(Uint128::new(18), 0).unwrap(), base_denom: "btc".to_string(), quote_denom: "eth".to_string(), diff --git a/src/tests/cancel_spot_order/successful_cancel_order_with_dummy_order.rs b/src/tests/cancel_spot_order/successful_cancel_order_with_dummy_order.rs index 7e37c4d..6427f96 100644 --- a/src/tests/cancel_spot_order/successful_cancel_order_with_dummy_order.rs +++ b/src/tests/cancel_spot_order/successful_cancel_order_with_dummy_order.rs @@ -15,7 +15,8 @@ fn successful_cancel_order_with_dummy_order() { // Create a mock message to instantiate the contract with the dummy order. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![dummy_order.clone()], + spot_orders: vec![dummy_order.clone()], + margin_orders: vec![], }; // Create a contract wrapper and store its code. diff --git a/src/tests/cancel_spot_order/unauthorized.rs b/src/tests/cancel_spot_order/unauthorized.rs index a4089b2..248d3b3 100644 --- a/src/tests/cancel_spot_order/unauthorized.rs +++ b/src/tests/cancel_spot_order/unauthorized.rs @@ -8,11 +8,12 @@ fn unauthorized() { // Create a mock message to instantiate the contract with an order owned by the "user" let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![SpotOrder::new_dummy()], + spot_orders: vec![SpotOrder::new_dummy()], + margin_orders: vec![], }; // Retrieve the order ID from the instantiated message for later use. - let id = instantiate_msg.orders[0].order_id.clone().to_owned(); + let id = instantiate_msg.spot_orders[0].order_id.clone().to_owned(); // Create a contract wrapper and store its code. let code = ContractWrapper::new(execute, instantiate, query); diff --git a/src/tests/cancel_spot_orders/successfully_cancel_orders.rs b/src/tests/cancel_spot_orders/successfully_cancel_orders.rs index ab11b47..cb1f240 100644 --- a/src/tests/cancel_spot_orders/successfully_cancel_orders.rs +++ b/src/tests/cancel_spot_orders/successfully_cancel_orders.rs @@ -9,11 +9,11 @@ fn successfully_cancel_orders() { vec![coin(16, "btc"), coin(5, "eth"), coin(20, "usdt")], )]; - let orders = vec![ + let spot_orders = vec![ SpotOrder { order_type: OrderType::LimitBuy, order_id: 0, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -26,7 +26,7 @@ fn successfully_cancel_orders() { SpotOrder { order_type: OrderType::LimitSell, order_id: 1, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -39,7 +39,7 @@ fn successfully_cancel_orders() { SpotOrder { order_type: OrderType::StopLoss, order_id: 2, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -52,7 +52,7 @@ fn successfully_cancel_orders() { SpotOrder { order_type: OrderType::StopLoss, order_id: 3, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -69,7 +69,8 @@ fn successfully_cancel_orders() { // Create a mock message to instantiate the contract with an empty list of orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders, + spot_orders, + margin_orders: vec![], }; let code = ContractWrapper::new(execute, instantiate, query); diff --git a/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs b/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs index 347e4ce..714c3b8 100644 --- a/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs +++ b/src/tests/cancel_spot_orders/successfully_cancel_orders_id.rs @@ -9,11 +9,11 @@ fn successfully_cancel_orders_ids() { vec![coin(16, "btc"), coin(5, "eth"), coin(20, "usdt")], )]; - let orders = vec![ + let spot_orders = vec![ SpotOrder { order_type: OrderType::LimitBuy, order_id: 0, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -26,7 +26,7 @@ fn successfully_cancel_orders_ids() { SpotOrder { order_type: OrderType::LimitSell, order_id: 1, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -39,7 +39,7 @@ fn successfully_cancel_orders_ids() { SpotOrder { order_type: OrderType::StopLoss, order_id: 2, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -52,7 +52,7 @@ fn successfully_cancel_orders_ids() { SpotOrder { order_type: OrderType::StopLoss, order_id: 3, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -69,7 +69,8 @@ fn successfully_cancel_orders_ids() { // Create a mock message to instantiate the contract with an empty list of orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders, + spot_orders, + margin_orders: vec![], }; let code = ContractWrapper::new(execute, instantiate, query); diff --git a/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs b/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs index bf58fbd..4616af1 100644 --- a/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs +++ b/src/tests/cancel_spot_orders/successfully_cancel_orders_type.rs @@ -9,11 +9,11 @@ fn successfully_cancel_orders_type() { vec![coin(16, "btc"), coin(5, "eth"), coin(20, "usdt")], )]; - let orders = vec![ + let spot_orders = vec![ SpotOrder { order_type: OrderType::LimitBuy, order_id: 0, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -26,7 +26,7 @@ fn successfully_cancel_orders_type() { SpotOrder { order_type: OrderType::LimitSell, order_id: 1, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -39,7 +39,7 @@ fn successfully_cancel_orders_type() { SpotOrder { order_type: OrderType::StopLoss, order_id: 2, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -52,7 +52,7 @@ fn successfully_cancel_orders_type() { SpotOrder { order_type: OrderType::StopLoss, order_id: 3, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), @@ -69,7 +69,8 @@ fn successfully_cancel_orders_type() { // Create a mock message to instantiate the contract with an empty list of orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders, + spot_orders, + margin_orders: vec![], }; let code = ContractWrapper::new(execute, instantiate, query); diff --git a/src/tests/cancel_spot_orders/unauthorize.rs b/src/tests/cancel_spot_orders/unauthorize.rs index cc97b8f..2d1d24a 100644 --- a/src/tests/cancel_spot_orders/unauthorize.rs +++ b/src/tests/cancel_spot_orders/unauthorize.rs @@ -7,7 +7,8 @@ fn unauthorize() { // Create a mock message to instantiate the contract with an empty list of orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; let code = ContractWrapper::new(execute, instantiate, query); diff --git a/src/tests/create_margin_order/coin_number.rs b/src/tests/create_margin_order/coin_number.rs index a34fe0c..e7df831 100644 --- a/src/tests/create_margin_order/coin_number.rs +++ b/src/tests/create_margin_order/coin_number.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use super::*; #[test] @@ -8,7 +10,8 @@ fn coin_number() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. let code = ContractWrapper::new(execute, instantiate, query); @@ -34,10 +37,16 @@ fn coin_number() { addr, &ExecuteMsg::CreateMarginOrder { position: MarginPosition::Short, - collateral: coin(600, "usdc"), + collateral: coin(600, "uusdc"), leverage: Decimal::from_atomics(Uint128::new(500), 2).unwrap(), borrow_asset: "uatom".to_string(), take_profit_price: Decimal::from_atomics(Uint128::new(500), 2).unwrap(), + order_type: OrderType::LimitSell, + trigger_price: OrderPrice { + base_denom: "uatom".to_string(), + quote_denom: "uusdc".to_string(), + rate: Decimal::from_str("1.5").unwrap(), + }, }, &[], ) diff --git a/src/tests/create_margin_order/collateral_amount.rs b/src/tests/create_margin_order/collateral_amount.rs index 8ce5bf3..0c8fe69 100644 --- a/src/tests/create_margin_order/collateral_amount.rs +++ b/src/tests/create_margin_order/collateral_amount.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use super::*; #[test] @@ -10,7 +12,8 @@ fn collateral_amount() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. let code = ContractWrapper::new(execute, instantiate, query); @@ -40,6 +43,12 @@ fn collateral_amount() { leverage: Decimal::from_atomics(Uint128::new(500), 2).unwrap(), borrow_asset: "uatom".to_string(), take_profit_price: Decimal::from_atomics(Uint128::new(500), 2).unwrap(), + order_type: OrderType::StopLoss, + trigger_price: OrderPrice { + base_denom: "uatom".to_string(), + quote_denom: "uusdc".to_string(), + rate: Decimal::from_str("1.25").unwrap(), + }, }, &[coin(45, "usdc")], ) diff --git a/src/tests/create_margin_order/succsessful_create_short_order.rs b/src/tests/create_margin_order/non_usdc_collateral_for_short.rs similarity index 63% rename from src/tests/create_margin_order/succsessful_create_short_order.rs rename to src/tests/create_margin_order/non_usdc_collateral_for_short.rs index 0391a99..4698307 100644 --- a/src/tests/create_margin_order/succsessful_create_short_order.rs +++ b/src/tests/create_margin_order/non_usdc_collateral_for_short.rs @@ -1,9 +1,11 @@ -use crate::tests::get_order_id_from_events::get_order_id_from_events; +use std::str::FromStr; + +use cosmwasm_std::StdError; use super::*; #[test] -fn successful_create_short_order() { - // Create a wallet for the "user" with an initial balance of 100 BTC. +fn non_usdc_collateral_for_short() { + // Create a wallet for the "user" with an initial balance of 10 BTC. let wallet = vec![("user", coins(10, "btc"))]; // Initialize the ElysApp instance with the specified wallet. @@ -12,7 +14,8 @@ fn successful_create_short_order() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -31,8 +34,8 @@ fn successful_create_short_order() { ) .unwrap(); - // User "user" creates a "short position" margin order for BTC, specifying the maximum price in BTC. - let resp = app + // User "user" creates a Short position Margin order with non uusdc as collaterals + let err = app .execute_contract( Addr::unchecked("user"), addr.clone(), @@ -42,31 +45,21 @@ fn successful_create_short_order() { leverage: Decimal::from_atomics(Uint128::new(215), 2).unwrap(), borrow_asset: "btc".to_string(), take_profit_price: Decimal::from_atomics(Uint128::new(200), 2).unwrap(), + order_type: OrderType::LimitSell, + trigger_price: OrderPrice { + base_denom: "btc".to_string(), + quote_denom: "usdc".to_string(), + rate: Decimal::from_str("1.7").unwrap(), + }, }, &coins(10, "btc"), // User's BTC balance. ) - .unwrap(); - - // Verify that the "user" no longer has any BTC after creating the order. - assert_eq!( - app.wrap() - .query_balance("user", "btc") - .unwrap() - .amount - .u128(), - 0 - ); + .unwrap_err(); - // Verify that the contract address sends the BTC to the margin module. assert_eq!( - app.wrap() - .query_balance(&addr, "btc") - .unwrap() - .amount - .u128(), - 0 + ContractError::StdError(StdError::generic_err( + "the collateral asset for a short can only be UUSDC" + )), + err.downcast().unwrap(), ); - - // Verify that an order ID is emitted in the contract's events. - assert!(get_order_id_from_events(&resp.events).is_some()); } diff --git a/src/tests/create_margin_order/successful_create_margin_market_order.rs b/src/tests/create_margin_order/successful_create_margin_market_order.rs new file mode 100644 index 0000000..d1c897c --- /dev/null +++ b/src/tests/create_margin_order/successful_create_margin_market_order.rs @@ -0,0 +1,82 @@ +use std::str::FromStr; + +use super::*; + +#[test] +fn successful_create_margin_market_order() { + // Create a wallet for the "user" with an initial balance of 10 BTC. + let wallet = vec![("user", coins(10, "btc"))]; + + // Initialize the ElysApp instance with the specified wallet. + let mut app = ElysApp::new_with_wallets(wallet); + + // Create a mock message to instantiate the contract with no initial orders. + let instantiate_msg = InstantiateMockMsg { + process_order_executor: "owner".to_string(), + spot_orders: vec![], + margin_orders: vec![], + }; + + // Create a contract wrapper and store its code. + let code = ContractWrapper::new(execute, instantiate, query).with_reply(reply); + let code_id = app.store_code(Box::new(code)); + + // Instantiate the contract with "owner" as the deployer. + let addr = app + .instantiate_contract( + code_id, + Addr::unchecked("owner"), + &instantiate_msg, + &[], + "Contract", + None, + ) + .unwrap(); + + // User "user" creates a "MakerBuy" margin order for BTC + app.execute_contract( + Addr::unchecked("user"), + addr.clone(), + &ExecuteMsg::CreateMarginOrder { + position: MarginPosition::Long, + collateral: coin(10, "btc"), + leverage: Decimal::from_atomics(Uint128::new(215), 2).unwrap(), + borrow_asset: "btc".to_string(), + take_profit_price: Decimal::from_atomics(Uint128::new(200), 2).unwrap(), + order_type: OrderType::MarketBuy, + trigger_price: OrderPrice { + base_denom: "btc".to_string(), + quote_denom: "usdc".to_string(), + rate: Decimal::from_str("1.7").unwrap(), + }, + }, + &coins(10, "btc"), // User's BTC balance. + ) + .unwrap(); + + // Verify that the "user" no longer has any BTC after creating the order. + assert_eq!( + app.wrap() + .query_balance("user", "btc") + .unwrap() + .amount + .u128(), + 0 + ); + + // Verify that the contract address send the BTC to the Margin Module. + assert_eq!( + app.wrap() + .query_balance(&addr, "btc") + .unwrap() + .amount + .u128(), + 0 + ); + + let last_module = app + .init_modules(|router, _, store| router.custom.get_last_module(store).unwrap()) + .unwrap(); + + assert_eq!(last_module, "MarginBrokerOpen"); +} diff --git a/src/tests/create_margin_order/successful_create_long_order.rs b/src/tests/create_margin_order/successful_create_margin_order.rs similarity index 79% rename from src/tests/create_margin_order/successful_create_long_order.rs rename to src/tests/create_margin_order/successful_create_margin_order.rs index 5738185..36d041f 100644 --- a/src/tests/create_margin_order/successful_create_long_order.rs +++ b/src/tests/create_margin_order/successful_create_margin_order.rs @@ -1,9 +1,11 @@ +use std::str::FromStr; + use crate::tests::get_order_id_from_events::get_order_id_from_events; use super::*; #[test] -fn successful_create_long_order() { +fn successful_create_margin_order() { // Create a wallet for the "user" with an initial balance of 10 BTC. let wallet = vec![("user", coins(10, "btc"))]; @@ -13,7 +15,8 @@ fn successful_create_long_order() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -32,7 +35,7 @@ fn successful_create_long_order() { ) .unwrap(); - // User "user" creates a "long position" margin order for BTC, specifying the maximum price in BTC. + // User "user" creates a non "MakerBuy" margin order for BTC let resp = app .execute_contract( Addr::unchecked("user"), @@ -43,6 +46,12 @@ fn successful_create_long_order() { leverage: Decimal::from_atomics(Uint128::new(215), 2).unwrap(), borrow_asset: "btc".to_string(), take_profit_price: Decimal::from_atomics(Uint128::new(200), 2).unwrap(), + order_type: OrderType::LimitSell, + trigger_price: OrderPrice { + base_denom: "btc".to_string(), + quote_denom: "usdc".to_string(), + rate: Decimal::from_str("1.7").unwrap(), + }, }, &coins(10, "btc"), // User's BTC balance. ) @@ -58,14 +67,14 @@ fn successful_create_long_order() { 0 ); - // Verify that the contract address sends the BTC to the margin module. + // Verify that the contract address locked the BTC. assert_eq!( app.wrap() .query_balance(&addr, "btc") .unwrap() .amount .u128(), - 0 + 10 ); // Verify that an order ID is emitted in the contract's events. diff --git a/src/tests/create_spot_order/coin_number.rs b/src/tests/create_spot_order/coin_number.rs index 1b38afc..7a78169 100644 --- a/src/tests/create_spot_order/coin_number.rs +++ b/src/tests/create_spot_order/coin_number.rs @@ -10,7 +10,8 @@ fn coin_number() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -36,7 +37,7 @@ fn coin_number() { addr, &ExecuteMsg::CreateSpotOrder { order_type: OrderType::StopLoss, - order_price: SpotOrderPrice { + order_price: OrderPrice { rate: Decimal::from_atomics(Uint128::new(17), 0).unwrap(), base_denom: "btc".to_string(), quote_denom: "eth".to_string(), diff --git a/src/tests/create_spot_order/not_enough_fund.rs b/src/tests/create_spot_order/not_enough_fund.rs index 5255c64..69ff0a5 100644 --- a/src/tests/create_spot_order/not_enough_fund.rs +++ b/src/tests/create_spot_order/not_enough_fund.rs @@ -14,13 +14,14 @@ fn not_enough_fund() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Define the parameters for creating an order with insufficient funds. let create_order_msg = ExecuteMsg::CreateSpotOrder { order_type: OrderType::LimitSell, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "eth".to_string(), rate: Decimal::from_atomics(Uint128::new(19), 0).unwrap(), diff --git a/src/tests/create_spot_order/order_price_denom.rs b/src/tests/create_spot_order/order_price_denom.rs index d8f4908..85246d5 100644 --- a/src/tests/create_spot_order/order_price_denom.rs +++ b/src/tests/create_spot_order/order_price_denom.rs @@ -12,12 +12,13 @@ fn order_price_denom() { let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; let create_order_msg = ExecuteMsg::CreateSpotOrder { order_type: OrderType::LimitSell, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "eth".to_string(), quote_denom: "usdc".to_string(), // Invalid pair. rate: Decimal::from_atomics(Uint128::new(1700), 0).unwrap(), @@ -50,7 +51,7 @@ fn order_price_denom() { ) .unwrap_err(); - let error_msg = ContractError::SpotOrderPriceDenom; + let error_msg = ContractError::OrderPriceDenom; assert_eq!(error_msg, err.downcast().unwrap()); diff --git a/src/tests/create_spot_order/order_same_denom.rs b/src/tests/create_spot_order/order_same_denom.rs index e36d671..7ada440 100644 --- a/src/tests/create_spot_order/order_same_denom.rs +++ b/src/tests/create_spot_order/order_same_denom.rs @@ -10,12 +10,13 @@ fn order_same_denom() { let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; let create_order_msg = ExecuteMsg::CreateSpotOrder { order_type: OrderType::LimitSell, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "eth".to_string(), rate: Decimal::from_atomics(Uint128::new(19), 0).unwrap(), diff --git a/src/tests/create_spot_order/order_wrong_fund.rs b/src/tests/create_spot_order/order_wrong_fund.rs index 27c10a9..c488b86 100644 --- a/src/tests/create_spot_order/order_wrong_fund.rs +++ b/src/tests/create_spot_order/order_wrong_fund.rs @@ -11,12 +11,13 @@ fn order_wrong_fund() { let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; let create_order_msg = ExecuteMsg::CreateSpotOrder { order_type: OrderType::LimitSell, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "eth".to_string(), rate: Decimal::from_atomics(Uint128::new(19), 0).unwrap(), diff --git a/src/tests/create_spot_order/successful_create_limit_buy_order.rs b/src/tests/create_spot_order/successful_create_limit_buy_order.rs index 82f0fb4..a465ba7 100644 --- a/src/tests/create_spot_order/successful_create_limit_buy_order.rs +++ b/src/tests/create_spot_order/successful_create_limit_buy_order.rs @@ -15,7 +15,8 @@ fn successful_create_limit_buy_order() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -41,7 +42,7 @@ fn successful_create_limit_buy_order() { addr.clone(), &ExecuteMsg::CreateSpotOrder { order_type: OrderType::LimitBuy, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(30000), 0).unwrap(), // The maximum price of 30000 USDC per BTC. diff --git a/src/tests/create_spot_order/successful_create_limit_sell_order.rs b/src/tests/create_spot_order/successful_create_limit_sell_order.rs index e332d61..66b3552 100644 --- a/src/tests/create_spot_order/successful_create_limit_sell_order.rs +++ b/src/tests/create_spot_order/successful_create_limit_sell_order.rs @@ -15,7 +15,8 @@ fn successful_create_limit_sell_order() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -41,7 +42,7 @@ fn successful_create_limit_sell_order() { addr.clone(), &ExecuteMsg::CreateSpotOrder { order_type: OrderType::LimitSell, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(40000), 0).unwrap(), // The desired selling price of 40000 USDC per BTC. diff --git a/src/tests/create_spot_order/successful_create_market_order.rs b/src/tests/create_spot_order/successful_create_market_order.rs index 82fc8f2..7d0ee0c 100644 --- a/src/tests/create_spot_order/successful_create_market_order.rs +++ b/src/tests/create_spot_order/successful_create_market_order.rs @@ -27,7 +27,8 @@ fn successful_create_stop_loss_order() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -54,7 +55,7 @@ fn successful_create_stop_loss_order() { &ExecuteMsg::CreateSpotOrder { order_type: OrderType::MarketBuy, // Empty order price - not utilized in market orders - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "".to_string(), quote_denom: "".to_string(), rate: Decimal::zero(), diff --git a/src/tests/create_spot_order/successful_create_stop_loss_order.rs b/src/tests/create_spot_order/successful_create_stop_loss_order.rs index ffeebd3..6226942 100644 --- a/src/tests/create_spot_order/successful_create_stop_loss_order.rs +++ b/src/tests/create_spot_order/successful_create_stop_loss_order.rs @@ -16,7 +16,8 @@ fn successful_create_stop_loss_order() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Create a contract wrapper and store its code. @@ -42,7 +43,7 @@ fn successful_create_stop_loss_order() { addr.clone(), &ExecuteMsg::CreateSpotOrder { order_type: OrderType::StopLoss, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(30000), 0).unwrap(), // The trigger price of 30000 USDC per BTC. diff --git a/src/tests/get_margin_order/not_found.rs b/src/tests/get_margin_order/not_found.rs new file mode 100644 index 0000000..a84c6a1 --- /dev/null +++ b/src/tests/get_margin_order/not_found.rs @@ -0,0 +1,55 @@ +use cosmwasm_std::StdError; + +use crate::msg::query_resp::GetMarginOrderResp; + +use super::*; + +// This test case verifies that querying a non-existent order in the contract results in an "OrderNotFound" error. +#[test] +fn not_found() { + // Initialize the ElysApp instance. + let mut app = ElysApp::new(); + + // Create a mock message to instantiate the contract with no initial orders. + let instantiate_msg = InstantiateMockMsg { + process_order_executor: "owner".to_string(), + spot_orders: vec![], + margin_orders: vec![], + }; + + // Define an order ID that does not exist in the contract (e.g., 0). + let id: u64 = 0; + + // Create a contract wrapper and store its code. + let code = ContractWrapper::new(execute, instantiate, query); + let code_id: u64 = app.store_code(Box::new(code)); + + // Instantiate the contract with "owner" as the deployer. + let addr: Addr = app + .instantiate_contract( + code_id, + Addr::unchecked("owner"), + &instantiate_msg, + &[], + "Contract", + None, + ) + .unwrap(); + + // Query the contract for the non-existent order and expect an "OrderNotFound" error. + let err: StdError = app + .wrap() + .query_wasm_smart::(&addr, &QueryMsg::GetMarginOrder { id }) + .unwrap_err(); + + // Define the expected error message. + let error_reference = StdError::GenericErr { + msg: format!( + "Querier contract error: {}", + ContractError::OrderNotFound { order_id: id }.to_string() + ), + }; + + // Verify that the error message matches the expected error. + assert_eq!(err, error_reference); +} diff --git a/src/tests/get_margin_order/successful_query_message.rs b/src/tests/get_margin_order/successful_query_message.rs new file mode 100644 index 0000000..9e49324 --- /dev/null +++ b/src/tests/get_margin_order/successful_query_message.rs @@ -0,0 +1,60 @@ +use crate::msg::query_resp::GetMarginOrderResp; + +use super::*; +// This test case verifies the successful query of an existing order in the contract. +#[test] +fn successful_query_message() { + // Initialize the ElysApp instance. + let mut app = ElysApp::new(); + + let order = MarginOrder::new( + &MarginPosition::Long, + &coin(255, "usdc"), + "btc", + "user", + &Decimal::one(), + &Decimal::one(), + &OrderType::LimitBuy, + &OrderPrice { + base_denom: "btc".to_string(), + quote_denom: "usdc".to_string(), + rate: Decimal::one(), + }, + &vec![], + ); + + // Create a mock message to instantiate the contract with an initial dummy order. + let instantiate_msg = InstantiateMockMsg { + process_order_executor: "owner".to_string(), + spot_orders: vec![], + margin_orders: vec![order.clone()], + }; + + // Extract the order ID from the dummy order. + let id = instantiate_msg.margin_orders[0].order_id; + + // Create a contract wrapper and store its code. + let code = ContractWrapper::new(execute, instantiate, query); + let code_id = app.store_code(Box::new(code)); + + // Instantiate the contract with "owner" as the deployer. + let addr = app + .instantiate_contract( + code_id, + Addr::unchecked("owner"), + &instantiate_msg, + &[], + "Contract", + None, + ) + .unwrap(); + + // Query the contract for the existing order. + let resp: GetMarginOrderResp = app + .wrap() + .query_wasm_smart(&addr, &QueryMsg::GetMarginOrder { id }) + .unwrap(); + + // Verify that the response matches the expected order (the initial dummy order). + assert_eq!(resp, GetMarginOrderResp { order }); +} diff --git a/src/tests/get_spot_order/not_found.rs b/src/tests/get_spot_order/not_found.rs index 076e839..392af4b 100644 --- a/src/tests/get_spot_order/not_found.rs +++ b/src/tests/get_spot_order/not_found.rs @@ -9,7 +9,8 @@ fn not_found() { // Create a mock message to instantiate the contract with no initial orders. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; // Define an order ID that does not exist in the contract (e.g., 0). diff --git a/src/tests/get_spot_order/successful_query_message.rs b/src/tests/get_spot_order/successful_query_message.rs index 7820227..046bbee 100644 --- a/src/tests/get_spot_order/successful_query_message.rs +++ b/src/tests/get_spot_order/successful_query_message.rs @@ -9,11 +9,12 @@ fn successful_query_message() { // Create a mock message to instantiate the contract with an initial dummy order. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![SpotOrder::new_dummy()], + spot_orders: vec![SpotOrder::new_dummy()], + margin_orders: vec![], }; // Extract the order ID from the dummy order. - let id = instantiate_msg.orders[0].order_id.clone().to_owned(); + let id = instantiate_msg.spot_orders[0].order_id.clone().to_owned(); // Create a contract wrapper and store its code. let code = ContractWrapper::new(execute, instantiate, query); diff --git a/src/tests/get_spot_orders/get_spot_orders.rs b/src/tests/get_spot_orders/get_spot_orders.rs index f08f503..c81c190 100644 --- a/src/tests/get_spot_orders/get_spot_orders.rs +++ b/src/tests/get_spot_orders/get_spot_orders.rs @@ -4,12 +4,13 @@ use super::*; #[test] fn get_spot_orders() { - let orders: Vec = create_orders(); + let spot_orders: Vec = create_orders(); let mut app = ElysApp::new(); let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: orders.clone(), + spot_orders: spot_orders.clone(), + margin_orders: vec![], }; let code = ContractWrapper::new(execute, instantiate, query); @@ -40,7 +41,7 @@ fn get_spot_orders() { ) .unwrap(); - let (first_third, the_rest) = orders.split_at(2); + let (first_third, the_rest) = spot_orders.split_at(2); assert_eq!(&resp.orders, first_third); @@ -84,7 +85,7 @@ fn create_orders() -> Vec { SpotOrder { order_type: OrderType::LimitBuy, order_id: 0, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_owned(), quote_denom: "usdc".to_owned(), rate: Decimal::from_atomics(Uint128::new(25), 1).unwrap(), @@ -97,7 +98,7 @@ fn create_orders() -> Vec { SpotOrder { order_type: OrderType::LimitSell, order_id: 1, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "eth".to_owned(), quote_denom: "usdt".to_owned(), rate: Decimal::from_atomics(Uint128::new(10), 1).unwrap(), @@ -110,7 +111,7 @@ fn create_orders() -> Vec { SpotOrder { order_type: OrderType::StopLoss, order_id: 2, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "xrp".to_owned(), quote_denom: "usdt".to_owned(), rate: Decimal::from_atomics(Uint128::new(5), 1).unwrap(), @@ -123,7 +124,7 @@ fn create_orders() -> Vec { SpotOrder { order_type: OrderType::StopLoss, order_id: 3, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "ltc".to_owned(), quote_denom: "usdc".to_owned(), rate: Decimal::from_atomics(Uint128::new(15), 1).unwrap(), @@ -136,7 +137,7 @@ fn create_orders() -> Vec { SpotOrder { order_type: OrderType::LimitBuy, order_id: 4, - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "ada".to_owned(), quote_denom: "usdt".to_owned(), rate: Decimal::from_atomics(Uint128::new(3), 1).unwrap(), diff --git a/src/tests/mock/instantiate.rs b/src/tests/mock/instantiate.rs index 83f9b48..9e95021 100644 --- a/src/tests/mock/instantiate.rs +++ b/src/tests/mock/instantiate.rs @@ -1,4 +1,7 @@ -use crate::{states::*, types::SpotOrder}; +use crate::{ + states::*, + types::{MarginOrder, SpotOrder}, +}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{Addr, DepsMut, Env, MessageInfo, Response, StdResult}; use elys_bindings::{ElysMsg, ElysQuery}; @@ -6,7 +9,8 @@ use elys_bindings::{ElysMsg, ElysQuery}; #[cw_serde] pub struct InstantiateMockMsg { pub process_order_executor: String, - pub orders: Vec, + pub spot_orders: Vec, + pub margin_orders: Vec, } pub fn instantiate( @@ -15,12 +19,12 @@ pub fn instantiate( _info: MessageInfo, msg: InstantiateMockMsg, ) -> StdResult> { - SPOT_ORDER.save(deps.storage, &msg.orders)?; + SPOT_ORDER.save(deps.storage, &msg.spot_orders)?; deps.querier .query_balance(msg.process_order_executor.clone(), "usdc")?; PROCESS_SPOT_ORDER_EXECUTOR.save(deps.storage, &Addr::unchecked(msg.process_order_executor))?; PROCESSED_SPOT_ORDER.save(deps.storage, &vec![])?; - MARGIN_ORDER.save(deps.storage, &vec![])?; + MARGIN_ORDER.save(deps.storage, &msg.margin_orders)?; REPLY_INFO.save(deps.storage, &vec![])?; Ok(Response::new()) } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 3313deb..bcf2c76 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -67,8 +67,23 @@ mod create_margin_order { use super::*; mod coin_number; mod collateral_amount; - mod successful_create_long_order; - mod succsessful_create_short_order; + mod non_usdc_collateral_for_short; + mod successful_create_margin_market_order; + mod successful_create_margin_order; +} + +mod cancel_margin_order { + use super::*; + mod not_found; + mod succesful_cancel_an_order; + mod unauthorize; +} + +mod get_margin_order { + use super::*; + + mod not_found; + mod successful_query_message; } pub use mock::instantiate::*; diff --git a/src/tests/process_spot_order/succesful_process_limit_buy_order.rs b/src/tests/process_spot_order/succesful_process_limit_buy_order.rs index ff92837..af90aa1 100644 --- a/src/tests/process_spot_order/succesful_process_limit_buy_order.rs +++ b/src/tests/process_spot_order/succesful_process_limit_buy_order.rs @@ -33,7 +33,7 @@ fn successful_process_limit_buy_order() { // Create a "limit buy" order (dummy order) with a specific rate and balance. let dummy_order = SpotOrder::new( OrderType::LimitBuy, - SpotOrderPrice { + OrderPrice { base_denom: "ubtc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(38), 0).unwrap(), // Rate at which ubtc will be bought (38 USDC per ubtc). @@ -48,7 +48,8 @@ fn successful_process_limit_buy_order() { // Create a mock message to instantiate the contract with the dummy order. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![dummy_order], + spot_orders: vec![dummy_order], + margin_orders: vec![], }; // Create an execution message to process orders. diff --git a/src/tests/process_spot_order/successful_process_5_of_10_orders.rs b/src/tests/process_spot_order/successful_process_5_of_10_orders.rs index d3f1ec3..546385a 100644 --- a/src/tests/process_spot_order/successful_process_5_of_10_orders.rs +++ b/src/tests/process_spot_order/successful_process_5_of_10_orders.rs @@ -31,11 +31,12 @@ fn successful_process_5_of_10_orders() { let code = ContractWrapper::new(execute, instantiate, query).with_reply(reply); let code_id = app.store_code(Box::new(code)); - let orders = create_dummy_orders(); + let spot_orders = create_dummy_orders(); let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders, + spot_orders, + margin_orders: vec![], }; let execute_msg = ExecuteMsg::ProcessSpotOrders {}; @@ -178,11 +179,11 @@ fn successful_process_5_of_10_orders() { let order_ids: Vec = read_processed_order_id(resp); - assert!(order_ids.contains(&instantiate_msg.orders[7].order_id)); - assert!(order_ids.contains(&instantiate_msg.orders[3].order_id)); - assert!(order_ids.contains(&instantiate_msg.orders[0].order_id)); - assert!(order_ids.contains(&instantiate_msg.orders[6].order_id)); - assert!(order_ids.contains(&instantiate_msg.orders[8].order_id)); + assert!(order_ids.contains(&instantiate_msg.spot_orders[7].order_id)); + assert!(order_ids.contains(&instantiate_msg.spot_orders[3].order_id)); + assert!(order_ids.contains(&instantiate_msg.spot_orders[0].order_id)); + assert!(order_ids.contains(&instantiate_msg.spot_orders[6].order_id)); + assert!(order_ids.contains(&instantiate_msg.spot_orders[8].order_id)); assert_eq!( app.wrap() @@ -244,7 +245,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(1, "eth"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "eth".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(1700), 0).unwrap(), @@ -256,7 +257,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(2, "btc"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(12000), 0).unwrap(), @@ -269,7 +270,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(3, "btc"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(10000), 0).unwrap(), @@ -282,7 +283,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(5, "eth"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "eth".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(1800), 0).unwrap(), @@ -295,7 +296,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(1, "eth"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "eth".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(1200), 0).unwrap(), @@ -308,7 +309,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(1, "eth"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "eth".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(2500), 0).unwrap(), @@ -321,7 +322,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(3, "btc"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(21000), 0).unwrap(), @@ -334,7 +335,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(2, "btc"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(25000), 0).unwrap(), @@ -347,7 +348,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(1, "btc"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(30000), 0).unwrap(), @@ -360,7 +361,7 @@ fn create_dummy_orders() -> Vec { order_amount: coin(1, "eth"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![SwapAmountInRoute::new(1, "usdc")], - order_price: SpotOrderPrice { + order_price: OrderPrice { base_denom: "eth".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(2100), 0).unwrap(), diff --git a/src/tests/process_spot_order/successful_process_limit_sell_order.rs b/src/tests/process_spot_order/successful_process_limit_sell_order.rs index 970ba5d..93b4e96 100644 --- a/src/tests/process_spot_order/successful_process_limit_sell_order.rs +++ b/src/tests/process_spot_order/successful_process_limit_sell_order.rs @@ -36,7 +36,7 @@ fn successful_process_limit_sell_order() { // Create a "limit sell" order (dummy order) with a specific rate and balance. let dummy_order = SpotOrder::new( OrderType::LimitSell, - SpotOrderPrice { + OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(30000), 0).unwrap(), // Rate at which BTC will be sold (30,000 USDC per BTC). @@ -51,7 +51,8 @@ fn successful_process_limit_sell_order() { // Create a mock message to instantiate the contract with the dummy order. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![dummy_order], + spot_orders: vec![dummy_order], + margin_orders: vec![], }; // Create an execution message to process orders. diff --git a/src/tests/process_spot_order/successful_process_stop_loss_order.rs b/src/tests/process_spot_order/successful_process_stop_loss_order.rs index 6ff4ae7..882bb53 100644 --- a/src/tests/process_spot_order/successful_process_stop_loss_order.rs +++ b/src/tests/process_spot_order/successful_process_stop_loss_order.rs @@ -37,7 +37,7 @@ fn successful_process_stop_loss_order() { // Create a "stop-loss" order (dummy order) with trigger price and balance. let dummy_order = SpotOrder::new( OrderType::StopLoss, - SpotOrderPrice { + OrderPrice { base_denom: "btc".to_string(), quote_denom: "usdc".to_string(), rate: Decimal::from_atomics(Uint128::new(20000), 0).unwrap(), // Trigger price of 20,000 USDC per BTC. @@ -52,7 +52,8 @@ fn successful_process_stop_loss_order() { // Create a mock message to instantiate the contract with the dummy order. let instantiate_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![dummy_order], + spot_orders: vec![dummy_order], + margin_orders: vec![], }; // Create an execution message to process orders. diff --git a/src/tests/process_spot_order/unauthorize.rs b/src/tests/process_spot_order/unauthorize.rs index 7e055a8..6bcbdf1 100644 --- a/src/tests/process_spot_order/unauthorize.rs +++ b/src/tests/process_spot_order/unauthorize.rs @@ -7,7 +7,8 @@ fn unauthorize() { let code_id = app.store_code(Box::new(code)); let init_msg = InstantiateMockMsg { process_order_executor: "owner".to_string(), - orders: vec![], + spot_orders: vec![], + margin_orders: vec![], }; let random_user = Addr::unchecked("random"); let exec_msg = ExecuteMsg::ProcessSpotOrders {}; diff --git a/src/types/margin_order.rs b/src/types/margin_order.rs index 73081e4..bf8d778 100644 --- a/src/types/margin_order.rs +++ b/src/types/margin_order.rs @@ -2,7 +2,7 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{Coin, Decimal}; use elys_bindings::types::MarginPosition; -use super::OrderType; +use super::{OrderPrice, OrderType}; #[cw_serde] pub struct MarginOrder { @@ -14,7 +14,7 @@ pub struct MarginOrder { pub leverage: Decimal, pub take_profit_price: Decimal, pub order_type: OrderType, - pub position_id: Option, + pub trigger_price: OrderPrice, } impl MarginOrder { @@ -26,6 +26,7 @@ impl MarginOrder { leverage: &Decimal, take_profit_price: &Decimal, order_type: &OrderType, + trigger_price: &OrderPrice, order_vec: &Vec, ) -> Self { let order_id: u64 = match order_vec.iter().max_by_key(|s| s.order_id) { @@ -42,7 +43,7 @@ impl MarginOrder { leverage: leverage.to_owned(), take_profit_price: take_profit_price.to_owned(), order_type: order_type.to_owned(), - position_id: None, + trigger_price: trigger_price.to_owned(), } } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 42ded31..70d8304 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -16,4 +16,4 @@ pub use margin_order::MarginOrder; pub use order_type::OrderType; pub use reply_info::ReplyInfo; pub use spot_order::spot_order::SpotOrder; -pub use spot_order_price::SpotOrderPrice; +pub use spot_order_price::OrderPrice; diff --git a/src/types/spot_order/impls/new.rs b/src/types/spot_order/impls/new.rs index a68a15d..f6e5784 100644 --- a/src/types/spot_order/impls/new.rs +++ b/src/types/spot_order/impls/new.rs @@ -4,7 +4,7 @@ use cosmwasm_std::{Addr, Coin}; impl SpotOrder { pub fn new( order_type: OrderType, - order_price: SpotOrderPrice, + order_price: OrderPrice, order_amount: Coin, owner_address: Addr, order_target_denom: String, diff --git a/src/types/spot_order/impls/new_dummy.rs b/src/types/spot_order/impls/new_dummy.rs index 258a125..28db732 100644 --- a/src/types/spot_order/impls/new_dummy.rs +++ b/src/types/spot_order/impls/new_dummy.rs @@ -9,7 +9,7 @@ impl SpotOrder { order_amount: coin(1000, "btc"), owner_address: Addr::unchecked("user"), order_amm_routes: vec![], - order_price: SpotOrderPrice { + order_price: OrderPrice { quote_denom: "eth".to_string(), base_denom: "btc".to_string(), rate: Decimal::from_atomics(Uint128::new(5), 0).unwrap(), diff --git a/src/types/spot_order/spot_order.rs b/src/types/spot_order/spot_order.rs index 0d07bba..3cb7c90 100644 --- a/src/types/spot_order/spot_order.rs +++ b/src/types/spot_order/spot_order.rs @@ -1,4 +1,4 @@ -use crate::types::{order_type::OrderType, SpotOrderPrice, SwapAmountInRoute}; +use crate::types::{order_type::OrderType, OrderPrice, SwapAmountInRoute}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{Addr, Coin}; @@ -6,7 +6,7 @@ use cosmwasm_std::{Addr, Coin}; pub struct SpotOrder { pub order_type: OrderType, pub order_id: u64, - pub order_price: SpotOrderPrice, + pub order_price: OrderPrice, pub order_amount: Coin, pub owner_address: Addr, pub order_target_denom: String, diff --git a/src/types/spot_order_price.rs b/src/types/spot_order_price.rs index 506395f..6302c2c 100644 --- a/src/types/spot_order_price.rs +++ b/src/types/spot_order_price.rs @@ -2,7 +2,7 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::Decimal; #[cw_serde] -pub struct SpotOrderPrice { +pub struct OrderPrice { pub base_denom: String, pub quote_denom: String, pub rate: Decimal, From 4927639658bb3b1cb65317777a0ff2bb73b8b179 Mon Sep 17 00:00:00 2001 From: politeWall <138504353+politeWall@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:53:35 +0100 Subject: [PATCH 3/5] fix: cargo.toml --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 12e5b6a..c26d8d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,13 +14,13 @@ thiserror = "1" schemars = "0.8.1" cosmwasm-schema = "1.1.4" cw-utils = "0.13" -elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "fix-margin" } +elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "main" } [dev-dependencies] cw-multi-test = "0.13.4" serde_json = "1.0.107" -elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "fix-margin", features = [ +elys-bindings = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "main", features = [ "testing", ] } -elys-bindings-test = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "fix-margin" } +elys-bindings-test = { version = "0.1.0", git = "https://github.com/elys-network/bindings", branch = "main" } From 802fd91e15a6482c2724b8076b82e2a6b4958132 Mon Sep 17 00:00:00 2001 From: politeWall <138504353+politeWall@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:02:35 +0100 Subject: [PATCH 4/5] fix: warning --- src/action/execute/create_margin_order.rs | 2 +- .../succesful_cancel_an_order.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/action/execute/create_margin_order.rs b/src/action/execute/create_margin_order.rs index 247168f..12ce51f 100644 --- a/src/action/execute/create_margin_order.rs +++ b/src/action/execute/create_margin_order.rs @@ -1,6 +1,6 @@ use super::*; use crate::msg::ReplyType; -use cosmwasm_std::{to_json_binary, Coin, Decimal, Int128, StdError, StdResult, Storage, SubMsg}; +use cosmwasm_std::{Coin, Decimal, Int128, StdError, StdResult, Storage, SubMsg}; pub fn create_margin_order( info: MessageInfo, diff --git a/src/tests/cancel_margin_order/succesful_cancel_an_order.rs b/src/tests/cancel_margin_order/succesful_cancel_an_order.rs index d458a5f..883a839 100644 --- a/src/tests/cancel_margin_order/succesful_cancel_an_order.rs +++ b/src/tests/cancel_margin_order/succesful_cancel_an_order.rs @@ -54,14 +54,13 @@ fn succesful_cancel_an_order() { ) .unwrap(); - let resp = app - .execute_contract( - Addr::unchecked("user"), - addr.clone(), - &ExecuteMsg::CancelMarginOrder { order_id: 0 }, - &[], - ) - .unwrap(); + app.execute_contract( + Addr::unchecked("user"), + addr.clone(), + &ExecuteMsg::CancelMarginOrder { order_id: 0 }, + &[], + ) + .unwrap(); assert_eq!( app.wrap() From 9183f9898daf17b0d1a6fa70197a0945533b7211 Mon Sep 17 00:00:00 2001 From: politeWall <138504353+politeWall@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:17:39 +0100 Subject: [PATCH 5/5] feat: update FE Script --- front_end_script/README.md | 33 ++++++++-- front_end_script/upload.js | 123 +++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 6 deletions(-) diff --git a/front_end_script/README.md b/front_end_script/README.md index a895417..96072b9 100644 --- a/front_end_script/README.md +++ b/front_end_script/README.md @@ -214,7 +214,7 @@ cancelMarginOrder("your_order_id_here"); cancelMarginOrder("1"); ``` -### 8. getMarginOrder(address,id) +### 8. getMarginOrder(id) This function retrieves information about a specific margin order by querying a CosmWasm contract on the blockchain. @@ -232,10 +232,31 @@ getMarginOrder("your_order_id_here"); #### Exemple ```js -getMarginOrder("255"); +getMarginOrder("2"); ``` -### 9. getMarginOrders(pagination) +### 9. getMarginPosition(address,id) + +This function retrieves information about a specific margin order by querying a CosmWasm contract on the blockchain. + +#### Parameters + +- `address` (String): The address associated with the margin order. +- `order_id` (String): The unique identifier for the order you want to retrieve. + +#### Usage + +```javascript +getMarginPosition("your_address", "your_order_id_here"); +``` + +#### Exemple + +```js +getMarginPosition("elys1x5fehwug2vtkyn4vpunwkfn9zxkpxl8jg0lwuu", "255"); +``` + +### 10. getMarginPositions(pagination) This function retrieves multiple margin orders by querying a CosmWasm contract on the blockchain. @@ -246,16 +267,16 @@ This function retrieves multiple margin orders by querying a CosmWasm contract o #### Usage ```javascript -getMarginOrders("pagination"); +getMarginPositions("pagination"); ``` #### Exemple ```js -getMarginOrders({ count_total: true, limit: 10, reverse: false, key: null }); +getMarginPositions({ count_total: true, limit: 10, reverse: false, key: null }); ``` -### 10. SwapEstimationByDenom(amount, denom_in, denom_out) +### 11. SwapEstimationByDenom(amount, denom_in, denom_out) This function retrieves an estimation of the value obtained by swapping one asset for another. diff --git a/front_end_script/upload.js b/front_end_script/upload.js index 0aedaa1..f108978 100644 --- a/front_end_script/upload.js +++ b/front_end_script/upload.js @@ -180,3 +180,126 @@ async function SwapEstimationByDenom(amount, denom_in, denom_out) { ); console.log(`Result: `, result); } + +async function createMarginOrder( + position_type, + collateral, + leverage_value, + borrow_asset, + take_profit_price, + order_type, + trigger_price +) { + const gasPrice = GasPrice.fromString(GASPRICE); + const sender_wallet = await DirectSecp256k1HdWallet.fromMnemonic( + sender.mnemonic, + { prefix: "elys" } + ); + const sender_client = await SigningCosmWasmClient.connectWithSigner( + rpcEndpoint, + sender_wallet + ); + const executeFee = calculateFee(300_000, gasPrice); + const msg = { + create_margin_order: { + position_type: position_type, + collateral: collateral, + leverage_value: leverage_value, + borrow_asset: borrow_asset, + take_profit_price: take_profit_price, + order_type: order_type, + trigger_price: trigger_price, + }, + }; + + const create_margin_order_res = await sender_client.execute( + sender.address, + trade_shield_contract_addr, + msg, + executeFee, + "", + coins(amount_send, denom_send) + ); + console.log("create_margin_order_res:", create_margin_order_res); +} + +async function cancelMarginOrder(order_id) { + const gasPrice = GasPrice.fromString(GASPRICE); + const sender_wallet = await DirectSecp256k1HdWallet.fromMnemonic( + sender.mnemonic, + { prefix: "elys" } + ); + const sender_client = await SigningCosmWasmClient.connectWithSigner( + rpcEndpoint, + sender_wallet + ); + const executeFee = calculateFee(300_000, gasPrice); + const msg = { + cancel_margin_order: { + order_id: order_id, + }, + }; + + const create_margin_order_res = await sender_client.execute( + sender.address, + trade_shield_contract_addr, + msg, + executeFee, + "" + ); + console.log("create_margin_order_res:", create_margin_order_res); +} + +async function getMarginOrder(order_id) { + const sender_wallet = await DirectSecp256k1HdWallet.fromMnemonic( + sender.mnemonic, + { prefix: "elys" } + ); + const sender_client = await SigningCosmWasmClient.connectWithSigner( + rpcEndpoint, + sender_wallet + ); + const result = await sender_client.queryContractSmart( + trade_shield_contract_addr, + { + get_margin_order: { order_id: order_id }, + } + ); + console.log(`Result: `, result); +} + +async function getMarginPosition(id, address) { + const sender_wallet = await DirectSecp256k1HdWallet.fromMnemonic( + sender.mnemonic, + { prefix: "elys" } + ); + const sender_client = await SigningCosmWasmClient.connectWithSigner( + rpcEndpoint, + sender_wallet + ); + const result = await sender_client.queryContractSmart( + trade_shield_contract_addr, + { + get_margin_position: { id: id, address: address }, + } + ); + console.log(`Result: `, result); +} + +async function getMarginPositions(pagination) { + const sender_wallet = await DirectSecp256k1HdWallet.fromMnemonic( + sender.mnemonic, + { prefix: "elys" } + ); + const sender_client = await SigningCosmWasmClient.connectWithSigner( + rpcEndpoint, + sender_wallet + ); + const result = await sender_client.queryContractSmart( + trade_shield_contract_addr, + { + get_margin_positions: { pagination: pagination }, + } + ); + console.log(`Result: `, result); +}