-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/stargate tester contract #220
Changes from 12 commits
9d50d68
122e45c
f82826b
7295a31
1585aa2
b657d5d
ebbb001
9d2c6ea
01e5f5a
752c205
8fc14a0
a20cb20
a8c5aee
ebf0280
825207d
42ab0c6
342efc6
0d5be4e
5718e0b
41e822a
e43ad9a
cd84611
2cfe4a1
9b4741f
c92a4ad
8a0f953
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
[package] | ||
authors = [ "Jose Luis Bernal Castillo <[email protected]>" ] | ||
edition = "2018" | ||
name = "injective-cosmwasm-stargate-example" | ||
version = "0.0.1" | ||
|
||
exclude = [ | ||
# Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. | ||
"contract.wasm", | ||
"hash.txt", | ||
] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[lib] | ||
crate-type = [ "cdylib", "rlib" ] | ||
|
||
[features] | ||
# use library feature to disable all instantiate/execute/query exports | ||
integration = [ ] | ||
library = [ ] | ||
|
||
[dependencies] | ||
base64 = { workspace = true } | ||
cosmos-sdk-proto = { workspace = true } | ||
cosmwasm-schema = { workspace = true } | ||
cosmwasm-std = { workspace = true } | ||
cw-storage-plus = { workspace = true } | ||
cw2 = { workspace = true } | ||
injective-cosmwasm = { workspace = true } | ||
injective-math = { workspace = true } | ||
injective-std = { workspace = true } | ||
prost = { workspace = true } | ||
schemars = { workspace = true } | ||
serde = { workspace = true } | ||
serde_json = { workspace = true } | ||
thiserror = { workspace = true } | ||
|
||
[dev-dependencies] | ||
injective-std = { workspace = true } | ||
injective-test-tube = { workspace = true } | ||
injective-testing = { workspace = true } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use crate::{ | ||
error::ContractError, | ||
handle::{handle_test_market_spot_order, handle_test_transient_derivative_order, handle_test_transient_spot_order}, | ||
msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, | ||
query::{handle_query_bank_params, handle_query_spot_market, handle_query_stargate_raw}, | ||
reply::{handle_create_derivative_order_reply_stargate, handle_create_order_reply_stargate}, | ||
}; | ||
|
||
use cosmwasm_std::{entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult}; | ||
use cw2::set_contract_version; | ||
use injective_cosmwasm::{InjectiveMsgWrapper, InjectiveQueryWrapper}; | ||
|
||
const CONTRACT_NAME: &str = "crates.io:injective:dummy-stargate-contract"; | ||
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); | ||
pub const CREATE_SPOT_ORDER_REPLY_ID: u64 = 0u64; | ||
pub const CREATE_DERIVATIVE_ORDER_REPLY_ID: u64 = 1u64; | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn instantiate(deps: DepsMut, _env: Env, _info: MessageInfo, _msg: InstantiateMsg) -> Result<Response, ContractError> { | ||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; | ||
Ok(Response::default()) | ||
} | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn execute( | ||
deps: DepsMut<InjectiveQueryWrapper>, | ||
env: Env, | ||
info: MessageInfo, | ||
msg: ExecuteMsg, | ||
) -> Result<Response<InjectiveMsgWrapper>, ContractError> { | ||
match msg { | ||
ExecuteMsg::TestTraderTransientSpotOrders { | ||
market_id, | ||
subaccount_id, | ||
price, | ||
quantity, | ||
} => handle_test_transient_spot_order(deps, env, &info, market_id, subaccount_id, price, quantity), | ||
ExecuteMsg::TestMarketOrderStargate { | ||
market_id, | ||
subaccount_id, | ||
price, | ||
quantity, | ||
} => handle_test_market_spot_order(deps, env.contract.address.as_ref(), market_id, subaccount_id, price, quantity), | ||
ExecuteMsg::TestTraderTransientDerivativeOrders { | ||
market_id, | ||
subaccount_id, | ||
price, | ||
quantity, | ||
margin, | ||
} => handle_test_transient_derivative_order(deps, env, &info, market_id, subaccount_id, price, quantity, margin), | ||
} | ||
} | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn query(deps: Deps<InjectiveQueryWrapper>, _env: Env, msg: QueryMsg) -> StdResult<Binary> { | ||
match msg { | ||
QueryMsg::QueryStargateRaw { path, query_request } => handle_query_stargate_raw(&deps.querier, path, query_request), | ||
QueryMsg::QueryBankParams {} => handle_query_bank_params(deps), | ||
QueryMsg::QuerySpotMarket { market_id } => handle_query_spot_market(deps, &market_id), | ||
} | ||
} | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn reply(deps: DepsMut<InjectiveQueryWrapper>, _env: Env, msg: Reply) -> Result<Response, ContractError> { | ||
match msg.id { | ||
CREATE_SPOT_ORDER_REPLY_ID => handle_create_order_reply_stargate(deps, &msg), | ||
CREATE_DERIVATIVE_ORDER_REPLY_ID => handle_create_derivative_order_reply_stargate(deps, &msg), | ||
_ => Err(ContractError::UnrecognizedReply(msg.id)), | ||
} | ||
} | ||
Comment on lines
+63
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Address potential conflict with existing reply IDs and improve error handling. The past review comments indicate a potential conflict with the Additionally, consider improving the error handling in the Apply this diff to improve the error handling: - _ => Err(ContractError::UnrecognizedReply(msg.id)),
+ _ => Err(ContractError::UnrecognizedReply(format!("Unrecognized reply ID: {}", msg.id))),
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; | ||
use base64::Engine; | ||
use prost::Message; | ||
|
||
pub fn encode_proto_message<T: Message>(msg: T) -> String { | ||
let mut buf = vec![]; | ||
T::encode(&msg, &mut buf).unwrap(); | ||
BASE64_STANDARD.encode(&buf) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
use cosmwasm_std::StdError; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug)] | ||
pub enum ContractError { | ||
#[error("{0}")] | ||
Std(#[from] StdError), | ||
#[error("Unrecognized reply id: {0}")] | ||
UnrecognizedReply(u64), | ||
#[error("Invalid reply from sub-message {id}, {err}")] | ||
ReplyParseFailure { id: u64, err: String }, | ||
#[error("Failure response from submsg: {0}")] | ||
SubMsgFailure(String), | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use crate::{ | ||
contract::{CREATE_DERIVATIVE_ORDER_REPLY_ID, CREATE_SPOT_ORDER_REPLY_ID}, | ||
msg::{MSG_CREATE_DERIVATIVE_LIMIT_ORDER_ENDPOINT, MSG_CREATE_SPOT_LIMIT_ORDER_ENDPOINT}, | ||
order_management::{create_derivative_limit_order, create_spot_limit_order, create_stargate_msg, encode_bytes_message}, | ||
spot_market_order_msg::create_spot_market_order_message, | ||
state::{CacheOrderInfo, ORDER_CALL_CACHE}, | ||
ContractError, | ||
}; | ||
use cosmos_sdk_proto::{cosmos::authz::v1beta1::MsgExec, traits::Message, Any}; | ||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response, SubMsg}; | ||
use injective_cosmwasm::{InjectiveMsgWrapper, InjectiveQuerier, InjectiveQueryWrapper, MarketId, OrderType, SubaccountId}; | ||
use injective_math::FPDecimal; | ||
|
||
pub const MSG_EXEC: &str = "/cosmos.authz.v1beta1.MsgExec"; | ||
|
||
pub fn handle_test_market_spot_order( | ||
deps: DepsMut<InjectiveQueryWrapper>, | ||
sender: &str, | ||
market_id: MarketId, | ||
subaccount_id: SubaccountId, | ||
price: String, | ||
quantity: String, | ||
) -> Result<Response<InjectiveMsgWrapper>, ContractError> { | ||
let querier = InjectiveQuerier::new(&deps.querier); | ||
let spot_market = querier.query_spot_market(&market_id).unwrap().market.unwrap(); | ||
|
||
let order_msg = create_spot_market_order_message( | ||
FPDecimal::must_from_str(price.as_str()), | ||
FPDecimal::must_from_str(quantity.as_str()), | ||
OrderType::Sell, | ||
sender, | ||
subaccount_id.as_str(), | ||
"", | ||
&spot_market, | ||
)?; | ||
|
||
Ok(Response::new().add_message(order_msg)) | ||
} | ||
|
||
pub fn handle_test_transient_spot_order( | ||
deps: DepsMut<InjectiveQueryWrapper>, | ||
env: Env, | ||
info: &MessageInfo, | ||
market_id: MarketId, | ||
subaccount_id: SubaccountId, | ||
price: String, | ||
quantity: String, | ||
) -> Result<Response<InjectiveMsgWrapper>, ContractError> { | ||
let querier = InjectiveQuerier::new(&deps.querier); | ||
let spot_market = querier.query_spot_market(&market_id).unwrap().market.unwrap(); | ||
|
||
let order_msg = create_spot_limit_order( | ||
FPDecimal::must_from_str(price.as_str()), | ||
FPDecimal::must_from_str(quantity.as_str()), | ||
OrderType::Sell, | ||
info.sender.as_str(), | ||
subaccount_id.as_str(), | ||
&spot_market, | ||
); | ||
|
||
let order_bytes = encode_bytes_message(&order_msg).unwrap(); | ||
|
||
let msg_exec = MsgExec { | ||
grantee: env.contract.address.to_string(), | ||
msgs: vec![Any { | ||
type_url: MSG_CREATE_SPOT_LIMIT_ORDER_ENDPOINT.to_string(), | ||
value: order_bytes, | ||
}], | ||
}; | ||
|
||
let order_submessage = SubMsg::reply_on_success( | ||
create_stargate_msg(MSG_EXEC, msg_exec.encode_to_vec()).unwrap(), | ||
CREATE_SPOT_ORDER_REPLY_ID, | ||
); | ||
|
||
save_cache_info(deps, market_id, subaccount_id)?; | ||
|
||
Ok(Response::new().add_submessage(order_submessage)) | ||
} | ||
|
||
pub fn handle_test_transient_derivative_order( | ||
deps: DepsMut<InjectiveQueryWrapper>, | ||
env: Env, | ||
info: &MessageInfo, | ||
market_id: MarketId, | ||
subaccount_id: SubaccountId, | ||
price: String, | ||
quantity: String, | ||
margin: String, | ||
) -> Result<Response<InjectiveMsgWrapper>, ContractError> { | ||
let querier: InjectiveQuerier = InjectiveQuerier::new(&deps.querier); | ||
let market = querier.query_derivative_market(&market_id).unwrap().market.unwrap(); | ||
|
||
let order_msg = create_derivative_limit_order( | ||
FPDecimal::must_from_str(price.as_str()), | ||
FPDecimal::must_from_str(quantity.as_str()), | ||
FPDecimal::must_from_str(margin.as_str()), | ||
OrderType::Buy, | ||
info.sender.as_str(), | ||
subaccount_id.as_str(), | ||
&market, | ||
); | ||
|
||
let order_bytes = encode_bytes_message(&order_msg).unwrap(); | ||
|
||
let msg_exec = MsgExec { | ||
grantee: env.contract.address.to_string(), | ||
msgs: vec![Any { | ||
type_url: MSG_CREATE_DERIVATIVE_LIMIT_ORDER_ENDPOINT.to_string(), | ||
value: order_bytes, | ||
}], | ||
}; | ||
|
||
let order_submessage = SubMsg::reply_on_success( | ||
create_stargate_msg(MSG_EXEC, msg_exec.encode_to_vec()).unwrap(), | ||
CREATE_DERIVATIVE_ORDER_REPLY_ID, | ||
); | ||
|
||
save_cache_info(deps, market_id, subaccount_id)?; | ||
|
||
Ok(Response::new().add_submessage(order_submessage)) | ||
} | ||
|
||
fn save_cache_info(deps: DepsMut<InjectiveQueryWrapper>, market_id: MarketId, subaccount_id: SubaccountId) -> Result<(), ContractError> { | ||
let cache_order_info = CacheOrderInfo { | ||
subaccount: subaccount_id, | ||
market_id, | ||
}; | ||
|
||
let mut order_cache = match ORDER_CALL_CACHE.may_load(deps.storage)? { | ||
Some(order_cache) => order_cache, | ||
None => vec![], | ||
}; | ||
|
||
order_cache.push(cache_order_info); | ||
|
||
ORDER_CALL_CACHE.save(deps.storage, &order_cache)?; | ||
Ok(()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
pub mod contract; | ||
mod encode_helper; | ||
mod error; | ||
mod handle; | ||
pub mod msg; | ||
mod order_management; | ||
mod query; | ||
mod reply; | ||
mod spot_market_order_msg; | ||
mod state; | ||
#[cfg(test)] | ||
mod testing; | ||
#[cfg(test)] | ||
pub mod utils; | ||
|
||
pub use crate::error::ContractError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure Minimum Notional Value is Enforced
The creation of the spot market handler should enforce a minimum notional value. This is critical for maintaining market stability and preventing manipulation.