diff --git a/.github/workflows/Basic.yml b/.github/workflows/Basic.yml index c573b186..97bbec7e 100644 --- a/.github/workflows/Basic.yml +++ b/.github/workflows/Basic.yml @@ -24,7 +24,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.72.0 + toolchain: 1.73.0 target: wasm32-unknown-unknown override: true @@ -41,7 +41,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: unit-test - toolchain: 1.72.0 + toolchain: 1.73.0 args: --locked env: RUST_BACKTRACE: 1 @@ -65,7 +65,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.72.0 + toolchain: 1.73.0 override: true components: rustfmt, clippy @@ -73,12 +73,12 @@ jobs: uses: actions-rs/cargo@v1 with: command: fmt - toolchain: 1.72.0 + toolchain: 1.73.0 args: --all -- --check - name: Run cargo clippy uses: actions-rs/cargo@v1 with: command: clippy - toolchain: 1.72.0 + toolchain: 1.73.0 args: -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index a9b494d3..f10c7ffc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ "injective-cosmwasm 0.2.22", "injective-math 0.2.4", "injective-protobuf", - "protobuf", + "protobuf 2.28.0", "schemars", - "serde 1.0.194", + "serde 1.0.197", "thiserror", ] @@ -271,7 +271,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -386,7 +386,18 @@ checksum = "73c9d2043a9e617b0d602fbc0a0ecd621568edbf3a9774890a6d562389bd8e1c" dependencies = [ "prost 0.11.9", "prost-types 0.11.9", - "tendermint-proto", + "tendermint-proto 0.32.2", +] + +[[package]] +name = "cosmos-sdk-proto" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32560304ab4c365791fd307282f76637213d8083c1a98490c35159cd67852237" +dependencies = [ + "prost 0.12.3", + "prost-types 0.12.3", + "tendermint-proto 0.34.1", ] [[package]] @@ -396,13 +407,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af13955d6f356272e6def9ff5e2450a7650df536d8934f47052a20c76513d2f6" dependencies = [ "bip32", - "cosmos-sdk-proto", + "cosmos-sdk-proto 0.19.0", "ecdsa 0.16.9", "eyre", "getrandom", "k256 0.13.2", "rand_core 0.6.4", - "serde 1.0.194", + "serde 1.0.197", "serde_json 1.0.111", "subtle-encoding", "tendermint", @@ -441,7 +452,7 @@ checksum = "0df41ea55f2946b6b43579659eec048cc2f66e8c8e2e3652fc5e5e476f673856" dependencies = [ "cosmwasm-schema-derive", "schemars", - "serde 1.0.194", + "serde 1.0.197", "serde_json 1.0.111", "thiserror", ] @@ -472,7 +483,7 @@ dependencies = [ "forward_ref", "hex", "schemars", - "serde 1.0.194", + "serde 1.0.197", "serde-json-wasm 0.5.1", "sha2 0.10.8", "static_assertions 1.1.0", @@ -486,7 +497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd2b4ae72a03e8f56c85df59d172d51d2d7dc9cec6e2bc811e3fb60c588032a4" dependencies = [ "cosmwasm-std", - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -588,7 +599,7 @@ dependencies = [ "k256 0.11.6", "prost 0.9.0", "schemars", - "serde 1.0.194", + "serde 1.0.197", "thiserror", ] @@ -600,7 +611,7 @@ checksum = "d9b6f91c0b94481a3e9ef1ceb183c37d00764f8751e39b45fc09f4d9b970d469" dependencies = [ "cosmwasm-std", "schemars", - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -611,7 +622,7 @@ checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" dependencies = [ "cosmwasm-std", "schemars", - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -625,7 +636,7 @@ dependencies = [ "cw2 0.16.0", "schemars", "semver", - "serde 1.0.194", + "serde 1.0.197", "thiserror", ] @@ -640,7 +651,7 @@ dependencies = [ "cw2 1.1.2", "schemars", "semver", - "serde 1.0.194", + "serde 1.0.197", "thiserror", ] @@ -654,7 +665,7 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus 0.16.0", "schemars", - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -668,7 +679,7 @@ dependencies = [ "cw-storage-plus 1.2.0", "schemars", "semver", - "serde 1.0.194", + "serde 1.0.197", "thiserror", ] @@ -776,7 +787,7 @@ dependencies = [ "cw2 0.16.0", "injective-cosmwasm 0.2.22", "schemars", - "serde 1.0.194", + "serde 1.0.197", "thiserror", ] @@ -845,7 +856,7 @@ dependencies = [ "hashbrown 0.12.3", "hex", "rand_core 0.6.4", - "serde 1.0.194", + "serde 1.0.197", "sha2 0.9.9", "zeroize", ] @@ -968,7 +979,7 @@ dependencies = [ "ethbloom", "ethereum-types-serialize", "fixed-hash 0.3.2", - "serde 1.0.194", + "serde 1.0.197", "uint 0.5.0", ] @@ -978,7 +989,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1873d77b32bc1891a79dad925f2acbc318ee942b38b9110f9dbc5fbeffcea350" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -1311,7 +1322,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -1487,7 +1498,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -1528,7 +1539,7 @@ dependencies = [ "hex", "injective-math 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "schemars", - "serde 1.0.194", + "serde 1.0.197", "serde_repr", "subtle-encoding", "tiny-keccak", @@ -1545,7 +1556,7 @@ dependencies = [ "hex", "injective-math 0.2.4", "schemars", - "serde 1.0.194", + "serde 1.0.197", "serde-json-wasm 1.0.0", "serde_repr", "serde_test", @@ -1557,15 +1568,21 @@ dependencies = [ name = "injective-cosmwasm-mock" version = "1.0.0" dependencies = [ + "cosmos-sdk-proto 0.20.0", + "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 1.2.0", "cw2 0.16.0", "injective-cosmwasm 0.2.22", "injective-math 0.2.4", + "injective-protobuf", "injective-std 0.1.5", "injective-test-tube", + "injective-testing 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "prost 0.11.9", + "protobuf 3.4.0", "schemars", - "serde 1.0.194", + "serde 1.0.197", "thiserror", ] @@ -1578,7 +1595,7 @@ dependencies = [ "ethereum-types", "primitive-types", "schemars", - "serde 1.0.194", + "serde 1.0.197", "subtle-encoding", ] @@ -1592,7 +1609,7 @@ dependencies = [ "ethereum-types", "primitive-types", "schemars", - "serde 1.0.194", + "serde 1.0.197", "subtle-encoding", ] @@ -1604,10 +1621,10 @@ dependencies = [ "cosmwasm-std", "ethereum-types", "num 0.4.1", - "protobuf", + "protobuf 2.28.0", "protobuf-codegen-pure", "schemars", - "serde 1.0.194", + "serde 1.0.197", "subtle-encoding", ] @@ -1623,7 +1640,7 @@ dependencies = [ "prost 0.11.9", "prost-types 0.11.9", "schemars", - "serde 1.0.194", + "serde 1.0.197", "serde-cw-value", ] @@ -1637,15 +1654,15 @@ dependencies = [ "prost 0.12.3", "prost-types 0.12.3", "schemars", - "serde 1.0.194", + "serde 1.0.197", "serde-cw-value", ] [[package]] name = "injective-test-tube" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f42f6affb7a2a6b2460d07c1bc4f470a1b0766ea46cf1d265a4ce7a2d3bd73" +checksum = "61cb772fd4c8c1da872b742633e73928cbf1cf0505a09ec8ad41934a4d7f10b4" dependencies = [ "base64 0.13.1", "bindgen", @@ -1655,7 +1672,7 @@ dependencies = [ "injective-cosmwasm 0.2.18", "injective-std 0.1.5", "prost 0.11.9", - "serde 1.0.194", + "serde 1.0.197", "serde_json 1.0.111", "test-tube-inj", "thiserror", @@ -1673,7 +1690,25 @@ dependencies = [ "injective-math 0.2.4", "rand 0.4.6", "secp256k1", - "serde 1.0.194", + "serde 1.0.197", + "tiny-keccak", +] + +[[package]] +name = "injective-testing" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49dc1d881d0b7726745ed776a87d1e6f93e877d2d5ebd0fe8be759f5424a091a" +dependencies = [ + "anyhow", + "base64 0.13.1", + "cosmwasm-std", + "cw-multi-test", + "injective-cosmwasm 0.2.18", + "injective-math 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6", + "secp256k1", + "serde 1.0.197", "tiny-keccak", ] @@ -2258,13 +2293,24 @@ dependencies = [ "bytes", ] +[[package]] +name = "protobuf" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58678a64de2fced2bdec6bca052a6716a0efe692d6e3f53d1bda6a1def64cfc0" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror", +] + [[package]] name = "protobuf-codegen" version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6" dependencies = [ - "protobuf", + "protobuf 2.28.0", ] [[package]] @@ -2273,10 +2319,19 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a29399fc94bcd3eeaa951c715f7bea69409b2445356b00519740bcd6ddd865" dependencies = [ - "protobuf", + "protobuf 2.28.0", "protobuf-codegen", ] +[[package]] +name = "protobuf-support" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ed294a835b0f30810e13616b1cd34943c6d1e84a8f3b0dcfe466d256c3e7e7" +dependencies = [ + "thiserror", +] + [[package]] name = "quote" version = "1.0.35" @@ -2539,7 +2594,7 @@ dependencies = [ "dyn-clone", "enumset", "schemars_derive", - "serde 1.0.194", + "serde 1.0.197", "serde_json 1.0.111", ] @@ -2648,9 +2703,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.194" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -2661,7 +2716,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75d32da6b8ed758b7d850b6c3c08f1d7df51a4df3cb201296e63e34a78e99d4" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -2670,7 +2725,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -2679,7 +2734,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83c37d03f3b0f6b5f77c11af1e7c772de1c9af83e50bef7bb6069601900ba67b" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -2688,14 +2743,14 @@ version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] name = "serde_derive" -version = "1.0.194" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -2731,7 +2786,7 @@ checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -2751,7 +2806,7 @@ version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] @@ -2939,7 +2994,7 @@ dependencies = [ "prost 0.11.9", "prost-types 0.11.9", "ripemd", - "serde 1.0.194", + "serde 1.0.197", "serde_bytes", "serde_json 1.0.111", "serde_repr", @@ -2947,7 +3002,7 @@ dependencies = [ "signature 2.2.0", "subtle", "subtle-encoding", - "tendermint-proto", + "tendermint-proto 0.32.2", "time", "zeroize", ] @@ -2959,7 +3014,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71a72dbbea6dde12045d261f2c70c0de039125675e8a026c8d5ad34522756372" dependencies = [ "flex-error", - "serde 1.0.194", + "serde 1.0.197", "serde_json 1.0.111", "tendermint", "toml", @@ -2978,7 +3033,25 @@ dependencies = [ "num-traits", "prost 0.11.9", "prost-types 0.11.9", - "serde 1.0.194", + "serde 1.0.197", + "serde_bytes", + "subtle-encoding", + "time", +] + +[[package]] +name = "tendermint-proto" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b797dd3d2beaaee91d2f065e7bdf239dc8d80bba4a183a288bc1279dd5a69a1e" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost 0.12.3", + "prost-types 0.12.3", + "serde 1.0.197", "serde_bytes", "subtle-encoding", "time", @@ -3002,14 +3075,14 @@ dependencies = [ "peg", "pin-project", "semver", - "serde 1.0.194", + "serde 1.0.197", "serde_bytes", "serde_json 1.0.111", "subtle", "subtle-encoding", "tendermint", "tendermint-config", - "tendermint-proto", + "tendermint-proto 0.32.2", "thiserror", "time", "tokio", @@ -3038,9 +3111,9 @@ dependencies = [ "cosmrs", "cosmwasm-std", "prost 0.11.9", - "serde 1.0.194", + "serde 1.0.197", "serde_json 1.0.111", - "tendermint-proto", + "tendermint-proto 0.32.2", "thiserror", ] @@ -3078,7 +3151,7 @@ checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "powerfmt", - "serde 1.0.194", + "serde 1.0.197", "time-core", "time-macros", ] @@ -3181,7 +3254,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.194", + "serde 1.0.197", ] [[package]] diff --git a/contracts/injective-cosmwasm-mock/Cargo.toml b/contracts/injective-cosmwasm-mock/Cargo.toml index 99be9837..9b9a55ad 100644 --- a/contracts/injective-cosmwasm-mock/Cargo.toml +++ b/contracts/injective-cosmwasm-mock/Cargo.toml @@ -20,6 +20,7 @@ crate-type = [ "cdylib", "rlib" ] backtraces = [ "cosmwasm-std/backtraces" ] # use library feature to disable all instantiate/execute/query exports library = [ ] +integration = [ ] [package.metadata.scripts] optimize = """docker run --rm -v "$(pwd)":/code \ @@ -30,14 +31,23 @@ optimize = """docker run --rm -v "$(pwd)":/code \ [dependencies] cosmwasm-std = { version = "1.5.0", features = [ "abort", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", "iterator", "stargate" ] } -cw-storage-plus = "1.2.0" -cw2 = "0.16.0" +cw-storage-plus = { version = "1.2.0" } +cw2 = { version = "0.16.0" } injective-cosmwasm = { path = "../../packages/injective-cosmwasm" } injective-math = { path = "../../packages/injective-math" } +injective-protobuf = { path = "../../packages/injective-protobuf"} +schemars = { version ="0.8.16"} +serde = { version = "1.0.196", default-features = false, features = [ "derive" ] } +thiserror = { version = "1.0.56" } +protobuf = { version = "3.3.0" } +prost = { version = "0.11.9" } injective-std = { version = "0.1.5" } -schemars = "0.8.8" -serde = { version = "1.0.137", default-features = false, features = [ "derive" ] } -thiserror = { version = "1.0.31" } +cosmos-sdk-proto = { version = "0.20.0", default-features = false } +cosmwasm-schema = { version = "1.5.0" } + + [dev-dependencies] -injective-test-tube = "1.1.6" +injective-test-tube = { version = "1.1.7" } +injective-std = { version = "0.1.5" } +injective-testing = { version = "0.1.6" } diff --git a/contracts/injective-cosmwasm-mock/src/contract.rs b/contracts/injective-cosmwasm-mock/src/contract.rs index b85d3e2c..40ddcba7 100644 --- a/contracts/injective-cosmwasm-mock/src/contract.rs +++ b/contracts/injective-cosmwasm-mock/src/contract.rs @@ -1,15 +1,29 @@ -#[cfg(not(feature = "library"))] -use cosmwasm_std::entry_point; -use cosmwasm_std::{to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; +use crate::{ + error::ContractError, + handle::{handle_test_transient_derivative_order, handle_test_transient_spot_order}, + msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, + query::{ + handle_aggregate_account_volume_query, handle_aggregate_market_volume_query, handle_contract_registration_info_query, + handle_derivative_market_mid_price_and_tob_query, handle_derivative_market_orderbook_query, handle_derivative_market_query, + handle_derivative_orders_to_cancel_up_to_amount_query, handle_effective_subaccount_position_query, handle_exchange_params_query, + handle_market_atomic_execution_fee_multiplier_query, handle_market_volatility_query, handle_oracle_price_query, + handle_oracle_volatility_query, handle_perpetual_market_funding_query, handle_perpetual_market_info_query, handle_pyth_price_query, + handle_spot_market_mid_price_and_tob_query, handle_spot_market_orderbook_query, handle_spot_market_query, + handle_spot_orders_to_cancel_up_to_amount_query, handle_staked_amount_query, handle_subaccount_deposit_query, + handle_token_factory_creation_fee, handle_token_factory_denom_total_supply, handle_trader_derivative_orders_query, + handle_trader_spot_orders_query, handle_vanilla_subaccount_position_query, + }, + reply::{handle_create_derivative_order_reply, handle_create_order_reply}, +}; +use cosmwasm_std::{entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult}; use cw2::set_contract_version; - use injective_cosmwasm::{create_deposit_msg, InjectiveMsgWrapper, InjectiveQuerier, InjectiveQueryWrapper}; -use crate::error::ContractError; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; - const CONTRACT_NAME: &str = "crates.io:injective:dummy"; 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; +pub const MSG_EXEC: &str = "/cosmos.authz.v1beta1.MsgExec"; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate(deps: DepsMut, _env: Env, _info: MessageInfo, _msg: InstantiateMsg) -> Result { @@ -19,23 +33,120 @@ pub fn instantiate(deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Instantia #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( - _deps: DepsMut, + deps: DepsMut, env: Env, - _info: MessageInfo, + info: MessageInfo, msg: ExecuteMsg, ) -> Result, ContractError> { match msg { ExecuteMsg::TestDepositMsg { subaccount_id, amount } => { Ok(Response::new().add_message(create_deposit_msg(env.contract.address, subaccount_id, amount))) } + ExecuteMsg::TestTraderTransientSpotOrders { + market_id, + subaccount_id, + price, + quantity, + } => handle_test_transient_spot_order(deps, env, &info, 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, _env: Env, msg: QueryMsg) -> StdResult { let querier = InjectiveQuerier::new(&deps.querier); - match msg { - QueryMsg::TestSpotMarketQuery { market_id } => to_json_binary(&querier.query_spot_market(&market_id)?.market), + QueryMsg::TestExchangeParamsQuery {} => handle_exchange_params_query(&querier), + QueryMsg::TestSubAccountDepositQuery { subaccount_id, denom } => handle_subaccount_deposit_query(&querier, &subaccount_id, denom), + QueryMsg::TestSpotMarketQuery { market_id } => handle_spot_market_query(&querier, &market_id), + QueryMsg::TestDerivativeMarketQuery { market_id } => handle_derivative_market_query(&querier, &market_id), + QueryMsg::TestEffectiveSubaccountPosition { market_id, subaccount_id } => { + handle_effective_subaccount_position_query(&querier, &market_id, &subaccount_id) + } + QueryMsg::TestVanillaSubaccountPosition { market_id, subaccount_id } => { + handle_vanilla_subaccount_position_query(&querier, &market_id, &subaccount_id) + } + QueryMsg::TestTraderDerivativeOrders { market_id, subaccount_id } => { + handle_trader_derivative_orders_query(&querier, &market_id, &subaccount_id) + } + QueryMsg::TestTraderSpotOrders { market_id, subaccount_id } => handle_trader_spot_orders_query(&querier, &market_id, &subaccount_id), + QueryMsg::TestSpotOrdersToCancelUpToAmount { + market_id, + subaccount_id, + base_amount, + quote_amount, + strategy, + reference_price, + } => handle_spot_orders_to_cancel_up_to_amount_query( + &querier, + &market_id, + &subaccount_id, + base_amount, + quote_amount, + strategy, + reference_price, + ), + QueryMsg::TestDerivativeOrdersToCancelUpToAmount { + market_id, + subaccount_id, + quote_amount, + strategy, + reference_price, + } => handle_derivative_orders_to_cancel_up_to_amount_query(&querier, &market_id, &subaccount_id, quote_amount, strategy, reference_price), + QueryMsg::TestPerpetualMarketInfo { market_id } => handle_perpetual_market_info_query(&querier, &market_id), + QueryMsg::TestPerpetualMarketFunding { market_id } => handle_perpetual_market_funding_query(&querier, &market_id), + QueryMsg::TestMarketVolatility { + market_id, + trade_grouping_sec, + max_age, + include_raw_history, + include_metadata, + } => handle_market_volatility_query(&querier, &market_id, trade_grouping_sec, max_age, include_raw_history, include_metadata), + QueryMsg::TestDerivativeMarketMidPriceAndTob { market_id } => handle_derivative_market_mid_price_and_tob_query(&querier, &market_id), + QueryMsg::TestAggregateMarketVolume { market_id } => handle_aggregate_market_volume_query(&querier, &market_id), + QueryMsg::TestAggregateAccountVolume { account_id } => handle_aggregate_account_volume_query(&querier, account_id), + QueryMsg::TestSpotMarketMidPriceAndTob { market_id } => handle_spot_market_mid_price_and_tob_query(&querier, &market_id), + QueryMsg::TestSpotMarketOrderbook { + market_id, + side, + limit_cumulative_quantity, + limit_cumulative_notional, + } => handle_spot_market_orderbook_query(&querier, &market_id, side, limit_cumulative_quantity, limit_cumulative_notional), + QueryMsg::TestDerivativeMarketOrderbook { + market_id, + limit_cumulative_notional, + } => handle_derivative_market_orderbook_query(&querier, &market_id, limit_cumulative_notional), + QueryMsg::TestMarketAtomicExecutionFeeMultiplier { market_id } => handle_market_atomic_execution_fee_multiplier_query(&querier, &market_id), + QueryMsg::TestQueryOracleVolatility { + base_info, + quote_info, + max_age, + include_raw_history, + include_metadata, + } => handle_oracle_volatility_query(&querier, base_info, quote_info, max_age, include_raw_history, include_metadata), + QueryMsg::TestQueryOraclePrice { oracle_type, base, quote } => handle_oracle_price_query(&querier, &oracle_type, base, quote), + QueryMsg::TestQueryPythPrice { price_id } => handle_pyth_price_query(&querier, price_id), + QueryMsg::TestQueryStakedAmount { + delegator_address, + max_delegations, + } => handle_staked_amount_query(&querier, deps.api.addr_validate(delegator_address.as_str())?, max_delegations), + QueryMsg::TestQueryTokenFactoryDenomTotalSupply { denom } => handle_token_factory_denom_total_supply(&querier, denom), + QueryMsg::TestQueryTokenFactoryCreationFee {} => handle_token_factory_creation_fee(&querier), + QueryMsg::TestQueryContractRegistrationInfo { contract_address } => handle_contract_registration_info_query(&querier, contract_address), + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result { + match msg.id { + CREATE_SPOT_ORDER_REPLY_ID => handle_create_order_reply(deps, &msg), + CREATE_DERIVATIVE_ORDER_REPLY_ID => handle_create_derivative_order_reply(deps, &msg), + _ => Err(ContractError::UnrecognizedReply(msg.id)), } } diff --git a/contracts/injective-cosmwasm-mock/src/error.rs b/contracts/injective-cosmwasm-mock/src/error.rs index 40dab9ff..54dea889 100644 --- a/contracts/injective-cosmwasm-mock/src/error.rs +++ b/contracts/injective-cosmwasm-mock/src/error.rs @@ -5,4 +5,10 @@ use thiserror::Error; 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), } diff --git a/contracts/injective-cosmwasm-mock/src/handle.rs b/contracts/injective-cosmwasm-mock/src/handle.rs new file mode 100644 index 00000000..39f6e40d --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/handle.rs @@ -0,0 +1,112 @@ +use crate::{ + contract::{CREATE_DERIVATIVE_ORDER_REPLY_ID, CREATE_SPOT_ORDER_REPLY_ID, MSG_EXEC}, + 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}, + 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::{scale::Scaled, FPDecimal}; + +pub fn handle_test_transient_spot_order( + deps: DepsMut, + env: Env, + info: &MessageInfo, + market_id: MarketId, + subaccount_id: SubaccountId, + price: String, + quantity: String, +) -> Result, 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()).scaled(18i32), + FPDecimal::must_from_str(quantity.as_str()).scaled(18i32), + 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, + env: Env, + info: &MessageInfo, + market_id: MarketId, + subaccount_id: SubaccountId, + price: String, + quantity: String, + margin: String, +) -> Result, 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()).scaled(18i32), + FPDecimal::must_from_str(quantity.as_str()).scaled(18i32), + FPDecimal::must_from_str(margin.as_str()).scaled(18i32), + 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, 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(()) +} diff --git a/contracts/injective-cosmwasm-mock/src/lib.rs b/contracts/injective-cosmwasm-mock/src/lib.rs index 213e21b9..9a4726e1 100644 --- a/contracts/injective-cosmwasm-mock/src/lib.rs +++ b/contracts/injective-cosmwasm-mock/src/lib.rs @@ -1,10 +1,14 @@ pub mod contract; mod error; +mod handle; pub mod msg; +mod order_management; +mod query; +mod reply; +mod state; #[cfg(test)] mod testing; - +mod types; #[cfg(test)] pub mod utils; - pub use crate::error::ContractError; diff --git a/contracts/injective-cosmwasm-mock/src/msg.rs b/contracts/injective-cosmwasm-mock/src/msg.rs index 523c43b5..ae2a95ad 100644 --- a/contracts/injective-cosmwasm-mock/src/msg.rs +++ b/contracts/injective-cosmwasm-mock/src/msg.rs @@ -1,7 +1,10 @@ use cosmwasm_std::Coin; -use injective_cosmwasm::{MarketId, SubaccountId}; +use injective_cosmwasm::{CancellationStrategy, MarketId, OracleInfo, OracleType, OrderSide, SubaccountId}; +use injective_math::FPDecimal; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +pub const MSG_CREATE_SPOT_LIMIT_ORDER_ENDPOINT: &str = "/injective.exchange.v1beta1.MsgCreateSpotLimitOrder"; +pub const MSG_CREATE_DERIVATIVE_LIMIT_ORDER_ENDPOINT: &str = "/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder"; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct InstantiateMsg {} @@ -9,11 +12,132 @@ pub struct InstantiateMsg {} #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { - TestDepositMsg { subaccount_id: SubaccountId, amount: Coin }, + TestDepositMsg { + subaccount_id: SubaccountId, + amount: Coin, + }, + TestTraderTransientSpotOrders { + market_id: MarketId, + subaccount_id: SubaccountId, + price: String, + quantity: String, + }, + TestTraderTransientDerivativeOrders { + market_id: MarketId, + subaccount_id: SubaccountId, + price: String, + quantity: String, + margin: String, + }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { - TestSpotMarketQuery { market_id: MarketId }, + TestExchangeParamsQuery {}, + TestSpotMarketQuery { + market_id: MarketId, + }, + TestDerivativeMarketQuery { + market_id: MarketId, + }, + TestSubAccountDepositQuery { + subaccount_id: SubaccountId, + denom: String, + }, + TestEffectiveSubaccountPosition { + market_id: MarketId, + subaccount_id: SubaccountId, + }, + TestVanillaSubaccountPosition { + market_id: MarketId, + subaccount_id: SubaccountId, + }, + TestTraderDerivativeOrders { + market_id: MarketId, + subaccount_id: SubaccountId, + }, + TestTraderSpotOrders { + market_id: MarketId, + subaccount_id: SubaccountId, + }, + TestSpotOrdersToCancelUpToAmount { + market_id: MarketId, + subaccount_id: SubaccountId, + base_amount: FPDecimal, + quote_amount: FPDecimal, + strategy: CancellationStrategy, + reference_price: Option, + }, + TestDerivativeOrdersToCancelUpToAmount { + market_id: MarketId, + subaccount_id: SubaccountId, + quote_amount: FPDecimal, + strategy: CancellationStrategy, + reference_price: Option, + }, + TestPerpetualMarketInfo { + market_id: MarketId, + }, + TestPerpetualMarketFunding { + market_id: MarketId, + }, + TestMarketVolatility { + market_id: MarketId, + trade_grouping_sec: u64, + max_age: u64, + include_raw_history: bool, + include_metadata: bool, + }, + TestDerivativeMarketMidPriceAndTob { + market_id: MarketId, + }, + TestAggregateMarketVolume { + market_id: MarketId, + }, + TestAggregateAccountVolume { + account_id: String, + }, + TestSpotMarketMidPriceAndTob { + market_id: MarketId, + }, + TestSpotMarketOrderbook { + market_id: MarketId, + side: OrderSide, + limit_cumulative_quantity: Option, + limit_cumulative_notional: Option, + }, + TestDerivativeMarketOrderbook { + market_id: MarketId, + limit_cumulative_notional: FPDecimal, + }, + TestMarketAtomicExecutionFeeMultiplier { + market_id: MarketId, + }, + TestQueryOracleVolatility { + base_info: Option, + quote_info: Option, + max_age: u64, + include_raw_history: bool, + include_metadata: bool, + }, + TestQueryOraclePrice { + oracle_type: OracleType, + base: String, + quote: String, + }, + TestQueryPythPrice { + price_id: String, + }, + TestQueryStakedAmount { + delegator_address: String, + max_delegations: u16, + }, + TestQueryTokenFactoryDenomTotalSupply { + denom: String, + }, + TestQueryTokenFactoryCreationFee {}, + TestQueryContractRegistrationInfo { + contract_address: String, + }, } diff --git a/contracts/injective-cosmwasm-mock/src/order_management.rs b/contracts/injective-cosmwasm-mock/src/order_management.rs new file mode 100644 index 00000000..158f5bd5 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/order_management.rs @@ -0,0 +1,70 @@ +use crate::types; +use cosmwasm_std::{CosmosMsg, StdResult}; +use injective_cosmwasm::{FullDerivativeMarket, InjectiveMsgWrapper, OrderType, SpotMarket}; +use injective_math::FPDecimal; +use prost::Message; + +pub fn create_stargate_msg(type_url: &str, value: Vec) -> StdResult> { + Ok(CosmosMsg::Stargate { + type_url: type_url.to_string(), + value: value.into(), + }) +} + +pub fn create_spot_limit_order( + price: FPDecimal, + quantity: FPDecimal, + order_type: OrderType, + sender: &str, + subaccount_id: &str, + market: &SpotMarket, +) -> types::MsgCreateSpotLimitOrder { + types::MsgCreateSpotLimitOrder { + sender: sender.to_string(), + order: Some(types::SpotOrder { + market_id: market.market_id.as_str().into(), + order_info: Some(types::OrderInfo { + subaccount_id: subaccount_id.to_string(), + fee_recipient: sender.to_string(), + price: price.to_string(), + quantity: quantity.to_string(), + }), + order_type: order_type as i32, + trigger_price: "".to_string(), + }), + } +} + +pub fn create_derivative_limit_order( + price: FPDecimal, + quantity: FPDecimal, + margin: FPDecimal, + order_type: OrderType, + sender: &str, + subaccount_id: &str, + market: &FullDerivativeMarket, +) -> types::MsgCreateDerivativeLimitOrder { + let market_id = market.market.as_ref().unwrap().market_id.as_str().to_string(); + + types::MsgCreateDerivativeLimitOrder { + sender: sender.to_string(), + order: Some(types::DerivativeOrder { + market_id, + order_info: Some(types::OrderInfo { + subaccount_id: subaccount_id.to_string(), + fee_recipient: sender.to_string(), + price: price.to_string(), + quantity: quantity.to_string(), + }), + order_type: order_type as i32, + margin: margin.to_string(), + trigger_price: "".to_string(), + }), + } +} + +pub(crate) fn encode_bytes_message(order_msg: &T) -> Result, prost::EncodeError> { + let mut buffer = Vec::new(); + order_msg.encode(&mut buffer)?; // Encode the message using prost + Ok(buffer) +} diff --git a/contracts/injective-cosmwasm-mock/src/query.rs b/contracts/injective-cosmwasm-mock/src/query.rs new file mode 100644 index 00000000..17d3c120 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/query.rs @@ -0,0 +1,161 @@ +use cosmwasm_std::{to_json_binary, Addr, Binary, StdResult}; +use injective_cosmwasm::{CancellationStrategy, InjectiveQuerier, MarketId, OracleInfo, OracleType, OrderSide, SubaccountId}; +use injective_math::FPDecimal; + +pub fn handle_exchange_params_query(querier: &InjectiveQuerier) -> StdResult { + to_json_binary(&querier.query_exchange_params()?) +} + +pub fn handle_subaccount_deposit_query(querier: &InjectiveQuerier, subaccount_id: &SubaccountId, denom: String) -> StdResult { + to_json_binary(&querier.query_subaccount_deposit(subaccount_id, &denom)?) +} + +pub fn handle_spot_market_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_spot_market(market_id)?) +} + +pub fn handle_derivative_market_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_derivative_market(market_id)?) +} + +pub fn handle_effective_subaccount_position_query( + querier: &InjectiveQuerier, + market_id: &MarketId, + subaccount_id: &SubaccountId, +) -> StdResult { + to_json_binary(&querier.query_effective_subaccount_position(market_id, subaccount_id)?) +} + +pub fn handle_vanilla_subaccount_position_query(querier: &InjectiveQuerier, market_id: &MarketId, subaccount_id: &SubaccountId) -> StdResult { + to_json_binary(&querier.query_vanilla_subaccount_position(market_id, subaccount_id)?) +} + +pub fn handle_trader_derivative_orders_query(querier: &InjectiveQuerier, market_id: &MarketId, subaccount_id: &SubaccountId) -> StdResult { + to_json_binary(&querier.query_trader_derivative_orders(market_id, subaccount_id)?) +} + +pub fn handle_trader_spot_orders_query(querier: &InjectiveQuerier, market_id: &MarketId, subaccount_id: &SubaccountId) -> StdResult { + to_json_binary(&querier.query_trader_spot_orders(market_id, subaccount_id)?) +} + +pub fn handle_spot_orders_to_cancel_up_to_amount_query( + querier: &InjectiveQuerier, + market_id: &MarketId, + subaccount_id: &SubaccountId, + base_amount: FPDecimal, + quote_amount: FPDecimal, + strategy: CancellationStrategy, + reference_price: Option, +) -> StdResult { + to_json_binary(&querier.query_spot_orders_to_cancel_up_to_amount( + market_id, + subaccount_id, + base_amount, + quote_amount, + strategy, + reference_price, + )?) +} + +pub fn handle_derivative_orders_to_cancel_up_to_amount_query( + querier: &InjectiveQuerier, + market_id: &MarketId, + subaccount_id: &SubaccountId, + quote_amount: FPDecimal, + strategy: CancellationStrategy, + reference_price: Option, +) -> StdResult { + to_json_binary(&querier.query_derivative_orders_to_cancel_up_to_amount(market_id, subaccount_id, quote_amount, strategy, reference_price)?) +} + +pub fn handle_perpetual_market_info_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_perpetual_market_info(market_id)?) +} + +pub fn handle_perpetual_market_funding_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_perpetual_market_funding(market_id)?) +} + +pub fn handle_market_volatility_query( + querier: &InjectiveQuerier, + market_id: &MarketId, + trade_grouping_sec: u64, + max_age: u64, + include_raw_history: bool, + include_metadata: bool, +) -> StdResult { + to_json_binary(&querier.query_market_volatility(market_id, trade_grouping_sec, max_age, include_raw_history, include_metadata)?) +} + +pub fn handle_derivative_market_mid_price_and_tob_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_derivative_market_mid_price_and_tob(market_id)?) +} + +pub fn handle_aggregate_market_volume_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_aggregate_market_volume(market_id)?) +} + +pub fn handle_aggregate_account_volume_query(querier: &InjectiveQuerier, account_id: String) -> StdResult { + to_json_binary(&querier.query_aggregate_account_volume(&account_id)?) +} + +pub fn handle_spot_market_mid_price_and_tob_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_spot_market_mid_price_and_tob(market_id)?) +} + +pub fn handle_spot_market_orderbook_query( + querier: &InjectiveQuerier, + market_id: &MarketId, + side: OrderSide, + limit_cumulative_quantity: Option, + limit_cumulative_notional: Option, +) -> StdResult { + to_json_binary(&querier.query_spot_market_orderbook(market_id, side, limit_cumulative_quantity, limit_cumulative_notional)?) +} + +pub fn handle_derivative_market_orderbook_query( + querier: &InjectiveQuerier, + market_id: &MarketId, + limit_cumulative_notional: FPDecimal, +) -> StdResult { + to_json_binary(&querier.query_derivative_market_orderbook(market_id, limit_cumulative_notional)?) +} + +pub fn handle_market_atomic_execution_fee_multiplier_query(querier: &InjectiveQuerier, market_id: &MarketId) -> StdResult { + to_json_binary(&querier.query_market_atomic_execution_fee_multiplier(market_id)?) +} + +pub fn handle_oracle_volatility_query( + querier: &InjectiveQuerier, + base_info: Option, + quote_info: Option, + max_age: u64, + include_raw_history: bool, + include_metadata: bool, +) -> StdResult { + to_json_binary(&querier.query_oracle_volatility(&base_info, "e_info, max_age, include_raw_history, include_metadata)?) +} + +pub fn handle_oracle_price_query(querier: &InjectiveQuerier, oracle_type: &OracleType, base: String, quote: String) -> StdResult { + to_json_binary(&querier.query_oracle_price(oracle_type, &base, "e)?) +} + +pub fn handle_pyth_price_query(querier: &InjectiveQuerier, price_id: String) -> StdResult { + to_json_binary(&querier.query_pyth_price(price_id.as_str())?) +} + +pub fn handle_token_factory_denom_total_supply(querier: &InjectiveQuerier, denom: String) -> StdResult { + to_json_binary(&querier.query_token_factory_denom_total_supply(&denom)?) +} + +pub fn handle_token_factory_creation_fee(querier: &InjectiveQuerier) -> StdResult { + to_json_binary(&querier.query_token_factory_creation_fee()?) +} + +pub fn handle_staked_amount_query(querier: &InjectiveQuerier, delegator_address: Addr, max_delegations: u16) -> StdResult { + to_json_binary(&querier.query_staked_amount(delegator_address, max_delegations)?) +} + +pub fn handle_contract_registration_info_query(querier: &InjectiveQuerier, contract_address: String) -> StdResult { + to_json_binary(&querier.query_contract_registration_info(&contract_address)?) +} diff --git a/contracts/injective-cosmwasm-mock/src/reply.rs b/contracts/injective-cosmwasm-mock/src/reply.rs new file mode 100644 index 00000000..78fe2c70 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/reply.rs @@ -0,0 +1,39 @@ +use crate::state::ORDER_CALL_CACHE; +use crate::ContractError; +use cosmwasm_std::{DepsMut, Event, Reply, Response}; +use injective_cosmwasm::{InjectiveQuerier, InjectiveQueryWrapper}; + +pub fn handle_create_order_reply(deps: DepsMut, _msg: &Reply) -> Result { + let mut response_str = "Something went wrong".to_string(); + + let querier: InjectiveQuerier = InjectiveQuerier::new(&deps.querier); + + if let Some(mut cache) = ORDER_CALL_CACHE.may_load(deps.storage)? { + if !cache.is_empty() { + let order_info = &cache[0]; + let response = querier.query_trader_transient_spot_orders(&order_info.market_id, &order_info.subaccount); + response_str = format!("{:?}", &response); + cache.clear(); + ORDER_CALL_CACHE.save(deps.storage, &cache)?; + } + }; + + Ok(Response::new().add_event(Event::new("transient_order").add_attributes([("query_str", response_str)]))) +} + +pub fn handle_create_derivative_order_reply(deps: DepsMut, _msg: &Reply) -> Result { + let mut response_str = "Something went wrong".to_string(); + let querier: InjectiveQuerier = InjectiveQuerier::new(&deps.querier); + + if let Some(mut cache) = ORDER_CALL_CACHE.may_load(deps.storage)? { + if !cache.is_empty() { + let order_info = &cache[0]; + let response = querier.query_trader_transient_derivative_orders(&order_info.market_id, &order_info.subaccount); + response_str = format!("{:?}", &response); + cache.clear(); + ORDER_CALL_CACHE.save(deps.storage, &cache)?; + } + }; + + Ok(Response::new().add_event(Event::new("transient_derivative_order").add_attributes([("query_str", response_str)]))) +} diff --git a/contracts/injective-cosmwasm-mock/src/state.rs b/contracts/injective-cosmwasm-mock/src/state.rs new file mode 100644 index 00000000..4f4d8280 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/state.rs @@ -0,0 +1,11 @@ +use cosmwasm_schema::cw_serde; +use cw_storage_plus::Item; +use injective_cosmwasm::{MarketId, SubaccountId}; + +pub const ORDER_CALL_CACHE: Item> = Item::new("order_call_cache"); + +#[cw_serde] +pub struct CacheOrderInfo { + pub subaccount: SubaccountId, + pub market_id: MarketId, +} diff --git a/contracts/injective-cosmwasm-mock/src/testing/mod.rs b/contracts/injective-cosmwasm-mock/src/testing/mod.rs index 1cbb6c94..c26da455 100644 --- a/contracts/injective-cosmwasm-mock/src/testing/mod.rs +++ b/contracts/injective-cosmwasm-mock/src/testing/mod.rs @@ -1 +1,6 @@ -mod query_spot_market_test; +mod test_exchange; +mod test_exchange_derivative; +mod test_oracle; +mod test_staking; +mod test_token_factory; +mod test_wasmx; diff --git a/contracts/injective-cosmwasm-mock/src/testing/query_spot_market_test.rs b/contracts/injective-cosmwasm-mock/src/testing/query_spot_market_test.rs deleted file mode 100644 index 1b42b787..00000000 --- a/contracts/injective-cosmwasm-mock/src/testing/query_spot_market_test.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::{ - msg::{ExecuteMsg, QueryMsg}, - utils::test_setup, -}; -use cosmwasm_std::{Addr, Coin}; -use injective_cosmwasm::{checked_address_to_subaccount_id, MarketId}; -use injective_math::{scale::Scaled, FPDecimal}; -use injective_std::types::injective::exchange::v1beta1::{MsgInstantSpotMarketLaunch, QuerySpotMarketsRequest}; -use injective_test_tube::{injective_cosmwasm::SpotMarketResponse, Account, Exchange, Module, Wasm}; - -pub const BASE_DENOM: &str = "inj"; -pub const QUOTE_DENOM: &str = "usdt"; - -pub fn dec_to_proto(val: FPDecimal) -> String { - val.scaled(18).to_string() -} - -#[test] -#[cfg_attr(not(feature = "integration"), ignore)] -fn test_msg_deposit() { - let (app, accs, contract_address) = test_setup(); - - let wasm = Wasm::new(&app); - let buyer = &accs[1]; - - // Execute contract - let buyer_subaccount_id = checked_address_to_subaccount_id(&Addr::unchecked(buyer.address()), 1u32); - let res = wasm.execute( - &contract_address, - &ExecuteMsg::TestDepositMsg { - subaccount_id: buyer_subaccount_id, - amount: Coin::new(100, "usdt"), - }, - &[Coin::new(100, "usdt")], - buyer, - ); - assert!(res.is_ok(), "Execution failed with error: {:?}", res.unwrap_err()); -} - -#[test] -#[cfg_attr(not(feature = "integration"), ignore)] -fn test_query_spot_market() { - let (app, accs, contract_address) = test_setup(); - let signer = &accs[2]; - let wasm = Wasm::new(&app); - let exchange = Exchange::new(&app); - - // Instantiate spot market - let ticker = "INJ/USDT".to_string(); - exchange - .instant_spot_market_launch( - MsgInstantSpotMarketLaunch { - sender: signer.address(), - ticker: ticker.clone(), - base_denom: BASE_DENOM.to_string(), - quote_denom: QUOTE_DENOM.to_string(), - min_price_tick_size: dec_to_proto(FPDecimal::must_from_str("0.000000000000001")), - min_quantity_tick_size: dec_to_proto(FPDecimal::must_from_str("1000000000000000")), - }, - signer, - ) - .unwrap(); - - let spot_markets = exchange - .query_spot_markets(&QuerySpotMarketsRequest { - status: "Active".to_string(), - market_ids: vec![], - }) - .unwrap() - .markets; - - let market = spot_markets.iter().find(|m| m.ticker == ticker).unwrap(); - let spot_market_id = market.market_id.to_string(); - - // Query - let market_id = MarketId::new(spot_market_id.clone()).unwrap(); - let query_msg = QueryMsg::TestSpotMarketQuery { market_id }; - let res: SpotMarketResponse = wasm.query(&contract_address, &query_msg).unwrap(); - assert_eq!(res.market.clone().unwrap().market_id.as_str(), spot_market_id.clone()); -} diff --git a/contracts/injective-cosmwasm-mock/src/testing/test_exchange.rs b/contracts/injective-cosmwasm-mock/src/testing/test_exchange.rs new file mode 100644 index 00000000..9db7b659 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/testing/test_exchange.rs @@ -0,0 +1,523 @@ +use crate::{ + msg::{ExecuteMsg, QueryMsg}, + utils::{ + add_spot_initial_liquidity, add_spot_order_as, add_spot_orders, dec_to_proto, execute_all_authorizations, + get_initial_liquidity_orders_vector, get_spot_market_id, human_to_dec, human_to_proto, scale_price_quantity_for_spot_market, + scale_price_quantity_for_spot_market_dec, str_coin, ExchangeType, HumanOrder, Setup, BASE_DECIMALS, BASE_DENOM, QUOTE_DECIMALS, QUOTE_DENOM, + }, +}; +use cosmwasm_std::{Addr, Coin}; +use injective_cosmwasm::{ + checked_address_to_subaccount_id, + exchange::{response::QueryOrderbookResponse, types::VolumeByType}, + CancellationStrategy, ExchangeParamsResponse, MarketId, MarketMidPriceAndTOBResponse, MarketVolatilityResponse, OrderSide, PriceLevel, + QueryAggregateVolumeResponse, QueryMarketAtomicExecutionFeeMultiplierResponse, SpotMarketResponse, SubaccountDepositResponse, SubaccountId, + TraderSpotOrdersResponse, TrimmedSpotLimitOrder, +}; +use injective_math::FPDecimal; +use injective_std::types::injective::exchange::v1beta1::{ + Deposit, MsgDeposit, MsgInstantSpotMarketLaunch, OrderType, QueryAggregateMarketVolumeResponse, QuerySubaccountDepositsRequest, +}; +use injective_test_tube::{injective_cosmwasm::get_default_subaccount_id_for_checked_address, Account, Exchange, Module, RunnerResult, Wasm}; + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_msg_deposit() { + let env = Setup::new(ExchangeType::None); + + let wasm = Wasm::new(&env.app); + let user = &env.users[0]; + + let subaccount_id = checked_address_to_subaccount_id(&Addr::unchecked(user.account.address()), 1u32); + // Execute contract + let res = wasm.execute( + &env.contract_address, + &ExecuteMsg::TestDepositMsg { + subaccount_id: subaccount_id.clone(), + amount: Coin::new(100, "usdt"), + }, + &[Coin::new(100, "usdt")], + &user.account, + ); + assert!(res.is_ok(), "Execution failed with error: {:?}", res.unwrap_err()); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_exchange_params() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + let res: ExchangeParamsResponse = wasm.query(&env.contract_address, &QueryMsg::TestExchangeParamsQuery {}).unwrap(); + + assert!(res.params.is_some()); + let params = res.params.unwrap(); + + let listing_fee_coin = str_coin("1000", BASE_DENOM, BASE_DECIMALS); + assert_eq!(params.spot_market_instant_listing_fee, listing_fee_coin); + assert_eq!(params.derivative_market_instant_listing_fee, listing_fee_coin); + assert_eq!(params.trading_rewards_vesting_duration, 604800); + assert_eq!(params.is_instant_derivative_market_launch_enabled, Some(true)); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_subaccount_deposit() { + let env = Setup::new(ExchangeType::None); + let exchange = Exchange::new(&env.app); + let wasm = Wasm::new(&env.app); + + let subaccount_id = checked_address_to_subaccount_id(&Addr::unchecked(env.users[0].account.address()), 1u32); + + let make_deposit = |amount: &str, denom_key: &str| { + exchange + .deposit( + MsgDeposit { + sender: env.users[0].account.address(), + subaccount_id: subaccount_id.to_string(), + amount: Some(injective_std::types::cosmos::base::v1beta1::Coin { + amount: amount.to_string(), + denom: env.denoms[denom_key].clone(), + }), + }, + &env.users[0].account, + ) + .unwrap(); + }; + + make_deposit("10000000000000000000", "base"); + make_deposit("100000000", "quote"); + + let response = exchange + .query_subaccount_deposits(&QuerySubaccountDepositsRequest { + subaccount_id: subaccount_id.to_string(), + subaccount: None, + }) + .unwrap(); + + assert_eq!( + response.deposits[&env.denoms["base"].clone()], + Deposit { + available_balance: human_to_proto("10.0", BASE_DECIMALS), + total_balance: human_to_proto("10.0", BASE_DECIMALS), + } + ); + assert_eq!( + response.deposits[&env.denoms["quote"].clone()], + Deposit { + available_balance: human_to_proto("100.0", QUOTE_DECIMALS), + total_balance: human_to_proto("100.0", QUOTE_DECIMALS), + } + ); + + let query_msg = QueryMsg::TestSubAccountDepositQuery { + subaccount_id: subaccount_id.clone(), + denom: BASE_DENOM.to_string(), + }; + let contract_response: SubaccountDepositResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(contract_response.deposits.total_balance, human_to_dec("10.0", BASE_DECIMALS)); + + let query_msg = QueryMsg::TestSubAccountDepositQuery { + subaccount_id: subaccount_id.clone(), + denom: QUOTE_DENOM.to_string(), + }; + let contract_response: SubaccountDepositResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(contract_response.deposits.available_balance, human_to_dec("100.0", QUOTE_DECIMALS)); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_spot_market_no_market_on_exchange() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + + // Query + let market_id = MarketId::new("0xd5a22be807011d5e42d5b77da3f417e22676efae494109cd01c242ad46630115").unwrap(); + let query_msg = QueryMsg::TestSpotMarketQuery { market_id }; + let res: RunnerResult = wasm.query(&env.contract_address, &query_msg); + assert_eq!(res, Ok(SpotMarketResponse { market: None })); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_spot_market() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + let exchange = Exchange::new(&env.app); + + // Instantiate spot market + let ticker = "INJ/USDT".to_string(); + let min_price_tick_size = FPDecimal::must_from_str("0.000000000000001"); + let min_quantity_tick_size = FPDecimal::must_from_str("1000000000000000"); + + exchange + .instant_spot_market_launch( + MsgInstantSpotMarketLaunch { + sender: env.signer.address(), + ticker: ticker.clone(), + base_denom: BASE_DENOM.to_string(), + quote_denom: QUOTE_DENOM.to_string(), + min_price_tick_size: dec_to_proto(min_price_tick_size), + min_quantity_tick_size: dec_to_proto(min_quantity_tick_size), + }, + &env.signer, + ) + .unwrap(); + + let spot_market_id = get_spot_market_id(&exchange, ticker.to_owned()); + + // Query + let market_id = MarketId::new(spot_market_id.clone()).unwrap(); + let query_msg = QueryMsg::TestSpotMarketQuery { market_id }; + let res: SpotMarketResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + + let response_market = res.market.unwrap(); + assert_eq!(response_market.market_id.as_str(), spot_market_id); + assert_eq!(response_market.ticker.as_str(), ticker); + assert_eq!(response_market.base_denom.as_str(), BASE_DENOM); + assert_eq!(response_market.quote_denom.as_str(), QUOTE_DENOM); + assert_eq!(response_market.min_price_tick_size.clone().to_string(), min_price_tick_size.to_string()); + assert_eq!(response_market.min_quantity_tick_size.to_string(), min_quantity_tick_size.to_string()); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_trader_spot_orders() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + let subaccount_id = get_default_subaccount_id_for_checked_address(&Addr::unchecked(env.users[0].account.address())) + .as_str() + .to_string(); + + let query_msg = QueryMsg::TestTraderSpotOrders { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id).unwrap(), + }; + + { + let (price, quantity) = scale_price_quantity_for_spot_market("10.01", "5.1", &BASE_DECIMALS, "E_DECIMALS); + add_spot_order_as(&env.app, market_id.to_owned(), &env.users[0], price, quantity, OrderType::Sell); + + let res: TraderSpotOrdersResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + let orders = res.orders.clone().unwrap(); + + assert_eq!(orders.len(), 1, "Expected exactly one order in the response"); + let expected_orders = TrimmedSpotLimitOrder { + price: human_to_dec("10.01", QUOTE_DECIMALS - BASE_DECIMALS), + quantity: human_to_dec("5.1", BASE_DECIMALS), + fillable: human_to_dec("5.1", BASE_DECIMALS), + isBuy: false, + order_hash: "".to_string(), + }; + assert_eq!(orders[0].price, expected_orders.price); + assert_eq!(orders[0].quantity, expected_orders.quantity); + assert_eq!(orders[0].fillable, expected_orders.fillable); + assert_eq!(orders[0].isBuy, expected_orders.isBuy); + } + + { + let (price, quantity) = scale_price_quantity_for_spot_market("9.90", "0.5", &BASE_DECIMALS, "E_DECIMALS); + add_spot_order_as(&env.app, market_id.to_owned(), &env.users[0], price, quantity, OrderType::Buy); + + let res: TraderSpotOrdersResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + let orders = res.orders.clone().unwrap(); + + assert_eq!(orders.len(), 2); + let expected_order = TrimmedSpotLimitOrder { + price: human_to_dec("9.90", QUOTE_DECIMALS - BASE_DECIMALS), + quantity: human_to_dec("0.5", BASE_DECIMALS), + fillable: human_to_dec("0.5", BASE_DECIMALS), + isBuy: true, + order_hash: "".to_string(), + }; + assert_eq!(orders[0].price, expected_order.price); + assert_eq!(orders[0].quantity, expected_order.quantity); + assert_eq!(orders[0].fillable, expected_order.fillable); + assert_eq!(orders[0].isBuy, expected_order.isBuy); + } +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_spot_market_mid_price_and_tob() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + add_spot_initial_liquidity(&env.app, market_id.clone()); + + let query_msg = QueryMsg::TestSpotMarketMidPriceAndTob { + market_id: MarketId::new(market_id.clone()).unwrap(), + }; + + let res: MarketMidPriceAndTOBResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(res.mid_price, Some(human_to_dec("10", QUOTE_DECIMALS - BASE_DECIMALS))); + assert_eq!(res.best_buy_price, Some(human_to_dec("9.9", QUOTE_DECIMALS - BASE_DECIMALS))); + assert_eq!(res.best_sell_price, Some(human_to_dec("10.1", QUOTE_DECIMALS - BASE_DECIMALS))); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_spot_market_orderbook() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + let liquidity_orders = get_initial_liquidity_orders_vector(); + add_spot_orders(&env.app, market_id.clone(), liquidity_orders.clone()); + + let query_msg = QueryMsg::TestSpotMarketOrderbook { + market_id: MarketId::new(market_id.clone()).unwrap(), + side: OrderSide::Unspecified, + limit_cumulative_quantity: None, + limit_cumulative_notional: None, + }; + + let res: QueryOrderbookResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + let buys_price_level = res.buys_price_level; + let sells_price_level = res.sells_price_level; + assert_eq!(buys_price_level.len(), 4); + assert_eq!(sells_price_level.len(), 4); + assert_eq!( + buys_price_level[0], + PriceLevel { + p: human_to_dec(liquidity_orders[sells_price_level.len()].price.as_str(), QUOTE_DECIMALS - BASE_DECIMALS), + q: human_to_dec(liquidity_orders[sells_price_level.len()].quantity.as_str(), BASE_DECIMALS), + } + ); + assert_eq!( + buys_price_level[1], + PriceLevel { + p: human_to_dec( + liquidity_orders[sells_price_level.len() + 1].price.as_str(), + QUOTE_DECIMALS - BASE_DECIMALS + ), + q: human_to_dec(liquidity_orders[sells_price_level.len() + 1].quantity.as_str(), BASE_DECIMALS), + } + ); + + assert_eq!( + sells_price_level[0], + PriceLevel { + p: human_to_dec( + liquidity_orders[sells_price_level.len() - 1].price.as_str(), + QUOTE_DECIMALS - BASE_DECIMALS + ), + q: human_to_dec(liquidity_orders[sells_price_level.len() - 1].quantity.as_str(), BASE_DECIMALS), + } + ); + assert_eq!( + sells_price_level[1], + PriceLevel { + p: human_to_dec( + liquidity_orders[sells_price_level.len() - 2].price.as_str(), + QUOTE_DECIMALS - BASE_DECIMALS + ), + q: human_to_dec(liquidity_orders[sells_price_level.len() - 2].quantity.as_str(), BASE_DECIMALS), + } + ); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_market_volatility() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + add_spot_initial_liquidity(&env.app, market_id.clone()); + + let query_msg = QueryMsg::TestMarketVolatility { + market_id: MarketId::new(market_id.clone()).unwrap(), + trade_grouping_sec: 0, + max_age: 0, + include_raw_history: false, + include_metadata: true, + }; + + let res: MarketVolatilityResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(res.volatility, None); + + let new_orders: Vec = vec![ + HumanOrder { + price: "10.4".to_string(), + quantity: "15".to_string(), + order_type: OrderType::Buy, + }, + HumanOrder { + price: "9.0".to_string(), + quantity: "10".to_string(), + order_type: OrderType::Sell, + }, + ]; + + add_spot_orders(&env.app, market_id.clone(), new_orders.clone()); + let res: MarketVolatilityResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(res.volatility, Some(FPDecimal::ZERO)); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_aggregate_market_volume() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + add_spot_initial_liquidity(&env.app, market_id.clone()); + + let query_msg = QueryMsg::TestAggregateMarketVolume { + market_id: MarketId::new(market_id.clone()).unwrap(), + }; + + let res: QueryAggregateMarketVolumeResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(res.volume.clone().unwrap().maker_volume, "0"); + assert_eq!(res.volume.clone().unwrap().taker_volume, "0"); + + // consume liquidity + let new_orders: Vec = vec![ + HumanOrder { + price: "10.1".to_string(), + quantity: "10".to_string(), + order_type: OrderType::Buy, + }, + HumanOrder { + price: "9.9".to_string(), + quantity: "5".to_string(), + order_type: OrderType::Sell, + }, + ]; + + add_spot_orders(&env.app, market_id.clone(), new_orders); + let res: QueryAggregateMarketVolumeResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(res.volume.clone().unwrap().maker_volume, "150500000"); + assert_eq!(res.volume.clone().unwrap().taker_volume, "150500000"); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_aggregate_account_volume() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + add_spot_initial_liquidity(&env.app, market_id.clone()); + + let query_msg = QueryMsg::TestAggregateAccountVolume { + account_id: env.users[1].subaccount_id.to_string(), + }; + + let res: QueryAggregateVolumeResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert!(res.aggregate_volumes.is_none()); + + let (price, quantity) = scale_price_quantity_for_spot_market("9.9", "1", &BASE_DECIMALS, "E_DECIMALS); + add_spot_order_as(&env.app, market_id.clone(), &env.users[1], price, quantity, OrderType::Sell); + + let res: QueryAggregateVolumeResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + let volume: &VolumeByType = &res.aggregate_volumes.unwrap()[0].volume; + assert_eq!(volume.maker_volume, FPDecimal::ZERO); + assert_eq!(volume.taker_volume, human_to_dec("9.9", QUOTE_DECIMALS)); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_market_atomic_execution_fee_multiplier() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + let query_msg = QueryMsg::TestMarketAtomicExecutionFeeMultiplier { + market_id: MarketId::new(market_id.clone()).unwrap(), + }; + let res: QueryMarketAtomicExecutionFeeMultiplierResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(res.multiplier, human_to_dec("0.0000025", QUOTE_DECIMALS)); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_spot_orders_to_cancel_up_to_amount() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + let subaccount_id = get_default_subaccount_id_for_checked_address(&Addr::unchecked(env.users[0].account.address())) + .as_str() + .to_string(); + + let query_spot_msg = QueryMsg::TestTraderSpotOrders { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id.to_owned()).unwrap(), + }; + + { + let (price, quantity) = scale_price_quantity_for_spot_market("9.90", "1", &BASE_DECIMALS, "E_DECIMALS); + add_spot_order_as(&env.app, market_id.to_owned(), &env.users[0], price, quantity, OrderType::Buy); + + let res: TraderSpotOrdersResponse = wasm.query(&env.contract_address, &query_spot_msg).unwrap(); + let orders = res.orders.clone().unwrap(); + + let expected_order = TrimmedSpotLimitOrder { + price: human_to_dec("9.90", QUOTE_DECIMALS - BASE_DECIMALS), + quantity: human_to_dec("1", BASE_DECIMALS), + fillable: human_to_dec("1", BASE_DECIMALS), + isBuy: true, + order_hash: "".to_string(), + }; + assert_eq!(orders[0].price, expected_order.price); + assert_eq!(orders[0].quantity, expected_order.quantity); + assert_eq!(orders[0].fillable, expected_order.fillable); + assert_eq!(orders[0].isBuy, expected_order.isBuy); + } + + { + let query_spot_cancel_msg = QueryMsg::TestSpotOrdersToCancelUpToAmount { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id).unwrap(), + base_amount: human_to_dec("0", BASE_DECIMALS), + quote_amount: human_to_dec("0.2", QUOTE_DECIMALS), + strategy: CancellationStrategy::UnspecifiedOrder, + reference_price: None, + }; + let res: TraderSpotOrdersResponse = wasm.query(&env.contract_address, &query_spot_cancel_msg).unwrap(); + let orders = res.orders.clone().unwrap(); + assert_eq!(orders.len(), 1); + } +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_trader_transient_spot_orders() { + let env = Setup::new(ExchangeType::Spot); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + let subaccount_id = checked_address_to_subaccount_id(&Addr::unchecked(env.users[0].account.address()), 0u32); + + execute_all_authorizations(&env.app, &env.users[0].account, env.contract_address.clone()); + add_spot_initial_liquidity(&env.app, market_id.clone()); + + let (scale_price, scale_quantity) = scale_price_quantity_for_spot_market_dec("9.8", "1", &BASE_DECIMALS, "E_DECIMALS); + + let res = wasm + .execute( + &env.contract_address, + &ExecuteMsg::TestTraderTransientSpotOrders { + market_id: MarketId::new(market_id).unwrap(), + subaccount_id: subaccount_id.clone(), + price: scale_price.to_string(), + quantity: scale_quantity.to_string(), + }, + &[], + &env.users[0].account, + ) + .unwrap(); + + let transient_query = res + .events + .iter() + .find(|e| e.ty == "wasm-transient_order") + .and_then(|event| event.attributes.iter().find(|a| a.key == "query_str")); + + assert!(transient_query.is_some()); + let expected_order_info = "TraderSpotOrdersResponse { orders: Some([TrimmedSpotLimitOrder { price: FPDecimal { num: 9800000, sign: 1 }, quantity: FPDecimal { num: 1000000000000000000000000000000000000, sign: 1 }"; + assert!(transient_query.unwrap().value.contains(expected_order_info)); +} diff --git a/contracts/injective-cosmwasm-mock/src/testing/test_exchange_derivative.rs b/contracts/injective-cosmwasm-mock/src/testing/test_exchange_derivative.rs new file mode 100644 index 00000000..f5f42516 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/testing/test_exchange_derivative.rs @@ -0,0 +1,396 @@ +use crate::{ + msg::{ExecuteMsg, QueryMsg}, + utils::{ + add_derivative_order_as, add_derivative_orders, add_perp_initial_liquidity, dec_to_proto, execute_all_authorizations, + get_initial_perp_liquidity_orders_vector, get_perpetual_market_id, human_to_dec, scale_price_quantity_perp_market, + scale_price_quantity_perp_market_dec, ExchangeType, HumanOrder, Setup, BASE_DENOM, QUOTE_DECIMALS, QUOTE_DENOM, + }, +}; +use cosmwasm_std::Addr; +use injective_cosmwasm::{ + checked_address_to_subaccount_id, exchange::response::QueryOrderbookResponse, CancellationStrategy, DerivativeMarketResponse, MarketId, + MarketMidPriceAndTOBResponse, PerpetualMarketFundingResponse, PerpetualMarketInfoResponse, PriceLevel, + SubaccountEffectivePositionInMarketResponse, SubaccountId, SubaccountPositionInMarketResponse, TraderDerivativeOrdersResponse, + TrimmedDerivativeLimitOrder, +}; +use injective_math::FPDecimal; +use injective_std::types::injective::exchange::v1beta1::{MsgInstantPerpetualMarketLaunch, OrderType}; +use injective_test_tube::{injective_cosmwasm::get_default_subaccount_id_for_checked_address, Account, Exchange, Module, Wasm}; + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_perpetual_market_info() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let exchange = Exchange::new(&env.app); + + let ticker = "INJ/USDT".to_string(); + let derivative_market_id = get_perpetual_market_id(&exchange, ticker.to_owned()); + let market_id = MarketId::new(derivative_market_id.clone()).unwrap(); + let query_msg = QueryMsg::TestPerpetualMarketInfo { + market_id: market_id.clone(), + }; + let res: PerpetualMarketInfoResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + + assert!(res.info.is_some()); + let market_info = res.info.clone().unwrap(); + assert_eq!(market_info.market_id, market_id); + assert_eq!(market_info.funding_interval, 3600i64); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_derivative_market() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + let exchange = Exchange::new(&env.app); + let ticker = "INJ/USDT".to_string(); + let initial_margin_ratio = FPDecimal::must_from_str("0.195"); + let maintenance_margin_ratio = FPDecimal::must_from_str("0.05"); + let min_price_tick_size = FPDecimal::must_from_str("1000.0"); + let min_quantity_tick_size = FPDecimal::must_from_str("1000000000000000"); + let quote_denom = QUOTE_DENOM.to_string(); + let maker_fee_rate = FPDecimal::ZERO; + let taker_fee_rate = FPDecimal::ZERO; + + exchange + .instant_perpetual_market_launch( + MsgInstantPerpetualMarketLaunch { + sender: env.signer.address(), + ticker: ticker.to_owned(), + quote_denom: quote_denom.to_owned(), + oracle_base: BASE_DENOM.to_owned(), + oracle_quote: quote_denom.to_owned(), + oracle_scale_factor: 6u32, + oracle_type: 2i32, + maker_fee_rate: dec_to_proto(maker_fee_rate).to_string(), + taker_fee_rate: dec_to_proto(taker_fee_rate), + initial_margin_ratio: dec_to_proto(initial_margin_ratio), + maintenance_margin_ratio: dec_to_proto(maintenance_margin_ratio), + min_price_tick_size: dec_to_proto(min_price_tick_size), + min_quantity_tick_size: dec_to_proto(min_quantity_tick_size), + }, + &env.signer, + ) + .unwrap(); + + let derivative_market_id = get_perpetual_market_id(&exchange, ticker.to_owned()); + + let market_id = MarketId::new(derivative_market_id.clone()).unwrap(); + let query_msg = QueryMsg::TestDerivativeMarketQuery { market_id }; + let res: DerivativeMarketResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + + let response_market = res.market.unwrap().market.unwrap(); + assert_eq!(response_market.market_id.as_str(), derivative_market_id); + assert_eq!(response_market.ticker, ticker); + assert_eq!(response_market.quote_denom, quote_denom); + assert_eq!(response_market.min_price_tick_size, min_price_tick_size); + assert_eq!(response_market.min_quantity_tick_size, min_quantity_tick_size); + assert_eq!(response_market.maker_fee_rate, maker_fee_rate); + assert_eq!(response_market.taker_fee_rate, taker_fee_rate); + assert_eq!(response_market.initial_margin_ratio, initial_margin_ratio); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_effective_subaccount_position() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + add_perp_initial_liquidity(&env.app, market_id.clone()); + + let (price, quantity, margin) = scale_price_quantity_perp_market("9.7", "1", "2", "E_DECIMALS); + + let subaccount_id = get_default_subaccount_id_for_checked_address(&Addr::unchecked(env.users[1].account.address())) + .as_str() + .to_string(); + + add_derivative_order_as( + &env.app, + market_id.to_owned(), + &env.users[1].account, + price, + quantity, + OrderType::Sell, + margin, + ); + + let query_msg = QueryMsg::TestEffectiveSubaccountPosition { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id.to_owned()).unwrap(), + }; + let res: SubaccountEffectivePositionInMarketResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert!(res.state.is_some()); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_vanilla_subaccount_position() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + add_perp_initial_liquidity(&env.app, market_id.clone()); + + let (price, quantity, margin) = scale_price_quantity_perp_market("9.7", "1", "2", "E_DECIMALS); + let trader = &env.users[1]; + let subaccount_id = get_default_subaccount_id_for_checked_address(&Addr::unchecked(trader.account.address())) + .as_str() + .to_string(); + + add_derivative_order_as( + &env.app, + market_id.to_owned(), + &env.users[1].account, + price, + quantity, + OrderType::Sell, + margin, + ); + + let query_msg = QueryMsg::TestVanillaSubaccountPosition { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id.to_owned()).unwrap(), + }; + let res: SubaccountPositionInMarketResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert!(res.state.is_some()); + + let liquidity_orders: Vec = vec![HumanOrder { + price: "9.7".to_string(), + quantity: "10".to_string(), + order_type: OrderType::Sell, + }]; + add_derivative_orders(&env.app, market_id.clone(), liquidity_orders.to_owned(), None); + + let _res: SubaccountPositionInMarketResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_trader_derivative_orders() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + let (price, quantity, margin) = scale_price_quantity_perp_market("10.1", "1", "2", "E_DECIMALS); + let subaccount_id = get_default_subaccount_id_for_checked_address(&Addr::unchecked(env.users[1].account.address())) + .as_str() + .to_string(); + + add_derivative_order_as( + &env.app, + market_id.to_owned(), + &env.users[1].account, + price, + quantity, + OrderType::Sell, + margin, + ); + + let query_msg = QueryMsg::TestTraderDerivativeOrders { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id).unwrap(), + }; + let res: TraderDerivativeOrdersResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert!(res.orders.is_some()); + let orders = res.orders.clone().unwrap(); + assert_eq!(orders.len(), 1); + let expected_order = TrimmedDerivativeLimitOrder { + price: human_to_dec("10.1", QUOTE_DECIMALS), + quantity: FPDecimal::must_from_str("1"), + margin: human_to_dec("20.2", QUOTE_DECIMALS), + fillable: FPDecimal::must_from_str("1"), + isBuy: false, + order_hash: "".to_string(), + }; + assert_eq!(orders[0].price, expected_order.price); + assert_eq!(orders[0].quantity, expected_order.quantity); + assert_eq!(orders[0].fillable, expected_order.fillable); + assert_eq!(orders[0].isBuy, expected_order.isBuy); + assert_eq!(orders[0].margin, expected_order.margin); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_derivative_orders_to_cancel_up_to_amount() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + let subaccount_id = get_default_subaccount_id_for_checked_address(&Addr::unchecked(env.users[1].account.address())) + .as_str() + .to_string(); + + let (price, quantity, margin) = scale_price_quantity_perp_market("10.1", "1", "2", "E_DECIMALS); + add_derivative_order_as( + &env.app, + market_id.to_owned(), + &env.users[1].account, + price, + quantity, + OrderType::Sell, + margin, + ); + let (price, quantity, margin) = scale_price_quantity_perp_market("12", "1", "2", "E_DECIMALS); + add_derivative_order_as( + &env.app, + market_id.to_owned(), + &env.users[1].account, + price, + quantity, + OrderType::Sell, + margin, + ); + let query_msg_derivative = QueryMsg::TestTraderDerivativeOrders { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id.to_owned()).unwrap(), + }; + let res: TraderDerivativeOrdersResponse = wasm.query(&env.contract_address, &query_msg_derivative).unwrap(); + assert!(res.orders.is_some()); + let orders = res.orders.clone().unwrap(); + assert_eq!(orders.len(), 2); + let query_derivative_order_cancel_msg = QueryMsg::TestDerivativeOrdersToCancelUpToAmount { + market_id: MarketId::new(market_id.clone()).unwrap(), + subaccount_id: SubaccountId::new(subaccount_id).unwrap(), + quote_amount: human_to_dec("0.2", QUOTE_DECIMALS), + strategy: CancellationStrategy::UnspecifiedOrder, + reference_price: None, + }; + let res: TraderDerivativeOrdersResponse = wasm.query(&env.contract_address, &query_derivative_order_cancel_msg).unwrap(); + assert!(res.orders.is_some()); + let orders = res.orders.clone().unwrap(); + assert_eq!(orders.len(), 1); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_perpetual_market_funding() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let exchange = Exchange::new(&env.app); + let ticker = "INJ/USDT".to_string(); + let derivative_market_id = get_perpetual_market_id(&exchange, ticker.to_owned()); + let market_id = MarketId::new(derivative_market_id.clone()).unwrap(); + let query_msg = QueryMsg::TestPerpetualMarketFunding { + market_id: market_id.clone(), + }; + let res: PerpetualMarketFundingResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert!(res.state.is_some()); + let state = res.state.unwrap(); + assert_eq!(state.cumulative_funding, FPDecimal::ZERO); + assert_eq!(state.cumulative_price, FPDecimal::ZERO); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_derivative_market_mid_price_and_tob() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + add_perp_initial_liquidity(&env.app, market_id.to_owned()); + + let query_msg = QueryMsg::TestDerivativeMarketMidPriceAndTob { + market_id: MarketId::new(market_id.clone()).unwrap(), + }; + + let res: MarketMidPriceAndTOBResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(res.mid_price, Some(human_to_dec("10", QUOTE_DECIMALS))); + assert_eq!(res.best_buy_price, Some(human_to_dec("9.9", QUOTE_DECIMALS))); + assert_eq!(res.best_sell_price, Some(human_to_dec("10.1", QUOTE_DECIMALS))); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_derivative_market_orderbook() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + + let liquidity_orders = get_initial_perp_liquidity_orders_vector(); + add_derivative_orders(&env.app, market_id.clone(), liquidity_orders.to_owned(), None); + + let query_msg = QueryMsg::TestDerivativeMarketOrderbook { + market_id: MarketId::new(market_id.clone()).unwrap(), + limit_cumulative_notional: FPDecimal::MAX, + }; + let res: QueryOrderbookResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + let buys_price_level = res.buys_price_level; + let sells_price_level = res.sells_price_level; + assert_eq!(buys_price_level.len(), 2); + assert_eq!(sells_price_level.len(), 2); + assert_eq!( + buys_price_level[0], + PriceLevel { + p: human_to_dec(liquidity_orders[2].price.as_str(), QUOTE_DECIMALS), + q: FPDecimal::must_from_str(liquidity_orders[2].quantity.as_str()), + } + ); + assert_eq!( + buys_price_level[1], + PriceLevel { + p: human_to_dec(liquidity_orders[3].price.as_str(), QUOTE_DECIMALS), + q: FPDecimal::must_from_str(liquidity_orders[3].quantity.as_str()), + } + ); + assert_eq!( + sells_price_level[0], + PriceLevel { + p: human_to_dec(liquidity_orders[1].price.as_str(), QUOTE_DECIMALS), + q: FPDecimal::must_from_str(liquidity_orders[1].quantity.as_str()), + } + ); + assert_eq!( + sells_price_level[1], + PriceLevel { + p: human_to_dec(liquidity_orders[0].price.as_str(), QUOTE_DECIMALS), + q: FPDecimal::must_from_str(liquidity_orders[0].quantity.as_str()), + } + ); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_trader_transient_derivative_orders() { + let env = Setup::new(ExchangeType::Derivative); + let wasm = Wasm::new(&env.app); + let market_id = env.market_id.unwrap(); + let subaccount_id = checked_address_to_subaccount_id(&Addr::unchecked(env.users[0].account.address()), 0u32); + execute_all_authorizations(&env.app, &env.users[0].account, env.contract_address.clone()); + add_perp_initial_liquidity(&env.app, market_id.clone()); + let (price, quantity, margin) = scale_price_quantity_perp_market("9.7", "0.5", "2", "E_DECIMALS); + add_derivative_order_as( + &env.app, + market_id.to_owned(), + &env.users[0].account, + price, + quantity, + OrderType::Sell, + margin, + ); + let (scale_price, scale_quantity, scaled_margin) = scale_price_quantity_perp_market_dec("9.7", "0.1", "2", "E_DECIMALS); + let res = wasm + .execute( + &env.contract_address, + &ExecuteMsg::TestTraderTransientDerivativeOrders { + market_id: MarketId::new(market_id).unwrap(), + subaccount_id: subaccount_id.clone(), + price: scale_price.to_string(), + quantity: scale_quantity.to_string(), + margin: scaled_margin.to_string(), + }, + &[], + &env.users[0].account, + ) + .unwrap(); + + let transient_query = res + .events + .iter() + .find(|e| e.ty == "wasm-transient_derivative_order") + .and_then(|event| event.attributes.iter().find(|a| a.key == "query_str")); + + assert!(transient_query.is_some()); + let expected_order_info = "Ok(TraderDerivativeOrdersResponse { orders: Some([TrimmedDerivativeLimitOrder { price: FPDecimal { num: 9700000000000000000000000, sign: 1 }, quantity: FPDecimal { num: 100000000000000000, sign: 1 }, margin: FPDecimal { num: 1940000000000000000000000, sign: 1 }, fillable: FPDecimal { num: 100000000000000000, sign: 1 }, isBuy: true"; + assert!(transient_query.unwrap().value.contains(expected_order_info)); +} diff --git a/contracts/injective-cosmwasm-mock/src/testing/test_oracle.rs b/contracts/injective-cosmwasm-mock/src/testing/test_oracle.rs new file mode 100644 index 00000000..17175525 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/testing/test_oracle.rs @@ -0,0 +1,105 @@ +use crate::msg::QueryMsg; +use crate::utils::{ + create_some_inj_price_attestation, relay_pyth_price, set_address_of_pyth_contract, str_coin, ExchangeType, Setup, BASE_DECIMALS, BASE_DENOM, + INJ_PYTH_PRICE_ID, +}; +use injective_cosmwasm::{OracleInfo, OraclePriceResponse, OracleType, OracleVolatilityResponse, PythPriceResponse}; +use injective_math::scale::Scaled; +use injective_math::FPDecimal; +use injective_std::types::injective::oracle::v1beta1::{QueryOraclePriceRequest, QueryPythPriceRequest}; +use injective_test_tube::{Module, Oracle, RunnerResult, Wasm}; + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_oracle_price() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + let oracle = Oracle::new(&env.app); + + let query_msg = QueryMsg::TestQueryOraclePrice { + oracle_type: OracleType::PriceFeed, + base: env.denoms["base"].to_owned(), + quote: env.denoms["quote"].to_owned(), + }; + + let query_oracle_price_request = QueryOraclePriceRequest { + oracle_type: 2i32, + base: env.denoms["base"].to_owned(), + quote: env.denoms["quote"].to_owned(), + }; + + let oracle_response = oracle.query_oracle_price(&query_oracle_price_request); + let contract_response: RunnerResult = wasm.query(&env.contract_address, &query_msg); + + let oracle_response_pair_state = oracle_response.unwrap().price_pair_state; + let contract_response_pair_state = contract_response.unwrap().price_pair_state; + + assert!(contract_response_pair_state.is_some()); + assert!(oracle_response_pair_state.is_some()); + let oracle_response_pair_state = oracle_response_pair_state.unwrap(); + let contract_response_pair_state = contract_response_pair_state.unwrap(); + let oracle_response_pair_price = FPDecimal::must_from_str(oracle_response_pair_state.pair_price.as_str()); + assert_eq!(contract_response_pair_state.pair_price.scaled(18), oracle_response_pair_price); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_oracle_volatility() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + + let base_oracle_info = Some(OracleInfo { + symbol: env.denoms["base"].to_owned(), + oracle_type: OracleType::PriceFeed, + scale_factor: 6u32, + }); + + let quote_oracle_info = Some(OracleInfo { + symbol: env.denoms["quote"].to_owned(), + oracle_type: OracleType::PriceFeed, + scale_factor: 6u32, + }); + + let query_msg = QueryMsg::TestQueryOracleVolatility { + base_info: base_oracle_info, + quote_info: quote_oracle_info, + max_age: 60u64, + include_raw_history: true, + include_metadata: false, + }; + let res: OracleVolatilityResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert!(res.volatility.is_none()); + assert!(res.raw_history.is_none()); +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_pyth_oracle_price() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + let oracle = Oracle::new(&env.app); + + let validator = env.app.get_first_validator_signing_account(BASE_DENOM.to_string(), 1.2f64).unwrap(); + let pyth_contract = env.app.init_account(&[str_coin("1000000", BASE_DENOM, BASE_DECIMALS)]).unwrap(); + + set_address_of_pyth_contract(&env.app, &validator, &pyth_contract); + let price_attestations = vec![create_some_inj_price_attestation("7", 5, env.app.get_block_time_seconds())]; + relay_pyth_price(&oracle, price_attestations, &pyth_contract); + + let price_pyth_oracle_response = oracle + .query_pyth_price(&QueryPythPriceRequest { + price_id: INJ_PYTH_PRICE_ID.to_string(), + }) + .unwrap(); + let price_pyth_oracle_response = FPDecimal::must_from_str(price_pyth_oracle_response.price_state.unwrap().ema_price.as_str()); + + let query_msg = QueryMsg::TestQueryPythPrice { + price_id: INJ_PYTH_PRICE_ID.to_string(), + }; + + let contract_response: PythPriceResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!( + contract_response.price_state.unwrap().ema_price.scaled(BASE_DECIMALS), + price_pyth_oracle_response + ); +} diff --git a/contracts/injective-cosmwasm-mock/src/testing/test_staking.rs b/contracts/injective-cosmwasm-mock/src/testing/test_staking.rs new file mode 100644 index 00000000..6157a539 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/testing/test_staking.rs @@ -0,0 +1,38 @@ +use crate::msg::QueryMsg; +use crate::utils::{ExchangeType, Setup, BASE_DENOM}; +use cosmwasm_std::Uint128; +use injective_cosmwasm::exchange::response::StakedAmountResponse; +use injective_std::types::cosmos::base::v1beta1::Coin; +use injective_std::types::cosmos::staking::v1beta1::MsgDelegate; +use injective_test_tube::{Account, Module, Staking, Wasm}; + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_staked_amount() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + let staking = Staking::new(&env.app); + let validator_address = env.app.get_first_validator_address().unwrap(); + + staking + .delegate( + MsgDelegate { + delegator_address: env.owner.address(), + validator_address, + amount: Some(Coin { + amount: "10".to_string(), + denom: BASE_DENOM.to_string(), + }), + }, + &env.owner, + ) + .unwrap(); + + let query_msg = QueryMsg::TestQueryStakedAmount { + delegator_address: env.owner.address(), + max_delegations: 100, + }; + + let response: StakedAmountResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(response.staked_amount, Uint128::new(10)); +} diff --git a/contracts/injective-cosmwasm-mock/src/testing/test_token_factory.rs b/contracts/injective-cosmwasm-mock/src/testing/test_token_factory.rs new file mode 100644 index 00000000..69d253d8 --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/testing/test_token_factory.rs @@ -0,0 +1,36 @@ +use crate::msg::QueryMsg; +use crate::utils::{str_coin, ExchangeType, Setup, BASE_DECIMALS, BASE_DENOM}; +use cosmwasm_std::Uint128; +use injective_cosmwasm::tokenfactory::response::{TokenFactoryCreateDenomFeeResponse, TokenFactoryDenomSupplyResponse}; +use injective_std::types::injective::tokenfactory::v1beta1::MsgCreateDenom; +use injective_test_tube::{Account, Module, TokenFactory, Wasm}; + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_token_factory_denom_total_supply() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + let factory = TokenFactory::new(&env.app); + + let test_denom = format!("factory/{}/test", env.owner.address()); + let msg_create_denom = MsgCreateDenom { + sender: env.owner.address(), + subdenom: "test".to_string(), + }; + + factory.create_denom(msg_create_denom, &env.owner).unwrap(); + let query_msg = QueryMsg::TestQueryTokenFactoryDenomTotalSupply { denom: test_denom }; + + let response: TokenFactoryDenomSupplyResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert_eq!(response.total_supply, Uint128::zero()) +} + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_token_factory_creation_fee() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + + let response: TokenFactoryCreateDenomFeeResponse = wasm.query(&env.contract_address, &QueryMsg::TestQueryTokenFactoryCreationFee {}).unwrap(); + assert_eq!(response.fee, vec![str_coin("10", BASE_DENOM, BASE_DECIMALS)]) +} diff --git a/contracts/injective-cosmwasm-mock/src/testing/test_wasmx.rs b/contracts/injective-cosmwasm-mock/src/testing/test_wasmx.rs new file mode 100644 index 00000000..2aa3f67a --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/testing/test_wasmx.rs @@ -0,0 +1,18 @@ +use crate::msg::QueryMsg; +use crate::utils::{ExchangeType, Setup}; +use injective_cosmwasm::wasmx::response::QueryContractRegistrationInfoResponse; +use injective_test_tube::{Module, Wasm}; + +#[test] +#[cfg_attr(not(feature = "integration"), ignore)] +fn test_query_contract_registration_info() { + let env = Setup::new(ExchangeType::None); + let wasm = Wasm::new(&env.app); + + let query_msg = QueryMsg::TestQueryContractRegistrationInfo { + contract_address: env.contract_address.to_owned(), + }; + + let response: QueryContractRegistrationInfoResponse = wasm.query(&env.contract_address, &query_msg).unwrap(); + assert!(response.contract.is_none()) +} diff --git a/contracts/injective-cosmwasm-mock/src/types.rs b/contracts/injective-cosmwasm-mock/src/types.rs new file mode 100644 index 00000000..e4e3642e --- /dev/null +++ b/contracts/injective-cosmwasm-mock/src/types.rs @@ -0,0 +1,170 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive( + Clone, + PartialEq, + Eq, + ::prost::Message, + ::serde::Serialize, + ::serde::Deserialize, + ::schemars::JsonSchema, + // CosmwasmExt, +)] +// #[proto_message(type_url = "/injective.exchange.v1beta1.OrderInfo")] +pub struct OrderInfo { + /// bytes32 subaccount ID that created the order + #[prost(string, tag = "1")] + #[serde(alias = "subaccountID")] + pub subaccount_id: ::prost::alloc::string::String, + /// address fee_recipient address that will receive fees for the order + #[prost(string, tag = "2")] + pub fee_recipient: ::prost::alloc::string::String, + /// price of the order + #[prost(string, tag = "3")] + pub price: ::prost::alloc::string::String, + /// quantity of the order + #[prost(string, tag = "4")] + pub quantity: ::prost::alloc::string::String, +} + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive( + Clone, + PartialEq, + Eq, + ::prost::Message, + ::serde::Serialize, + ::serde::Deserialize, + ::schemars::JsonSchema, + // CosmwasmExt, +)] +// #[proto_message(type_url = "/injective.exchange.v1beta1.SpotOrder")] +pub struct SpotOrder { + /// market_id represents the unique ID of the market + #[prost(string, tag = "1")] + #[serde(alias = "marketID")] + pub market_id: ::prost::alloc::string::String, + /// order_info contains the information of the order + #[prost(message, optional, tag = "2")] + pub order_info: ::core::option::Option, + /// order types + #[prost(enumeration = "OrderType", tag = "3")] + // #[serde( + // serialize_with = "crate::serde::as_str::serialize", + // deserialize_with = "crate::serde::as_str::deserialize" + // )] + pub order_type: i32, + /// trigger_price is the trigger price used by stop/take orders + #[prost(string, tag = "4")] + pub trigger_price: ::prost::alloc::string::String, +} + +/// MsgCreateSpotMarketOrder defines a SDK message for creating a new spot market +/// order. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive( + Clone, + PartialEq, + Eq, + ::prost::Message, + ::serde::Serialize, + ::serde::Deserialize, + ::schemars::JsonSchema, + // CosmwasmExt, +)] +// #[proto_message(type_url = "/injective.exchange.v1beta1.MsgCreateSpotMarketOrder")] +pub struct MsgCreateSpotMarketOrder { + #[prost(string, tag = "1")] + pub sender: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub order: ::core::option::Option, +} + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive( + Clone, + PartialEq, + Eq, + ::prost::Message, + ::serde::Serialize, + ::serde::Deserialize, + ::schemars::JsonSchema, + // CosmwasmExt, +)] +// #[proto_message(type_url = "/injective.exchange.v1beta1.MsgCreateSpotLimitOrder")] +pub struct MsgCreateSpotLimitOrder { + #[prost(string, tag = "1")] + pub sender: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub order: ::core::option::Option, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +#[derive(::serde::Serialize, ::serde::Deserialize, ::schemars::JsonSchema)] +pub enum OrderType { + Unspecified = 0, + Buy = 1, + Sell = 2, + StopBuy = 3, + StopSell = 4, + TakeBuy = 5, + TakeSell = 6, + BuyPo = 7, + SellPo = 8, + BuyAtomic = 9, + SellAtomic = 10, +} + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive( + Clone, + PartialEq, + Eq, + ::prost::Message, + ::serde::Serialize, + ::serde::Deserialize, + ::schemars::JsonSchema, + //CosmwasmExt +)] +//#[proto_message(type_url = "/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder")] +pub struct MsgCreateDerivativeLimitOrder { + #[prost(string, tag = "1")] + pub sender: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub order: ::core::option::Option, +} + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive( + Clone, + PartialEq, + Eq, + ::prost::Message, + ::serde::Serialize, + ::serde::Deserialize, + ::schemars::JsonSchema, + // CosmwasmExt, +)] +// #[proto_message(type_url = "/injective.exchange.v1beta1.DerivativeOrder")] +pub struct DerivativeOrder { + /// market_id represents the unique ID of the market + #[prost(string, tag = "1")] + #[serde(alias = "marketID")] + pub market_id: ::prost::alloc::string::String, + /// order_info contains the information of the order + #[prost(message, optional, tag = "2")] + pub order_info: ::core::option::Option, + /// order types + #[prost(enumeration = "OrderType", tag = "3")] + // #[serde( + // serialize_with = "crate::serde::as_str::serialize", + // deserialize_with = "crate::serde::as_str::deserialize" + // )] + pub order_type: i32, + /// margin is the margin used by the limit order + #[prost(string, tag = "4")] + pub margin: ::prost::alloc::string::String, + /// trigger_price is the trigger price used by stop/take orders + #[prost(string, tag = "5")] + pub trigger_price: ::prost::alloc::string::String, +} diff --git a/contracts/injective-cosmwasm-mock/src/utils.rs b/contracts/injective-cosmwasm-mock/src/utils.rs index e60f7b65..ae74b15d 100644 --- a/contracts/injective-cosmwasm-mock/src/utils.rs +++ b/contracts/injective-cosmwasm-mock/src/utils.rs @@ -1,32 +1,833 @@ -use crate::msg::InstantiateMsg; -use cosmwasm_std::Coin; -use injective_test_tube::{Account, InjectiveTestApp, Module, SigningAccount, Wasm}; +use crate::msg::{InstantiateMsg, MSG_CREATE_DERIVATIVE_LIMIT_ORDER_ENDPOINT, MSG_CREATE_SPOT_LIMIT_ORDER_ENDPOINT}; +use cosmwasm_std::{coin, Addr, Coin}; +use injective_cosmwasm::{checked_address_to_subaccount_id, SubaccountId}; +use injective_math::{scale::Scaled, FPDecimal}; +use injective_std::{ + shim::{Any, Timestamp}, + types::{ + cosmos::{ + authz::v1beta1::{GenericAuthorization, Grant, MsgGrant, MsgRevoke, MsgRevokeResponse}, + bank::v1beta1::{MsgSend, SendAuthorization}, + base::v1beta1::Coin as BaseCoin, + gov::{ + v1::{MsgSubmitProposal, MsgVote}, + v1beta1::MsgSubmitProposal as MsgSubmitProposalV1Beta1, + }, + }, + injective::{ + exchange::v1beta1::{ + DerivativeOrder, MsgCreateDerivativeLimitOrder, MsgCreateSpotLimitOrder, MsgInstantPerpetualMarketLaunch, MsgInstantSpotMarketLaunch, + OrderInfo, OrderType, QueryDerivativeMarketsRequest, QuerySpotMarketsRequest, SpotOrder, + }, + insurance::v1beta1::MsgCreateInsuranceFund, + oracle::v1beta1::{ + GrantPriceFeederPrivilegeProposal, MsgRelayPriceFeedPrice, MsgRelayPythPrices, MsgUpdateParams, OracleType, Params, PriceAttestation, + }, + }, + }, +}; +use injective_test_tube::{ + injective_cosmwasm::get_default_subaccount_id_for_checked_address, Account, Authz, Bank, Exchange, ExecuteResponse, Gov, InjectiveTestApp, + Insurance, Module, Oracle, Runner, SigningAccount, Wasm, +}; +use injective_testing::human_to_i64; +use prost::Message; +use std::{collections::HashMap, ops::Neg, str::FromStr}; -pub fn test_setup() -> (InjectiveTestApp, Vec, String) { - let app = InjectiveTestApp::new(); - let mut accs = app - .init_accounts(&[Coin::new(1_000_000_000_000, "usdt"), Coin::new(1_000_000_000_000, "inj")], 2) +pub const EXCHANGE_DECIMALS: i32 = 18i32; +pub const BASE_DECIMALS: i32 = 18i32; +pub const ATOM_DECIMALS: i32 = 8i32; +pub const QUOTE_DECIMALS: i32 = 6i32; + +pub const ATOM_DENOM: &str = "atom"; +pub const BASE_DENOM: &str = "inj"; +pub const QUOTE_DENOM: &str = "usdt"; +pub const INJ_PYTH_PRICE_ID: &str = "0x7a5bc1d2b56ad029048cd63964b3ad2776eadf812edc1a43a31406cb54bff592"; +pub const USDT_PYTH_PRICE_ID: &str = "0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588"; +pub const GOV_MODULE_ADDRESS: &str = "inj10d07y265gmmuvt4z0w9aw880jnsr700jstypyt"; + +pub struct UserInfo { + pub account: SigningAccount, + pub subaccount_id: SubaccountId, +} +pub struct Setup { + pub app: InjectiveTestApp, + pub owner: SigningAccount, + pub signer: SigningAccount, + pub validator: SigningAccount, + pub users: Vec, + pub denoms: HashMap, + pub contract_address: String, + pub code_id: u64, + pub market_id: Option, +} + +pub enum ExchangeType { + Spot, + Derivative, + None, +} + +impl Setup { + pub fn new(exchange_type: ExchangeType) -> Self { + let app = InjectiveTestApp::new(); + let wasm = Wasm::new(&app); + let mut market_id = None; + + let mut denoms = HashMap::new(); + denoms.insert("atom".to_string(), ATOM_DENOM.to_string()); + denoms.insert("quote".to_string(), QUOTE_DENOM.to_string()); + denoms.insert("base".to_string(), BASE_DENOM.to_string()); + + let signer = app.init_account(&[str_coin("1000000", BASE_DENOM, BASE_DECIMALS)]).unwrap(); + + let validator = app.get_first_validator_signing_account(BASE_DENOM.to_string(), 1.2f64).unwrap(); + + let owner = app + .init_account(&[ + str_coin("1000000", ATOM_DENOM, ATOM_DECIMALS), + str_coin("1000000", BASE_DENOM, BASE_DECIMALS), + str_coin("1000000", QUOTE_DENOM, QUOTE_DECIMALS), + ]) + .unwrap(); + + let mut users: Vec = Vec::new(); + for _ in 0..10 { + let user = app + .init_account(&[ + str_coin("1000000", ATOM_DENOM, ATOM_DECIMALS), + str_coin("1000000", BASE_DENOM, BASE_DECIMALS), + str_coin("1000", QUOTE_DENOM, QUOTE_DECIMALS), + ]) + .unwrap(); + + let user_subaccount_id = checked_address_to_subaccount_id(&Addr::unchecked(user.address()), 0u32); + + users.push(UserInfo { + account: user, + subaccount_id: user_subaccount_id, + }); + } + + let wasm_byte_code = std::fs::read(wasm_file("injective_cosmwasm_mock".to_string())).unwrap(); + let code_id = wasm.store_code(&wasm_byte_code, None, &owner).unwrap().data.code_id; + + // Instantiate contract + let contract_address: String = wasm + .instantiate(code_id, &InstantiateMsg {}, Some(&owner.address()), Some("mock-contract"), &[], &owner) + .unwrap() + .data + .address; + + assert!(!contract_address.is_empty(), "Contract address is empty"); + + send(&Bank::new(&app), "1000000000000000000000", BASE_DENOM, &owner, &validator); + + launch_insurance_fund( + &app, + &owner, + "INJ/USDT", + denoms["quote"].as_str(), + denoms["base"].as_str(), + denoms["quote"].as_str(), + OracleType::PriceFeed, + ); + + launch_price_feed_oracle( + &app, + &signer, + &validator, + denoms["base"].as_str(), + denoms["quote"].as_str(), + human_to_dec("10.01", BASE_DECIMALS).to_string(), + ); + + match exchange_type { + ExchangeType::Spot => { + let exchange = Exchange::new(&app); + market_id = Some(launch_spot_market(&exchange, &owner, "INJ/USDT".to_string())); + } + ExchangeType::Derivative => { + let exchange = Exchange::new(&app); + market_id = Some(launch_perp_market(&exchange, &owner, "INJ/USDT".to_string())); + } + ExchangeType::None => {} + } + + Self { + app, + owner, + signer, + validator, + users, + denoms, + contract_address, + code_id, + market_id, + } + } +} + +impl Default for Setup { + fn default() -> Self { + Self::new(ExchangeType::None) + } +} + +pub fn wasm_file(contract_name: String) -> String { + let snaked_name = contract_name.replace('-', "_"); + let arch = std::env::consts::ARCH; + + let target = format!("../../target/wasm32-unknown-unknown/release/{snaked_name}.wasm"); + + let artifacts_dir = std::env::var("ARTIFACTS_DIR_PATH").unwrap_or_else(|_| "artifacts".to_string()); + let arch_target = format!("../../{artifacts_dir}/{snaked_name}-{arch}.wasm"); + + if std::path::Path::new(&target).exists() { + target + } else if std::path::Path::new(&arch_target).exists() { + arch_target + } else { + format!("../../{artifacts_dir}/{snaked_name}.wasm") + } +} + +pub fn str_coin(human_amount: &str, denom: &str, decimals: i32) -> Coin { + let scaled_amount = human_to_dec(human_amount, decimals); + let as_int: u128 = scaled_amount.into(); + coin(as_int, denom) +} + +pub fn send(bank: &Bank, amount: &str, denom: &str, from: &SigningAccount, to: &SigningAccount) { + bank.send( + MsgSend { + from_address: from.address(), + to_address: to.address(), + amount: vec![BaseCoin { + amount: amount.to_string(), + denom: denom.to_string(), + }], + }, + from, + ) + .unwrap(); +} + +pub fn launch_price_feed_oracle( + app: &InjectiveTestApp, + signer: &SigningAccount, + validator: &SigningAccount, + base: &str, + quote: &str, + dec_price: String, +) { + let gov = Gov::new(app); + let oracle = Oracle::new(app); + + let mut buf = vec![]; + GrantPriceFeederPrivilegeProposal::encode( + &GrantPriceFeederPrivilegeProposal { + title: "test-proposal".to_string(), + description: "test-proposal".to_string(), + base: base.to_string(), + quote: quote.to_string(), + relayers: vec![signer.address()], + }, + &mut buf, + ) + .unwrap(); + + let res = gov + .submit_proposal_v1beta1( + MsgSubmitProposalV1Beta1 { + content: Some(Any { + type_url: "/injective.oracle.v1beta1.GrantPriceFeederPrivilegeProposal".to_string(), + value: buf, + }), + initial_deposit: vec![BaseCoin { + amount: "100000000000000000000".to_string(), + denom: "inj".to_string(), + }], + proposer: validator.address(), + }, + validator, + ) + .unwrap(); + + let proposal_id = res.events.iter().find(|e| e.ty == "submit_proposal").unwrap().attributes[0] + .value + .to_owned(); + + gov.vote( + MsgVote { + proposal_id: u64::from_str(&proposal_id).unwrap(), + voter: validator.address(), + option: 1i32, + metadata: "".to_string(), + }, + validator, + ) + .unwrap(); + + // NOTE: increase the block time in order to move past the voting period + app.increase_time(10u64); + + oracle + .relay_price_feed( + MsgRelayPriceFeedPrice { + sender: signer.address(), + base: vec![base.to_string()], + quote: vec![quote.to_string()], + price: vec![dec_price], // 1.2@18dp + }, + signer, + ) + .unwrap(); +} + +pub fn launch_insurance_fund( + app: &InjectiveTestApp, + signer: &SigningAccount, + ticker: &str, + quote: &str, + oracle_base: &str, + oracle_quote: &str, + oracle_type: OracleType, +) { + let insurance = Insurance::new(app); + + insurance + .create_insurance_fund( + MsgCreateInsuranceFund { + sender: signer.address(), + ticker: ticker.to_string(), + quote_denom: quote.to_string(), + oracle_base: oracle_base.to_string(), + oracle_quote: oracle_quote.to_string(), + oracle_type: oracle_type as i32, + expiry: -1i64, + initial_deposit: Some(BaseCoin { + amount: human_to_dec("1_000", QUOTE_DECIMALS).to_string(), + denom: quote.to_string(), + }), + }, + signer, + ) .unwrap(); - accs.push(app.init_account(&[Coin::new(1_000_000_000_000_000_000_000_000_000, "inj")]).unwrap()); +} + +pub fn launch_spot_market(exchange: &Exchange, signer: &SigningAccount, ticker: String) -> String { + exchange + .instant_spot_market_launch( + MsgInstantSpotMarketLaunch { + sender: signer.address(), + ticker: ticker.clone(), + base_denom: BASE_DENOM.to_string(), + quote_denom: QUOTE_DENOM.to_string(), + min_price_tick_size: dec_to_proto(FPDecimal::must_from_str("0.000000000000001")), + min_quantity_tick_size: dec_to_proto(FPDecimal::must_from_str("1")), + }, + signer, + ) + .unwrap(); + + get_spot_market_id(exchange, ticker) +} + +pub fn get_spot_market_id(exchange: &Exchange, ticker: String) -> String { + let spot_markets = exchange + .query_spot_markets(&QuerySpotMarketsRequest { + status: "Active".to_string(), + market_ids: vec![], + }) + .unwrap() + .markets; + + let market = spot_markets.iter().find(|m| m.ticker == ticker).unwrap(); + market.market_id.to_string() +} - let seller = &accs[0]; - let buyer = &accs[1]; +pub fn launch_perp_market(exchange: &Exchange, signer: &SigningAccount, ticker: String) -> String { + exchange + .instant_perpetual_market_launch( + MsgInstantPerpetualMarketLaunch { + sender: signer.address(), + ticker: ticker.to_owned(), + quote_denom: "usdt".to_string(), + oracle_base: "inj".to_string(), + oracle_quote: "usdt".to_string(), + oracle_scale_factor: 6u32, + oracle_type: 2i32, + maker_fee_rate: "0".to_owned(), + taker_fee_rate: "0".to_owned(), + initial_margin_ratio: "195000000000000000".to_owned(), + maintenance_margin_ratio: "50000000000000000".to_owned(), + min_price_tick_size: "1000000000000000000000".to_owned(), + min_quantity_tick_size: "1000000000000000".to_owned(), + }, + signer, + ) + .unwrap(); - // `Wasm` is the module we use to interact with cosmwasm releated logic on the appchain - // it implements `Module` trait which you will see more later. - let wasm = Wasm::new(&app); + get_perpetual_market_id(exchange, ticker) +} - // Load compiled wasm bytecode - let wasm_byte_code = std::fs::read("../../artifacts/injective_cosmwasm_mock-aarch64.wasm").unwrap(); - let code_id = wasm.store_code(&wasm_byte_code, None, buyer).unwrap().data.code_id; +pub fn get_perpetual_market_id(exchange: &Exchange, ticker: String) -> String { + let perpetual_markets = exchange + .query_derivative_markets(&QueryDerivativeMarketsRequest { + status: "Active".to_string(), + market_ids: vec![], + with_mid_price_and_tob: false, + }) + .unwrap() + .markets; - // Instantiate contract - let contract_address: String = wasm - .instantiate(code_id, &InstantiateMsg {}, Some(&seller.address()), Some("mock-contract"), &[], seller) + let market = perpetual_markets + .iter() + .filter(|m| m.market.is_some()) + .find(|m| m.market.as_ref().unwrap().ticker == ticker) .unwrap() - .data - .address; - assert!(!contract_address.is_empty(), "Contract address is empty"); + .market + .as_ref() + .unwrap(); + + market.market_id.to_string() +} + +#[derive(Clone)] +pub struct HumanOrder { + pub price: String, + pub quantity: String, + pub order_type: OrderType, +} +pub fn add_spot_order_as(app: &InjectiveTestApp, market_id: String, trader: &UserInfo, price: String, quantity: String, order_type: OrderType) { + let exchange = Exchange::new(app); + exchange + .create_spot_limit_order( + MsgCreateSpotLimitOrder { + sender: trader.account.address().clone(), + order: Some(SpotOrder { + market_id: market_id.to_owned(), + order_info: Some(OrderInfo { + subaccount_id: trader.subaccount_id.to_string(), + fee_recipient: trader.account.address(), + price, + quantity, + }), + order_type: order_type.into(), + trigger_price: "".to_string(), + }), + }, + &trader.account, + ) + .unwrap(); +} + +pub fn add_spot_orders(app: &InjectiveTestApp, market_id: String, orders: Vec) { + let account = app + .init_account(&[ + str_coin("1000000", BASE_DENOM, BASE_DECIMALS), + str_coin("1000000", QUOTE_DENOM, QUOTE_DECIMALS), + ]) + .unwrap(); + + let subaccount_id = checked_address_to_subaccount_id(&Addr::unchecked(account.address()), 0u32); + + let trader = UserInfo { account, subaccount_id }; + + for order in orders { + let (price, quantity) = scale_price_quantity_for_spot_market(order.price.as_str(), order.quantity.as_str(), &BASE_DECIMALS, "E_DECIMALS); + add_spot_order_as(app, market_id.to_owned(), &trader, price, quantity, order.order_type); + } +} + +pub fn get_initial_liquidity_orders_vector() -> Vec { + vec![ + HumanOrder { + price: "15".to_string(), + quantity: "10".to_string(), + order_type: OrderType::Sell, + }, + HumanOrder { + price: "12".to_string(), + quantity: "5".to_string(), + order_type: OrderType::Sell, + }, + HumanOrder { + price: "10.2".to_string(), + quantity: "5".to_string(), + order_type: OrderType::Sell, + }, + HumanOrder { + price: "10.1".to_string(), + quantity: "10".to_string(), + order_type: OrderType::Sell, + }, + HumanOrder { + price: "9.9".to_string(), + quantity: "10".to_string(), + order_type: OrderType::Buy, + }, + HumanOrder { + price: "9.8".to_string(), + quantity: "5".to_string(), + order_type: OrderType::Buy, + }, + HumanOrder { + price: "8".to_string(), + quantity: "5".to_string(), + order_type: OrderType::Buy, + }, + HumanOrder { + price: "5".to_string(), + quantity: "10".to_string(), + order_type: OrderType::Buy, + }, + ] +} + +pub fn add_spot_initial_liquidity(app: &InjectiveTestApp, market_id: String) { + add_spot_orders(app, market_id, get_initial_liquidity_orders_vector()); +} + +pub fn get_initial_perp_liquidity_orders_vector() -> Vec { + vec![ + HumanOrder { + price: "10.2".to_string(), + quantity: "2".to_string(), + order_type: OrderType::Sell, + }, + HumanOrder { + price: "10.1".to_string(), + quantity: "1".to_string(), + order_type: OrderType::Sell, + }, + HumanOrder { + price: "9.9".to_string(), + quantity: "1".to_string(), + order_type: OrderType::Buy, + }, + HumanOrder { + price: "9.8".to_string(), + quantity: "2".to_string(), + order_type: OrderType::Buy, + }, + ] +} + +pub fn add_derivative_order_as( + app: &InjectiveTestApp, + market_id: String, + trader: &SigningAccount, + price: String, + quantity: String, + order_type: OrderType, + margin: String, +) { + let exchange = Exchange::new(app); + exchange + .create_derivative_limit_order( + MsgCreateDerivativeLimitOrder { + sender: trader.address(), + order: Some(DerivativeOrder { + market_id: market_id.to_owned(), + order_info: Some(OrderInfo { + subaccount_id: get_default_subaccount_id_for_checked_address(&Addr::unchecked(trader.address())) + .as_str() + .to_string(), + fee_recipient: trader.address(), + price, + quantity, + }), + margin, + order_type: order_type.into(), + trigger_price: "".to_string(), + }), + }, + trader, + ) + .unwrap(); +} + +pub fn add_derivative_orders(app: &InjectiveTestApp, market_id: String, orders: Vec, margin: Option) { + let trader = app + .init_account(&[ + str_coin("1000000", BASE_DENOM, BASE_DECIMALS), + str_coin("1000000", QUOTE_DENOM, QUOTE_DECIMALS), + ]) + .unwrap(); + + let margin = margin.unwrap_or("2".into()); + + for order in orders { + let (price, quantity, order_margin) = + scale_price_quantity_perp_market(order.price.as_str(), order.quantity.as_str(), &margin, "E_DECIMALS); + add_derivative_order_as(app, market_id.to_owned(), &trader, price, quantity, order.order_type, order_margin); + } +} + +pub fn add_perp_initial_liquidity(app: &InjectiveTestApp, market_id: String) { + add_derivative_orders(app, market_id, get_initial_perp_liquidity_orders_vector(), None); +} + +pub fn revoke_authorization(app: &InjectiveTestApp, granter: &SigningAccount, grantee: String, msg_type_url: String) { + let _res: ExecuteResponse = app + .execute_multiple( + &[( + MsgRevoke { + granter: granter.address(), + grantee, + msg_type_url, + }, + MsgRevoke::TYPE_URL, + )], + granter, + ) + .unwrap(); +} + +pub fn create_generic_authorization(app: &InjectiveTestApp, granter: &SigningAccount, grantee: String, msg: String, expiration: Option) { + let authz = Authz::new(app); + + let mut buf = vec![]; + GenericAuthorization::encode(&GenericAuthorization { msg }, &mut buf).unwrap(); + + authz + .grant( + MsgGrant { + granter: granter.address(), + grantee, + grant: Some(Grant { + authorization: Some(Any { + type_url: "/cosmos.authz.v1beta1.GenericAuthorization".to_string(), + value: buf.clone(), + }), + expiration, + }), + }, + granter, + ) + .unwrap(); +} + +pub fn create_send_authorization(app: &InjectiveTestApp, granter: &SigningAccount, grantee: String, amount: BaseCoin, expiration: Option) { + let authz = Authz::new(app); + + let mut buf = vec![]; + SendAuthorization::encode( + &SendAuthorization { + spend_limit: vec![amount], + allow_list: vec![], + }, + &mut buf, + ) + .unwrap(); + + authz + .grant( + MsgGrant { + granter: granter.address(), + grantee, + grant: Some(Grant { + authorization: Some(Any { + type_url: "/cosmos.bank.v1beta1.SendAuthorization".to_string(), + value: buf.clone(), + }), + expiration, + }), + }, + granter, + ) + .unwrap(); +} + +pub fn execute_all_authorizations(app: &InjectiveTestApp, granter: &SigningAccount, grantee: String) { + create_generic_authorization(app, granter, grantee.clone(), MSG_CREATE_SPOT_LIMIT_ORDER_ENDPOINT.to_string(), None); + + create_generic_authorization( + app, + granter, + grantee.clone(), + MSG_CREATE_DERIVATIVE_LIMIT_ORDER_ENDPOINT.to_string(), + None, + ); + + create_generic_authorization( + app, + granter, + grantee.clone(), + "/injective.exchange.v1beta1.MsgCreateDerivativeMarketOrder".to_string(), + None, + ); + + create_generic_authorization( + app, + granter, + grantee.clone(), + "/injective.exchange.v1beta1.MsgBatchUpdateOrders".to_string(), + None, + ); + + create_generic_authorization(app, granter, grantee, "/injective.exchange.v1beta1.MsgWithdraw".to_string(), None); +} + +// Human Utils +pub fn human_to_proto(raw_number: &str, decimals: i32) -> String { + FPDecimal::must_from_str(&raw_number.replace('_', "")).scaled(18 + decimals).to_string() +} + +pub fn human_to_dec(raw_number: &str, decimals: i32) -> FPDecimal { + FPDecimal::must_from_str(&raw_number.replace('_', "")).scaled(decimals) +} + +pub fn dec_to_proto(val: FPDecimal) -> String { + val.scaled(18).to_string() +} + +pub fn scale_price_quantity_for_spot_market(price: &str, quantity: &str, base_decimals: &i32, quote_decimals: &i32) -> (String, String) { + let (scaled_price, scaled_quantity) = scale_price_quantity_for_spot_market_dec(price, quantity, base_decimals, quote_decimals); + (dec_to_proto(scaled_price), dec_to_proto(scaled_quantity)) +} + +pub fn scale_price_quantity_for_spot_market_dec(price: &str, quantity: &str, base_decimals: &i32, quote_decimals: &i32) -> (FPDecimal, FPDecimal) { + let price_dec = FPDecimal::must_from_str(price.replace('_', "").as_str()); + let quantity_dec = FPDecimal::must_from_str(quantity.replace('_', "").as_str()); + + let scaled_price = price_dec.scaled(quote_decimals - base_decimals); + let scaled_quantity = quantity_dec.scaled(*base_decimals); + + (scaled_price, scaled_quantity) +} + +pub fn scale_price_quantity_perp_market(price: &str, quantity: &str, margin_ratio: &str, quote_decimals: &i32) -> (String, String, String) { + let (scaled_price, scaled_quantity, scaled_margin) = scale_price_quantity_perp_market_dec(price, quantity, margin_ratio, quote_decimals); + + (dec_to_proto(scaled_price), dec_to_proto(scaled_quantity), dec_to_proto(scaled_margin)) +} + +pub fn scale_price_quantity_perp_market_dec( + price: &str, + quantity: &str, + margin_ratio: &str, + quote_decimals: &i32, +) -> (FPDecimal, FPDecimal, FPDecimal) { + let price_dec = FPDecimal::must_from_str(price.replace('_', "").as_str()); + let quantity_dec = FPDecimal::must_from_str(quantity.replace('_', "").as_str()); + let margin_ratio_dec = FPDecimal::must_from_str(margin_ratio.replace('_', "").as_str()); + + let scaled_price = price_dec.scaled(*quote_decimals); + let scaled_quantity = quantity_dec; + + let scaled_margin = (price_dec * quantity_dec * margin_ratio_dec).scaled(*quote_decimals); + + (scaled_price, scaled_quantity, scaled_margin) +} + +pub fn set_address_of_pyth_contract(app: &InjectiveTestApp, validator: &SigningAccount, pyth_address: &SigningAccount) { + let gov = Gov::new(app); + + let mut buf = vec![]; + MsgUpdateParams::encode( + &MsgUpdateParams { + authority: GOV_MODULE_ADDRESS.to_string(), + params: Some(Params { + pyth_contract: pyth_address.address(), + }), + }, + &mut buf, + ) + .unwrap(); + + let res = gov + .submit_proposal( + MsgSubmitProposal { + messages: vec![Any { + type_url: "/injective.oracle.v1beta1.MsgUpdateParams".to_string(), + value: buf, + }], + initial_deposit: vec![BaseCoin { + amount: "100000000000000000000".to_string(), + denom: "inj".to_string(), + }], + proposer: validator.address(), + metadata: "".to_string(), + title: "Set Pyth contract address".to_string(), + summary: "Set Pyth contract address".to_string(), + }, + validator, + ) + .unwrap(); + + let proposal_id = res.events.iter().find(|e| e.ty == "submit_proposal").unwrap().attributes[0] + .value + .to_owned(); + + gov.vote( + MsgVote { + proposal_id: u64::from_str(&proposal_id).unwrap(), + voter: validator.address(), + option: 1i32, + metadata: "".to_string(), + }, + validator, + ) + .unwrap(); + + // NOTE: increase the block time in order to move past the voting period + app.increase_time(11u64); +} + +pub fn relay_pyth_price(oracle: &Oracle, price_attestations: Vec, pyth_address: &SigningAccount) { + let pyth_price_msg = MsgRelayPythPrices { + sender: pyth_address.address(), + price_attestations, + }; + + oracle.relay_pyth_prices(pyth_price_msg, pyth_address).unwrap(); +} + +pub fn create_some_inj_price_attestation(human_price: &str, decimal_precision: i32, publish_time: i64) -> PriceAttestation { + if decimal_precision < 0 { + panic!("Desired exponent cannot be negative") + }; + + let (price_i64, exponent_to_use) = if decimal_precision == 1 { + (human_price.parse::().unwrap(), 1) + } else { + (human_to_i64(human_price, decimal_precision), decimal_precision.neg()) + }; + + PriceAttestation { + price_id: INJ_PYTH_PRICE_ID.to_string(), + price: price_i64, + conf: 500, + expo: exponent_to_use, + ema_price: price_i64, + ema_conf: 2000, + ema_expo: exponent_to_use, + publish_time, + } +} + +pub fn create_some_usdt_price_attestation(human_price: &str, decimal_precision: i32, publish_time: i64) -> PriceAttestation { + if decimal_precision < 0 { + panic!("Desired exponent cannot be negative") + }; + + let (price_i64, exponent_to_use) = if decimal_precision == 0 { + (human_price.parse::().unwrap(), 0) + } else { + (human_to_i64(human_price, decimal_precision), decimal_precision.neg()) + }; - (app, accs, contract_address) + PriceAttestation { + price_id: USDT_PYTH_PRICE_ID.to_string(), + price: price_i64, + conf: 500, + expo: exponent_to_use, + ema_price: price_i64, + ema_conf: 2000, + ema_expo: exponent_to_use, + publish_time, + } } diff --git a/packages/injective-cosmwasm/CHANGELOG.md b/packages/injective-cosmwasm/CHANGELOG.md new file mode 100644 index 00000000..a74c6761 --- /dev/null +++ b/packages/injective-cosmwasm/CHANGELOG.md @@ -0,0 +1,25 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] - yyyy-mm-dd + +### Added + +### Changed + + +## [0.2.22] - 2024-03-21 + +### Added +- Tests queries (injective-cosmwasm-mock) covering functionality of querier.rs + +### Fixed + - Exchange aggregate volume query to use the correct parsing. + +### Removed +- Grants related queries. +- Exchange denom decimal query. \ No newline at end of file diff --git a/packages/injective-cosmwasm/src/exchange/response.rs b/packages/injective-cosmwasm/src/exchange/response.rs index 53af1c15..d1135ea2 100644 --- a/packages/injective-cosmwasm/src/exchange/response.rs +++ b/packages/injective-cosmwasm/src/exchange/response.rs @@ -99,7 +99,7 @@ pub struct QueryOrderbookResponse { /// Response to query for aggregate volumes of a given account/subaccount - divided by markets #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct QueryAggregateVolumeResponse { - pub aggregate_volumes: Vec, + pub aggregate_volumes: Option>, } /// Response to query for aggregate volume for a given market diff --git a/packages/injective-cosmwasm/src/exchange_mock_querier.rs b/packages/injective-cosmwasm/src/exchange_mock_querier.rs index 396bcb52..9d57ae29 100644 --- a/packages/injective-cosmwasm/src/exchange_mock_querier.rs +++ b/packages/injective-cosmwasm/src/exchange_mock_querier.rs @@ -25,9 +25,8 @@ use crate::{ CancellationStrategy, Deposit, DerivativeMarketResponse, ExchangeParamsResponse, FullDerivativeMarket, InjectiveQuery, InjectiveQueryWrapper, MarketMidPriceAndTOBResponse, MarketStatus, MarketVolatilityResponse, OracleInfo, OracleVolatilityResponse, OrderSide, PerpetualMarketFundingResponse, PerpetualMarketInfoResponse, PythPriceResponse, QueryAggregateMarketVolumeResponse, QueryAggregateVolumeResponse, - QueryDenomDecimalResponse, QueryDenomDecimalsResponse, QueryMarketAtomicExecutionFeeMultiplierResponse, SpotMarket, SpotMarketResponse, - SubaccountDepositResponse, SubaccountEffectivePositionInMarketResponse, SubaccountPositionInMarketResponse, TraderDerivativeOrdersResponse, - TraderSpotOrdersResponse, + QueryMarketAtomicExecutionFeeMultiplierResponse, SpotMarket, SpotMarketResponse, SubaccountDepositResponse, + SubaccountEffectivePositionInMarketResponse, SubaccountPositionInMarketResponse, TraderDerivativeOrdersResponse, TraderSpotOrdersResponse, }; use crate::{MarketId, SubaccountId}; @@ -191,7 +190,7 @@ fn default_aggregate_market_volume_handler() -> QuerierResult { fn default_aggregate_account_volume_handler() -> QuerierResult { let response = QueryAggregateVolumeResponse { - aggregate_volumes: vec![ + aggregate_volumes: Some(vec![ MarketVolume { market_id: MarketId::unchecked("market_id_1"), volume: VolumeByType { @@ -206,21 +205,11 @@ fn default_aggregate_account_volume_handler() -> QuerierResult { taker_volume: FPDecimal::from(25000000u128), }, }, - ], + ]), }; SystemResult::Ok(ContractResult::from(to_json_binary(&response))) } -fn default_denom_decimal_handler() -> QuerierResult { - let response = QueryDenomDecimalResponse { decimals: 6 }; - SystemResult::Ok(ContractResult::from(to_json_binary(&response))) -} - -fn default_denom_decimals_handler() -> QuerierResult { - let response = QueryDenomDecimalsResponse { denom_decimals: vec![] }; - SystemResult::Ok(ContractResult::from(to_json_binary(&response))) -} - fn default_oracle_volatility_response_handler() -> QuerierResult { let response = OracleVolatilityResponse { volatility: Some(FPDecimal::ONE), @@ -580,14 +569,6 @@ impl WasmMockQuerier { _ => panic!("unsupported"), }, QueryRequest::Custom(query) => match query.query_data.clone() { - InjectiveQuery::Grants { - granter: _, - grantee: _, - msg_type_url: _, - pagination: _, - } => todo!(), - InjectiveQuery::GranteeGrants { grantee: _, pagination: _ } => todo!(), - InjectiveQuery::GranterGrants { granter: _, pagination: _ } => todo!(), InjectiveQuery::SubaccountDeposit { subaccount_id, denom } => match &self.subaccount_deposit_response_handler { Some(handler) => handler.handle(subaccount_id, denom), None => default_subaccount_deposit_response_handler(), @@ -690,14 +671,6 @@ impl WasmMockQuerier { Some(handler) => handler.handle(account), None => default_aggregate_account_volume_handler(), }, - InjectiveQuery::DenomDecimal { denom } => match &self.denom_decimal_handler { - Some(handler) => handler.handle(denom), - None => default_denom_decimal_handler(), - }, - InjectiveQuery::DenomDecimals { denoms } => match &self.denom_decimals_handler { - Some(handler) => handler.handle(denoms), - None => default_denom_decimals_handler(), - }, InjectiveQuery::StakedAmount { delegator_address, max_delegations, diff --git a/packages/injective-cosmwasm/src/querier.rs b/packages/injective-cosmwasm/src/querier.rs index f0f0bd3d..ab604d9d 100644 --- a/packages/injective-cosmwasm/src/querier.rs +++ b/packages/injective-cosmwasm/src/querier.rs @@ -1,18 +1,11 @@ -use cosmwasm_std::{Addr, QuerierWrapper, StdResult}; - -use injective_math::FPDecimal; - -use crate::authz::response::{GranteeGrantsResponse, GranterGrantsResponse, GrantsResponse}; -use crate::exchange::response::StakedAmountResponse; use crate::exchange::{ cancel::CancellationStrategy, order::OrderSide, response::{ DerivativeMarketResponse, ExchangeParamsResponse, MarketMidPriceAndTOBResponse, MarketVolatilityResponse, OracleVolatilityResponse, - PerpetualMarketFundingResponse, PerpetualMarketInfoResponse, QueryAggregateVolumeResponse, QueryDenomDecimalResponse, - QueryDenomDecimalsResponse, QueryMarketAtomicExecutionFeeMultiplierResponse, QueryOrderbookResponse, SpotMarketResponse, - SubaccountDepositResponse, SubaccountEffectivePositionInMarketResponse, SubaccountPositionInMarketResponse, TraderDerivativeOrdersResponse, - TraderSpotOrdersResponse, + PerpetualMarketFundingResponse, PerpetualMarketInfoResponse, QueryAggregateMarketVolumeResponse, QueryAggregateVolumeResponse, + QueryMarketAtomicExecutionFeeMultiplierResponse, QueryOrderbookResponse, SpotMarketResponse, StakedAmountResponse, SubaccountDepositResponse, + SubaccountEffectivePositionInMarketResponse, SubaccountPositionInMarketResponse, TraderDerivativeOrdersResponse, TraderSpotOrdersResponse, }, types::{MarketId, SubaccountId}, }; @@ -25,6 +18,8 @@ use crate::query::{InjectiveQuery, InjectiveQueryWrapper}; use crate::route::InjectiveRoute; use crate::tokenfactory::response::{TokenFactoryCreateDenomFeeResponse, TokenFactoryDenomSupplyResponse}; use crate::wasmx::response::QueryContractRegistrationInfoResponse; +use cosmwasm_std::{Addr, QuerierWrapper, StdResult}; +use injective_math::FPDecimal; pub struct InjectiveQuerier<'a> { querier: &'a QuerierWrapper<'a, InjectiveQueryWrapper>, @@ -35,48 +30,6 @@ impl<'a> InjectiveQuerier<'a> { InjectiveQuerier { querier } } - // Authz - pub fn query_grants(&self, grantee: &str, granter: &str, msg_type_url: &str, pagination: &Option) -> StdResult { - let request = InjectiveQueryWrapper { - route: InjectiveRoute::Authz, - query_data: InjectiveQuery::Grants { - grantee: grantee.to_string(), - granter: granter.to_string(), - msg_type_url: msg_type_url.to_string(), - pagination: *pagination, - }, - }; - - let res: GrantsResponse = self.querier.query(&request.into())?; - Ok(res) - } - - pub fn query_grantee_grants(&self, grantee: &str, pagination: &Option) -> StdResult { - let request = InjectiveQueryWrapper { - route: InjectiveRoute::Authz, - query_data: InjectiveQuery::GranteeGrants { - grantee: grantee.to_string(), - pagination: *pagination, - }, - }; - - let res: GranteeGrantsResponse = self.querier.query(&request.into())?; - Ok(res) - } - - pub fn query_granter_grants(&self, granter: &str, pagination: &Option) -> StdResult { - let request = InjectiveQueryWrapper { - route: InjectiveRoute::Authz, - query_data: InjectiveQuery::GranterGrants { - granter: granter.to_string(), - pagination: *pagination, - }, - }; - - let res: GranterGrantsResponse = self.querier.query(&request.into())?; - Ok(res) - } - // Exchange pub fn query_exchange_params(&self) -> StdResult { let request = InjectiveQueryWrapper { @@ -340,7 +293,7 @@ impl<'a> InjectiveQuerier<'a> { Ok(res) } - pub fn query_aggregate_market_volume + Clone>(&self, market_id: &'a T) -> StdResult { + pub fn query_aggregate_market_volume + Clone>(&self, market_id: &'a T) -> StdResult { let request = InjectiveQueryWrapper { route: InjectiveRoute::Exchange, query_data: InjectiveQuery::AggregateMarketVolume { @@ -348,7 +301,7 @@ impl<'a> InjectiveQuerier<'a> { }, }; - let res: QueryAggregateVolumeResponse = self.querier.query(&request.into())?; + let res: QueryAggregateMarketVolumeResponse = self.querier.query(&request.into())?; Ok(res) } @@ -359,33 +312,10 @@ impl<'a> InjectiveQuerier<'a> { account: account_id.clone().into(), }, }; - let res: QueryAggregateVolumeResponse = self.querier.query(&request.into())?; Ok(res) } - pub fn query_denom_decimal + Clone>(&self, denom: &'a T) -> StdResult { - let request = InjectiveQueryWrapper { - route: InjectiveRoute::Exchange, - query_data: InjectiveQuery::DenomDecimal { denom: denom.clone().into() }, - }; - - let res: QueryDenomDecimalResponse = self.querier.query(&request.into())?; - Ok(res) - } - - pub fn query_denom_decimals> + Clone>(&self, denoms: &'a T) -> StdResult { - let request = InjectiveQueryWrapper { - route: InjectiveRoute::Exchange, - query_data: InjectiveQuery::DenomDecimals { - denoms: denoms.clone().into(), - }, - }; - - let res: QueryDenomDecimalsResponse = self.querier.query(&request.into())?; - Ok(res) - } - pub fn query_spot_market_mid_price_and_tob + Clone>(&self, market_id: &'a T) -> StdResult { let request = InjectiveQueryWrapper { route: InjectiveRoute::Exchange, diff --git a/packages/injective-cosmwasm/src/query.rs b/packages/injective-cosmwasm/src/query.rs index 3a4b8066..b62eadea 100644 --- a/packages/injective-cosmwasm/src/query.rs +++ b/packages/injective-cosmwasm/src/query.rs @@ -26,21 +26,6 @@ pub struct InjectiveQueryWrapper { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum InjectiveQuery { - // Authz - Grants { - granter: String, - grantee: String, - msg_type_url: String, - pagination: Option, - }, - GranteeGrants { - grantee: String, - pagination: Option, - }, - GranterGrants { - granter: String, - pagination: Option, - }, // Exchange ExchangeParams {}, SubaccountDeposit { @@ -130,12 +115,6 @@ pub enum InjectiveQuery { AggregateAccountVolume { account: String, }, - DenomDecimal { - denom: String, - }, - DenomDecimals { - denoms: Vec, - }, MarketAtomicExecutionFeeMultiplier { market_id: MarketId, }, diff --git a/packages/injective-protobuf/src/proto/mod.rs b/packages/injective-protobuf/src/proto/mod.rs index de6005c4..de0fb666 100644 --- a/packages/injective-protobuf/src/proto/mod.rs +++ b/packages/injective-protobuf/src/proto/mod.rs @@ -1,9 +1,9 @@ // @generated +pub mod account; pub mod auth; pub mod coin; pub mod distribution; pub mod exchange; -pub mod tx; pub mod oracle; -pub mod account; +pub mod tx;