use test_tube_tx::{fn_execute, fn_query, Module};
use tx_wasm_sdk::types::tx::dex::v1::{
EmptyResponse, MsgCancelOrder, MsgCancelOrdersByDenom, MsgPlaceOrder,
QueryAccountDenomOrdersCountRequest, QueryAccountDenomOrdersCountResponse,
QueryOrderBookOrdersRequest, QueryOrderBookOrdersResponse, QueryOrderBookParamsRequest,
QueryOrderBookParamsResponse, QueryOrderBooksRequest, QueryOrderBooksResponse,
QueryOrderRequest, QueryOrderResponse, QueryOrdersRequest, QueryOrdersResponse,
QueryParamsRequest, QueryParamsResponse,
};
use test_tube_tx::runner::Runner;
pub struct Dex<'a, R: Runner<'a>> {
runner: &'a R,
}
impl<'a, R: Runner<'a>> Module<'a, R> for Dex<'a, R> {
fn new(runner: &'a R) -> Self {
Self { runner }
}
}
impl<'a, R> Dex<'a, R>
where
R: Runner<'a>,
{
fn_execute! { pub place_order: MsgPlaceOrder => EmptyResponse }
fn_execute! { pub cancel_order: MsgCancelOrder => EmptyResponse }
fn_execute! { pub cancel_orders_by_denom: MsgCancelOrdersByDenom => EmptyResponse }
fn_query! {
pub query_params ["/coreum.dex.v1.Query/Params"]: QueryParamsRequest => QueryParamsResponse
}
fn_query! {
pub query_order_book_params ["/coreum.dex.v1.Query/OrderBookParams"]: QueryOrderBookParamsRequest => QueryOrderBookParamsResponse
}
fn_query! {
pub query_account_denom_orders_count ["/coreum.dex.v1.Query/AccountDenomOrdersCount"]: QueryAccountDenomOrdersCountRequest => QueryAccountDenomOrdersCountResponse
}
fn_query! {
pub query_order_book_orders ["/coreum.dex.v1.Query/OrderBookOrders"]: QueryOrderBookOrdersRequest => QueryOrderBookOrdersResponse
}
fn_query! {
pub query_order_books ["/coreum.dex.v1.Query/OrderBooks"]: QueryOrderBooksRequest => QueryOrderBooksResponse
}
fn_query! {
pub query_order ["/coreum.dex.v1.Query/Order"]: QueryOrderRequest => QueryOrderResponse
}
fn_query! {
pub query_orders ["/coreum.dex.v1.Query/Orders"]: QueryOrdersRequest => QueryOrdersResponse
}
}
#[cfg(test)]
mod tests {
use tx_wasm_sdk::types::tx::asset::ft::v1::{DexSettings, Feature, MsgIssue};
use tx_wasm_sdk::types::tx::dex::v1::{
MsgCancelOrder, MsgCancelOrdersByDenom, MsgPlaceOrder, OrderType,
QueryAccountDenomOrdersCountRequest, QueryOrderBookOrdersRequest,
QueryOrderBookParamsRequest, QueryOrderBooksRequest, QueryOrderRequest, QueryOrdersRequest,
QueryParamsRequest, Side, TimeInForce,
};
use cosmwasm_std::Coin;
use tx_wasm_sdk::types::cosmos::base::v1beta1::Coin as BaseCoin;
use crate::runner::app::FEE_DENOM;
use crate::{Account, AssetFT, Dex, Module, TXTestApp};
#[test]
fn dex_testing() {
let app = TXTestApp::new();
let acc1 = app
.init_account(&[Coin::new(100_000_000_000_000_000_000u128, FEE_DENOM)])
.unwrap();
app.init_account(&[Coin::new(100_000_000_000_000_000_000u128, FEE_DENOM)])
.unwrap();
let assetft = AssetFT::new(&app);
let dex = Dex::new(&app);
let request_params = dex.query_params(&QueryParamsRequest {}).unwrap();
let params = request_params.params.unwrap();
assert_eq!(
params.default_unified_ref_amount,
"1000000000000000000000000"
);
assert_eq!(params.price_tick_exponent, -6);
assert_eq!(params.max_orders_per_denom, 100);
assert_eq!(
params.order_reserve.unwrap(),
BaseCoin {
amount: 10000000u128.to_string(),
denom: FEE_DENOM.to_string(),
}
);
assetft
.issue(
MsgIssue {
issuer: acc1.address(),
symbol: "TKN1".to_string(),
subunit: "tkn1".to_string(),
precision: 5,
initial_amount: "1000000".to_string(),
description: "dex token 1".to_string(),
features: vec![
Feature::DexOrderCancellation as i32,
Feature::DexUnifiedRefAmountChange as i32,
],
burn_rate: "0".to_string(),
send_commission_rate: "0".to_string(),
uri: "token_1_uri".to_string(),
uri_hash: "token_1_uri_hash".to_string(),
extension_settings: None,
dex_settings: Some(DexSettings {
unified_ref_amount: params.default_unified_ref_amount.to_string(),
whitelisted_denoms: vec![],
}),
},
&acc1,
)
.unwrap();
let denom1 = format!("{}-{}", "tkn1", acc1.address()).to_lowercase();
assetft
.issue(
MsgIssue {
issuer: acc1.address(),
symbol: "TKN2".to_string(),
subunit: "tkn2".to_string(),
precision: 5,
initial_amount: "1000000".to_string(),
description: "dex token 2".to_string(),
features: vec![
Feature::DexOrderCancellation as i32,
Feature::DexUnifiedRefAmountChange as i32,
],
burn_rate: "0".to_string(),
send_commission_rate: "0".to_string(),
uri: "token_2_uri".to_string(),
uri_hash: "token_2_uri_hash".to_string(),
extension_settings: None,
dex_settings: Some(DexSettings {
unified_ref_amount: params.default_unified_ref_amount.to_string(),
whitelisted_denoms: vec![],
}),
},
&acc1,
)
.unwrap();
let denom2 = format!("{}-{}", "tkn2", acc1.address()).to_lowercase();
let msg_place_order = MsgPlaceOrder {
sender: acc1.address(),
r#type: OrderType::Limit as i32,
id: "id".to_string(),
base_denom: denom1.clone(),
quote_denom: denom2.clone(),
price: "1e-1".to_string(),
quantity: "10000".to_string(),
side: Side::Sell as i32,
good_til: None,
time_in_force: TimeInForce::Gtc as i32,
};
dex.place_order(msg_place_order.clone(), &acc1).unwrap();
let request_order_book_params = dex
.query_order_book_params(&QueryOrderBookParamsRequest {
base_denom: denom1.clone(),
quote_denom: denom2.clone(),
})
.unwrap();
assert_eq!(request_order_book_params.price_tick, "1e-6");
assert_eq!(request_order_book_params.quantity_step, "10000");
assert_eq!(
request_order_book_params.base_denom_unified_ref_amount,
"1000000000000000000000000"
);
assert_eq!(
request_order_book_params.quote_denom_unified_ref_amount,
"1000000000000000000000000"
);
let request_order_books = dex
.query_order_books(&QueryOrderBooksRequest { pagination: None })
.unwrap();
assert_eq!(request_order_books.order_books.len(), 2);
dex.cancel_order(
MsgCancelOrder {
sender: acc1.address().to_string(),
id: "id".to_string(),
},
&acc1,
)
.unwrap();
let mut msg_place_order = msg_place_order.clone();
msg_place_order.id = "id2".to_string();
dex.place_order(msg_place_order, &acc1).unwrap();
let request_order_book_orders = dex
.query_order_book_orders(&QueryOrderBookOrdersRequest {
base_denom: denom1.clone(),
quote_denom: denom2.clone(),
side: Side::Sell as i32,
pagination: None,
})
.unwrap();
assert_eq!(request_order_book_orders.orders.len(), 1);
assert_eq!(request_order_book_orders.orders[0].id, "id2");
assert_eq!(request_order_book_orders.orders[0].price, "1e-1");
let request_order = dex
.query_order(&QueryOrderRequest {
creator: acc1.address().to_string(),
id: "id2".to_string(),
})
.unwrap();
let order = request_order.order.unwrap();
assert_eq!(order.id, "id2");
assert_eq!(order.price, "1e-1");
let request_orders = dex
.query_orders(&QueryOrdersRequest {
creator: acc1.address().to_string(),
pagination: None,
})
.unwrap();
assert_eq!(request_orders.orders.len(), 1);
assert_eq!(request_orders.orders[0].id, "id2");
assert_eq!(request_orders.orders[0].price, "1e-1");
let request_account_denom_orders_count = dex
.query_account_denom_orders_count(&QueryAccountDenomOrdersCountRequest {
account: acc1.address().to_string(),
denom: denom1.clone(),
})
.unwrap();
assert_eq!(request_account_denom_orders_count.count, 1);
dex.cancel_orders_by_denom(
MsgCancelOrdersByDenom {
sender: acc1.address().to_string(),
account: acc1.address().to_string(),
denom: denom1.clone(),
},
&acc1,
)
.unwrap();
}
}