diff --git a/Cargo.toml b/Cargo.toml index b2f9f8ccb..b02bca409 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "packages/macros/*", "packages/interchain/*", "packages/integrations/*", + "packages/cw-orch-on-chain", ] exclude = [ "test_contracts/compatibility-test", # TODO: add new after cw-orch-core 2.0.0 as it's breaking, it shouldn't be compatible @@ -44,6 +45,7 @@ neutron-test-tube = { version = "4.2.3" } anyhow = "1.0" serde = { version = "1.0.208", default-features = false, features = ["derive"] } tokio = { version = "1.39", features = ["full"] } +async-std = "1.13.0" cw-orch = { path = "./cw-orch", version = "0.27.0" } cw-orch-daemon = { path = "./cw-orch-daemon", version = "0.28.0" } diff --git a/artifacts/checksums.txt b/artifacts/checksums.txt index a85e2ea5e..f223a6d87 100644 --- a/artifacts/checksums.txt +++ b/artifacts/checksums.txt @@ -1,4 +1,5 @@ -cc02664dc02c571fd0e4bb02061b737571a510a6a4ac01f8cc783545bec6fff4 counter_contract.wasm +9f8d3bc6ea5c58c31dbed31588df591447ffd2410b3c4d1587e2adb8a29c0931 counter_contract.wasm +9b3dbccb37e232d6e21ced348008707ed913762dba8c51e7a75687af05022a73 counter_cousin_contract.wasm a266c5ab0ffdf78b3aee593d07d3c822fa3c2745bc7bc8210e49860439d65a73 cw_orch_compatibility_test.wasm -0dc79fb31e732310554a07881cfe8a193c068d2f93539356817e5aaf551650dd mock_contract.wasm -08d65b781d7357a6777c836229d971b6c87a5fdfc7cba9806ed508f917859f08 mock_contract_u64.wasm +322d2535c672abb0338f23689d703a468d6bdebe9ce975a842e9a8d5e95bf770 mock_contract.wasm +cdc883c20f370bd68494912e28053f0bef666e8f96c889ba8412b50f4a2cd1ed mock_contract_u64.wasm diff --git a/artifacts/counter_contract.wasm b/artifacts/counter_contract.wasm index 2ee52daf1..e3cad79f0 100644 Binary files a/artifacts/counter_contract.wasm and b/artifacts/counter_contract.wasm differ diff --git a/artifacts/counter_cousin_contract.wasm b/artifacts/counter_cousin_contract.wasm new file mode 100644 index 000000000..fcc72ff2c Binary files /dev/null and b/artifacts/counter_cousin_contract.wasm differ diff --git a/artifacts/mock_contract.wasm b/artifacts/mock_contract.wasm index 256dae795..26fef7d31 100644 Binary files a/artifacts/mock_contract.wasm and b/artifacts/mock_contract.wasm differ diff --git a/artifacts/mock_contract_u64.wasm b/artifacts/mock_contract_u64.wasm index e5108ea3d..0dc066d01 100644 Binary files a/artifacts/mock_contract_u64.wasm and b/artifacts/mock_contract_u64.wasm differ diff --git a/contracts-ws/Cargo.toml b/contracts-ws/Cargo.toml index e9b454ef9..3b015d278 100644 --- a/contracts-ws/Cargo.toml +++ b/contracts-ws/Cargo.toml @@ -12,6 +12,7 @@ cosmwasm-std = "2.0.0" cw20 = { version = "2.0.0" } cw20-base = { version = "2.0.0" } cw-storage-plus = { version = "2.0.0" } +async-std = "1.13.0" serde = { version = "1.0.103", default-features = false, features = ["derive"] } anyhow = "1.0" diff --git a/contracts-ws/contracts/counter/Cargo.toml b/contracts-ws/contracts/counter/Cargo.toml index 86b59ea77..8aa09c816 100644 --- a/contracts-ws/contracts/counter/Cargo.toml +++ b/contracts-ws/contracts/counter/Cargo.toml @@ -24,7 +24,7 @@ serde = { workspace = true } serde_json = "1.0.125" cw-orch = { workspace = true, features = ["daemon"] } # Unused, only there to check for wasm compatibility -cw-orch-interchain = { workspace = true, features = ["daemon"] } +# cw-orch-interchain = { workspace = true, features = ["daemon"] } [[example]] name = "deploy" @@ -35,3 +35,4 @@ dotenv = { version = "0.15.0" } pretty_env_logger = { version = "0.5.0" } cw-orch = { workspace = true, features = ["daemon"] } anyhow = { workspace = true } +async-std = { workspace = true } diff --git a/contracts-ws/contracts/counter/examples/async.rs b/contracts-ws/contracts/counter/examples/async.rs index 320b595c8..93083fb4d 100644 --- a/contracts-ws/contracts/counter/examples/async.rs +++ b/contracts-ws/contracts/counter/examples/async.rs @@ -1,12 +1,12 @@ // ANCHOR: full_async_example use counter_contract::AsyncCounterQueryMsgFns; use counter_contract::CounterContract; -use cw_orch::{anyhow, prelude::*, tokio}; +use cw_orch::{anyhow, prelude::*}; // From https://github.com/CosmosContracts/juno/blob/32568dba828ff7783aea8cb5bb4b8b5832888255/docker/test-user.env#L2 const LOCAL_MNEMONIC: &str = "clip hire initial neck maid actor venue client foam budget lock catalog sweet steak waste crater broccoli pipe steak sister coyote moment obvious choose"; -#[tokio::main] +#[async_std::main] pub async fn main() -> anyhow::Result<()> { std::env::set_var("LOCAL_MNEMONIC", LOCAL_MNEMONIC); dotenv::dotenv().ok(); // Used to load the `.env` file if any diff --git a/contracts-ws/contracts/counter/tests/integration_tests.rs b/contracts-ws/contracts/counter/tests/integration_tests.rs index 02b0ec53d..480ecac35 100644 --- a/contracts-ws/contracts/counter/tests/integration_tests.rs +++ b/contracts-ws/contracts/counter/tests/integration_tests.rs @@ -57,7 +57,7 @@ fn count() -> anyhow::Result<()> { assert_eq!(count.count, 0); // Check negative case - let exec_res: Result = + let exec_res: Result = contract.call_as(&user).reset(0); let expected_err = ContractError::Unauthorized {}; diff --git a/contracts-ws/contracts/counter_cousin/Cargo.toml b/contracts-ws/contracts/counter_cousin/Cargo.toml new file mode 100644 index 000000000..5d5dc7722 --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "counter-cousin-contract" +version = "0.11.0" +description = "counter constract" +keywords = ["cosmwasm", "blockchain"] +edition = { workspace = true } +exclude = [".env"] + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["export"] +export = [] + +[dependencies] +cosmwasm-std = { workspace = true } +cw-storage-plus = { workspace = true } +cw2 = "2.0" +cosmwasm-schema = "2.1" +schemars = "0.8.21" +thiserror = { version = "1.0.63" } +serde = { workspace = true } +serde_json = "1.0.125" +cw-orch = { workspace = true, features = ["daemon"] } +# Unused, only there to check for wasm compatibility +# cw-orch-interchain = { workspace = true, features = ["daemon"] } + +cw-orch-on-chain = { path = "../../../packages/cw-orch-on-chain" } + +[dev-dependencies] +# Deps for deployment +dotenv = { version = "0.15.0" } +pretty_env_logger = { version = "0.5.0" } +cw-orch = { workspace = true, features = ["daemon"] } +anyhow = { workspace = true } +cw-orch-osmosis-test-tube = { path = "../../../packages/cw-orch-osmosis-test-tube" } diff --git a/contracts-ws/contracts/counter_cousin/README.md b/contracts-ws/contracts/counter_cousin/README.md new file mode 100644 index 000000000..238af38f9 --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/README.md @@ -0,0 +1,3 @@ +Refer to [https://orchestrator.abstract.money/](https://orchestrator.abstract.money/) for more details on how to use this crate + +Check out the [examples](./examples) and [tests](./tests) in this crate to understand how to use it by example. diff --git a/contracts-ws/contracts/counter_cousin/src/contract.rs b/contracts-ws/contracts/counter_cousin/src/contract.rs new file mode 100644 index 000000000..de0de7135 --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/contract.rs @@ -0,0 +1,59 @@ +use cosmwasm_std::{ + entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, +}; +use cw2::set_contract_version; + +use crate::{error::*, execute, msg::*, query, state::*}; + +// version info for migration info +pub const CONTRACT_NAME: &str = "crates.io:counter"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +// ANCHOR: interface_entry +// ANCHOR: entry_point_line +#[cfg_attr(feature = "export", entry_point)] +// ANCHOR_END: entry_point_line +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + let state = State { + count: msg.count, + owner: info.sender.clone(), + }; + set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + STATE.save(deps.storage, &state)?; + + Ok(Response::new() + .add_attribute("method", "instantiate") + .add_attribute("owner", info.sender) + .add_attribute("count", msg.count.to_string())) +} + +#[cfg_attr(feature = "export", entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::Increment {} => execute::increment(deps), + ExecuteMsg::Reset { count } => execute::reset(deps, info, count), + ExecuteMsg::IncrementCousin {} => execute::increment_cousin(deps, &env), + ExecuteMsg::SetCousin { cousin } => execute::set_cousin(deps, env, info, cousin), + } +} + +#[cfg_attr(feature = "export", entry_point)] +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::GetCount {} => to_json_binary(&query::count(deps)?), + QueryMsg::GetCousinCount {} => to_json_binary(&query::cousin_count(deps, env)?), + QueryMsg::GetRawCousinCount {} => to_json_binary(&query::raw_cousin_count(deps, &env)?), + } +} + +// ANCHOR_END: interface_entry diff --git a/contracts-ws/contracts/counter_cousin/src/error.rs b/contracts-ws/contracts/counter_cousin/src/error.rs new file mode 100644 index 000000000..191f1ecec --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/error.rs @@ -0,0 +1,16 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("{0}")] + OrchError(#[from] cw_orch::prelude::CwOrchError), + + #[error("Unauthorized")] + Unauthorized {}, + // Add any other custom errors you like here. + // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details. +} diff --git a/contracts-ws/contracts/counter_cousin/src/execute.rs b/contracts-ws/contracts/counter_cousin/src/execute.rs new file mode 100644 index 000000000..d39661993 --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/execute.rs @@ -0,0 +1,43 @@ +use crate::msg::ExecuteMsgFns; +use crate::CounterContract; +use crate::{error::*, state::*}; +use cosmwasm_std::{DepsMut, Env, MessageInfo, Response}; + +pub fn increment(deps: DepsMut) -> Result { + STATE.update(deps.storage, |mut state| -> Result<_, ContractError> { + state.count += 1; + Ok(state) + })?; + + Ok(Response::new().add_attribute("action", "increment")) +} + +pub fn increment_cousin(deps: DepsMut, env: &Env) -> Result { + let increment_msg = CounterContract::load(deps, env, "cousin").increment()?; + + Ok(Response::new().add_message(increment_msg)) +} + +pub fn reset(deps: DepsMut, info: MessageInfo, count: i32) -> Result { + STATE.update(deps.storage, |mut state| -> Result<_, ContractError> { + if info.sender != state.owner { + return Err(ContractError::Unauthorized {}); + } + state.count = count; + Ok(state) + })?; + Ok(Response::new().add_attribute("action", "reset")) +} + +pub fn set_cousin( + deps: DepsMut, + env: Env, + info: MessageInfo, + cousin: String, +) -> Result { + assert_owner(deps.as_ref(), &info)?; + + CounterContract::load(deps, &env, "cousin").set_raw_address(&cousin)?; + + Ok(Response::new().add_attribute("action", "set_cousin")) +} diff --git a/contracts-ws/contracts/counter_cousin/src/interface.rs b/contracts-ws/contracts/counter_cousin/src/interface.rs new file mode 100644 index 000000000..60aa4c9ed --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/interface.rs @@ -0,0 +1,72 @@ +// ANCHOR: custom_interface +use cw_orch::{interface, prelude::*}; + +use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use cw_orch_on_chain::core::OnChain; + +use cosmwasm_std::{Deps, Env, StdResult}; + +#[interface(InstantiateMsg, ExecuteMsg, QueryMsg, MigrateMsg)] +pub struct CounterContract; + +impl Uploadable for CounterContract { + /// Return the path to the wasm file corresponding to the contract + fn wasm(_chain: &ChainInfoOwned) -> WasmPath { + artifacts_dir_from_workspace!() + .find_wasm_path("counter_cousin_contract") + .unwrap() + } + /// Returns a CosmWasm contract wrapper + fn wrapper() -> Box> { + Box::new(ContractWrapper::new_with_empty( + crate::contract::execute, + crate::contract::instantiate, + crate::contract::query, + )) + } +} +// ANCHOR_END: custom_interface +use cosmwasm_std::DepsMut; +use cw_orch_on_chain::core::OnChainDeps; + +// All of those could be generated by the interface macro +impl<'a> CounterContract> { + pub fn load( + deps: impl Into>, + env: &Env, + contract_id: &str, + ) -> CounterContract> { + let chain = OnChain::new(deps, env); + CounterContract::new(contract_id, chain) + } + + pub fn save( + deps: DepsMut<'a>, + env: &Env, + contract_id: &str, + address: Addr, + ) -> CounterContract> { + let chain = OnChain::new(deps, env); + let contract = CounterContract::new(contract_id, chain); + contract.set_address(&address); + contract + } + + pub fn with_address( + deps: Deps<'a>, + env: &Env, + contract_id: &str, + address: Addr, + ) -> CounterContract> { + let chain = OnChain::new(deps, env); + let contract = CounterContract::new(contract_id, chain); + contract.set_address(&address); + contract + } + + pub fn set_raw_address(&self, address: &str) -> StdResult<()> { + let address = self.environment().deps.api().addr_validate(address)?; + self.set_address(&address); + Ok(()) + } +} diff --git a/contracts-ws/contracts/counter_cousin/src/lib.rs b/contracts-ws/contracts/counter_cousin/src/lib.rs new file mode 100644 index 000000000..8852cb8fe --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/lib.rs @@ -0,0 +1,11 @@ +pub mod contract; +mod error; +pub(crate) mod execute; +pub mod interface; +pub mod msg; +pub(crate) mod query; +pub mod state; + +pub use error::ContractError; +pub use interface::CounterContract; +pub use msg::{ExecuteMsgFns as CounterExecuteMsgFns, QueryMsgFns as CounterQueryMsgFns}; diff --git a/contracts-ws/contracts/counter_cousin/src/msg.rs b/contracts-ws/contracts/counter_cousin/src/msg.rs new file mode 100644 index 000000000..69ecbe8dd --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/msg.rs @@ -0,0 +1,66 @@ +#![warn(missing_docs)] +//! # Counter contract + +use cosmwasm_schema::{cw_serde, QueryResponses}; + +#[cw_serde] +/// Instantiate method for counter +pub struct InstantiateMsg { + /// Initial count + pub count: i32, +} + +// ANCHOR: exec_msg +#[cw_serde] +#[derive(cw_orch::ExecuteFns)] // Function generation +/// Execute methods for counter +pub enum ExecuteMsg { + /// Increment count by one + Increment {}, + /// Reset count + Reset { + /// Count value after reset + count: i32, + }, + /// Increment cousin count + IncrementCousin {}, + /// Sets the cousin contract, that this contract can query + SetCousin { + /// Address of the cousin contract of this counter + cousin: String, + }, +} +// ANCHOR_END: exec_msg + +// ANCHOR: query_msg +#[cw_serde] +#[derive(cw_orch::QueryFns)] // Function generation +#[derive(QueryResponses)] +/// Query methods for counter +pub enum QueryMsg { + /// GetCount returns the current count as a json-encoded number + #[returns(GetCountResponse)] + GetCount {}, + /// GetCount returns the current count as a json-encoded number + #[returns(GetCountResponse)] + GetCousinCount {}, + /// GetCount returns the current count as a json-encoded number + #[returns(GetCountResponse)] + GetRawCousinCount {}, +} + +// Custom response for the query +#[cw_serde] +/// Response from get_count query +pub struct GetCountResponse { + /// Current count in the state + pub count: i32, +} +// ANCHOR_END: query_msg + +#[cw_serde] +/// Migrate message for count contract +pub struct MigrateMsg { + /// Your favorite type of tea + pub t: String, +} diff --git a/contracts-ws/contracts/counter_cousin/src/query.rs b/contracts-ws/contracts/counter_cousin/src/query.rs new file mode 100644 index 000000000..8f2e3ab21 --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/query.rs @@ -0,0 +1,24 @@ +use cosmwasm_std::{Deps, Env, StdResult}; + +use crate::interface::CounterContract; +use crate::msg::QueryMsgFns; +use crate::{msg::GetCountResponse, state::STATE}; +use cw_orch::prelude::*; + +pub fn count(deps: Deps) -> StdResult { + let state = STATE.load(deps.storage)?; + Ok(GetCountResponse { count: state.count }) +} + +pub fn cousin_count(deps: Deps, env: Env) -> StdResult { + CounterContract::load(deps, &env, "cousin") + .get_count() + .map_err(Into::into) +} + +pub fn raw_cousin_count(deps: Deps, env: &Env) -> StdResult { + let cousin_state = CounterContract::load(deps, env, "cousin").item_query(STATE)?; + Ok(GetCountResponse { + count: cousin_state.count, + }) +} diff --git a/contracts-ws/contracts/counter_cousin/src/state.rs b/contracts-ws/contracts/counter_cousin/src/state.rs new file mode 100644 index 000000000..d3493aa65 --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/src/state.rs @@ -0,0 +1,22 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::ContractError; +use cosmwasm_std::{Addr, Deps, MessageInfo}; +use cw_storage_plus::Item; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct State { + pub count: i32, + pub owner: Addr, +} + +pub const STATE: Item = Item::new("state"); + +pub fn assert_owner(deps: Deps, info: &MessageInfo) -> Result<(), ContractError> { + let state = STATE.load(deps.storage)?; + if info.sender != state.owner { + return Err(ContractError::Unauthorized {}); + } + Ok(()) +} diff --git a/contracts-ws/contracts/counter_cousin/tests/integration_tests.rs b/contracts-ws/contracts/counter_cousin/tests/integration_tests.rs new file mode 100644 index 000000000..bb24b1eba --- /dev/null +++ b/contracts-ws/contracts/counter_cousin/tests/integration_tests.rs @@ -0,0 +1,108 @@ +use counter_cousin_contract::{ + msg::InstantiateMsg, CounterContract, CounterExecuteMsgFns, CounterQueryMsgFns, +}; +// Use prelude to get all the necessary imports +use cw_orch::prelude::*; +use cw_orch_osmosis_test_tube::OsmosisTestTube; + +use cosmwasm_std::{coins, Addr}; + +// consts for testing +const USER: &str = "user"; +const ADMIN: &str = "admin"; + +#[test] +fn mock() -> anyhow::Result<()> { + // Create the mock. This will be our chain object throughout + let mock = Mock::new(ADMIN); + let user = Addr::unchecked(USER); + + // Set up the contract (Definition below) ↓↓ + let (contract, cousin) = setup(mock.clone())?; + + // Increment the count of the contract + contract.call_as(&user).increment()?; + contract.call_as(&user).increment()?; + + cousin.call_as(&user).increment()?; + cousin.call_as(&user).increment()?; + cousin.call_as(&user).increment()?; + + let count = contract.get_count()?; + assert_eq!(count.count, 3); + + let count = contract.get_cousin_count()?; + assert_eq!(count.count, 4); + + let count = cousin.get_count()?; + assert_eq!(count.count, 4); + + let count = cousin.get_cousin_count()?; + assert_eq!(count.count, 3); + + Ok(()) +} + +#[test] +fn test_tube() -> anyhow::Result<()> { + // Create the mock. This will be our chain object throughout + let mut test_tube = OsmosisTestTube::new(coins(100_000_000_000_000, "uosmo")); + let user = test_tube.init_account(coins(100_000_000_000_000, "uosmo"))?; + + // Set up the contract (Definition below) ↓↓ + let (contract, cousin) = setup(test_tube.clone())?; + + // Increment the count of the contract + contract.call_as(&user).increment()?; + contract.call_as(&user).increment()?; + + cousin.call_as(&user).increment()?; + cousin.call_as(&user).increment()?; + cousin.call_as(&user).increment()?; + + let count = contract.get_count()?; + assert_eq!(count.count, 3); + + let count = contract.get_cousin_count()?; + assert_eq!(count.count, 4); + + let count = cousin.get_count()?; + assert_eq!(count.count, 4); + + let count = cousin.get_cousin_count()?; + assert_eq!(count.count, 3); + + let count = contract.get_raw_cousin_count()?; + assert_eq!(count.count, 4); + + let count = cousin.get_raw_cousin_count()?; + assert_eq!(count.count, 3); + + Ok(()) +} + +/// Instantiate the contract in any CosmWasm environment +fn setup( + chain: Chain, +) -> anyhow::Result<(CounterContract, CounterContract)> { + // ANCHOR: constructor + // Construct the counter interface + let contract = CounterContract::new("cousin", chain.clone()); + let cousin = CounterContract::new("counter", chain.clone()); + // ANCHOR_END: constructor + + // Upload the contract + contract.upload()?; + cousin.upload()?; + + // Instantiate the contract + let msg = InstantiateMsg { count: 1i32 }; + contract.instantiate(&msg, None, &[])?; + cousin.instantiate(&msg, None, &[])?; + + contract.set_cousin(cousin.address()?)?; + cousin.set_cousin(contract.address()?)?; + + // Return the interface + Ok((contract, cousin)) +} diff --git a/contracts-ws/contracts/mock_contract/src/msg_tests.rs b/contracts-ws/contracts/mock_contract/src/msg_tests.rs index e4f9333c4..34d668c39 100644 --- a/contracts-ws/contracts/mock_contract/src/msg_tests.rs +++ b/contracts-ws/contracts/mock_contract/src/msg_tests.rs @@ -57,19 +57,19 @@ pub fn execute_ordered( pub fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { Ok(vec![].into()) } -#[cfg(not(target_arch = "wasm32"))] + mod interface { use super::*; use cw_orch::prelude::*; impl Uploadable for TestContract { - fn wrapper() -> ::ContractSource { + fn wrapper() -> Box> { Box::new(ContractWrapper::new_with_empty(execute, instantiate, query)) } } impl Uploadable for OrderedTestContract { - fn wrapper() -> ::ContractSource { + fn wrapper() -> Box> { Box::new(ContractWrapper::new_with_empty( execute_ordered, instantiate, diff --git a/cw-orch-daemon/Cargo.toml b/cw-orch-daemon/Cargo.toml index 23c7feea0..f24dfd8cc 100644 --- a/cw-orch-daemon/Cargo.toml +++ b/cw-orch-daemon/Cargo.toml @@ -44,7 +44,6 @@ bitcoin = { version = "0.32.2" } bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] } hex = { version = "0.4.3" } ripemd = { version = "0.1.3" } -tokio = { workspace = true, features = ["full"] } tonic = { workspace = true, features = ["tls"] } reqwest = { version = "0.12.5" } base64 = { version = "0.22.1" } @@ -78,6 +77,7 @@ uid = "0.1.7" toml = "0.8" http = "1.1.0" libc-print = "0.1.23" +async-std = { workspace = true, features = ["attributes"] } [dev-dependencies] cw-orch-daemon = { path = "." } diff --git a/cw-orch-daemon/examples/batch-sender.rs b/cw-orch-daemon/examples/batch-sender.rs index f64f1178c..c0e521035 100644 --- a/cw-orch-daemon/examples/batch-sender.rs +++ b/cw-orch-daemon/examples/batch-sender.rs @@ -1,3 +1,4 @@ +use async_std::task::block_on; use counter_contract::{ msg::InstantiateMsg, CounterContract, CounterExecuteMsgFns, CounterQueryMsgFns, }; @@ -26,7 +27,7 @@ pub fn main() -> anyhow::Result<()> { let count = counter.get_count()?; assert_eq!(count.count, 0); - chain.rt_handle.block_on(chain.sender().broadcast(None))?; + block_on(chain.sender().broadcast(None))?; let count = counter.get_count()?; assert_eq!(count.count, 1); @@ -39,7 +40,7 @@ pub fn main() -> anyhow::Result<()> { counter.increment()?; counter.increment()?; - chain.rt_handle.block_on(chain.sender().broadcast(None))?; + block_on(chain.sender().broadcast(None))?; let count = counter.get_count()?; assert_eq!(count.count, 7); diff --git a/cw-orch-daemon/examples/daemon-capabilities.rs b/cw-orch-daemon/examples/daemon-capabilities.rs index 25b7cf49b..a492c32fc 100644 --- a/cw-orch-daemon/examples/daemon-capabilities.rs +++ b/cw-orch-daemon/examples/daemon-capabilities.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use cosmrs::{tx::Msg, AccountId, Coin, Denom}; use cosmwasm_std::{coins, Addr}; // ANCHOR: full_counter_example +use async_std::task::block_on; use cw_orch_daemon::senders::tx::TxSender; use cw_orch_daemon::DaemonBuilder; use cw_orch_networks::networks; @@ -21,8 +22,7 @@ pub fn main() -> anyhow::Result<()> { // ANCHOR: send_tx let wallet = daemon.sender(); - let rt = daemon.rt_handle.clone(); - rt.block_on(wallet.bank_send( + block_on(wallet.bank_send( &Addr::unchecked(""), coins(345, "ujunox"), ))?; @@ -45,11 +45,11 @@ pub fn main() -> anyhow::Result<()> { denom: Denom::from_str("ujuno").unwrap(), }, }; - rt.block_on(wallet.commit_tx(vec![tx_msg.clone()], None))?; + block_on(wallet.commit_tx(vec![tx_msg.clone()], None))?; // ANCHOR_END: cosmrs_tx // ANCHOR: any_tx - rt.block_on(wallet.commit_tx_any( + block_on(wallet.commit_tx_any( vec![cosmrs::Any { type_url: "/cosmos.staking.v1beta1.MsgBeginRedelegate".to_string(), value: tx_msg.to_any().unwrap().value, @@ -59,8 +59,7 @@ pub fn main() -> anyhow::Result<()> { // ANCHOR_END: any_tx // ANCHOR: simulate_tx - let (gas_needed, fee_needed) = - rt.block_on(wallet.simulate(vec![tx_msg.to_any().unwrap()], None))?; + let (gas_needed, fee_needed) = block_on(wallet.simulate(vec![tx_msg.to_any().unwrap()], None))?; log::info!( "Submitting this transaction will necessitate: diff --git a/cw-orch-daemon/examples/hd_index.rs b/cw-orch-daemon/examples/hd_index.rs index c407e3496..3acbc1681 100644 --- a/cw-orch-daemon/examples/hd_index.rs +++ b/cw-orch-daemon/examples/hd_index.rs @@ -1,3 +1,4 @@ +use async_std::task::block_on; use cosmwasm_std::coins; use cw_orch::{anyhow, prelude::*}; use cw_orch_daemon::CosmosOptions; @@ -16,7 +17,7 @@ pub fn main() -> anyhow::Result<()> { .authz_granter(&Addr::unchecked(LOCAL_JUNO_GRANTER)); let chain = Daemon::builder(network).build_sender(sender)?; - chain.rt_handle.block_on( + block_on( chain .sender() .bank_send(&Addr::unchecked(LOCAL_JUNO_GRANTER), coins(10000, "ujuno")), diff --git a/cw-orch-daemon/src/channel.rs b/cw-orch-daemon/src/channel.rs index 6f58ac461..d3505fc59 100644 --- a/cw-orch-daemon/src/channel.rs +++ b/cw-orch-daemon/src/channel.rs @@ -84,7 +84,7 @@ mod tests { use crate::DaemonAsync; use speculoos::prelude::*; - #[tokio::test] + #[async_std::test] #[serial_test::serial] async fn no_connection() { let mut chain = cw_orch_daemon::networks::LOCAL_JUNO; @@ -103,7 +103,7 @@ mod tests { )) } - #[tokio::test] + #[async_std::test] #[serial_test::serial] async fn network_grpcs_list_is_empty() { let mut chain = cw_orch_daemon::networks::LOCAL_JUNO; diff --git a/cw-orch-daemon/src/core.rs b/cw-orch-daemon/src/core.rs index f3b7f5fd9..5835be81c 100644 --- a/cw-orch-daemon/src/core.rs +++ b/cw-orch-daemon/src/core.rs @@ -173,12 +173,12 @@ impl DaemonAsyncBase { let wait_time = average_block_speed.mul_f64(amount as f64); // now wait for that amount of time - tokio::time::sleep(wait_time).await; + async_std::task::sleep(wait_time).await; // now check every block until we hit the target while last_height < end_height { // wait - tokio::time::sleep(average_block_speed).await; + async_std::task::sleep(average_block_speed).await; // ping latest block last_height = Node::new_async(self.channel())._block_height().await?; @@ -188,7 +188,7 @@ impl DaemonAsyncBase { /// Wait for a given amount of seconds. pub async fn wait_seconds(&self, secs: u64) -> Result<(), DaemonError> { - tokio::time::sleep(Duration::from_secs(secs)).await; + async_std::task::sleep(Duration::from_secs(secs)).await; Ok(()) } diff --git a/cw-orch-daemon/src/lib.rs b/cw-orch-daemon/src/lib.rs index 18f529eac..2e1045296 100644 --- a/cw-orch-daemon/src/lib.rs +++ b/cw-orch-daemon/src/lib.rs @@ -55,7 +55,3 @@ pub(crate) mod cosmos_modules { tendermint::v0_34::abci as tendermint_abci, }; } - -lazy_static::lazy_static! { - pub static ref RUNTIME: tokio::runtime::Runtime = tokio::runtime::Runtime::new().unwrap(); -} diff --git a/cw-orch-daemon/src/live_mock.rs b/cw-orch-daemon/src/live_mock.rs index 98aae87cc..e67b2fd18 100644 --- a/cw-orch-daemon/src/live_mock.rs +++ b/cw-orch-daemon/src/live_mock.rs @@ -4,7 +4,7 @@ use crate::queriers::Bank; use crate::queriers::CosmWasm; use crate::queriers::Staking; -use crate::RUNTIME; +use async_std::task::block_on; use cosmwasm_std::testing::{MockApi, MockStorage}; use cosmwasm_std::Addr; use cosmwasm_std::AllBalanceResponse; @@ -78,20 +78,17 @@ impl WasmMockQuerier { /// Function used to handle a query and customize the query behavior /// This implements some queries by querying an actual node for the responses pub fn handle_query(&self, request: &QueryRequest) -> QuerierResult { - let handle = RUNTIME.handle(); match &request { QueryRequest::Wasm(x) => { - let querier = CosmWasm::new_sync(self.channel.clone(), handle); + let querier = CosmWasm::new_sync(self.channel.clone()); match x { WasmQuery::Smart { contract_addr, msg } => { // We forward the request to the cosmwasm querier - let query_result: Result = handle - .block_on( - querier - ._contract_state(&Addr::unchecked(contract_addr), msg.to_vec()), - ) - .map(|query_result| query_result.into()); + let query_result: Result = block_on( + querier._contract_state(&Addr::unchecked(contract_addr), msg.to_vec()), + ) + .map(|query_result| query_result.into()); SystemResult::Ok(ContractResult::from(query_result)) } WasmQuery::Raw { contract_addr, key } => { @@ -111,7 +108,6 @@ impl WasmMockQuerier { QueryRequest::Bank(x) => { let querier = Bank { channel: self.channel.clone(), - rt_handle: Some(handle.clone()), }; match x { BankQuery::Balance { address, denom } => { @@ -140,8 +136,7 @@ impl WasmMockQuerier { let querier = Staking::new_async(self.channel.clone()); match x { StakingQuery::BondedDenom {} => { - let query_result = handle - .block_on(querier._params()) + let query_result = block_on(querier._params()) .map(|result| { BondedDenomResponse::new(result.params.unwrap().bond_denom) }) @@ -152,29 +147,28 @@ impl WasmMockQuerier { // This query is not perfect. I guess that on_chain you should be able to get ALL delegations and not a paginated result // TODO, do better here StakingQuery::AllDelegations { delegator } => { - let query_result = handle - .block_on( - querier._delegator_delegations(&Addr::unchecked(delegator), None), - ) - .map(|result| { - AllDelegationsResponse::new( - result - .delegation_responses - .into_iter() - .filter_map(|delegation| { - delegation.delegation.map(|d| { - Delegation::new( - Addr::unchecked(d.delegator_address), - d.validator_address, - to_cosmwasm_coin(delegation.balance.unwrap()), - ) - }) + let query_result = block_on( + querier._delegator_delegations(&Addr::unchecked(delegator), None), + ) + .map(|result| { + AllDelegationsResponse::new( + result + .delegation_responses + .into_iter() + .filter_map(|delegation| { + delegation.delegation.map(|d| { + Delegation::new( + Addr::unchecked(d.delegator_address), + d.validator_address, + to_cosmwasm_coin(delegation.balance.unwrap()), + ) }) - .collect(), - ) - }) - .map(|query_result| to_json_binary(&query_result)) - .unwrap(); + }) + .collect(), + ) + }) + .map(|query_result| to_json_binary(&query_result)) + .unwrap(); SystemResult::Ok(ContractResult::from(query_result)) } _ => todo!(), @@ -191,12 +185,11 @@ impl WasmMockQuerier { impl WasmMockQuerier { /// Creates a querier from chain information pub fn new(chain: ChainInfoOwned) -> Self { - let channel = RUNTIME - .block_on(GrpcChannel::connect( - &chain.grpc_urls, - chain.chain_id.as_str(), - )) - .unwrap(); + let channel = block_on(GrpcChannel::connect( + &chain.grpc_urls, + chain.chain_id.as_str(), + )) + .unwrap(); WasmMockQuerier { channel } } diff --git a/cw-orch-daemon/src/queriers/authz.rs b/cw-orch-daemon/src/queriers/authz.rs index 14766f873..08bbe8348 100644 --- a/cw-orch-daemon/src/queriers/authz.rs +++ b/cw-orch-daemon/src/queriers/authz.rs @@ -2,29 +2,23 @@ use crate::{cosmos_modules, error::DaemonError, Daemon}; use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest; use cosmwasm_std::Addr; use cw_orch_core::environment::{Querier, QuerierGetter}; -use tokio::runtime::Handle; use tonic::transport::Channel; /// Queries for Cosmos AuthZ Module /// All the async function are prefixed with `_` pub struct Authz { pub channel: Channel, - pub rt_handle: Option, } impl Authz { pub fn new(daemon: &Daemon) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), } } pub fn new_async(channel: Channel) -> Self { - Self { - channel, - rt_handle: None, - } + Self { channel } } } diff --git a/cw-orch-daemon/src/queriers/bank.rs b/cw-orch-daemon/src/queriers/bank.rs index ac7fa3831..3539cdf6a 100644 --- a/cw-orch-daemon/src/queriers/bank.rs +++ b/cw-orch-daemon/src/queriers/bank.rs @@ -1,29 +1,24 @@ use crate::{cosmos_modules, error::DaemonError, senders::query::QuerySender, DaemonBase}; +use async_std::task::block_on; use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest; use cosmwasm_std::{Addr, Coin, StdError}; use cw_orch_core::environment::{BankQuerier, Querier, QuerierGetter}; -use tokio::runtime::Handle; use tonic::transport::Channel; /// Queries for Cosmos Bank Module /// All the async function are prefixed with `_` pub struct Bank { pub channel: Channel, - pub rt_handle: Option, } impl Bank { pub fn new(daemon: &DaemonBase) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), } } pub fn new_async(channel: Channel) -> Self { - Self { - channel, - rt_handle: None, - } + Self { channel } } } @@ -169,23 +164,14 @@ impl BankQuerier for Bank { address: &Addr, denom: Option, ) -> Result, Self::Error> { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._balance(address, denom)) + block_on(self._balance(address, denom)) } fn total_supply(&self) -> Result, Self::Error> { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._total_supply()) + block_on(self._total_supply()) } fn supply_of(&self, denom: impl Into) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._supply_of(denom)) + block_on(self._supply_of(denom)) } } diff --git a/cw-orch-daemon/src/queriers/cosmwasm.rs b/cw-orch-daemon/src/queriers/cosmwasm.rs index 6fa942e91..0f1a2699c 100644 --- a/cw-orch-daemon/src/queriers/cosmwasm.rs +++ b/cw-orch-daemon/src/queriers/cosmwasm.rs @@ -3,6 +3,7 @@ use std::{marker::PhantomData, str::FromStr}; use crate::senders::query::QuerySender; use crate::senders::QueryOnlySender; use crate::{cosmos_modules, error::DaemonError, DaemonBase}; +use async_std::task::block_on; use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest; use cosmrs::AccountId; use cosmwasm_std::{ @@ -14,14 +15,12 @@ use cw_orch_core::{ contract::interface_traits::Uploadable, environment::{Querier, QuerierGetter, WasmQuerier}, }; -use tokio::runtime::Handle; use tonic::transport::Channel; /// Querier for the CosmWasm SDK module /// All the async function are prefixed with `_` pub struct CosmWasmBase { pub channel: Channel, - pub rt_handle: Option, _sender: PhantomData, } @@ -31,21 +30,18 @@ impl CosmWasmBase { pub fn new(daemon: &DaemonBase) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), _sender: PhantomData, } } pub fn new_async(channel: Channel) -> Self { Self { channel, - rt_handle: None, _sender: PhantomData, } } - pub fn new_sync(channel: Channel, handle: &Handle) -> Self { + pub fn new_sync(channel: Channel) -> Self { Self { channel, - rt_handle: Some(handle.clone()), _sender: PhantomData, } } @@ -238,28 +234,18 @@ impl CosmWasmBase { impl WasmQuerier for CosmWasmBase { type Chain = DaemonBase; fn code_id_hash(&self, code_id: u64) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._code_id_hash(code_id)) + block_on(self._code_id_hash(code_id)) } fn contract_info( &self, address: &Addr, ) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._contract_info(address)) + block_on(self._contract_info(address)) } fn raw_query(&self, address: &Addr, query_data: Vec) -> Result, Self::Error> { - let response = self - .rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._contract_raw_state(address, query_data))?; + let response = block_on(self._contract_raw_state(address, query_data))?; Ok(response.data) } @@ -269,20 +255,14 @@ impl WasmQuerier for CosmWasmBase { address: &Addr, query_data: &Q, ) -> Result { - let response = self - .rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._contract_state(address, to_json_binary(&query_data)?.to_vec()))?; + let response = + block_on(self._contract_state(address, to_json_binary(&query_data)?.to_vec()))?; Ok(from_json(response)?) } fn code(&self, code_id: u64) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._code(code_id)) + block_on(self._code(code_id)) } fn instantiate2_addr( diff --git a/cw-orch-daemon/src/queriers/feegrant.rs b/cw-orch-daemon/src/queriers/feegrant.rs index a899f1598..e30a153ff 100644 --- a/cw-orch-daemon/src/queriers/feegrant.rs +++ b/cw-orch-daemon/src/queriers/feegrant.rs @@ -2,29 +2,23 @@ use crate::{cosmos_modules, error::DaemonError, Daemon}; use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest; use cosmwasm_std::Addr; use cw_orch_core::environment::{Querier, QuerierGetter}; -use tokio::runtime::Handle; use tonic::transport::Channel; /// Querier for the Cosmos Gov module /// All the async function are prefixed with `_` pub struct FeeGrant { pub channel: Channel, - pub rt_handle: Option, } impl FeeGrant { pub fn new(daemon: &Daemon) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), } } pub fn new_async(channel: Channel) -> Self { - Self { - channel, - rt_handle: None, - } + Self { channel } } } diff --git a/cw-orch-daemon/src/queriers/gov.rs b/cw-orch-daemon/src/queriers/gov.rs index 18cfcb916..b9ecfb72b 100644 --- a/cw-orch-daemon/src/queriers/gov.rs +++ b/cw-orch-daemon/src/queriers/gov.rs @@ -2,29 +2,23 @@ use crate::{cosmos_modules, error::DaemonError, Daemon}; use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest; use cosmwasm_std::Addr; use cw_orch_core::environment::{Querier, QuerierGetter}; -use tokio::runtime::Handle; use tonic::transport::Channel; /// Querier for the Cosmos Gov module /// All the async function are prefixed with `_` pub struct Gov { pub channel: Channel, - pub rt_handle: Option, } impl Gov { pub fn new(daemon: &Daemon) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), } } pub fn new_async(channel: Channel) -> Self { - Self { - channel, - rt_handle: None, - } + Self { channel } } } diff --git a/cw-orch-daemon/src/queriers/ibc.rs b/cw-orch-daemon/src/queriers/ibc.rs index 0c96f00b9..699db75e2 100644 --- a/cw-orch-daemon/src/queriers/ibc.rs +++ b/cw-orch-daemon/src/queriers/ibc.rs @@ -12,29 +12,23 @@ use cosmrs::proto::ibc::{ }; use cw_orch_core::environment::{Querier, QuerierGetter}; use prost::Message; -use tokio::runtime::Handle; use tonic::transport::Channel; /// Querier for the Cosmos IBC module /// All the async function are prefixed with `_` pub struct Ibc { pub channel: Channel, - pub rt_handle: Option, } impl Ibc { pub fn new(daemon: &Daemon) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), } } pub fn new_async(channel: Channel) -> Self { - Self { - channel, - rt_handle: None, - } + Self { channel } } } diff --git a/cw-orch-daemon/src/queriers/node.rs b/cw-orch-daemon/src/queriers/node.rs index 0958da8a2..cf7876ca0 100644 --- a/cw-orch-daemon/src/queriers/node.rs +++ b/cw-orch-daemon/src/queriers/node.rs @@ -5,6 +5,7 @@ use crate::{ tx_resp::CosmTxResponse, DaemonBase, }; +use async_std::task::block_on; use cosmrs::{ proto::cosmos::{ base::query::v1beta1::PageRequest, @@ -17,7 +18,6 @@ use cw_orch_core::{ environment::{NodeQuerier, Querier, QuerierGetter}, log::query_target, }; -use tokio::runtime::Handle; use tonic::transport::Channel; /// Querier for the Tendermint node. @@ -25,21 +25,16 @@ use tonic::transport::Channel; /// All the async function are prefixed with `_` pub struct Node { pub channel: Channel, - pub rt_handle: Option, } impl Node { pub fn new(daemon: &DaemonBase) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), } } pub fn new_async(channel: Channel) -> Self { - Self { - channel, - rt_handle: None, - } + Self { channel } } } @@ -123,7 +118,7 @@ impl Node { while latest_block_height <= 1 { // wait to get some blocks - tokio::time::sleep(Duration::from_secs(1)).await; + async_std::task::sleep(Duration::from_secs(1)).await; latest_block = self._latest_block().await?; latest_block_height = latest_block.header.height.value(); } @@ -263,7 +258,7 @@ impl Node { } log::debug!(target: &query_target(), "TX not found with error: {:?}", err); log::debug!(target: &query_target(), "Waiting {} milli-seconds", block_speed.as_millis()); - tokio::time::sleep(block_speed).await; + async_std::task::sleep(block_speed).await; } } } @@ -340,7 +335,7 @@ impl Node { if retry_on_empty && resp.is_empty() { log::debug!(target: &query_target(), "No TX found with events {:?}", events); log::debug!(target: &query_target(), "Waiting 10s"); - tokio::time::sleep(Duration::from_secs(10)).await; + async_std::task::sleep(Duration::from_secs(10)).await; } else { log::debug!( target: &query_target(), @@ -353,7 +348,7 @@ impl Node { Err(err) => { log::debug!(target: &query_target(), "TX not found with error: {:?}", err); log::debug!(target: &query_target(), "Waiting 10s"); - tokio::time::sleep(Duration::from_secs(10)).await; + async_std::task::sleep(Duration::from_secs(10)).await; } } } @@ -371,48 +366,29 @@ impl NodeQuerier for Node { type Response = CosmTxResponse; fn latest_block(&self) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._block_info()) + block_on(self._block_info()) } fn block_by_height(&self, height: u64) -> Result { - let block = self - .rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._block_by_height(height))?; + let block = block_on(self._block_by_height(height))?; block_to_block_info(block) } fn block_height(&self) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._block_height()) + block_on(self._block_height()) } fn block_time(&self) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._block_time()) + block_on(self._block_time()) } fn simulate_tx(&self, tx_bytes: Vec) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._simulate_tx(tx_bytes)) + block_on(self._simulate_tx(tx_bytes)) } fn find_tx(&self, hash: String) -> Result { - self.rt_handle - .as_ref() - .ok_or(DaemonError::QuerierNeedRuntime)? - .block_on(self._find_tx(hash)) + block_on(self._find_tx(hash)) } } diff --git a/cw-orch-daemon/src/queriers/staking.rs b/cw-orch-daemon/src/queriers/staking.rs index 98936ea43..a4cf66e4a 100644 --- a/cw-orch-daemon/src/queriers/staking.rs +++ b/cw-orch-daemon/src/queriers/staking.rs @@ -4,7 +4,6 @@ use crate::{cosmos_modules, error::DaemonError, Daemon}; use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest; use cosmwasm_std::{Addr, StdError}; use cw_orch_core::environment::{Querier, QuerierGetter}; -use tokio::runtime::Handle; use tonic::transport::Channel; use super::bank::cosmrs_to_cosmwasm_coin; @@ -13,22 +12,17 @@ use super::bank::cosmrs_to_cosmwasm_coin; /// All the async function are prefixed with `_` pub struct Staking { pub channel: Channel, - pub rt_handle: Option, } impl Staking { pub fn new(daemon: &Daemon) -> Self { Self { channel: daemon.channel(), - rt_handle: Some(daemon.rt_handle.clone()), } } pub fn new_async(channel: Channel) -> Self { - Self { - channel, - rt_handle: None, - } + Self { channel } } } diff --git a/cw-orch-daemon/src/sync/builder.rs b/cw-orch-daemon/src/sync/builder.rs index 79d90ef16..26d6bae81 100644 --- a/cw-orch-daemon/src/sync/builder.rs +++ b/cw-orch-daemon/src/sync/builder.rs @@ -1,6 +1,7 @@ use crate::senders::builder::SenderBuilder; -use crate::{DaemonAsyncBuilder, DaemonBase, DaemonState, Wallet, RUNTIME}; +use crate::{DaemonAsyncBuilder, DaemonBase, DaemonState, Wallet}; +use async_std::task::block_on; use cw_orch_core::environment::ChainInfoOwned; use super::super::error::DaemonError; @@ -21,7 +22,6 @@ pub struct DaemonBuilder { pub(crate) chain: ChainInfoOwned, // # Optional - pub(crate) handle: Option, pub(crate) deployment_id: Option, pub(crate) state_path: Option, // State from rebuild or existing daemon @@ -38,7 +38,6 @@ impl DaemonBuilder { pub fn new(chain: impl Into) -> Self { Self { chain: chain.into(), - handle: None, deployment_id: None, state_path: None, state: None, @@ -49,24 +48,6 @@ impl DaemonBuilder { } } - /// Set a custom tokio runtime handle to use for the Daemon - /// - /// ## Example - /// ```no_run - /// use cw_orch_daemon::{Daemon, networks}; - /// use tokio::runtime::Runtime; - /// let rt = Runtime::new().unwrap(); - /// let Daemon = Daemon::builder(networks::LOCAL_JUNO) - /// .handle(rt.handle()) - /// // ... - /// .build() - /// .unwrap(); - /// ``` - pub fn handle(&mut self, handle: &tokio::runtime::Handle) -> &mut Self { - self.handle = Some(handle.clone()); - self - } - /// Set the deployment id to use for the Daemon interactions /// Defaults to `default` pub fn deployment_id(&mut self, deployment_id: impl Into) -> &mut Self { @@ -139,17 +120,12 @@ impl DaemonBuilder { /// Build a Daemon with the default [`Wallet`] implementation. pub fn build(&self) -> Result, DaemonError> { - let rt_handle = self - .handle - .clone() - .unwrap_or_else(|| RUNTIME.handle().clone()); - let builder = self.clone(); // build the underlying daemon - let daemon = rt_handle.block_on(DaemonAsyncBuilder::from(builder).build())?; + let daemon = block_on(DaemonAsyncBuilder::from(builder).build())?; - Ok(DaemonBase { rt_handle, daemon }) + Ok(DaemonBase { daemon }) } /// Build a daemon @@ -157,18 +133,12 @@ impl DaemonBuilder { &self, sender_options: T, ) -> Result, DaemonError> { - let rt_handle = self - .handle - .clone() - .unwrap_or_else(|| RUNTIME.handle().clone()); - let builder = self.clone(); // build the underlying daemon - let daemon = - rt_handle.block_on(DaemonAsyncBuilder::from(builder).build_sender(sender_options))?; + let daemon = block_on(DaemonAsyncBuilder::from(builder).build_sender(sender_options))?; - Ok(DaemonBase { rt_handle, daemon }) + Ok(DaemonBase { daemon }) } /// Specifies path to the daemon state file diff --git a/cw-orch-daemon/src/sync/core.rs b/cw-orch-daemon/src/sync/core.rs index 7320cc17b..8e77f1438 100644 --- a/cw-orch-daemon/src/sync/core.rs +++ b/cw-orch-daemon/src/sync/core.rs @@ -6,6 +6,7 @@ use crate::{ senders::{builder::SenderBuilder, query::QuerySender}, CosmTxResponse, DaemonAsyncBase, DaemonBuilder, DaemonError, DaemonState, }; +use async_std::task::block_on; use cosmwasm_std::{Addr, Coin}; use cw_orch_core::{ contract::{interface_traits::Uploadable, WasmPath}, @@ -13,7 +14,6 @@ use cw_orch_core::{ }; use cw_orch_traits::stargate::Stargate; use serde::Serialize; -use tokio::runtime::Handle; use tonic::transport::Channel; use crate::senders::tx::TxSender; @@ -29,9 +29,7 @@ Is constructed with the [DaemonBuilder]. ```rust,no_run use cw_orch_daemon::{Daemon, networks}; -use tokio::runtime::Runtime; -let rt = Runtime::new().unwrap(); let daemon: Daemon = Daemon::builder(networks::JUNO_1) .build() .unwrap(); @@ -47,8 +45,6 @@ See [Querier](crate::queriers) for examples. */ pub struct DaemonBase { pub(crate) daemon: DaemonAsyncBase, - /// Runtime handle to execute async tasks - pub rt_handle: Handle, } impl DaemonBase { @@ -73,13 +69,8 @@ impl DaemonBase { self, sender_options: T, ) -> DaemonBase<::Sender> { - let new_daemon = self - .rt_handle - .block_on(self.daemon.new_sender(sender_options)); - DaemonBase { - daemon: new_daemon, - rt_handle: self.rt_handle.clone(), - } + let new_daemon = block_on(self.daemon.new_sender(sender_options)); + DaemonBase { daemon: new_daemon } } /// Flushes all the state related to the current chain @@ -110,7 +101,6 @@ impl DaemonBase { deployment_id: Some(self.daemon.state.deployment_id.clone()), state_path: None, write_on_change: None, - handle: Some(self.rt_handle.clone()), mnemonic: None, // If it was test it will just use same tempfile as state is_test: false, @@ -172,7 +162,7 @@ impl TxHandler for DaemonBase { } fn upload(&self, uploadable: &T) -> Result { - self.rt_handle.block_on(self.daemon.upload(uploadable)) + block_on(self.daemon.upload(uploadable)) } fn execute( @@ -181,8 +171,7 @@ impl TxHandler for DaemonBase { coins: &[cosmwasm_std::Coin], contract_address: &Addr, ) -> Result { - self.rt_handle - .block_on(self.daemon.execute(exec_msg, coins, contract_address)) + block_on(self.daemon.execute(exec_msg, coins, contract_address)) } fn instantiate( @@ -193,7 +182,7 @@ impl TxHandler for DaemonBase { admin: Option<&Addr>, coins: &[Coin], ) -> Result { - self.rt_handle.block_on( + block_on( self.daemon .instantiate(code_id, init_msg, label, admin, coins), ) @@ -205,7 +194,7 @@ impl TxHandler for DaemonBase { new_code_id: u64, contract_address: &Addr, ) -> Result { - self.rt_handle.block_on( + block_on( self.daemon .migrate(migrate_msg, new_code_id, contract_address), ) @@ -220,7 +209,7 @@ impl TxHandler for DaemonBase { coins: &[cosmwasm_std::Coin], salt: cosmwasm_std::Binary, ) -> Result { - self.rt_handle.block_on( + block_on( self.daemon .instantiate2(code_id, init_msg, label, admin, coins, salt), ) @@ -231,7 +220,7 @@ impl TxHandler for DaemonBase { contract_source: &T, access_config: Option, ) -> Result { - self.rt_handle.block_on( + block_on( self.daemon .upload_with_access_config(contract_source, access_config), ) @@ -244,19 +233,18 @@ impl Stargate for DaemonBase { msgs: Vec, memo: Option<&str>, ) -> Result { - self.rt_handle - .block_on( - self.sender().commit_tx_any( - msgs.iter() - .map(|msg| cosmrs::Any { - type_url: msg.type_url.clone(), - value: msg.value.clone(), - }) - .collect(), - memo, - ), - ) - .map_err(Into::into) + block_on( + self.sender().commit_tx_any( + msgs.iter() + .map(|msg| cosmrs::Any { + type_url: msg.type_url.clone(), + value: msg.value.clone(), + }) + .collect(), + memo, + ), + ) + .map_err(Into::into) } } @@ -264,19 +252,19 @@ impl QueryHandler for DaemonBase { type Error = DaemonError; fn wait_blocks(&self, amount: u64) -> Result<(), DaemonError> { - self.rt_handle.block_on(self.daemon.wait_blocks(amount))?; + block_on(self.daemon.wait_blocks(amount))?; Ok(()) } fn wait_seconds(&self, secs: u64) -> Result<(), DaemonError> { - self.rt_handle.block_on(self.daemon.wait_seconds(secs))?; + block_on(self.daemon.wait_seconds(secs))?; Ok(()) } fn next_block(&self) -> Result<(), DaemonError> { - self.rt_handle.block_on(self.daemon.next_block())?; + block_on(self.daemon.next_block())?; Ok(()) } diff --git a/cw-orch-daemon/src/tx_broadcaster.rs b/cw-orch-daemon/src/tx_broadcaster.rs index e4c295290..a6197c6f4 100644 --- a/cw-orch-daemon/src/tx_broadcaster.rs +++ b/cw-orch-daemon/src/tx_broadcaster.rs @@ -99,7 +99,7 @@ impl TxBroadcaster { block_speed.as_millis(), s.reason ); - tokio::time::sleep(block_speed).await; + async_std::task::sleep(block_speed).await; tx_response = broadcast_helper(&mut tx_builder, signer).await; continue; diff --git a/cw-orch-daemon/tests/authz.rs b/cw-orch-daemon/tests/authz.rs index a90e18008..0655c0895 100644 --- a/cw-orch-daemon/tests/authz.rs +++ b/cw-orch-daemon/tests/authz.rs @@ -4,7 +4,6 @@ mod tests { /* Authz tests */ - use cosmrs::proto::cosmos::{ authz::v1beta1::{ GenericAuthorization, GrantAuthorization, MsgGrant, QueryGranteeGrantsResponse, @@ -45,8 +44,6 @@ mod tests { ) .unwrap(); - let runtime = daemon.rt_handle.clone(); - let grantee = second_daemon.sender_addr(); let current_timestamp = daemon.block_info()?.time; @@ -91,7 +88,7 @@ mod tests { // Grants let authz_querier: Authz = daemon.querier(); - let grants: QueryGrantsResponse = runtime.block_on(async { + let grants: QueryGrantsResponse = block_on(async { authz_querier ._grants(&sender, &grantee, MsgSend::type_url(), None) .await @@ -100,34 +97,33 @@ mod tests { // Grantee grants let grantee_grants: QueryGranteeGrantsResponse = - runtime.block_on(async { authz_querier._grantee_grants(&grantee, None).await })?; + block_on(async { authz_querier._grantee_grants(&grantee, None).await })?; assert_eq!(grantee_grants.grants, vec![grant_authorization.clone()]); // Granter grants let granter_grants: QueryGranterGrantsResponse = - runtime.block_on(async { authz_querier._granter_grants(&sender, None).await })?; + block_on(async { authz_querier._granter_grants(&sender, None).await })?; assert_eq!(granter_grants.grants, vec![grant_authorization]); // No grant gives out an error - runtime - .block_on(async { - authz_querier - ._grants(&grantee, &sender, MsgSend::type_url(), None) - .await - }) - .unwrap_err(); + block_on(async { + authz_querier + ._grants(&grantee, &sender, MsgSend::type_url(), None) + .await + }) + .unwrap_err(); // Check use of grants // The we send some funds to the account - runtime.block_on( + block_on( daemon .sender() .bank_send(&grantee, coins(100_000, LOCAL_JUNO.gas_denom)), )?; - + use async_std::task::block_on; // And send a large amount of tokens on their behalf - runtime.block_on( + block_on( second_daemon .sender() .bank_send(&grantee, coins(500_000, LOCAL_JUNO.gas_denom)), diff --git a/cw-orch-daemon/tests/querier.rs b/cw-orch-daemon/tests/querier.rs index 9bc334d1d..26c063a89 100644 --- a/cw-orch-daemon/tests/querier.rs +++ b/cw-orch-daemon/tests/querier.rs @@ -2,6 +2,7 @@ mod common; #[cfg(feature = "node-tests")] mod queriers { + use async_std::task::block_on; use cosmwasm_std::Addr; use cw_orch_core::contract::interface_traits::*; @@ -16,7 +17,6 @@ mod queriers { queriers::{CosmWasm, Gov, Ibc, Node, Staking}, Daemon, DaemonError, }; - use tokio::runtime::Runtime; use cosmrs::{ cosmwasm::MsgExecuteContract, @@ -43,12 +43,11 @@ mod queriers { */ #[test] fn ibc() { - let rt = Runtime::new().unwrap(); - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let ibc = Ibc::new_async(channel); - let clients = rt.block_on(ibc._clients()); + let clients = block_on(ibc._clients()); asserting!("clients is ok").that(&clients).is_ok(); } @@ -57,15 +56,14 @@ mod queriers { */ #[test] fn staking() { - let rt = Runtime::new().unwrap(); - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let staking = Staking::new_async(channel); - let params = rt.block_on(staking._params()); + let params = block_on(staking._params()); asserting!("params is ok").that(¶ms).is_ok(); - let validators = rt.block_on(staking._validators(StakingBondStatus::Bonded)); + let validators = block_on(staking._validators(StakingBondStatus::Bonded)); asserting!("validators is ok").that(&validators).is_ok(); asserting!("validators is not empty") .that(&validators.unwrap().len()) @@ -77,12 +75,11 @@ mod queriers { */ #[test] fn gov() { - let rt = Runtime::new().unwrap(); - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let gov = Gov::new_async(channel); - let params = rt.block_on(gov._params("voting")); + let params = block_on(gov._params("voting")); asserting!("params is ok").that(¶ms).is_ok(); } @@ -91,39 +88,38 @@ mod queriers { */ #[test] fn bank() { - let rt = Runtime::new().unwrap(); - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let bank = Bank::new_async(channel); - let params = rt.block_on(bank._params()); + let params = block_on(bank._params()); asserting!("params is ok").that(¶ms).is_ok(); - let balances = rt.block_on(bank._balance( + let balances = block_on(bank._balance( &Addr::unchecked("juno16g2rahf5846rxzp3fwlswy08fz8ccuwk03k57y"), None, )); asserting!("balances is ok").that(&balances).is_ok(); - let spendable_balances = rt.block_on(bank._spendable_balances(&Addr::unchecked( + let spendable_balances = block_on(bank._spendable_balances(&Addr::unchecked( "juno16g2rahf5846rxzp3fwlswy08fz8ccuwk03k57y", ))); asserting!("spendable_balances is ok") .that(&spendable_balances) .is_ok(); - let total_supply = rt.block_on(bank._total_supply()); + let total_supply = block_on(bank._total_supply()); asserting!("total_supply is ok").that(&total_supply).is_ok(); - let supply_of = rt.block_on(bank._supply_of("ujunox")); + let supply_of = block_on(bank._supply_of("ujunox")); asserting!("supply_of is ok").that(&supply_of).is_ok(); - let denom_metadata = rt.block_on(bank._denom_metadata("ucosm")); + let denom_metadata = block_on(bank._denom_metadata("ucosm")); asserting!("denom_metadata is err, should not exists") .that(&denom_metadata) .is_err(); - let denoms_metadata = rt.block_on(bank._denoms_metadata(None)); + let denoms_metadata = block_on(bank._denoms_metadata(None)); asserting!("denoms_metadata is ok, but empty") .that(&denoms_metadata) .is_ok(); @@ -134,12 +130,11 @@ mod queriers { */ #[test] fn cosmwasm() { - let rt = Runtime::new().unwrap(); - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let cw = CosmWasm::new_async(channel); - let params = rt.block_on(cw._params()); + let params = block_on(cw._params()); asserting!("params is ok").that(¶ms).is_ok(); } @@ -148,27 +143,24 @@ mod queriers { */ #[test] fn node() { - let rt = Runtime::new().unwrap(); - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let node = Node::new_async(channel); - let block_height = rt.block_on(node._block_height()); + let block_height = block_on(node._block_height()); asserting!("block_height is ok").that(&block_height).is_ok(); - let latest_block = rt.block_on(node._latest_block()); + let latest_block = block_on(node._latest_block()); asserting!("latest_block is ok").that(&latest_block).is_ok(); - let block_time = rt.block_on(node._block_time()); + let block_time = block_on(node._block_time()); asserting!("block_time is ok").that(&block_time).is_ok(); } #[test] #[serial_test::serial] fn simulate_tx() { - let rt = Runtime::new().unwrap(); - - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let node = Node::new_async(channel); @@ -200,7 +192,7 @@ mod queriers { let body = tx::Body::new(msgs, memo, 100u32); - let simulate_tx = rt.block_on(node._simulate_tx(body.into_bytes().unwrap())); + let simulate_tx = block_on(node._simulate_tx(body.into_bytes().unwrap())); asserting!("that simulate_tx worked but msg is wrong") .that(&simulate_tx) @@ -213,8 +205,7 @@ mod queriers { use cw_orch_daemon::TxSender; use cw_orch_networks::networks; - let rt = Runtime::new().unwrap(); - let channel = rt.block_on(build_channel()); + let channel = block_on(build_channel()); let cosm_wasm = CosmWasm::new_async(channel); let daemon = Daemon::builder(networks::LOCAL_JUNO) .is_test(true) @@ -233,7 +224,7 @@ mod queriers { let contract_address = contract.address().unwrap(); - let contract_info = rt.block_on(cosm_wasm._contract_info(&contract_address)); + let contract_info = block_on(cosm_wasm._contract_info(&contract_address)); asserting!("contract info is ok") .that(&contract_info) diff --git a/cw-orch-interchain/Cargo.toml b/cw-orch-interchain/Cargo.toml index 85d6565d6..9f22b1e95 100644 --- a/cw-orch-interchain/Cargo.toml +++ b/cw-orch-interchain/Cargo.toml @@ -32,6 +32,7 @@ cw-orch-interchain-mock = { workspace = true } cw-orch-interchain-daemon = { workspace = true, optional = true } cw-orch-starship = { workspace = true, optional = true } ibc-relayer-types.workspace = true +async-std = { workspace = true } #Used only for testing cosmwasm-std.workspace = true @@ -50,7 +51,6 @@ env_logger = "0.11.5" ibc-relayer-types.workspace = true log.workspace = true speculoos.workspace = true -tokio = "1.39.2" cosmos-sdk-proto = { workspace = true } prost-types = { workspace = true } ibc-proto = { workspace = true } diff --git a/cw-orch-interchain/tests/common/bank.rs b/cw-orch-interchain/tests/common/bank.rs index eb66b6147..5ffeb93e7 100644 --- a/cw-orch-interchain/tests/common/bank.rs +++ b/cw-orch-interchain/tests/common/bank.rs @@ -1,3 +1,4 @@ +use async_std::task::block_on; use cosmwasm_std::{BankMsg, Coin, CosmosMsg}; use cw_orch::prelude::*; @@ -26,7 +27,7 @@ impl BankModule for Mock { })], ) .unwrap(); - Ok(app_responses[0].clone()) + Ok(app_responses[0].clone().into()) } } @@ -36,7 +37,6 @@ impl BankModule for Daemon { recipient: &Addr, funds: Vec, ) -> Result<::Response, ::Error> { - self.rt_handle - .block_on(self.sender().bank_send(recipient, funds)) + block_on(self.sender().bank_send(recipient, funds)) } } diff --git a/cw-orch/Cargo.toml b/cw-orch/Cargo.toml index d86f7a3c2..df148412a 100644 --- a/cw-orch/Cargo.toml +++ b/cw-orch/Cargo.toml @@ -41,12 +41,7 @@ required-features = ["daemon"] [features] default = [] # enable the optional dependencies -daemon = [ - "dep:tokio", - "dep:cosmrs", - "dep:cw-orch-daemon", - "dep:cw-orch-networks", -] +daemon = ["dep:cosmrs", "dep:cw-orch-daemon", "dep:cw-orch-networks"] eth = ["daemon", "cw-orch-core/eth", "cw-orch-daemon?/eth"] snapshot-testing = ["dep:insta", "dep:sanitize-filename"] @@ -55,11 +50,16 @@ snapshot-testing = ["dep:insta", "dep:sanitize-filename"] cw-orch-contract-derive = { workspace = true } cw-orch-fns-derive = { workspace = true } +# Moved from wasm protected +anyhow = { workspace = true } +cw-orch-traits = { workspace = true } +cw-orch-core = { workspace = true } +cosmwasm-std = { workspace = true } + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # Daemon deps cw-orch-networks = { workspace = true, optional = true } -tokio = { workspace = true, features = ["full"], optional = true } cosmrs = { workspace = true, features = [ "dev", "cosmwasm", @@ -75,9 +75,7 @@ insta = { version = "1.39.0", features = ["yaml"], optional = true } sanitize-filename = { version = "0.5.0", optional = true } # Default deps -cosmwasm-std = { workspace = true } cw-utils = { workspace = true } -anyhow = { workspace = true } serde = { workspace = true } schemars = "0.8.21" log = { workspace = true } @@ -87,8 +85,6 @@ hex = "0.4.3" # Env deps # This packages will most likely make wasm not compilable cw-orch-daemon = { workspace = true, optional = true } -cw-orch-traits = { workspace = true } -cw-orch-core = { workspace = true } cw-orch-mock = { workspace = true } [dev-dependencies] @@ -103,3 +99,4 @@ dotenv = "0.15.0" osmosis-std = "0.26.0" prost = { workspace = true } prost-types = { workspace = true } +async-std = { workspace = true } diff --git a/cw-orch/examples/async_daemon.rs b/cw-orch/examples/async_daemon.rs index 355f39cc8..4816de26f 100644 --- a/cw-orch/examples/async_daemon.rs +++ b/cw-orch/examples/async_daemon.rs @@ -7,7 +7,7 @@ use cw_orch_mock::Mock; /// RUST_LOG (recommended value `info`) to see the app logs /// /// TEST_MNEMONIC to be able to sign and broadcast a transaction on UNI testnet -#[tokio::main] +#[async_std::main] pub async fn main() -> anyhow::Result<()> { // We start by loading environment variables from a .env file. // You can use a .env file to specify environment variables. diff --git a/cw-orch/examples/complex_testnet_daemon.rs b/cw-orch/examples/complex_testnet_daemon.rs index b3175a78e..76e55638a 100644 --- a/cw-orch/examples/complex_testnet_daemon.rs +++ b/cw-orch/examples/complex_testnet_daemon.rs @@ -1,3 +1,4 @@ +use async_std::task::block_on; use cosmwasm_std::coins; use counter_contract::{ msg::{ExecuteMsg, GetCountResponse, InstantiateMsg, QueryMsg}, @@ -98,14 +99,12 @@ pub fn main() { .unwrap(); // We send some funds to the counter contract let contract_addr = counter.address().unwrap(); - daemon - .rt_handle - .block_on( - daemon - .sender() - .bank_send(&contract_addr, coins(50_000, denom.clone())), - ) - .unwrap(); + block_on( + daemon + .sender() + .bank_send(&contract_addr, coins(50_000, denom.clone())), + ) + .unwrap(); // We verify they have received their funds assert_eq!( daemon diff --git a/cw-orch/examples/queries/testnet_queries.rs b/cw-orch/examples/queries/testnet_queries.rs index 8899e9e6a..f5fc816de 100644 --- a/cw-orch/examples/queries/testnet_queries.rs +++ b/cw-orch/examples/queries/testnet_queries.rs @@ -1,10 +1,12 @@ use anyhow::Result as AnyResult; +use async_std::task::block_on; use cosmwasm_std::Addr; use cw_orch::daemon::Daemon; use cw_orch::prelude::BankQuerier; use cw_orch::prelude::QuerierGetter; use cw_orch_daemon::queriers::Ibc; use cw_orch_daemon::queriers::{Bank, Staking}; + pub const TEST_MNEMONIC: &str="scare silent genuine cheese monitor industry item cloth pet gather cruise long confirm van lunar tomato scrub silk guide eight truly rural remember swim"; pub fn main() -> AnyResult<()> { @@ -23,18 +25,14 @@ pub fn main() -> AnyResult<()> { let staking_query_client: Staking = daemon.querier(); let validator = Addr::unchecked("junovaloper185hgkqs8q8ysnc8cvkgd8j2knnq2m0ah6ae73gntv9ampgwpmrxqlfzywn"); - let validator_result = daemon - .rt_handle - .block_on(staking_query_client._validator(&validator))?; + let validator_result = block_on(staking_query_client._validator(&validator))?; println!("Validator info of {} : {:?}", sender, validator_result); // We do an actual IBC query on MAINNET let ibc_query_client: Ibc = daemon.querier(); let port_id = "transfer"; let channel_id = "channel-0"; - let channel_result = daemon - .rt_handle - .block_on(ibc_query_client._channel(port_id, channel_id))?; + let channel_result = block_on(ibc_query_client._channel(port_id, channel_id))?; println!( "Channel info of {port_id}:{channel_id} : {:?}", channel_result diff --git a/cw-orch/src/lib.rs b/cw-orch/src/lib.rs index 7dd770f75..5b0e49fc9 100644 --- a/cw-orch/src/lib.rs +++ b/cw-orch/src/lib.rs @@ -7,10 +7,8 @@ pub use cw_orch_contract_derive::interface; pub use cw_orch_fns_derive::{ExecuteFns, QueryFns}; // prelude -#[cfg(not(target_arch = "wasm32"))] pub mod prelude; -#[cfg(not(target_arch = "wasm32"))] mod error; #[cfg(not(target_arch = "wasm32"))] @@ -21,21 +19,20 @@ pub mod daemon; #[cfg(feature = "snapshot-testing")] pub mod snapshots; +/// Re-export anyhow for use in the macros +pub extern crate anyhow; +// This re-export should not be touched or the derive macros WILL break +pub use cw_orch_core as core; +pub use cw_orch_core::{build, contract}; +/// Related to execution environments +pub mod environment { + pub use cw_orch_core::environment::*; +} + #[cfg(not(target_arch = "wasm32"))] /// used to avoid repeating the #[cfg(not(target_arch = "wasm32"))] macro for each export pub mod wasm_protected { - /// Re-export anyhow for use in the macros - pub extern crate anyhow; - - // This re-export should not be touched or the derive macros WILL break - pub use cw_orch_core as core; - pub use cw_orch_core::{build, contract}; - - /// Related to execution environments - pub mod environment { - pub use cw_orch_core::environment::*; - } /// Related environment variables definition pub mod env_vars { pub use cw_orch_core::CoreEnvVars; @@ -44,10 +41,6 @@ pub mod wasm_protected { } pub use cw_orch_mock as mock; - /// Re-export tokio, the async runtime when using daemons. - #[cfg(feature = "daemon")] - pub extern crate tokio; - // Rexporting for the macro to work properly #[cfg(feature = "snapshot-testing")] pub extern crate insta; diff --git a/cw-orch/src/prelude.rs b/cw-orch/src/prelude.rs index 79bf61aba..89b8564c4 100644 --- a/cw-orch/src/prelude.rs +++ b/cw-orch/src/prelude.rs @@ -36,6 +36,7 @@ pub use cw_orch_core::environment::Environment; // Chains pub use crate::environment::{ChainInfo, ChainInfoOwned}; +#[cfg(not(target_arch = "wasm32"))] // Mock for testing pub use crate::mock::{Mock, MockBech32}; @@ -46,10 +47,11 @@ pub use crate::error::CwOrchError; pub use crate::contract::{ArtifactsDir, WasmPath}; // re-export as it is used in the public API -pub use crate::mock::cw_multi_test::{Contract as MockContract, ContractWrapper}; +pub use crate::core::contract::{ContractWrapper, MockContract}; pub use cosmwasm_std::{Addr, Coin, Empty}; // builder, core type, networks mod, queriers mod, traits +#[cfg(not(target_arch = "wasm32"))] #[cfg(feature = "daemon")] pub use crate::daemon::{ live_mock, @@ -62,6 +64,7 @@ pub use crate::daemon::{ DaemonBuilder, }; +#[cfg(not(target_arch = "wasm32"))] #[cfg(feature = "daemon")] pub use cw_orch_networks::networks; diff --git a/cw-orch/tests/entry_point_macro.rs b/cw-orch/tests/entry_point_macro.rs index 2a89e6b7f..0cc10ec40 100644 --- a/cw-orch/tests/entry_point_macro.rs +++ b/cw-orch/tests/entry_point_macro.rs @@ -1,8 +1,9 @@ use cw_orch_core::environment::TxHandler; use mock_contract::{ExecuteMsg, InstantiateMsg, MigrateMsg, MockContract, QueryMsg}; -use cosmwasm_std::Event; -use cw_orch::prelude::{ContractInstance, CwOrchExecute, CwOrchMigrate, CwOrchQuery}; +use cw_orch::prelude::{ + ContractInstance, CwOrchExecute, CwOrchMigrate, CwOrchQuery, IndexResponse, +}; use cw_orch::prelude::CwOrchUpload; use cw_orch::prelude::{CwOrchInstantiate, Mock}; @@ -23,10 +24,12 @@ fn test_execute() { contract.instantiate(&InstantiateMsg {}, None, &[]).unwrap(); let response = contract.execute(&ExecuteMsg::FirstMessage {}, &[]).unwrap(); - response.has_event( - &Event::new("wasm") - .add_attribute("_contract_addr", "contract0") - .add_attribute("action", "first message passed"), + assert!(response + .event_attr_value("wasm", "_contract_address") + .is_ok(),); + assert_eq!( + response.event_attr_value("wasm", "action").unwrap(), + "first message passed" ); contract diff --git a/cw-orch/tests/fns_macro.rs b/cw-orch/tests/fns_macro.rs index 08bbb9739..1ce4d31f7 100644 --- a/cw-orch/tests/fns_macro.rs +++ b/cw-orch/tests/fns_macro.rs @@ -1,9 +1,7 @@ use mock_contract::{ExecuteMsgFns, InstantiateMsg, MockContract, QueryMsgFns}; -use cosmwasm_std::Event; - -use cw_orch::prelude::CwOrchUpload; use cw_orch::prelude::{CwOrchInstantiate, Mock}; +use cw_orch::prelude::{CwOrchUpload, IndexResponse}; #[test] fn test_execute() { @@ -13,11 +11,12 @@ fn test_execute() { contract.instantiate(&InstantiateMsg {}, None, &[]).unwrap(); let response = contract.first_message().unwrap(); - - response.has_event( - &Event::new("wasm") - .add_attribute("_contract_addr", "contract0") - .add_attribute("action", "first message passed"), + assert!(response + .event_attr_value("wasm", "_contract_address") + .is_ok(),); + assert_eq!( + response.event_attr_value("wasm", "action").unwrap(), + "first message passed" ); contract.second_message("".to_string(), &[]).unwrap_err(); diff --git a/cw-orch/tests/interface_macro.rs b/cw-orch/tests/interface_macro.rs index 56ebcea68..827074dac 100644 --- a/cw-orch/tests/interface_macro.rs +++ b/cw-orch/tests/interface_macro.rs @@ -1,11 +1,10 @@ use cw_orch::{ environment::TxHandler, - prelude::{ContractWrapper, Uploadable}, + prelude::{ContractWrapper, IndexResponse, Uploadable}, }; use mock_contract::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; -use cosmwasm_std::Event; use cw_orch::prelude::{ ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, Mock, @@ -53,10 +52,12 @@ fn test_execute() { contract.instantiate(&InstantiateMsg {}, None, &[]).unwrap(); let response = contract.execute(&ExecuteMsg::FirstMessage {}, &[]).unwrap(); - response.has_event( - &Event::new("wasm") - .add_attribute("_contract_addr", "contract0") - .add_attribute("action", "first message passed"), + assert!(response + .event_attr_value("wasm", "_contract_address") + .is_ok(),); + assert_eq!( + response.event_attr_value("wasm", "action").unwrap(), + "first message passed" ); contract diff --git a/cw-orch/tests/interface_macro_generics.rs b/cw-orch/tests/interface_macro_generics.rs index b43477d1a..d1e2c3bc6 100644 --- a/cw-orch/tests/interface_macro_generics.rs +++ b/cw-orch/tests/interface_macro_generics.rs @@ -1,7 +1,6 @@ use cw_orch::{interface, prelude::*}; use mock_contract::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; -use cosmwasm_std::Event; use cw_orch::prelude::Mock; #[interface(InstantiateMsg, ExecuteMsg, QueryMsg, MigrateMsg, id = "test:mock_contract")] @@ -38,11 +37,12 @@ fn test_execute() { contract.instantiate(&InstantiateMsg {}, None, &[]).unwrap(); let response = contract.execute(&ExecuteMsg::FirstMessage {}, &[]).unwrap(); - - response.has_event( - &Event::new("wasm") - .add_attribute("_contract_addr", "contract0") - .add_attribute("action", "first message passed"), + assert!(response + .event_attr_value("wasm", "_contract_address") + .is_ok(),); + assert_eq!( + response.event_attr_value("wasm", "action").unwrap(), + "first message passed" ); contract diff --git a/packages/clone-testing/Cargo.toml b/packages/clone-testing/Cargo.toml index 4e8f3c5c4..d887f6e2a 100644 --- a/packages/clone-testing/Cargo.toml +++ b/packages/clone-testing/Cargo.toml @@ -13,19 +13,19 @@ description = "Adapter for interacting with cw-multi-test via the cw-orchestrato cosmwasm-std = { workspace = true } cw-orch-core = { workspace = true } -cw-orch-mock = { workspace = true } cw-orch-daemon = { workspace = true } -clone-cw-multi-test = { version = "0.6.1" } +# clone-cw-multi-test = { version = "0.6.1" } +clone-cw-multi-test = { git = "https://github.com/abstractsdk/cw-multi-test-fork", branch = "clone-testing/remove-tokio" } cw-utils = { workspace = true } serde = { workspace = true } log = { workspace = true } anyhow = { workspace = true } -tokio = { workspace = true } itertools = "0.12.0" sha2 = "0.10.8" tonic = { workspace = true } +async-std = { workspace = true } [dev-dependencies] cosmwasm-schema = "2.0.0" diff --git a/packages/clone-testing/src/core.rs b/packages/clone-testing/src/core.rs index 9ff00b395..72a469617 100644 --- a/packages/clone-testing/src/core.rs +++ b/packages/clone-testing/src/core.rs @@ -1,5 +1,6 @@ use std::{cell::RefCell, fmt::Debug, io::Read, rc::Rc}; +use async_std::task::block_on; use clone_cw_multi_test::{ addons::{MockAddressGenerator, MockApiBech32}, wasm_emulation::{channel::RemoteChannel, storage::analyzer::StorageAnalyzer}, @@ -17,10 +18,9 @@ use cw_orch_core::{ }, CwEnvError, }; -use cw_orch_daemon::{queriers::Node, read_network_config, DEFAULT_DEPLOYMENT, RUNTIME}; +use cw_orch_daemon::{queriers::Node, read_network_config, DEFAULT_DEPLOYMENT}; use cw_utils::NativeBalance; use serde::Serialize; -use tokio::runtime::Runtime; use crate::{contract::CloneTestingContract, queriers::bank::CloneBankQuerier}; @@ -60,9 +60,8 @@ pub type CloneTestingApp = App; /// // We just use the MockState as an example here, but you can implement your own state struct. /// use cw_orch_clone_testing::MockState as CustomState; /// -/// let rt = tokio::runtime::Runtime::new().unwrap(); /// let chain = cw_orch_daemon::networks::JUNO_1; -/// let mock: CloneTesting = CloneTesting::new_custom(&rt, chain.clone(), CustomState::new(chain.clone().into(), "mock")).unwrap(); +/// let mock: CloneTesting = CloneTesting::new_custom(chain.clone(), CustomState::new(chain.clone().into(), "mock")).unwrap(); /// ``` #[derive(Clone)] pub struct CloneTesting { @@ -168,32 +167,21 @@ impl CloneTesting { impl CloneTesting { /// Create a mock environment with the default mock state. - pub fn new(chain: impl Into) -> Result { - Self::new_with_runtime(&RUNTIME, chain) - } - /// Create a mock environment with the default mock state. - /// It uses a custom runtime object to control async requests - pub fn new_with_runtime( - rt: &Runtime, - chain: impl Into, - ) -> Result { + pub fn new(chain: impl Into) -> Result { let chain_data = chain.into(); CloneTesting::new_custom( - rt, chain_data.clone(), MockState::new(chain_data, DEFAULT_DEPLOYMENT), ) } pub fn new_with_deployment_id( - rt: &Runtime, chain: impl Into, deployment_id: &str, ) -> Result { let chain_data = chain.into(); CloneTesting::new_custom( - rt, chain_data.clone(), MockState::new(chain_data, deployment_id), ) @@ -204,7 +192,6 @@ impl CloneTesting { /// Create a mock environment with a custom mock state. /// The state is customizable by implementing the `StateInterface` trait on a custom struct and providing it on the custom constructor. pub fn new_custom( - rt: &Runtime, chain: impl Into, custom_state: S, ) -> Result { @@ -218,7 +205,6 @@ impl CloneTesting { let pub_address_prefix = chain.network_info.pub_address_prefix.clone(); let remote_channel = RemoteChannel::new( - rt, &chain .grpc_urls .iter() @@ -236,10 +222,8 @@ impl CloneTesting { let bank = BankKeeper::new().with_remote(remote_channel.clone()); // We update the block_height - let block_info = remote_channel - .rt - .block_on(Node::new_async(remote_channel.channel.clone())._block_info()) - .unwrap(); + let block_info = + block_on(Node::new_async(remote_channel.channel.clone())._block_info()).unwrap(); // Finally we instantiate a new app let app = AppBuilder::default() @@ -496,9 +480,9 @@ mod test { }; use cw20::{BalanceResponse, MinterResponse}; use cw_orch_core::contract::WasmPath; + use cw_orch_core::contract::{ContractWrapper, MockContract}; use cw_orch_core::environment::QueryHandler; use cw_orch_daemon::networks::JUNO_1; - use cw_orch_mock::cw_multi_test::{Contract as MockContract, ContractWrapper}; use speculoos::prelude::*; pub struct MockCw20; @@ -631,10 +615,9 @@ mod test { let denom = "uosmo"; let chain = JUNO_1; - let rt = Runtime::new().unwrap(); let mock_state = MockState::new(JUNO_1.into(), "default_id"); - let chain: CloneTesting = CloneTesting::<_>::new_custom(&rt, chain, mock_state)?; + let chain: CloneTesting = CloneTesting::<_>::new_custom(chain, mock_state)?; let recipient = chain.init_account(); chain diff --git a/packages/clone-testing/src/lib.rs b/packages/clone-testing/src/lib.rs index cfdeb435b..b12f6ece6 100644 --- a/packages/clone-testing/src/lib.rs +++ b/packages/clone-testing/src/lib.rs @@ -25,10 +25,10 @@ mod contract { }; use cosmwasm_std::{Checksum, Deps, DepsMut, Empty, QuerierWrapper}; - pub struct CloneTestingContract(Box>); + pub struct CloneTestingContract(Box>); impl CloneTestingContract { - pub fn new(contract: Box>) -> Self { + pub fn new(contract: Box>) -> Self { Self(contract) } } diff --git a/packages/cw-orch-core/Cargo.toml b/packages/cw-orch-core/Cargo.toml index dce02fc18..56c53472b 100644 --- a/packages/cw-orch-core/Cargo.toml +++ b/packages/cw-orch-core/Cargo.toml @@ -18,13 +18,18 @@ all-features = true [features] default = [] +cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] +mock = ["dep:cw-multi-test"] eth = ["dep:snailquote"] [dependencies] thiserror = { workspace = true } -cosmwasm-std = { workspace = true } +cosmwasm-std = { workspace = true, features = [ + "cosmwasm_1_2", + "staking", + "stargate", +] } serde = { workspace = true } -cw-multi-test = { workspace = true } log = { workspace = true } sha2 = { workspace = true } @@ -39,6 +44,10 @@ cw-utils = { workspace = true } cosmos-sdk-proto = { workspace = true, features = ["cosmwasm"] } cw-storage-plus = { workspace = true } +# Mock Specific Deps +cw-multi-test = { workspace = true, optional = true } + + [dev-dependencies] speculoos = { workspace = true } anyhow = { workspace = true } diff --git a/packages/cw-orch-core/src/contract/interface_traits.rs b/packages/cw-orch-core/src/contract/interface_traits.rs index e7f527293..bb63d3f09 100644 --- a/packages/cw-orch-core/src/contract/interface_traits.rs +++ b/packages/cw-orch-core/src/contract/interface_traits.rs @@ -1,4 +1,5 @@ use super::{Contract, WasmPath}; +use crate::contract::wrapper::Contract as MockContract; use crate::environment::AccessConfig; use crate::{ environment::{ @@ -9,7 +10,6 @@ use crate::{ log::contract_target, }; use cosmwasm_std::{Addr, Binary, Coin, Empty}; -use cw_multi_test::Contract as MockContract; use cw_storage_plus::{Item, Map, PrimaryKey}; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; diff --git a/packages/cw-orch-core/src/contract/mod.rs b/packages/cw-orch-core/src/contract/mod.rs index c799ce0d2..5108c184c 100644 --- a/packages/cw-orch-core/src/contract/mod.rs +++ b/packages/cw-orch-core/src/contract/mod.rs @@ -2,6 +2,11 @@ mod contract_instance; mod deploy; pub mod interface_traits; mod paths; +/// Cloned from cosmwasm/cw_multi_test +mod wrapper; +#[cfg(feature = "mock")] +pub use wrapper::cw_multi_test_impl::BoxedContractWrapper; +pub use wrapper::{Contract as MockContract, ContractWrapper}; pub use contract_instance::Contract; pub use deploy::Deploy; diff --git a/packages/cw-orch-core/src/contract/wrapper.rs b/packages/cw-orch-core/src/contract/wrapper.rs new file mode 100644 index 000000000..02452ffdd --- /dev/null +++ b/packages/cw-orch-core/src/contract/wrapper.rs @@ -0,0 +1,1104 @@ +//! # Implementation of the contract trait and contract wrapper + +use anyhow::{anyhow, bail, Error as AnyError, Result as AnyResult}; +use cosmwasm_std::{ + from_json, Binary, Checksum, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, + MessageInfo, QuerierWrapper, Reply, Response, SubMsg, +}; +use cosmwasm_std::{ + IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, + IbcChannelOpenResponse, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, +}; +use serde::de::DeserializeOwned; +use std::fmt::{Debug, Display}; +use std::ops::Deref; + +/// This trait serves as a primary interface for interacting with contracts. +#[rustfmt::skip] +pub trait Contract +where + C: CustomMsg, + Q: CustomQuery, +{ + /// Evaluates contract's `execute` entry-point. + fn execute(&self, deps: DepsMut, env: Env, info: MessageInfo, msg: Vec) -> AnyResult>; + + /// Evaluates contract's `instantiate` entry-point. + fn instantiate(&self, deps: DepsMut, env: Env, info: MessageInfo, msg: Vec) -> AnyResult>; + + /// Evaluates contract's `query` entry-point. + fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult; + + /// Evaluates contract's `sudo` entry-point. + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + + /// Evaluates contract's `reply` entry-point. + fn reply(&self, deps: DepsMut, env: Env, msg: Reply) -> AnyResult>; + + /// Evaluates contract's `migrate` entry-point. + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + + /// Returns the provided checksum of the contract's Wasm blob. + fn checksum(&self) -> Option { + None + } + + /// Executes the contract ibc_channel_open endpoint + #[allow(unused)] + fn ibc_channel_open( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelOpenMsg, + ) -> AnyResult { + bail!("No Ibc capabilities on this contract") + } + + /// Executes the contract ibc_channel_connect endpoint + #[allow(unused)] + fn ibc_channel_connect( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelConnectMsg, + ) -> AnyResult> { + bail!("No Ibc capabilities on this contract") + } + + /// Executes the contract ibc_channel_close endpoint + #[allow(unused)] + fn ibc_channel_close( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelCloseMsg, + ) -> AnyResult> { + bail!("No Ibc capabilities on this contract") + } + + /// Executes the contract ibc_packet_receive endpoint + #[allow(unused)] + fn ibc_packet_receive( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketReceiveMsg, + ) -> AnyResult> { + bail!("No Ibc capabilities on this contract") + } + + /// Executes the contract ibc_packet_acknowledge endpoint + #[allow(unused)] + fn ibc_packet_acknowledge( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketAckMsg, + ) -> AnyResult> { + bail!("No Ibc capabilities on this contract") + } + + /// Executes the contract ibc_packet_timeout endpoint + #[allow(unused)] + fn ibc_packet_timeout( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketTimeoutMsg, + ) -> AnyResult> { + bail!("No Ibc capabilities on this contract") + } +} + +#[rustfmt::skip] +mod closures { + use super::*; + + // function types + pub type IbcFn = fn(deps: DepsMut, env: Env, msg: T) -> Result; + + pub type ContractFn = fn(deps: DepsMut, env: Env, info: MessageInfo, msg: T) -> Result, E>; + pub type PermissionedFn = fn(deps: DepsMut, env: Env, msg: T) -> Result, E>; + pub type ReplyFn = fn(deps: DepsMut, env: Env, msg: Reply) -> Result, E>; + pub type QueryFn = fn(deps: Deps, env: Env, msg: T) -> Result; + + // closure types + pub type IbcClosure = Box,Env, T) -> Result>; + + pub type ContractClosure = Box, Env, MessageInfo, T) -> Result, E>>; + pub type PermissionedClosure = Box, Env, T) -> Result, E>>; + pub type ReplyClosure = Box, Env, Reply) -> Result, E>>; + pub type QueryClosure = Box, Env, T) -> Result>; +} + +use closures::*; + +/// This structure wraps the [Contract] trait implementor +/// and provides generic access to the contract's entry-points. +/// +/// List of generic types used in [ContractWrapper]: +/// - **T1** type of message passed to [execute] entry-point. +/// - **T2** type of message passed to [instantiate] entry-point. +/// - **T3** type of message passed to [query] entry-point. +/// - **T4** type of message passed to [sudo] entry-point. +/// - instead of **~~T5~~**, always the `Reply` type is used in [reply] entry-point. +/// - **T6** type of message passed to [migrate] entry-point. +/// - **E1** type of error returned from [execute] entry-point. +/// - **E2** type of error returned from [instantiate] entry-point. +/// - **E3** type of error returned from [query] entry-point. +/// - **E4** type of error returned from [sudo] entry-point. +/// - **E5** type of error returned from [reply] entry-point. +/// - **E6** type of error returned from [migrate] entry-point. +/// - **C** type of custom message returned from all entry-points except [query]. +/// - **Q** type of custom query in `Querier` passed as 'Deps' or 'DepsMut' to all entry-points. +/// +/// The following table summarizes the purpose of all generic types used in [ContractWrapper]. +/// ```text +/// ┌─────────────────────┬────────────────────────┬─────────────────────┬─────────┬─────────┬───────┬───────┐ +/// │ Contract │ Contract │ │ │ │ │ │ +/// │ entry-point │ wrapper │ Closure type │ Message │ Message │ Error │ Query │ +/// │ │ member │ │ IN │ OUT │ OUT │ │ +/// ╞═════════════════════╪════════════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡ +/// │ (1) │ │ │ │ │ │ │ +/// ╞═════════════════════╪════════════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡ +/// │ execute │ execute_fn │ ContractClosure │ T1 │ C │ E1 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ instantiate │ instantiate_fn │ ContractClosure │ T2 │ C │ E2 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ query │ query_fn │ QueryClosure │ T3 │ Binary │ E3 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ sudo │ sudo_fn │ PermissionedClosure │ T4 │ C │ E4 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ reply │ reply_fn │ ReplyClosure │ Reply │ C │ E5 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ migrate │ migrate_fn │ PermissionedClosure │ T6 │ C │ E6 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ ibc_channel_open │ ibc_channel_open_fn │ IbcClosure │ -- │ C │ E7 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ ibc_channel_connect │ ibc_channel_connect_fn │ IbcClosure │ -- │ C │ E8 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ ibc_channel_close │ ibc_channel_close_fn │ IbcClosure │ -- │ C │ E9 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ ibc_packet_receive │ ibc_packet_receive_fn │ IbcClosure │ -- │ C │ E10 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ ibc_packet_ack │ ibc_packet_ack_fn │ IbcClosure │ -- │ C │ E11 │ Q │ +/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ ibc_packet_timeout │ ibc_packet_timeout_fn │ IbcClosure │ -- │ C │ E12 │ Q │ +/// └─────────────────────┴────────────────────────┴─────────────────────┴─────────┴─────────┴───────┴───────┘ +/// ``` +/// The general schema depicting which generic type is used in entry points is shown below. +/// Entry point, when called, is provided minimum two arguments: custom query of type **Q** +/// (inside `Deps` or `DepsMut`) and input message of type **T1**, **T2**, **T3**, **T4**, +/// **Reply** or **T6**. As a result, entry point returns custom output message of type +/// Response<**C**> or **Binary** and an error of type **E1**, **E2**, **E3**, **E4**, **E5** +/// or **E6**. +/// +/// ```text +/// entry_point(query, .., message_in) -> Result +/// ┬ ┬ ┬ ┬ +/// Q >──┘ │ │ └──> E1,E2,E3,E4,E5,E6 +/// T1,T2,T3,T4,Reply,T6 >────┘ └─────────────> C,Binary +/// ``` +/// Generic type **C** defines a custom message that is specific for the **whole blockchain**. +/// Similarly, the generic type **Q** defines a custom query that is also specific +/// to the **whole blockchain**. Other generic types are specific to the implemented contract. +/// So all smart contracts used in the same blockchain will have the same types for **C** and **Q**, +/// but each contract may use different type for other generic types. +/// It means that e.g. **T1** in smart contract `A` may differ from **T1** in smart contract `B`. +/// +/// [execute]: Contract::execute +/// [instantiate]: Contract::instantiate +/// [query]: Contract::query +/// [sudo]: Contract::sudo +/// [reply]: Contract::reply +/// [migrate]: Contract::migrate +pub struct ContractWrapper< + T1, + T2, + T3, + E1, + E2, + E3, + C = Empty, + Q = Empty, + T4 = Empty, + E4 = AnyError, + E5 = AnyError, + T6 = Empty, + E6 = AnyError, + E7 = AnyError, + E8 = AnyError, + E9 = AnyError, + E10 = AnyError, + E11 = AnyError, + E12 = AnyError, +> where + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point. + E7: Display + Debug + Send + Sync, // Type of error returned from `channel_open` entry-point. + E8: Display + Debug + Send + Sync, // Type of error returned from `channel_connect` entry-point. + E9: Display + Debug + Send + Sync, // Type of error returned from `channel_close` entry-point. + E10: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_receive` entry-point. + E11: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_ack` entry-point. + E12: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_timeout` entry-point. + C: CustomMsg, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points. +{ + execute_fn: ContractClosure, + instantiate_fn: ContractClosure, + query_fn: QueryClosure, + sudo_fn: Option>, + reply_fn: Option>, + migrate_fn: Option>, + checksum: Option, + + channel_open_fn: Option>, + channel_connect_fn: Option, E8, Q>>, + channel_close_fn: Option, E9, Q>>, + + ibc_packet_receive_fn: Option, E10, Q>>, + ibc_packet_ack_fn: Option, E11, Q>>, + ibc_packet_timeout_fn: Option, E12, Q>>, +} + +impl ContractWrapper +where + T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. +{ + /// Creates a new contract wrapper with default settings. + pub fn new( + execute_fn: ContractFn, + instantiate_fn: ContractFn, + query_fn: QueryFn, + ) -> Self { + Self { + execute_fn: Box::new(execute_fn), + instantiate_fn: Box::new(instantiate_fn), + query_fn: Box::new(query_fn), + sudo_fn: None, + reply_fn: None, + migrate_fn: None, + checksum: None, + + channel_open_fn: None, + channel_connect_fn: None, + channel_close_fn: None, + + ibc_packet_receive_fn: None, + ibc_packet_ack_fn: None, + ibc_packet_timeout_fn: None, + } + } + + /// This will take a contract that returns `Response` and will _upgrade_ it + /// to `Response` if needed, to be compatible with a chain-specific extension. + pub fn new_with_empty( + execute_fn: ContractFn, + instantiate_fn: ContractFn, + query_fn: QueryFn, + ) -> Self { + Self { + execute_fn: customize_contract_fn(execute_fn), + instantiate_fn: customize_contract_fn(instantiate_fn), + query_fn: customize_query_fn(query_fn), + sudo_fn: None, + reply_fn: None, + migrate_fn: None, + checksum: None, + + channel_open_fn: None, + channel_connect_fn: None, + channel_close_fn: None, + + ibc_packet_receive_fn: None, + ibc_packet_ack_fn: None, + ibc_packet_timeout_fn: None, + } + } +} + +#[allow(clippy::type_complexity)] +impl + ContractWrapper +where + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. +{ + /// Populates [ContractWrapper] with contract's `sudo` entry-point and custom message type. + pub fn with_sudo( + self, + sudo_fn: PermissionedFn, + ) -> ContractWrapper + where + T4A: DeserializeOwned + 'static, + E4A: Display + Debug + Send + Sync + 'static, + { + ContractWrapper { + execute_fn: self.execute_fn, + instantiate_fn: self.instantiate_fn, + query_fn: self.query_fn, + sudo_fn: Some(Box::new(sudo_fn)), + reply_fn: self.reply_fn, + migrate_fn: self.migrate_fn, + checksum: None, + + channel_open_fn: self.channel_open_fn, + channel_connect_fn: self.channel_connect_fn, + channel_close_fn: self.channel_close_fn, + + ibc_packet_receive_fn: self.ibc_packet_receive_fn, + ibc_packet_ack_fn: self.ibc_packet_ack_fn, + ibc_packet_timeout_fn: self.ibc_packet_timeout_fn, + } + } + + /// Populates [ContractWrapper] with contract's `sudo` entry-point and `Empty` as a custom message. + pub fn with_sudo_empty( + self, + sudo_fn: PermissionedFn, + ) -> ContractWrapper + where + T4A: DeserializeOwned + 'static, + E4A: Display + Debug + Send + Sync + 'static, + { + ContractWrapper { + execute_fn: self.execute_fn, + instantiate_fn: self.instantiate_fn, + query_fn: self.query_fn, + sudo_fn: Some(customize_permissioned_fn(sudo_fn)), + reply_fn: self.reply_fn, + migrate_fn: self.migrate_fn, + checksum: None, + + channel_open_fn: self.channel_open_fn, + channel_connect_fn: self.channel_connect_fn, + channel_close_fn: self.channel_close_fn, + + ibc_packet_receive_fn: self.ibc_packet_receive_fn, + ibc_packet_ack_fn: self.ibc_packet_ack_fn, + ibc_packet_timeout_fn: self.ibc_packet_timeout_fn, + } + } + + /// Populates [ContractWrapper] with contract's `reply` entry-point and custom message type. + pub fn with_reply( + self, + reply_fn: ReplyFn, + ) -> ContractWrapper + where + E5A: Display + Debug + Send + Sync + 'static, + { + ContractWrapper { + execute_fn: self.execute_fn, + instantiate_fn: self.instantiate_fn, + query_fn: self.query_fn, + sudo_fn: self.sudo_fn, + reply_fn: Some(Box::new(reply_fn)), + migrate_fn: self.migrate_fn, + checksum: None, + + channel_open_fn: self.channel_open_fn, + channel_connect_fn: self.channel_connect_fn, + channel_close_fn: self.channel_close_fn, + + ibc_packet_receive_fn: self.ibc_packet_receive_fn, + ibc_packet_ack_fn: self.ibc_packet_ack_fn, + ibc_packet_timeout_fn: self.ibc_packet_timeout_fn, + } + } + + /// Populates [ContractWrapper] with contract's `reply` entry-point and `Empty` as a custom message. + pub fn with_reply_empty( + self, + reply_fn: ReplyFn, + ) -> ContractWrapper + where + E5A: Display + Debug + Send + Sync + 'static, + { + ContractWrapper { + execute_fn: self.execute_fn, + instantiate_fn: self.instantiate_fn, + query_fn: self.query_fn, + sudo_fn: self.sudo_fn, + reply_fn: Some(customize_permissioned_fn(reply_fn)), + migrate_fn: self.migrate_fn, + checksum: None, + + channel_open_fn: self.channel_open_fn, + channel_connect_fn: self.channel_connect_fn, + channel_close_fn: self.channel_close_fn, + + ibc_packet_receive_fn: self.ibc_packet_receive_fn, + ibc_packet_ack_fn: self.ibc_packet_ack_fn, + ibc_packet_timeout_fn: self.ibc_packet_timeout_fn, + } + } + + /// Populates [ContractWrapper] with contract's `migrate` entry-point and custom message type. + pub fn with_migrate( + self, + migrate_fn: PermissionedFn, + ) -> ContractWrapper + where + T6A: DeserializeOwned + 'static, + E6A: Display + Debug + Send + Sync + 'static, + { + ContractWrapper { + execute_fn: self.execute_fn, + instantiate_fn: self.instantiate_fn, + query_fn: self.query_fn, + sudo_fn: self.sudo_fn, + reply_fn: self.reply_fn, + migrate_fn: Some(Box::new(migrate_fn)), + checksum: None, + + channel_open_fn: self.channel_open_fn, + channel_connect_fn: self.channel_connect_fn, + channel_close_fn: self.channel_close_fn, + + ibc_packet_receive_fn: self.ibc_packet_receive_fn, + ibc_packet_ack_fn: self.ibc_packet_ack_fn, + ibc_packet_timeout_fn: self.ibc_packet_timeout_fn, + } + } + + /// Populates [ContractWrapper] with contract's `migrate` entry-point and `Empty` as a custom message. + pub fn with_migrate_empty( + self, + migrate_fn: PermissionedFn, + ) -> ContractWrapper + where + T6A: DeserializeOwned + 'static, + E6A: Display + Debug + Send + Sync + 'static, + { + ContractWrapper { + execute_fn: self.execute_fn, + instantiate_fn: self.instantiate_fn, + query_fn: self.query_fn, + sudo_fn: self.sudo_fn, + reply_fn: self.reply_fn, + migrate_fn: Some(customize_permissioned_fn(migrate_fn)), + checksum: None, + + channel_open_fn: self.channel_open_fn, + channel_connect_fn: self.channel_connect_fn, + channel_close_fn: self.channel_close_fn, + + ibc_packet_receive_fn: self.ibc_packet_receive_fn, + ibc_packet_ack_fn: self.ibc_packet_ack_fn, + ibc_packet_timeout_fn: self.ibc_packet_timeout_fn, + } + } + + /// Populates [ContractWrapper] with the provided checksum of the contract's Wasm blob. + pub fn with_checksum(mut self, checksum: Checksum) -> Self { + self.checksum = Some(checksum); + self + } + + /// Adding IBC endpoint capabilities + pub fn with_ibc( + self, + channel_open_fn: IbcFn, + channel_connect_fn: IbcFn, E8A, Q>, + channel_close_fn: IbcFn, E9A, Q>, + + ibc_packet_receive_fn: IbcFn, E10A, Q>, + ibc_packet_ack_fn: IbcFn, E11A, Q>, + ibc_packet_timeout_fn: IbcFn, E12A, Q>, + ) -> ContractWrapper< + T1, + T2, + T3, + E1, + E2, + E3, + C, + Q, + T4, + E4, + E5, + T6, + E6, + E7A, + E8A, + E9A, + E10A, + E11A, + E12A, + > + where + E7A: Display + Debug + Send + Sync + 'static, + E8A: Display + Debug + Send + Sync + 'static, + E9A: Display + Debug + Send + Sync + 'static, + E10A: Display + Debug + Send + Sync + 'static, + E11A: Display + Debug + Send + Sync + 'static, + E12A: Display + Debug + Send + Sync + 'static, + { + ContractWrapper { + execute_fn: self.execute_fn, + instantiate_fn: self.instantiate_fn, + query_fn: self.query_fn, + sudo_fn: self.sudo_fn, + reply_fn: self.reply_fn, + migrate_fn: self.migrate_fn, + checksum: None, + + channel_open_fn: Some(Box::new(channel_open_fn)), + channel_connect_fn: Some(Box::new(channel_connect_fn)), + channel_close_fn: Some(Box::new(channel_close_fn)), + + ibc_packet_receive_fn: Some(Box::new(ibc_packet_receive_fn)), + ibc_packet_ack_fn: Some(Box::new(ibc_packet_ack_fn)), + ibc_packet_timeout_fn: Some(Box::new(ibc_packet_timeout_fn)), + } + } +} + +fn customize_contract_fn( + raw_fn: ContractFn, +) -> ContractClosure +where + T: DeserializeOwned + 'static, + E: Display + Debug + Send + Sync + 'static, + C: CustomMsg, + Q: CustomQuery + DeserializeOwned, +{ + Box::new( + move |mut deps: DepsMut, + env: Env, + info: MessageInfo, + msg: T| + -> Result, E> { + let deps = decustomize_deps_mut(&mut deps); + raw_fn(deps, env, info, msg).map(customize_response::) + }, + ) +} + +fn customize_query_fn(raw_fn: QueryFn) -> QueryClosure +where + T: DeserializeOwned + 'static, + E: Display + Debug + Send + Sync + 'static, + Q: CustomQuery + DeserializeOwned, +{ + Box::new( + move |deps: Deps, env: Env, msg: T| -> Result { + let deps = decustomize_deps(&deps); + raw_fn(deps, env, msg) + }, + ) +} + +fn customize_permissioned_fn( + raw_fn: PermissionedFn, +) -> PermissionedClosure +where + T: DeserializeOwned + 'static, + E: Display + Debug + Send + Sync + 'static, + C: CustomMsg, + Q: CustomQuery + DeserializeOwned, +{ + Box::new( + move |mut deps: DepsMut, env: Env, msg: T| -> Result, E> { + let deps = decustomize_deps_mut(&mut deps); + raw_fn(deps, env, msg).map(customize_response::) + }, + ) +} + +fn decustomize_deps_mut<'a, Q>(deps: &'a mut DepsMut) -> DepsMut<'a, Empty> +where + Q: CustomQuery + DeserializeOwned, +{ + DepsMut { + storage: deps.storage, + api: deps.api, + querier: QuerierWrapper::new(deps.querier.deref()), + } +} + +fn decustomize_deps<'a, Q>(deps: &'a Deps<'a, Q>) -> Deps<'a, Empty> +where + Q: CustomQuery + DeserializeOwned, +{ + Deps { + storage: deps.storage, + api: deps.api, + querier: QuerierWrapper::new(deps.querier.deref()), + } +} + +fn customize_response(resp: Response) -> Response +where + C: CustomMsg, +{ + let mut customized_resp = Response::::new() + .add_submessages(resp.messages.into_iter().map(customize_msg::)) + .add_events(resp.events) + .add_attributes(resp.attributes); + customized_resp.data = resp.data; + customized_resp +} + +fn customize_msg(msg: SubMsg) -> SubMsg +where + C: CustomMsg, +{ + SubMsg { + id: msg.id, + payload: Binary::default(), + msg: match msg.msg { + CosmosMsg::Wasm(wasm) => CosmosMsg::Wasm(wasm), + CosmosMsg::Bank(bank) => CosmosMsg::Bank(bank), + CosmosMsg::Staking(staking) => CosmosMsg::Staking(staking), + CosmosMsg::Distribution(distribution) => CosmosMsg::Distribution(distribution), + CosmosMsg::Custom(_) => unreachable!(), + CosmosMsg::Ibc(ibc) => CosmosMsg::Ibc(ibc), + #[cfg(feature = "cosmwasm_2_0")] + CosmosMsg::Any(any) => CosmosMsg::Any(any), + _ => panic!("unknown message variant {:?}", msg), + }, + gas_limit: msg.gas_limit, + reply_on: msg.reply_on, + } +} + +impl Contract + for ContractWrapper +where + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. + E7: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_open` entry-point. + E8: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_connect` entry-point. + E9: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_close` entry-point. + E10: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_receive` entry-point. + E11: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_ack` entry-point. + E12: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_timeout` entry-point. + C: CustomMsg, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points. +{ + /// Calls [execute] on wrapped [Contract] trait implementor. + /// + /// [execute]: Contract::execute + fn execute( + &self, + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: Vec, + ) -> AnyResult> { + let msg: T1 = from_json(msg)?; + (self.execute_fn)(deps, env, info, msg).map_err(|err: E1| anyhow!(err)) + } + + /// Calls [instantiate] on wrapped [Contract] trait implementor. + /// + /// [instantiate]: Contract::instantiate + fn instantiate( + &self, + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: Vec, + ) -> AnyResult> { + let msg: T2 = from_json(msg)?; + (self.instantiate_fn)(deps, env, info, msg).map_err(|err: E2| anyhow!(err)) + } + + /// Calls [query] on wrapped [Contract] trait implementor. + /// + /// [query]: Contract::query + fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { + let msg: T3 = from_json(msg)?; + (self.query_fn)(deps, env, msg).map_err(|err: E3| anyhow!(err)) + } + + /// Calls [sudo] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [sudo]. + /// + /// [sudo]: Contract::sudo + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + let msg: T4 = from_json(msg)?; + match &self.sudo_fn { + Some(sudo) => sudo(deps, env, msg).map_err(|err: E4| anyhow!(err)), + None => bail!("sudo is not implemented for contract"), + } + } + + /// Calls [reply] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [reply]. + /// + /// [reply]: Contract::reply + fn reply(&self, deps: DepsMut, env: Env, reply_data: Reply) -> AnyResult> { + let msg: Reply = reply_data; + match &self.reply_fn { + Some(reply) => reply(deps, env, msg).map_err(|err: E5| anyhow!(err)), + None => bail!("reply is not implemented for contract"), + } + } + + /// Calls [migrate] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [migrate]. + /// + /// [migrate]: Contract::migrate + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + let msg: T6 = from_json(msg)?; + match &self.migrate_fn { + Some(migrate) => migrate(deps, env, msg).map_err(|err: E6| anyhow!(err)), + None => bail!("migrate is not implemented for contract"), + } + } + + /// Returns the provided checksum of the contract's Wasm blob. + fn checksum(&self) -> Option { + self.checksum + } + + fn ibc_channel_open( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelOpenMsg, + ) -> AnyResult { + match &self.channel_open_fn { + Some(channel_open) => channel_open(deps, env, msg).map_err(|err| anyhow!(err)), + None => bail!("channel open not implemented for contract"), + } + } + fn ibc_channel_connect( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelConnectMsg, + ) -> AnyResult> { + match &self.channel_connect_fn { + Some(channel_connect) => channel_connect(deps, env, msg).map_err(|err| anyhow!(err)), + None => bail!("channel connect not implemented for contract"), + } + } + fn ibc_channel_close( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelCloseMsg, + ) -> AnyResult> { + match &self.channel_close_fn { + Some(channel_close) => channel_close(deps, env, msg).map_err(|err| anyhow!(err)), + None => bail!("channel close not implemented for contract"), + } + } + + fn ibc_packet_receive( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketReceiveMsg, + ) -> AnyResult> { + match &self.ibc_packet_receive_fn { + Some(packet_receive) => packet_receive(deps, env, msg).map_err(|err| anyhow!(err)), + None => bail!("packet receive not implemented for contract"), + } + } + fn ibc_packet_acknowledge( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketAckMsg, + ) -> AnyResult> { + match &self.ibc_packet_ack_fn { + Some(packet_ack) => packet_ack(deps, env, msg).map_err(|err| anyhow!(err)), + None => bail!("packet ack not implemented for contract"), + } + } + fn ibc_packet_timeout( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketTimeoutMsg, + ) -> AnyResult> { + match &self.ibc_packet_timeout_fn { + Some(packet_timeout) => packet_timeout(deps, env, msg).map_err(|err| anyhow!(err)), + None => bail!("packet timeout not implemented for contract"), + } + } +} + +#[cfg(feature = "mock")] +pub mod cw_multi_test_impl { + use super::*; + pub struct BoxedContractWrapper(Box>); + + impl From>> for BoxedContractWrapper { + fn from(value: Box>) -> Self { + Self(value) + } + } + + impl cw_multi_test::Contract for BoxedContractWrapper + where + C: CustomMsg, + Q: CustomQuery + DeserializeOwned, + { + fn execute( + &self, + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: Vec, + ) -> AnyResult> { + Contract::::execute(self.0.as_ref(), deps, env, info, msg) + } + + fn instantiate( + &self, + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: Vec, + ) -> AnyResult> { + Contract::::instantiate(self.0.as_ref(), deps, env, info, msg) + } + + fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { + Contract::::query(self.0.as_ref(), deps, env, msg) + } + + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + Contract::::sudo(self.0.as_ref(), deps, env, msg) + } + + fn reply(&self, deps: DepsMut, env: Env, reply_data: Reply) -> AnyResult> { + Contract::::reply(self.0.as_ref(), deps, env, reply_data) + } + + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + Contract::::migrate(self.0.as_ref(), deps, env, msg) + } + + fn checksum(&self) -> Option { + Contract::::checksum(self.0.as_ref()) + } + + fn ibc_channel_open( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelOpenMsg, + ) -> AnyResult { + Contract::::ibc_channel_open(self.0.as_ref(), deps, env, msg) + } + fn ibc_channel_connect( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelConnectMsg, + ) -> AnyResult> { + Contract::::ibc_channel_connect(self.0.as_ref(), deps, env, msg) + } + fn ibc_channel_close( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelCloseMsg, + ) -> AnyResult> { + Contract::::ibc_channel_close(self.0.as_ref(), deps, env, msg) + } + + fn ibc_packet_receive( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketReceiveMsg, + ) -> AnyResult> { + Contract::::ibc_packet_receive(self.0.as_ref(), deps, env, msg) + } + fn ibc_packet_acknowledge( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketAckMsg, + ) -> AnyResult> { + Contract::::ibc_packet_acknowledge(self.0.as_ref(), deps, env, msg) + } + fn ibc_packet_timeout( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketTimeoutMsg, + ) -> AnyResult> { + Contract::::ibc_packet_timeout(self.0.as_ref(), deps, env, msg) + } + } + + impl Contract + for cw_multi_test::ContractWrapper< + T1, + T2, + T3, + E1, + E2, + E3, + C, + Q, + T4, + E4, + E5, + T6, + E6, + E7, + E8, + E9, + E10, + E11, + E12, + > + where + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. + E7: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_open` entry-point. + E8: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_connect` entry-point. + E9: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_close` entry-point. + E10: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_receive` entry-point. + E11: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_ack` entry-point. + E12: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_timeout` entry-point. + C: CustomMsg, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points. + { + fn execute( + &self, + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: Vec, + ) -> AnyResult> { + >::execute(self, deps, env, info, msg) + } + + fn instantiate( + &self, + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: Vec, + ) -> AnyResult> { + >::instantiate(self, deps, env, info, msg) + } + + fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { + >::query(self, deps, env, msg) + } + + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + >::sudo(self, deps, env, msg) + } + + fn reply(&self, deps: DepsMut, env: Env, reply_data: Reply) -> AnyResult> { + >::reply(self, deps, env, reply_data) + } + + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + >::migrate(self, deps, env, msg) + } + + fn checksum(&self) -> Option { + >::checksum(self) + } + + fn ibc_channel_open( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelOpenMsg, + ) -> AnyResult { + >::ibc_channel_open(self, deps, env, msg) + } + fn ibc_channel_connect( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelConnectMsg, + ) -> AnyResult> { + >::ibc_channel_connect(self, deps, env, msg) + } + fn ibc_channel_close( + &self, + deps: DepsMut, + env: Env, + msg: IbcChannelCloseMsg, + ) -> AnyResult> { + >::ibc_channel_close(self, deps, env, msg) + } + + fn ibc_packet_receive( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketReceiveMsg, + ) -> AnyResult> { + >::ibc_packet_receive(self, deps, env, msg) + } + fn ibc_packet_acknowledge( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketAckMsg, + ) -> AnyResult> { + >::ibc_packet_acknowledge(self, deps, env, msg) + } + fn ibc_packet_timeout( + &self, + deps: DepsMut, + env: Env, + msg: IbcPacketTimeoutMsg, + ) -> AnyResult> { + >::ibc_packet_timeout(self, deps, env, msg) + } + } +} diff --git a/packages/cw-orch-core/src/environment/index_response.rs b/packages/cw-orch-core/src/environment/index_response.rs index dfe6029c6..728d08888 100644 --- a/packages/cw-orch-core/src/environment/index_response.rs +++ b/packages/cw-orch-core/src/environment/index_response.rs @@ -1,5 +1,4 @@ use cosmwasm_std::{Addr, Binary, Event, StdError, StdResult}; -use cw_multi_test::AppResponse; #[cfg(feature = "eth")] use snailquote::unescape; @@ -71,6 +70,37 @@ pub trait IndexResponse { } } +/// Cloned from cosmwasm/cw_multi_test +/// A subset of data returned as a response of a contract entry point, +/// such as `instantiate`, `execute` or `migrate`. +#[derive(Default, Clone, Debug)] +pub struct AppResponse { + /// Response events. + pub events: Vec, + /// Response data. + pub data: Option, +} + +#[cfg(feature = "mock")] +impl From for AppResponse { + fn from(value: cw_multi_test::AppResponse) -> Self { + Self { + events: value.events, + data: value.data, + } + } +} + +#[cfg(feature = "mock")] +impl From for cw_multi_test::AppResponse { + fn from(value: AppResponse) -> Self { + Self { + events: value.events, + data: value.data, + } + } +} + impl IndexResponse for AppResponse { fn events(&self) -> Vec { self.events.clone() @@ -115,11 +145,10 @@ impl IndexResponse for AppResponse { #[cfg(test)] mod index_response_test { use cosmwasm_std::{Addr, Event}; - use cw_multi_test::AppResponse; use speculoos::prelude::*; - use super::IndexResponse; + use super::{AppResponse, IndexResponse}; const CONTRACT_ADDRESS: &str = "cosmos1fd68ah02gr2y8ze7tm9te7m70zlmc7vjyyhs6xlhsdmqqcjud4dql4wpxr"; diff --git a/packages/cw-orch-core/src/environment/mod.rs b/packages/cw-orch-core/src/environment/mod.rs index fc1202720..975bdc7d1 100644 --- a/packages/cw-orch-core/src/environment/mod.rs +++ b/packages/cw-orch-core/src/environment/mod.rs @@ -7,7 +7,7 @@ mod tx_handler; pub use chain_info::{ChainInfo, ChainInfoOwned, ChainKind, NetworkInfo, NetworkInfoOwned}; pub use envs::{BankSetter, CwEnv, Environment, MutCwEnv}; -pub use index_response::IndexResponse; +pub use index_response::{AppResponse, IndexResponse}; pub use queriers::{ bank::BankQuerier, env::{EnvironmentInfo, EnvironmentQuerier}, diff --git a/packages/cw-orch-core/src/environment/tx_handler.rs b/packages/cw-orch-core/src/environment/tx_handler.rs index fed8761a9..265f1d497 100644 --- a/packages/cw-orch-core/src/environment/tx_handler.rs +++ b/packages/cw-orch-core/src/environment/tx_handler.rs @@ -133,9 +133,8 @@ impl From for cosmos_sdk_proto::cosmwasm::wasm::v1::AccessConfig { #[cfg(test)] mod tests { use cosmwasm_std::Empty; - use cw_multi_test::AppResponse; - use crate::environment::StateInterface; + use crate::{environment::StateInterface, AppResponse}; use super::*; diff --git a/packages/cw-orch-core/src/error.rs b/packages/cw-orch-core/src/error.rs index 2a91f11f2..e3bef86d9 100644 --- a/packages/cw-orch-core/src/error.rs +++ b/packages/cw-orch-core/src/error.rs @@ -6,7 +6,7 @@ use std::{ str::ParseBoolError, }; -use cosmwasm_std::Instantiate2AddressError; +use cosmwasm_std::{Instantiate2AddressError, StdError}; use thiserror::Error; /// cw-orchestrator error wrapper using thiserror. @@ -64,3 +64,9 @@ impl CwEnvError { } } } + +impl From for StdError { + fn from(val: CwEnvError) -> Self { + StdError::generic_err(val.to_string()) + } +} diff --git a/packages/cw-orch-core/src/lib.rs b/packages/cw-orch-core/src/lib.rs index 07b6f2bd8..f9f395364 100644 --- a/packages/cw-orch-core/src/lib.rs +++ b/packages/cw-orch-core/src/lib.rs @@ -3,6 +3,8 @@ pub mod env; pub use env::CoreEnvVars; pub mod environment; +pub use environment::AppResponse; + pub mod build; mod error; pub mod log; diff --git a/packages/cw-orch-mock/Cargo.toml b/packages/cw-orch-mock/Cargo.toml index 0c4f06fd4..a106bb835 100644 --- a/packages/cw-orch-mock/Cargo.toml +++ b/packages/cw-orch-mock/Cargo.toml @@ -10,8 +10,8 @@ description = "Adapter for interacting with cw-multi-test via the cw-orchestrato # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cw-orch-core = { workspace = true } -cosmwasm-std = { workspace = true, features = ["cosmwasm_1_2"] } +cw-orch-core = { workspace = true, features = ["mock"] } +cosmwasm-std = { workspace = true } cw-multi-test = { workspace = true } cw-utils = { workspace = true } serde = { workspace = true } diff --git a/packages/cw-orch-mock/src/core.rs b/packages/cw-orch-mock/src/core.rs index 9d376a489..b057c196a 100644 --- a/packages/cw-orch-mock/src/core.rs +++ b/packages/cw-orch-mock/src/core.rs @@ -5,16 +5,16 @@ use cosmwasm_std::{ to_json_binary, Addr, Api, Binary, CosmosMsg, Empty, Event, WasmMsg, }; use cw_multi_test::{ - ibc::IbcSimpleModule, App, AppResponse, BankKeeper, Contract, DistributionKeeper, Executor, - FailingModule, GovFailingModule, MockApiBech32, StakeKeeper, StargateFailing, WasmKeeper, + ibc::IbcSimpleModule, App, BankKeeper, DistributionKeeper, Executor, FailingModule, + GovFailingModule, MockApiBech32, StakeKeeper, StargateFailing, WasmKeeper, }; use serde::Serialize; use super::state::MockState; use cw_orch_core::{ - contract::interface_traits::Uploadable, + contract::{interface_traits::Uploadable, BoxedContractWrapper, MockContract}, environment::{AccessConfig, ChainState, IndexResponse, StateInterface, TxHandler}, - CwEnvError, + AppResponse, CwEnvError, }; pub type MockApp = App< @@ -104,9 +104,11 @@ impl MockBase { pub fn upload_custom( &self, contract_id: &str, - wrapper: Box>, + wrapper: Box>, ) -> Result { - let code_id = self.app.borrow_mut().store_code(wrapper); + let boxed_wrapper: BoxedContractWrapper = wrapper.into(); + + let code_id = self.app.borrow_mut().store_code(Box::new(boxed_wrapper)); // add contract code_id to events manually let mut event = Event::new("store_code"); event = event.add_attribute("code_id", code_id.to_string()); @@ -131,7 +133,7 @@ impl ChainState for MockBase { impl TxHandler for MockBase { type Response = AppResponse; type Error = CwEnvError; - type ContractSource = Box>; + type ContractSource = Box>; type Sender = Addr; fn sender(&self) -> &Self::Sender { @@ -147,7 +149,8 @@ impl TxHandler for MockBase { } fn upload(&self, _contract: &T) -> Result { - let code_id = self.app.borrow_mut().store_code(T::wrapper()); + let boxed_wrapper: BoxedContractWrapper = T::wrapper().into(); + let code_id = self.app.borrow_mut().store_code(Box::new(boxed_wrapper)); // add contract code_id to events manually let mut event = Event::new("store_code"); event = event.add_attribute("code_id", code_id.to_string()); @@ -173,6 +176,7 @@ impl TxHandler for MockBase { coins, ) .map_err(From::from) + .map(Into::into) } fn instantiate( @@ -247,6 +251,7 @@ impl TxHandler for MockBase { new_code_id, ) .map_err(From::from) + .map(Into::into) } fn upload_with_access_config( diff --git a/packages/cw-orch-mock/src/queriers/node.rs b/packages/cw-orch-mock/src/queriers/node.rs index f8c5d8af4..07044759f 100644 --- a/packages/cw-orch-mock/src/queriers/node.rs +++ b/packages/cw-orch-mock/src/queriers/node.rs @@ -1,10 +1,9 @@ use std::{cell::RefCell, rc::Rc}; use cosmwasm_std::Api; -use cw_multi_test::AppResponse; use cw_orch_core::{ environment::{NodeQuerier, Querier, QuerierGetter, StateInterface}, - CwEnvError, + AppResponse, CwEnvError, }; use crate::{core::MockApp, MockBase}; diff --git a/packages/cw-orch-neutron-test-tube/src/core.rs b/packages/cw-orch-neutron-test-tube/src/core.rs index 13dfbbcbb..ca28f8f6e 100644 --- a/packages/cw-orch-neutron-test-tube/src/core.rs +++ b/packages/cw-orch-neutron-test-tube/src/core.rs @@ -7,8 +7,7 @@ use cw_orch_core::contract::WasmPath; use cw_orch_core::environment::{BankQuerier, BankSetter, ChainInfo, DefaultQueriers, NetworkInfo}; use cosmwasm_std::{Binary, Coin, Uint128}; -use cw_orch_core::CwEnvError; -use cw_orch_mock::cw_multi_test::AppResponse; +use cw_orch_core::{AppResponse, CwEnvError}; use neutron_test_tube::{ neutron_std::{cosmwasm_to_proto_coins, types::cosmos::bank::v1beta1::MsgSend}, Account, Bank, Module, NeutronTestApp, Runner, RunnerError, SigningAccount, Wasm, diff --git a/packages/cw-orch-neutron-test-tube/src/queriers/node.rs b/packages/cw-orch-neutron-test-tube/src/queriers/node.rs index a875ca0b0..3efe92373 100644 --- a/packages/cw-orch-neutron-test-tube/src/queriers/node.rs +++ b/packages/cw-orch-neutron-test-tube/src/queriers/node.rs @@ -4,9 +4,8 @@ use crate::NeutronTestTube; use cosmwasm_std::{BlockInfo, Timestamp}; use cw_orch_core::{ environment::{NodeQuerier, Querier, QuerierGetter, StateInterface}, - CwEnvError, + AppResponse, CwEnvError, }; -use cw_orch_mock::cw_multi_test::AppResponse; use neutron_test_tube::NeutronTestApp; pub struct NeutronTestTubeNodeQuerier { diff --git a/packages/cw-orch-on-chain/Cargo.toml b/packages/cw-orch-on-chain/Cargo.toml new file mode 100644 index 000000000..480599c9a --- /dev/null +++ b/packages/cw-orch-on-chain/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "cw-orch-on-chain" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +cw-orch-core = { workspace = true } +cosmwasm-std = { workspace = true } +serde.workspace = true +thiserror.workspace = true +cw-storage-plus.workspace = true diff --git a/packages/cw-orch-on-chain/src/core.rs b/packages/cw-orch-on-chain/src/core.rs new file mode 100644 index 000000000..5272af481 --- /dev/null +++ b/packages/cw-orch-on-chain/src/core.rs @@ -0,0 +1,443 @@ +use std::{ + cell::{Ref, RefCell, RefMut}, + collections::HashMap, + rc::Rc, +}; + +use cosmwasm_std::{ + instantiate2_address, to_json_binary, Addr, Api, Binary, Coin, CosmosMsg, Deps, DepsMut, Env, + QuerierWrapper, StdError, Storage, +}; +use cw_orch_core::environment::{ + BankQuerier, ChainState, DefaultQueriers, EnvironmentQuerier, IndexResponse, NodeQuerier, + Querier, QuerierGetter, QueryHandler, StateInterface, TxHandler, WasmQuerier, +}; +use cw_storage_plus::Item; +use serde::Serialize; + +use crate::error::OnChainError; + +#[derive(Clone)] +pub enum OnChainDeps<'a> { + Mut(Rc>>), + Ref(Rc>>), +} + +impl<'a> From> for OnChainDeps<'a> { + fn from(value: DepsMut<'a>) -> Self { + OnChainDeps::Mut(Rc::new(RefCell::new(value))) + } +} +impl<'a> From> for OnChainDeps<'a> { + fn from(value: Deps<'a>) -> Self { + OnChainDeps::Ref(Rc::new(RefCell::new(value))) + } +} + +impl<'a> OnChainDeps<'a> { + pub fn storage(&self) -> Ref<'_, dyn Storage> { + match self { + OnChainDeps::Mut(deps) => Ref::map(deps.borrow(), |deps| deps.storage), + OnChainDeps::Ref(deps) => Ref::map(deps.borrow(), |deps| deps.storage), + } + } + + pub fn storage_mut(&self) -> Result, StdError> { + match self { + OnChainDeps::Mut(deps) => Ok(RefMut::map(deps.borrow_mut(), |deps| deps.storage)), + OnChainDeps::Ref(_deps) => Err(StdError::generic_err( + "Can't access storage mut on ref deps", + )), + } + } + + pub fn querier(&self) -> Ref<'_, QuerierWrapper<'a>> { + match self { + OnChainDeps::Mut(deps) => Ref::map(deps.borrow(), |deps| &deps.querier), + OnChainDeps::Ref(deps) => Ref::map(deps.borrow(), |deps| &deps.querier), + } + } + + pub fn api(&self) -> Ref<'_, dyn Api> { + match self { + OnChainDeps::Mut(deps) => Ref::map(deps.borrow(), |deps| deps.api), + OnChainDeps::Ref(deps) => Ref::map(deps.borrow(), |deps| deps.api), + } + } +} + +#[derive(Clone)] +pub struct OnChain<'a> { + pub env: Env, + pub deps: OnChainDeps<'a>, + pub state: Rc>>, +} + +impl<'a> OnChain<'a> { + pub fn new(deps: impl Into>, env: &Env) -> OnChain<'a> { + OnChain { + env: env.clone(), + deps: deps.into(), + state: Rc::new(RefCell::new(HashMap::default())), + } + } +} + +#[derive(Clone, Debug)] +pub struct CwOrchCosmosMsg(pub CosmosMsg); + +impl From for CwOrchCosmosMsg { + fn from(value: CosmosMsg) -> Self { + Self(value) + } +} +impl From for CosmosMsg { + fn from(value: CwOrchCosmosMsg) -> Self { + value.0 + } +} + +impl IndexResponse for CwOrchCosmosMsg { + fn events(&self) -> Vec { + unimplemented!() + } + + fn event_attr_value( + &self, + _event_type: &str, + _attr_key: &str, + ) -> cosmwasm_std::StdResult { + unimplemented!() + } + + fn event_attr_values(&self, _event_type: &str, _attr_key: &str) -> Vec { + unimplemented!() + } + + fn data(&self) -> Option { + unimplemented!() + } +} + +#[derive(Clone)] +pub struct OnChainState<'a> { + pub deps: OnChainDeps<'a>, + pub state: Rc>>, +} + +impl<'a> StateInterface for OnChainState<'a> { + fn get_address(&self, contract_id: &str) -> Result { + let complete_contract_id = format!("cw-orch-on-chain-{}", contract_id); + let store = Item::::new_dyn(complete_contract_id.to_string()); + + self.state + .borrow() + .get(&complete_contract_id) + .cloned() + .ok_or(StdError::not_found(complete_contract_id)) + .or_else(|_| store.load(&*self.deps.storage())) + .map_err(Into::into) + } + + fn set_address(&mut self, contract_id: &str, address: &Addr) { + let complete_contract_id = format!("cw-orch-on-chain-{}", contract_id); + let store = Item::::new_dyn(complete_contract_id.to_string()); + + match self.deps.storage_mut() { + Ok(mut storage_mut) => { + store.save(&mut *(storage_mut), address).unwrap(); + } + Err(_) => { + self.state + .borrow_mut() + .insert(complete_contract_id, address.clone()); + } + } + } + + fn remove_address(&mut self, _contract_id: &str) { + todo!() + } + + fn get_code_id(&self, _contract_id: &str) -> Result { + todo!() + } + + fn set_code_id(&mut self, _contract_id: &str, _code_id: u64) { + todo!() + } + + fn remove_code_id(&mut self, _contract_id: &str) { + todo!() + } + + fn get_all_addresses( + &self, + ) -> Result, cw_orch_core::CwEnvError> { + todo!() + } + + fn get_all_code_ids( + &self, + ) -> Result, cw_orch_core::CwEnvError> { + todo!() + } +} + +impl<'a> ChainState for OnChain<'a> { + type Out = OnChainState<'a>; + + fn state(&self) -> Self::Out { + OnChainState { + deps: self.deps.clone(), + state: self.state.clone(), + } + } +} + +impl<'a> TxHandler for OnChain<'a> { + type Response = CwOrchCosmosMsg; + + type Error = OnChainError; + + type ContractSource = (); + + type Sender = Addr; + + fn sender(&self) -> &Self::Sender { + &self.env.contract.address + } + + fn sender_addr(&self) -> Addr { + self.env.contract.address.clone() + } + + fn set_sender(&mut self, _sender: Self::Sender) { + unimplemented!() + } + + fn upload( + &self, + _contract_source: &T, + ) -> Result { + unimplemented!("Upload not possible from on-chain") + } + + fn instantiate( + &self, + code_id: u64, + init_msg: &I, + label: Option<&str>, + admin: Option<&Addr>, + coins: &[cosmwasm_std::Coin], + ) -> Result { + Ok(CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Instantiate { + admin: admin.map(|a| a.to_string()), + code_id, + msg: to_json_binary(init_msg)?, + funds: coins.to_vec(), + label: label.unwrap_or("Instantiated with cw-orch").to_string(), + }) + .into()) + } + + fn instantiate2( + &self, + code_id: u64, + init_msg: &I, + label: Option<&str>, + admin: Option<&Addr>, + coins: &[cosmwasm_std::Coin], + salt: Binary, + ) -> Result { + Ok(CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Instantiate2 { + admin: admin.map(|a| a.to_string()), + code_id, + msg: to_json_binary(init_msg)?, + funds: coins.to_vec(), + label: label.unwrap_or("Instantiated with cw-orch").to_string(), + salt, + }) + .into()) + } + + fn execute( + &self, + exec_msg: &E, + coins: &[Coin], + contract_address: &Addr, + ) -> Result { + Ok(CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Execute { + contract_addr: contract_address.to_string(), + msg: to_json_binary(exec_msg)?, + funds: coins.to_vec(), + }) + .into()) + } + + fn migrate( + &self, + migrate_msg: &M, + new_code_id: u64, + contract_address: &Addr, + ) -> Result { + Ok(CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Migrate { + contract_addr: contract_address.to_string(), + msg: to_json_binary(migrate_msg)?, + new_code_id, + }) + .into()) + } +} + +impl<'a> QueryHandler for OnChain<'a> { + type Error = OnChainError; + + fn wait_blocks(&self, _amount: u64) -> Result<(), Self::Error> { + unimplemented!("You can't manipulate blocks, you're on-chain") + } + + fn wait_seconds(&self, _secs: u64) -> Result<(), Self::Error> { + unimplemented!("You can't manipulate time, you're on-chain") + } + + fn next_block(&self) -> Result<(), Self::Error> { + unimplemented!("You can't manipulate blocks, you're on-chain") + } +} + +impl<'a> Querier for OnChain<'a> { + type Error = OnChainError; +} + +impl<'a> QuerierGetter> for OnChain<'a> { + fn querier(&self) -> Self { + self.clone() + } +} + +impl<'a> DefaultQueriers for OnChain<'a> { + type Bank = OnChain<'a>; + + type Wasm = OnChain<'a>; + + type Node = OnChain<'a>; +} + +impl<'a> BankQuerier for OnChain<'a> { + fn balance(&self, _address: &Addr, _denom: Option) -> Result, Self::Error> { + todo!() + } + + fn total_supply(&self) -> Result, Self::Error> { + todo!() + } + + fn supply_of(&self, _denom: impl Into) -> Result { + todo!() + } +} + +impl<'a> WasmQuerier for OnChain<'a> { + type Chain = OnChain<'a>; + + fn code_id_hash(&self, code_id: u64) -> Result { + Ok(self.code(code_id)?.checksum) + } + + fn contract_info( + &self, + address: &Addr, + ) -> Result { + self.deps + .querier() + .query_wasm_contract_info(address) + .map_err(Into::into) + } + + fn raw_query(&self, address: &Addr, query_keys: Vec) -> Result, Self::Error> { + self.deps + .querier() + .query_wasm_raw(address, query_keys) + .map(|r| r.unwrap_or_default()) + .map_err(Into::into) + } + + fn smart_query( + &self, + address: &Addr, + query_msg: &Q, + ) -> Result { + self.deps + .querier() + .query_wasm_smart(address, query_msg) + .map_err(Into::into) + } + + fn code(&self, code_id: u64) -> Result { + self.deps + .querier() + .query_wasm_code_info(code_id) + .map_err(Into::into) + } + + fn local_hash< + T: cw_orch_core::contract::interface_traits::Uploadable + + cw_orch_core::contract::interface_traits::ContractInstance, + >( + &self, + _contract: &T, + ) -> Result { + unimplemented!() + } + + fn instantiate2_addr( + &self, + code_id: u64, + creator: &Addr, + salt: cosmwasm_std::Binary, + ) -> Result { + let checksum = self.code_id_hash(code_id)?; + let creator_canon = self.deps.api().addr_canonicalize(creator.as_str())?; + let canon = instantiate2_address(checksum.as_slice(), &creator_canon, salt.as_slice())?; + self.deps + .api() + .addr_humanize(&canon) + .map(|a| a.to_string()) + .map_err(Into::into) + } +} + +impl<'a> EnvironmentQuerier for OnChain<'a> { + fn env_info(&self) -> cw_orch_core::environment::EnvironmentInfo { + todo!() + } +} + +impl<'a> NodeQuerier for OnChain<'a> { + type Response = CwOrchCosmosMsg; + + fn latest_block(&self) -> Result { + todo!() + } + + fn block_by_height(&self, _height: u64) -> Result { + todo!() + } + + fn block_height(&self) -> Result { + todo!() + } + + fn block_time(&self) -> Result { + todo!() + } + + fn simulate_tx(&self, _tx_bytes: Vec) -> Result { + todo!() + } + + fn find_tx(&self, _hash: String) -> Result { + todo!() + } +} diff --git a/packages/cw-orch-on-chain/src/error.rs b/packages/cw-orch-on-chain/src/error.rs new file mode 100644 index 000000000..0aaf732e1 --- /dev/null +++ b/packages/cw-orch-on-chain/src/error.rs @@ -0,0 +1,26 @@ +#![allow(missing_docs)] + +use cosmwasm_std::StdError; +use cw_orch_core::CwEnvError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum OnChainError { + #[error(transparent)] + CosmwasmStd(#[from] cosmwasm_std::StdError), + + #[error(transparent)] + Instantiate2(#[from] cosmwasm_std::Instantiate2AddressError), +} + +impl From for CwEnvError { + fn from(val: OnChainError) -> Self { + CwEnvError::AnyError(val.into()) + } +} + +impl From for StdError { + fn from(val: OnChainError) -> Self { + StdError::generic_err(val.to_string()) + } +} diff --git a/packages/cw-orch-on-chain/src/lib.rs b/packages/cw-orch-on-chain/src/lib.rs new file mode 100644 index 000000000..f741f031c --- /dev/null +++ b/packages/cw-orch-on-chain/src/lib.rs @@ -0,0 +1,17 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} + +pub mod core; +pub mod error; diff --git a/packages/cw-orch-osmosis-test-tube/src/core.rs b/packages/cw-orch-osmosis-test-tube/src/core.rs index 447cebfb2..8b347b9b1 100644 --- a/packages/cw-orch-osmosis-test-tube/src/core.rs +++ b/packages/cw-orch-osmosis-test-tube/src/core.rs @@ -7,8 +7,7 @@ use cw_orch_core::contract::WasmPath; use cw_orch_core::environment::{BankQuerier, BankSetter, ChainInfo, DefaultQueriers, NetworkInfo}; use cosmwasm_std::{Binary, Coin, Uint128}; -use cw_orch_core::CwEnvError; -use cw_orch_mock::cw_multi_test::AppResponse; +use cw_orch_core::{AppResponse, CwEnvError}; use cw_orch_traits::Stargate; use osmosis_test_tube::{Account, Bank, Gamm, Module, Runner, RunnerError, SigningAccount, Wasm}; diff --git a/packages/cw-orch-osmosis-test-tube/src/queriers/node.rs b/packages/cw-orch-osmosis-test-tube/src/queriers/node.rs index 39863d308..e11a4aeb1 100644 --- a/packages/cw-orch-osmosis-test-tube/src/queriers/node.rs +++ b/packages/cw-orch-osmosis-test-tube/src/queriers/node.rs @@ -4,9 +4,8 @@ use crate::OsmosisTestTube; use cosmwasm_std::{BlockInfo, Timestamp}; use cw_orch_core::{ environment::{NodeQuerier, Querier, QuerierGetter, StateInterface}, - CwEnvError, + AppResponse, CwEnvError, }; -use cw_orch_mock::cw_multi_test::AppResponse; use osmosis_test_tube::OsmosisTestApp; pub struct OsmosisTestTubeNodeQuerier { diff --git a/packages/integrations/cw-plus/Cargo.toml b/packages/integrations/cw-plus/Cargo.toml index 940438667..31bb9e3c7 100644 --- a/packages/integrations/cw-plus/Cargo.toml +++ b/packages/integrations/cw-plus/Cargo.toml @@ -41,4 +41,4 @@ dotenv = "0.15.0" octocrab = "0.39.0" pretty_env_logger = "0.5.0" reqwest = "0.12.7" -tokio.workspace = true +async-std = { workspace = true } diff --git a/packages/integrations/cw-plus/examples/download_wasms.rs b/packages/integrations/cw-plus/examples/download_wasms.rs index 89f82d73b..bfe5d1ec2 100644 --- a/packages/integrations/cw-plus/examples/download_wasms.rs +++ b/packages/integrations/cw-plus/examples/download_wasms.rs @@ -16,7 +16,7 @@ pub const ALL_CONTRACTS: &[&str] = &[ "cw20_ics20", ]; -#[tokio::main] +#[async_std::main] async fn main() -> anyhow::Result<()> { let crate_dir = env!("CARGO_MANIFEST_DIR"); let artifacts_dir = PathBuf::from_str(crate_dir)?.join("artifacts"); diff --git a/packages/interchain/interchain-core/Cargo.toml b/packages/interchain/interchain-core/Cargo.toml index a9ce3f71c..287395553 100644 --- a/packages/interchain/interchain-core/Cargo.toml +++ b/packages/interchain/interchain-core/Cargo.toml @@ -28,7 +28,6 @@ prost = "0.13.1" serde_json = { workspace = true } serde = { workspace = true } thiserror = { workspace = true } -tokio = "1.39.2" tonic = { workspace = true, features = ["tls", "tls-roots"] } [dev-dependencies] diff --git a/packages/interchain/interchain-core/src/env.rs b/packages/interchain/interchain-core/src/env.rs index ba6ba0a56..cbcec148d 100644 --- a/packages/interchain/interchain-core/src/env.rs +++ b/packages/interchain/interchain-core/src/env.rs @@ -379,7 +379,7 @@ pub trait InterchainEnv: Clone { fn await_packets( &self, chain_id: ChainId, - tx_response: ::Response, + tx_response: impl Into<::Response>, ) -> Result, Self::Error>; /// Follow every IBC packets sent out during the transaction @@ -432,7 +432,7 @@ pub trait InterchainEnv: Clone { fn await_and_check_packets( &self, chain_id: ChainId, - tx_response: ::Response, + tx_response: impl Into<::Response>, ) -> Result, InterchainError> { let tx_result = self .await_packets(chain_id, tx_response) diff --git a/packages/interchain/interchain-daemon/Cargo.toml b/packages/interchain/interchain-daemon/Cargo.toml index 627d35b0b..e0bc231a4 100644 --- a/packages/interchain/interchain-daemon/Cargo.toml +++ b/packages/interchain/interchain-daemon/Cargo.toml @@ -16,8 +16,6 @@ repository.workspace = true cw-orch-daemon = { workspace = true } cw-orch-core = { workspace = true } -tokio = { workspace = true } - async-recursion = "1.1.1" base64 = "0.22.1" cosmwasm-schema = "2.1.3" @@ -37,6 +35,7 @@ cw-orch-interchain-core = { workspace = true, features = ["daemon"] } cw-orch-starship = { workspace = true } dialoguer = "0.11.0" cosmwasm-std = { workspace = true } +async-std = "1.13.0" [dev-dependencies] diff --git a/packages/interchain/interchain-daemon/examples/starship_channel.rs b/packages/interchain/interchain-daemon/examples/starship_channel.rs index da1060fac..1ff677e46 100644 --- a/packages/interchain/interchain-daemon/examples/starship_channel.rs +++ b/packages/interchain/interchain-daemon/examples/starship_channel.rs @@ -1,3 +1,4 @@ +use async_std::task::block_on; use cosmwasm_std::IbcOrder; use cw_orch_core::environment::QuerierGetter; use cw_orch_daemon::queriers::Ibc; @@ -17,7 +18,7 @@ fn assert_ordering( .interchain_channel .get_ordered_ports_from("juno-1")?; - let channel_info = juno.rt_handle.block_on(ibc_querier._channel( + let channel_info = block_on(ibc_querier._channel( channel.0.port.to_string(), channel.0.channel.unwrap().to_string(), ))?; diff --git a/packages/interchain/interchain-daemon/src/channel_creator.rs b/packages/interchain/interchain-daemon/src/channel_creator.rs index 524b0f884..aed4aa99b 100644 --- a/packages/interchain/interchain-daemon/src/channel_creator.rs +++ b/packages/interchain/interchain-daemon/src/channel_creator.rs @@ -1,3 +1,4 @@ +use async_std::task::block_on; use cosmwasm_std::IbcOrder; use cw_orch_interchain_core::env::ChainId; use cw_orch_starship::Starship; @@ -63,7 +64,7 @@ impl ChannelCreator for Starship { order: Option, ) -> Result { // The connection_id is decided upon automatically by starship and returned by the client - let connection_id = self.rt_handle.block_on(self.client().create_channel( + let connection_id = block_on(self.client().create_channel( src_chain, dst_chain, src_port.as_str(), diff --git a/packages/interchain/interchain-daemon/src/ibc_tracker.rs b/packages/interchain/interchain-daemon/src/ibc_tracker.rs index 52ccb6a35..62d94e507 100644 --- a/packages/interchain/interchain-daemon/src/ibc_tracker.rs +++ b/packages/interchain/interchain-daemon/src/ibc_tracker.rs @@ -12,7 +12,6 @@ use futures_util::future::join_all; use futures_util::stream::FuturesUnordered; use futures_util::StreamExt; use log::*; -use tokio::runtime::Handle; use std::collections::HashMap; use std::collections::HashSet; @@ -65,16 +64,16 @@ pub trait IbcTracker: ChannelAccess + Send + Sync + Clone { state.update_state(self.channel(), &chain_id).await?; debug!(target: &chain_id, "state updated"); } - tokio::time::sleep(config.log_interval).await; + async_std::task::sleep(config.log_interval).await; } } - fn detach_cron_log(self, rt: &Handle, config: IbcTrackerConfig) -> Result<(), Box> + fn detach_cron_log(self, config: IbcTrackerConfig) -> Result<(), Box> where S: 'static, Self: 'static, { - rt.spawn(async move { + async_std::task::spawn(async move { self.cron_log(config).await.unwrap(); }); Ok(()) @@ -102,7 +101,7 @@ impl> IbcPacketLogger for T { let channel = daemon.channel().clone(); - daemon.rt_handle.spawn(async move { + async_std::task::spawn(async move { channel.cron_log(config).await.unwrap(); }); Ok(()) diff --git a/packages/interchain/interchain-daemon/src/interchain_env.rs b/packages/interchain/interchain-daemon/src/interchain_env.rs index f7ed82fc8..9436c73da 100644 --- a/packages/interchain/interchain-daemon/src/interchain_env.rs +++ b/packages/interchain/interchain-daemon/src/interchain_env.rs @@ -1,13 +1,14 @@ use cosmwasm_std::IbcOrder; use cw_orch_core::environment::{ChainInfoOwned, ChainState, IndexResponse}; use cw_orch_daemon::queriers::{Ibc, Node}; -use cw_orch_daemon::{CosmTxResponse, Daemon, DaemonError, RUNTIME}; +use cw_orch_daemon::{CosmTxResponse, Daemon, DaemonError}; use cw_orch_interchain_core::channel::{IbcPort, InterchainChannel}; use cw_orch_interchain_core::env::{ChainId, ChannelCreation}; use cw_orch_interchain_core::{InterchainEnv, NestedPacketsFlow, SinglePacketFlow}; +use async_std::task::block_on; +use async_std::task::sleep; use ibc_relayer_types::core::ics04_channel::packet::Sequence; -use tokio::time::sleep; use tonic::transport::Channel; use crate::channel_creator::{ChannelCreationValidator, ChannelCreator}; @@ -24,7 +25,6 @@ use futures::future::try_join4; use std::collections::HashMap; use std::str::FromStr; use std::time::Duration; -use tokio::runtime::Handle; /// Represents a set of locally running blockchain nodes and a Hermes relayer. #[derive(Clone)] @@ -36,8 +36,6 @@ pub struct DaemonInterchain { // Allows logging on separate files log: Option, - - rt_handle: Handle, } impl DaemonInterchain { @@ -49,27 +47,11 @@ impl DaemonInterchain { where T: Into, { - Self::new_with_runtime(chains, channel_creator, RUNTIME.handle()) - } - - /// Builds a new [`DaemonInterchain`] instance. - /// For use with starship, we advise to use [`cw_orch_starship::Starship::interchain_env`] instead - /// channel_creator allows you to specify an object that is able to create channels - /// Use [`crate::ChannelCreationValidator`] for manual channel creations. - /// runtime allows you to control the async runtime (for advanced devs) - pub fn new_with_runtime( - chains: Vec, - channel_creator: &C, - runtime: &Handle, - ) -> IcDaemonResult - where - T: Into, - { - let mut env = Self::raw(runtime, channel_creator); + let mut env = Self::raw(channel_creator); // We create daemons for each chains for chain_data in chains { - env.build_daemon(runtime, chain_data.into(), None::)?; + env.build_daemon(chain_data.into(), None::)?; } Ok(env) @@ -79,42 +61,35 @@ impl DaemonInterchain { /// The `channel_creator` argument will be responsible for creation interchain channel /// If using starship, prefer using Starship::interchain_env for environment creation pub fn from_daemons(daemons: Vec, channel_creator: &C) -> Self { - let mut env = Self::raw(&daemons.first().unwrap().rt_handle, channel_creator); + let mut env = Self::raw(channel_creator); env.add_daemons(daemons); env } - fn raw(rt: &Handle, channel_creator: &C) -> Self { + fn raw(channel_creator: &C) -> Self { Self { daemons: HashMap::new(), channel_creator: channel_creator.clone(), log: None, - rt_handle: rt.clone(), } } /// Build a daemon from chain data and mnemonic and add it to the current configuration fn build_daemon( &mut self, - runtime: &Handle, chain_data: ChainInfoOwned, mnemonic: Option>, ) -> IcDaemonResult<()> { let mut daemon_builder = Daemon::builder(chain_data); - let mut daemon_builder = daemon_builder.handle(runtime); - daemon_builder = if let Some(mn) = mnemonic { - daemon_builder.mnemonic(mn) - } else { - daemon_builder - }; + if let Some(mn) = mnemonic { + daemon_builder.mnemonic(mn); + } // State is shared between daemons, so if a daemon already exists, we use its state - daemon_builder = if let Some(daemon) = self.daemons.values().next() { - daemon_builder.state(daemon.state()) - } else { - daemon_builder - }; + if let Some(daemon) = self.daemons.values().next() { + daemon_builder.state(daemon.state()); + } let daemon = daemon_builder.build().unwrap(); @@ -197,7 +172,7 @@ impl InterchainEnv for DaemonInterchain { let (src_port, dst_port) = ibc_channel.get_mut_ordered_ports_from(src_chain)?; // We start by getting the connection-id of the counterparty chain - let connection_end = self.rt_handle.block_on( + let connection_end = block_on( Ibc::new_async(src_port.chain.clone()) ._connection_end(src_port.connection_id.clone().unwrap()), )?; @@ -205,9 +180,7 @@ impl InterchainEnv for DaemonInterchain { dst_port.connection_id = Some(connection_end.unwrap().counterparty.unwrap().connection_id); // Then we make sure the channel is indeed created between the two chains - let channel_creation = self - .rt_handle - .block_on(self.find_channel_creation_tx(src_chain, ibc_channel))?; + let channel_creation = block_on(self.find_channel_creation_tx(src_chain, ibc_channel))?; let src_channel_id = channel_creation .ack @@ -240,8 +213,9 @@ impl InterchainEnv for DaemonInterchain { fn await_packets( &self, chain_id: ChainId, - tx_response: CosmTxResponse, + tx_response: impl Into, ) -> Result, Self::Error> { + let tx_response = tx_response.into(); log::info!( target: chain_id, "Investigating sent packet events on tx {}", @@ -249,14 +223,10 @@ impl InterchainEnv for DaemonInterchain { ); // We crate an interchain env object that is safe to send between threads - let interchain_env = self - .rt_handle - .block_on(PacketInspector::new(self.daemons.values().collect()))?; + let interchain_env = block_on(PacketInspector::new(self.daemons.values().collect()))?; // We follow the trail - let ibc_trail = self - .rt_handle - .block_on(interchain_env.wait_ibc(chain_id.to_string(), tx_response))?; + let ibc_trail = block_on(interchain_env.wait_ibc(chain_id.to_string(), tx_response))?; Ok(ibc_trail) } @@ -271,12 +241,10 @@ impl InterchainEnv for DaemonInterchain { sequence: Sequence, ) -> Result, Self::Error> { // We crate an interchain env object that is safe to send between threads - let interchain_env = self - .rt_handle - .block_on(PacketInspector::new(self.daemons.values().collect()))?; + let interchain_env = block_on(PacketInspector::new(self.daemons.values().collect()))?; // We follow the trail - let ibc_trail = self.rt_handle.block_on(interchain_env.follow_packet( + let ibc_trail = block_on(interchain_env.follow_packet( src_chain, src_port, src_channel, @@ -324,9 +292,8 @@ impl DaemonInterchain { ) -> Result, InterchainDaemonError> { let grpc_channel1 = self.get_chain(chain_id)?.channel(); - let tx = self.rt_handle.block_on( - Node::new_async(grpc_channel1.clone())._find_tx(packet_send_tx_hash.clone()), - )?; + let tx = + block_on(Node::new_async(grpc_channel1.clone())._find_tx(packet_send_tx_hash.clone()))?; let ibc_trail = self.await_packets(chain_id, tx)?; diff --git a/packages/interchain/interchain-mock/src/interchain.rs b/packages/interchain/interchain-mock/src/interchain.rs index dfb17689b..79542b586 100644 --- a/packages/interchain/interchain-mock/src/interchain.rs +++ b/packages/interchain/interchain-mock/src/interchain.rs @@ -1,7 +1,7 @@ #![warn(missing_docs)] use cosmwasm_std::{from_json, testing::MockApi, Api, Event, IbcOrder}; -use cw_orch_core::environment::QueryHandler; +use cw_orch_core::{environment::QueryHandler, AppResponse}; use cw_orch_interchain_core::{ channel::InterchainChannel, env::{ChainId, ChannelCreation}, @@ -14,7 +14,7 @@ use cw_orch_mock::{ relayer::{self, ChannelCreationResult}, types::{Connection, MockIbcQuery}, }, - AppResponse, MockApiBech32, + MockApiBech32, }, Mock, MockBech32, MockState, }; @@ -211,10 +211,10 @@ impl InterchainEnv> for MockInterchainEnvBase { src_channel_id: ChannelId::from_str(&src_channel)?, dst_channel_id: ChannelId::from_str(&dst_channel)?, channel_creation_txs: ChannelCreation { - init, - r#try, - ack, - confirm, + init: init.into(), + r#try: r#try.into(), + ack: ack.into(), + confirm: confirm.into(), }, }) } @@ -222,8 +222,10 @@ impl InterchainEnv> for MockInterchainEnvBase { fn await_packets( &self, chain_id: ChainId, - tx_response: AppResponse, + tx_response: impl Into, ) -> Result>, Self::Error> { + let tx_response = tx_response.into(); + // We start by analyzing sent packets in the response let packets = find_ibc_packets_sent_in_tx(&self.get_chain(chain_id)?, &tx_response)?; @@ -307,7 +309,7 @@ impl InterchainEnv> for MockInterchainEnvBase { timeout_tx, close_channel_confirm: _, } => IbcPacketOutcome::Timeout { - timeout_tx: TxId::new(src_chain.to_string(), timeout_tx), + timeout_tx: TxId::new(src_chain.to_string(), timeout_tx.into()), }, relayer::RelayingResult::Acknowledgement { tx, ack } => { let ack_string = @@ -321,8 +323,8 @@ impl InterchainEnv> for MockInterchainEnvBase { ack_string, ); IbcPacketOutcome::Success { - receive_tx: TxId::new(dst_chain.to_string(), relay_result.receive_tx), - ack_tx: TxId::new(src_chain.to_string(), tx), + receive_tx: TxId::new(dst_chain.to_string(), relay_result.receive_tx.into()), + ack_tx: TxId::new(src_chain.to_string(), tx.into()), ack, } } diff --git a/packages/interchain/proto/Cargo.toml b/packages/interchain/proto/Cargo.toml index 28324984c..efa95e347 100644 --- a/packages/interchain/proto/Cargo.toml +++ b/packages/interchain/proto/Cargo.toml @@ -22,7 +22,6 @@ prost = { workspace = true } cosmwasm-std = { workspace = true } ibc-relayer-types = { workspace = true } log = { workspace = true } -tokio = { workspace = true } tonic = { workspace = true } osmosis-std = { version = "0.26.0" } diff --git a/packages/interchain/starship/Cargo.toml b/packages/interchain/starship/Cargo.toml index b85c6ab98..07ac658e0 100644 --- a/packages/interchain/starship/Cargo.toml +++ b/packages/interchain/starship/Cargo.toml @@ -23,6 +23,7 @@ cosmwasm-std = { workspace = true } cw-orch-daemon = { workspace = true } cw-orch-core = { workspace = true } tokio = { workspace = true } +async-std = { workspace = true } url = "2.5.2" log.workspace = true diff --git a/packages/interchain/starship/src/client/core.rs b/packages/interchain/starship/src/client/core.rs index f0ad4a5f2..75d302ff7 100644 --- a/packages/interchain/starship/src/client/core.rs +++ b/packages/interchain/starship/src/client/core.rs @@ -1,12 +1,12 @@ //! Interactions with docker using bollard use std::fmt::Debug; +use async_std::task::block_on; use cosmwasm_std::IbcOrder; use ibc_chain_registry::chain::ChainData; use kube::runtime::reflector::Lookup; use serde_json::Value; use tokio::io::AsyncReadExt; -use tokio::runtime::Handle; use url::Url; use crate::client::StarshipClientError; @@ -50,11 +50,10 @@ impl Debug for StarshipClient { impl StarshipClient { /// Create a Starship object from the localhost chain registry. pub fn new( - rt: Handle, url: Option<&str>, starship_config: Option, ) -> StarshipClientResult { - let starship = rt.block_on(Self::new_async(url, starship_config))?; + let starship = block_on(Self::new_async(url, starship_config))?; Ok(starship) } diff --git a/packages/interchain/starship/src/lib.rs b/packages/interchain/starship/src/lib.rs index 01e22c92b..4e60701d7 100644 --- a/packages/interchain/starship/src/lib.rs +++ b/packages/interchain/starship/src/lib.rs @@ -7,12 +7,12 @@ pub const STARSHIP_CONFIG_ENV_NAME: &str = "CW_ORCH_STARSHIP_CONFIG_PATH"; pub mod client; use crate::client::StarshipClient; +use async_std::task::block_on; use cw_orch_core::environment::{ChainInfoOwned, ChainState, NetworkInfoOwned}; use cw_orch_core::CwEnvError; -use cw_orch_daemon::{Daemon, DaemonBuilder, RUNTIME}; +use cw_orch_daemon::{Daemon, DaemonBuilder}; use ibc_chain_registry::chain::ChainData; use std::collections::HashMap; -use tokio::runtime::Handle; #[derive(Clone)] /// Starship integration @@ -20,19 +20,11 @@ pub struct Starship { /// Daemon objects representing all the chains available inside the starship environment pub daemons: HashMap, starship_client: StarshipClient, - /// Runtime handle for awaiting async functions - pub rt_handle: Handle, } impl Starship { /// Creates a new instance and connects to a starship deployment pub fn new(url: Option<&str>) -> Result { - let runtime = RUNTIME.handle(); - Self::new_with_runtime(runtime, url) - } - - /// Creates a new instance and connects to a starship deployment - pub fn new_with_runtime(rt_handle: &Handle, url: Option<&str>) -> Result { let starship_config = match try_to_read_starship_config() { Ok(config) => Some(config), Err(e) => { @@ -40,11 +32,11 @@ impl Starship { None } }; - let starship_client = StarshipClient::new(rt_handle.clone(), url, starship_config)?; + let starship_client = StarshipClient::new(url, starship_config)?; let mut daemons: HashMap = HashMap::new(); for chain in starship_client.chains.iter() { - let mnemonic = rt_handle.block_on(async { + let mnemonic = block_on(async { let registry = starship_client.registry().await; registry .test_mnemonic(chain.chain_id.as_str()) @@ -53,11 +45,7 @@ impl Starship { }); let mut daemon_builder = DaemonBuilder::new(chain_data_conversion(chain.clone())); - let mut daemon_builder = daemon_builder - .mnemonic(mnemonic) - .load_network(false) - .handle(rt_handle); - + let mut daemon_builder = daemon_builder.mnemonic(mnemonic).load_network(false); if let Some(existing_daemon) = daemons.values().next() { daemon_builder = daemon_builder.state(existing_daemon.state()) } @@ -68,9 +56,9 @@ impl Starship { Ok(Self { daemons, starship_client, - rt_handle: rt_handle.clone(), }) } + /// Get a chain daemon from the starship infrastructure pub fn daemon(&self, chain_id: &str) -> Result<&Daemon, CwEnvError> { self.daemons diff --git a/packages/macros/cw-orch-contract-derive/src/lib.rs b/packages/macros/cw-orch-contract-derive/src/lib.rs index a1f891d23..685ff57a4 100644 --- a/packages/macros/cw-orch-contract-derive/src/lib.rs +++ b/packages/macros/cw-orch-contract-derive/src/lib.rs @@ -224,22 +224,13 @@ pub fn interface(attrs: TokenStream, input: TokenStream) -> TokenStream { ) }; let struct_def = quote!( - #[cfg(not(target_arch = "wasm32"))] #[derive( ::std::clone::Clone, )] pub struct #name(::cw_orch::core::contract::Contract, #(#all_phantom_markers,)*); - #[cfg(target_arch = "wasm32")] - #[derive( - ::std::clone::Clone, - )] - pub struct #name; - - #[cfg(not(target_arch = "wasm32"))] #default_num - #[cfg(not(target_arch = "wasm32"))] impl ::cw_orch::core::contract::interface_traits::ContractInstance for #name { fn as_instance(&self) -> &::cw_orch::core::contract::Contract { &self.0 @@ -249,22 +240,18 @@ pub fn interface(attrs: TokenStream, input: TokenStream) -> TokenStream { } } - #[cfg(not(target_arch = "wasm32"))] impl ::cw_orch::core::contract::interface_traits::InstantiableContract for #name #all_debug_serialize { type InstantiateMsg = #init; } - #[cfg(not(target_arch = "wasm32"))] impl ::cw_orch::core::contract::interface_traits::ExecutableContract for #name #all_debug_serialize { type ExecuteMsg = #exec; } - #[cfg(not(target_arch = "wasm32"))] impl ::cw_orch::core::contract::interface_traits::QueryableContract for #name #all_debug_serialize { type QueryMsg = #query; } - #[cfg(not(target_arch = "wasm32"))] impl ::cw_orch::core::contract::interface_traits::MigratableContract for #name #all_debug_serialize { type MigrateMsg = #migrate; } diff --git a/packages/macros/cw-orch-fns-derive/src/fns_derive.rs b/packages/macros/cw-orch-fns-derive/src/fns_derive.rs index 4f1b9b7e9..fec8c8b89 100644 --- a/packages/macros/cw-orch-fns-derive/src/fns_derive.rs +++ b/packages/macros/cw-orch-fns-derive/src/fns_derive.rs @@ -260,17 +260,10 @@ pub fn fns_derive(msg_type: MsgType, sync_type: SyncType, mut input: ItemEnum) - let trait_condition = quote!(::cw_orch::core::contract::interface_traits::#trait_name); let derived_trait = quote!( - #[cfg(not(target_arch = "wasm32"))] /// Automatically derived trait that allows you to call the variants of the message directly without the need to construct the struct yourself. pub trait #bname #cw_orch_generics : #trait_condition #combined_trait_where_clause { #(#variant_fns)* } - - #[cfg(target_arch = "wasm32")] - /// Automatically derived trait that allows you to call the variants of the message directly without the need to construct the struct yourself. - pub trait #bname{ - - } ); // Generating the generics for the blanket implementation @@ -296,7 +289,6 @@ pub fn fns_derive(msg_type: MsgType, sync_type: SyncType, mut input: ItemEnum) - let expand = quote!( #derived_trait - #[cfg(not(target_arch = "wasm32"))] #derived_trait_blanket_impl );