Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
# https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
strategy:
matrix:
msrv: [1.72.0] # dep/feat syntax fixed with co-exist dep
msrv: [1.73.0] # dep/feat syntax fixed with co-exist dep
name: ubuntu / ${{ matrix.msrv }}
steps:
- uses: actions/checkout@v4
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
- Added a test to make sure the derive macros stay compatible with new cw-orch versions
- Changed the derive macros import from cw_orch to cw_orch_core. This allows changing the cw-orch API without breaking the derive macros.
- Cw-orch mock env info doesn't error when using chain ids that don't match the `osmosis-1` pattern
- Add interchain capabilites as well as clone-testing
- Bumped MSRV to 1.73 because of dependency `cosmwasm-vm@1.5.5`
- Remove `impl_into`, the old `impl_into` behavior is now the default behavior
- EXCITING FEATURE : Added an item and a map query method to be able to query cw-storage-plus structure outside of contracts easily
- Add `flush_state` method for Local Chain Daemons
- Add `flush_state` method for Local Chain Daemons

### Breaking

Expand Down
40 changes: 35 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
[workspace]
members = ["cw-orch", "cw-orch-daemon", "packages/*", "contracts/*"]
members = [
"cw-orch",
"cw-orch-daemon",
"cw-orch-interchain",
"packages/cw-orch-core",
"packages/cw-orch-mock",
"packages/cw-orch-networks",
"packages/cw-orch-osmosis-test-tube",
"packages/cw-orch-traits",
"contracts/*",
"packages/macros/*",
"packages/interchain/*",
]
resolver = "2"

[workspace.package]
Expand All @@ -17,22 +29,36 @@ cw-multi-test = { package = "abstract-cw-multi-test", version = "1.0.0", feature
cw20 = { package = "abstract-cw20", version = "1.2.2" }
cw20-base = { package = "abstract-cw20-base", version = "1.2.2" }

# Test Tube env deps. We use git dependencies because the crates.io version recompiles every time
osmosis-test-tube = { version = "24.0.1" }


anyhow = "1.0"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
tokio = { version = "1.4", features = ["full"] }

cw-orch = { path = "./cw-orch", version = "0.22.0" }
cw-orch-daemon = { path = "./cw-orch-daemon", version = "0.22.0" }
cw-orch-core = { path = "packages/cw-orch-core", version = "1.0.0" }
cw-orch-traits = { path = "packages/cw-orch-traits", version = "0.22.0" }
cw-orch-mock = { path = "packages/cw-orch-mock", version = "0.22.0" }
cw-orch-contract-derive = { path = "packages/cw-orch-contract-derive", version = "0.21.0" }
cw-orch-fns-derive = { path = "packages/cw-orch-fns-derive", version = "0.19.0" }
cw-orch-networks = { path = "packages/cw-orch-networks", version = "0.22.0" }

# Macros
cw-orch-contract-derive = { path = "packages/macros/cw-orch-contract-derive", version = "0.21.0" }
cw-orch-fns-derive = { path = "packages/macros/cw-orch-fns-derive", version = "0.19.0" }

# Extensions
cw-orch-osmosis-test-tube = { version = "0.1.0", path = "packages/cw-orch-osmosis-test-tube" }

# Interchain
cw-orch-interchain-core = { path = "packages/interchain/interchain-core", version = "0.2.0" }
cw-orch-interchain-daemon = { path = "packages/interchain/interchain-daemon", version = "0.2.0" }
cw-orch-interchain-mock = { path = "packages/interchain/interchain-mock", version = "0.2.0" }
cw-orch-starship = { path = "packages/interchain/starship", version = "0.2.0" }

#Clone Testing
cw-orch-clone-testing = { version = "0.4.1", path = "packages/clone-testing" }


thiserror = { version = "1.0.21" }
sha2 = { version = "0.10.8" }
serde_json = "1.0.79"
Expand All @@ -45,3 +71,7 @@ speculoos = "0.11.0"

# Logging
log = "0.4.14"

# Interchain
ibc-relayer-types = { version = "0.25.0" }
ibc-chain-registry = { version = "0.25.0" }
7 changes: 4 additions & 3 deletions artifacts/checksums.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
06ff69733298934834d2a6bf55deb089380ec57c5279645085c11d43959b9698 counter_contract.wasm
0df014cb19a0a74905b25b619c0f71e99cb1c11d0630ccfa0ad3bef9df1ef017 mock_contract.wasm
6dea2f6da5be93ce418b02feddf6256440876bb85ff8a464b434e4319a60a02f mock_contract_u64.wasm
877962e071ee6213cb42e93c8b08d7a706c603ffbfb6c0f4141210ce2fa257ab counter_contract.wasm
4cf7e489c29fe736f1a7d6903019bc76053c0531caad5c5d5f6c1783452336e2 cw_orch_compatibility_test.wasm
1404ed74888640c4c7a422a5e436cf6d46d5252add3f12905ee499057f6f4c87 mock_contract.wasm
f39c5344861fc07a0aeb074c962f5b1ac413c7afb2749a4d6cbae487bc7f2fab mock_contract_u64.wasm
Binary file modified artifacts/counter_contract.wasm
Binary file not shown.
Binary file added artifacts/cw_orch_compatibility_test.wasm
Binary file not shown.
Binary file modified artifacts/mock_contract.wasm
Binary file not shown.
Binary file modified artifacts/mock_contract_u64.wasm
Binary file not shown.
14 changes: 12 additions & 2 deletions contracts/counter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ thiserror = { version = "1.0.21" }
serde = { workspace = true }
serde_json = "1.0.79"
cw-orch = { path = "../../cw-orch", features = ["daemon"] }
# Unused, only there to check for wasm compatibility
cw-orch-interchain = { path = "../../cw-orch-interchain", features = [
"daemon",
] }

[[example]]
name = "deploy"
Expand All @@ -32,5 +36,11 @@ name = "deploy"
dotenv = { version = "0.15.0" }
pretty_env_logger = { version = "0.5.0" }
cw-orch = { path = "../../cw-orch", features = ["daemon"] }
cw-orch-osmosis-test-tube = { version = "0.1.0", path = "../../packages/cw-orch-osmosis-test-tube" }
anyhow.workspace = true
cw-orch-osmosis-test-tube = { workspace = true }
anyhow = { workspace = true }

# Clone Testing test
cw-orch-clone-testing = { workspace = true }
cw20 = { workspace = true }
cw20-base = { workspace = true }
log = { workspace = true }
202 changes: 202 additions & 0 deletions contracts/counter/tests/clone-testing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_schema::QueryResponses;
use cosmwasm_std::coins;
use cosmwasm_std::Addr;
use cosmwasm_std::ContractInfoResponse;
use cosmwasm_std::QueryRequest;
use cosmwasm_std::WasmQuery;
use counter_contract::msg::MigrateMsg;
use counter_contract::CounterContract;
use counter_contract::CounterQueryMsgFns;
use cw20::BalanceResponse;
use cw20::Cw20QueryMsg;
use cw_orch::daemon::networks::PHOENIX_1;
use cw_orch::prelude::CallAs;
use cw_orch::prelude::ContractInstance;
use cw_orch::prelude::CwOrchMigrate;
use cw_orch::prelude::CwOrchUpload;
use cw_orch::prelude::Uploadable;
use cw_orch::prelude::*;
use cw_orch::tokio::runtime::Runtime;
use cw_orch_clone_testing::CloneTesting;

use cosmwasm_std::Empty;

/// For those Who don't know, CAVERN PROTOCOL is a money market
#[test]
pub fn cavern_integration_test() -> cw_orch::anyhow::Result<()> {
pretty_env_logger::init();

let sender = Addr::unchecked(SENDER);
let market_addr = Addr::unchecked(MARKET_ADDR);

// Instantiation of the fork platform is a breeze.
let runtime = Runtime::new()?;
let mut app = CloneTesting::new(&runtime, PHOENIX_1)?;
app.set_sender(sender.clone());

// We add some funds to the sender, because they need some, for what we are about to do.
app.set_balance(&sender, coins(10_000_000, CURRENCY))?;

// We query to verify the state changed
let response_before = query_a_currency_balance(&app)?;
log::info!("A currency balance before deposit : {:?}", response_before);

let market = CavernMarket::new("cavern:money-market", app.clone());
market.set_address(&market_addr);

market.deposit_stable(&coins(10_000, CURRENCY))?;

let response_after = query_a_currency_balance(&app)?;
log::info!("A currency balance after deposit : {:?}", response_after);

// We assert the balance has changed when depositing some funds
assert_ne!(response_before, response_after);

// From here on, we do funky stuff.

// 1. We migrate the money-market contract to a counter contract.
// 2. We test to see that the counter contract is not properly instantiated because it was migrated on top of another contract
// 3. We migrate back to the old code_id to resume normal operations
// 4. We dump all the changes we have made locally to inspect what changed

// 0. We start by saving some useful information for later (admin for migration (1.) + code id for remigration (3.))

let contract_info: ContractInfoResponse = app
.app
.borrow()
.wrap()
.query(&QueryRequest::Wasm(WasmQuery::ContractInfo {
contract_addr: market_addr.to_string(),
}))
.unwrap();
let money_market_admin = Addr::unchecked(contract_info.admin.unwrap());
let money_market_code_id = contract_info.code_id;

// 1. We migrate
let counter_contract = CounterContract::new(app.clone());
counter_contract.upload().unwrap();
counter_contract.set_address(&market.address().unwrap());

counter_contract
.call_as(&money_market_admin)
.migrate(
&MigrateMsg { t: "t".to_string() },
counter_contract.code_id().unwrap(),
)
.unwrap();

// 2. We see that the state is not correctly initialized on this contract (because it's the wrong code id)
let err = counter_contract.get_count().unwrap_err();

if !err
.to_string()
.contains("type: counter_contract::state::State;")
{
panic!(
"Error {} should contain counter_contract::state::State not found",
err
);
}

// 3. Now we migrate back and deposit again to verify migration is possible back and forth (from off-chain to on-chain contracts)
market
.call_as(&money_market_admin)
.migrate(&Empty {}, money_market_code_id)
.unwrap();
market.deposit_stable(&coins(10_000, CURRENCY))?;

// We query to verify the state changed
let response_after_migration = query_a_currency_balance(&app)?;
log::info!(
"A Currency balance after migrate and deposit : {:?}",
response_after_migration
);
assert_ne!(response_after_migration, response_after);

// 4. We dump all the storage changes to analyze them
let analysis = app.storage_analysis();
log::info!(
"All contracts storage {:?}",
analysis.all_readable_contract_storage()
);

analysis.compare_all_readable_contract_storage();
analysis.compare_all_balances();

Ok(())
}

#[cw_orch::interface(Empty, CavernExecuteMsg, Empty, Empty)]
pub struct CavernMarket;

impl Uploadable for CavernMarket<CloneTesting> {}

#[cosmwasm_schema::cw_serde]
#[derive(cw_orch::ExecuteFns)] // Function generation
pub enum CavernExecuteMsg {
////////////////////
/// User operations
////////////////////
/// Deposit stable asset to get interest
#[payable]
DepositStable {},
}

/// COUNTER CONTRACT MSGs
#[cw_serde]
#[derive(cw_orch::QueryFns)] // Function generation
#[derive(QueryResponses)]
pub enum QueryMsg {
// GetCount returns the current count as a json-encoded number
#[returns(GetCountResponse)]
GetCount {},
// GetCount returns the current count of the cousin contract
#[returns(GetCountResponse)]
GetCousinCount {},
}

// Custom response for the query
#[cw_serde]
pub struct GetCountResponse {
pub count: i32,
}

const A_CURRENCY: &str = "terra1gwdxyqtu75es0x5l6cd9flqhh87zjtj7qdankayyr0vtt7s9w4ssm7ds8m";
const SENDER: &str = "terra1ytj0hhw39j88qsx4yapsr6ker83jv3aj354gmj";
const MARKET_ADDR: &str = "terra1zqlcp3aty4p4rjv96h6qdascdn953v6crhwedu5vddxjnp349upscluex6";
const CURRENCY: &str = "ibc/B3504E092456BA618CC28AC671A71FB08C6CA0FD0BE7C8A5B5A3E2DD933CC9E4";

fn query_a_currency_balance(chain: &CloneTesting) -> cw_orch::anyhow::Result<BalanceResponse> {
Ok(chain.query(
&Cw20QueryMsg::Balance {
address: chain.sender.to_string(),
},
&Addr::unchecked(A_CURRENCY),
)?)
}

#[test]
fn query_hash() -> cw_orch::anyhow::Result<()> {
let runtime = Runtime::new()?;
let app = CloneTesting::new(&runtime, PHOENIX_1)?;
let market = CavernMarket::new("cavern:money-market", app.clone());
let market_addr = Addr::unchecked(MARKET_ADDR);
market.set_address(&market_addr);
market.set_code_id(1340);

app.wasm_querier().code_id_hash(market.code_id()?)?;
Ok(())
}

#[test]
fn query_contract_info() -> cw_orch::anyhow::Result<()> {
let runtime = Runtime::new()?;
let app = CloneTesting::new(&runtime, PHOENIX_1)?;
let market = CavernMarket::new("cavern:money-market", app.clone());
let market_addr = Addr::unchecked(MARKET_ADDR);
market.set_address(&market_addr);

app.wasm_querier().contract_info(market.address()?)?;
Ok(())
}
4 changes: 2 additions & 2 deletions cw-orch-daemon/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cw-orch-daemon"
version = "0.22.1"
version = "0.22.2"
authors = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
Expand Down Expand Up @@ -43,7 +43,7 @@ prost = { version = "0.12.3" }
bitcoin = { version = "0.30.0" }
hex = { version = "0.4.3" }
ripemd = { version = "0.1.3" }
tokio = { version = "1.4", features = ["full"] }
tokio = { workspace = true, features = ["full"] }
tonic = { workspace = true, features = ["tls", "tls-roots"] }
reqwest = { version = "0.11.9" }
base64 = { version = "0.21.0" }
Expand Down
3 changes: 3 additions & 0 deletions cw-orch-daemon/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ pub enum DaemonError {
QuerierNeedRuntime,
#[error(transparent)]
Instantiate2Error(#[from] Instantiate2AddressError),

#[error("Error opening file {0},err: ({1})")]
OpenFile(String, String),
}

impl DaemonError {
Expand Down
4 changes: 2 additions & 2 deletions cw-orch-daemon/src/json_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ pub fn write(filename: &String, chain_id: &String, network_id: &String, deploy_i
}

pub fn read(filename: &String) -> Result<Value, DaemonError> {
let file =
File::open(filename).unwrap_or_else(|_| panic!("File should be present at {}", filename));
let file = File::open(filename)
.map_err(|err| DaemonError::OpenFile(filename.to_string(), err.to_string()))?;
let json: serde_json::Value = from_reader(file)?;
Ok(json)
}
10 changes: 6 additions & 4 deletions cw-orch-daemon/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,9 @@ impl StateInterface for DaemonState {
/// Read address for contract in deployment id from state file
fn get_address(&self, contract_id: &str) -> Result<Addr, CwEnvError> {
let value = self
.get(&self.deployment_id)?
.get(contract_id)
.get(&self.deployment_id)
.ok()
.and_then(|v| v.get(contract_id).cloned())
.ok_or_else(|| CwEnvError::AddrNotInStore(contract_id.to_owned()))?
.clone();
Ok(Addr::unchecked(value.as_str().unwrap()))
Expand All @@ -208,8 +209,9 @@ impl StateInterface for DaemonState {
/// Get the locally-saved version of the contract's version on this network
fn get_code_id(&self, contract_id: &str) -> Result<u64, CwEnvError> {
let value = self
.get("code_ids")?
.get(contract_id)
.get("code_ids")
.ok()
.and_then(|v| v.get(contract_id).cloned())
.ok_or_else(|| CwEnvError::CodeIdNotInStore(contract_id.to_owned()))?
.clone();
Ok(value.as_u64().unwrap())
Expand Down
Loading