diff --git a/Cargo.lock b/Cargo.lock index 2a21d28..2c1bf26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,8 +59,7 @@ dependencies = [ [[package]] name = "apollo-cw-multi-test" version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302ade9b31bee51ac98dceaa0818fdf28d92794150b84460a8edf4053a3339b1" +source = "git+https://github.com/apollodao/cw-multi-test.git?rev=7e7bc2b91a8199c47815b45ef23b3ab07390ae3a#7e7bc2b91a8199c47815b45ef23b3ab07390ae3a" dependencies = [ "anyhow", "cosmwasm-std", @@ -74,6 +73,7 @@ dependencies = [ "regex", "schemars", "serde", + "sha2 0.10.8", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index b12a016..d6de468 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,7 +112,7 @@ apollo-utils = { version = "0.1.1", optional = true } regex = { version = "1.7.3", optional = true } # Cw-multi-test deps -apollo-cw-multi-test = { version = "0.18.1", features = ["stargate"], optional = true } +apollo-cw-multi-test = { git = "https://github.com/apollodao/cw-multi-test.git", rev = "7e7bc2b91a8199c47815b45ef23b3ab07390ae3a",features = ["stargate"], optional = true } bech32 = { version = "0.11.0", optional = true } sha2 = { version = "0.10.8", optional = true } paste = { version = "1.0.12", optional = true } diff --git a/src/astroport/utils.rs b/src/astroport/utils.rs index 07eb81d..ef7f52c 100644 --- a/src/astroport/utils.rs +++ b/src/astroport/utils.rs @@ -1014,4 +1014,3 @@ mod tests { ); } } - diff --git a/src/helpers.rs b/src/helpers.rs index 1c5840b..bdd52df 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -3,7 +3,11 @@ use std::fmt::Debug; use std::{collections::HashMap, str::FromStr}; use cosmwasm_std::{Coin, StdError, StdResult, Uint128}; -use osmosis_std::types::cosmos::bank::v1beta1::{MsgSend, MsgSendResponse, QueryBalanceRequest}; +use osmosis_std::types::cosmos::bank::v1beta1::{ + MsgSend, MsgSendResponse, QueryAllBalancesRequest, QueryAllBalancesResponse, + QueryBalanceRequest, +}; +use osmosis_std::types::cosmos::base::query::v1beta1::PageRequest; use osmosis_std::types::cosmos::base::v1beta1::Coin as ProtoCoin; use serde::Serialize; use test_tube::{Account, Module, Runner, RunnerExecuteResult, RunnerResult, SigningAccount}; @@ -108,6 +112,19 @@ pub fn bank_balance_query<'a>( .ok_or_else(|| StdError::generic_err("Bank balance query failed")) } +pub fn bank_all_balances_query<'a>( + runner: &'a impl Runner<'a>, + address: String, + pagination: Option, +) -> StdResult { + Bank::new(runner) + .query_all_balances(&QueryAllBalancesRequest { + address, + pagination, + }) + .or_else(|_| Err(StdError::generic_err("Bank all balances query failed"))) +} + pub fn bank_send<'a>( runner: &'a impl Runner<'a>, sender: &SigningAccount, @@ -187,3 +204,4 @@ fn test_unwrap_panic() { let res: Result = Err("random"); Unwrap::Err("test").unwrap(res); } + diff --git a/src/multi_test/mod.rs b/src/multi_test/mod.rs index 49686bc..a554b74 100644 --- a/src/multi_test/mod.rs +++ b/src/multi_test/mod.rs @@ -11,3 +11,4 @@ pub mod api; pub use crate::create_contract_wrappers; pub use runner::MultiTestRunner; +pub mod test_addresses; diff --git a/src/multi_test/runner.rs b/src/multi_test/runner.rs index daf16b0..73224c4 100644 --- a/src/multi_test/runner.rs +++ b/src/multi_test/runner.rs @@ -1,10 +1,11 @@ use crate::multi_test::api::MockApiBech32; +use crate::multi_test::test_addresses::MockAddressGenerator; use crate::{traits::CwItRunner, ContractType}; use anyhow::bail; use apollo_cw_multi_test::BankKeeper; +use apollo_cw_multi_test::WasmKeeper; use apollo_cw_multi_test::{BankSudo, BasicAppBuilder}; use cosmrs::{crypto::secp256k1::SigningKey, proto::cosmos::base::abci::v1beta1::GasInfo}; - use cosmwasm_std::{ coin, Addr, BankMsg, Binary, Coin, CosmosMsg, Empty, QueryRequest, StakingMsg, WasmMsg, }; @@ -25,8 +26,6 @@ use test_tube::{ Account, DecodeError, EncodeError, FeeSetting, Runner, RunnerError, SigningAccount, }; -use super::api::MockApiBech; - pub struct MultiTestRunner<'a> { pub app: apollo_cw_multi_test::App>, pub address_prefix: &'a str, @@ -37,8 +36,12 @@ impl<'a> MultiTestRunner<'a> { /// with the given address prefix. pub fn new(address_prefix: &'a str) -> Self { // Construct app + let wasm_keeper: WasmKeeper = + WasmKeeper::new().with_address_generator(MockAddressGenerator); + let app = BasicAppBuilder::::new() .with_api(MockApiBech32::new(address_prefix)) + .with_wasm(wasm_keeper) .build(|_, _, _| {}); Self { @@ -362,7 +365,10 @@ mod tests { use cosmrs::proto::cosmos::bank::v1beta1::MsgSendResponse; use cosmwasm_std::{coin, Event, Uint128}; + use crate::test_helpers::*; + use crate::{artifact::Artifact, helpers::upload_wasm_file}; use apollo_cw_multi_test::ContractWrapper; + use cw20::MinterResponse; use osmosis_std::types::cosmos::bank::v1beta1::{ QueryBalanceRequest, QuerySupplyOfRequest, QueryTotalSupplyRequest, @@ -374,11 +380,6 @@ mod tests { }; use test_tube::{Bank, Module, RunnerExecuteResult, Wasm}; - use crate::multi_test::api::MockApiBech; - use crate::{artifact::Artifact, helpers::upload_wasm_file}; - - use crate::test_helpers::*; - use super::*; fn instantiate_astro_token( @@ -457,18 +458,17 @@ mod tests { fn wasm_execute_contract() { // start the keeper let app = MultiTestRunner::new("osmo"); - let mock_api = MockApiBech32::new("osmo"); let alice = app.init_account(&[coin(1000, "uosmo")]).unwrap(); let res = instantiate_astro_token(&app, &alice).unwrap(); - let contract_addr = mock_api.addr_make(&res.data.address); + let contract_addr = res.data.address; let wasm = Wasm::new(&app); let res = wasm .execute( - &contract_addr.to_string(), + &contract_addr, &cw20_base::msg::ExecuteMsg::Mint { recipient: alice.address(), amount: 100u128.into(), @@ -483,7 +483,7 @@ mod tests { assert_eq!( wasm_event, &Event::new("wasm") - .add_attribute("_contract_addr", contract_addr) + .add_attribute("_contract_address", contract_addr) .add_attribute("action", "mint") .add_attribute("to", alice.address()) .add_attribute("amount", "100") @@ -493,6 +493,7 @@ mod tests { #[test] fn wasm_smart_query_contract() { let app = MultiTestRunner::new("osmo"); + let alice = app.init_account(&[coin(1000, "uosmo")]).unwrap(); let res = instantiate_astro_token(&app, &alice).unwrap(); @@ -527,13 +528,12 @@ mod tests { #[test] fn wasm_contract_info_query() { let app = MultiTestRunner::new("osmo"); + let alice = app.init_account(&[coin(1000, "uosmo")]).unwrap(); let res = instantiate_astro_token(&app, &alice).unwrap(); - println!("res: {:?}", res); - let mock_api = MockApiBech32::new("osmo"); - let contract_addr = res.data.address; //mock_api.addr_make(&res.data.address).to_string(); - println!("contract_addr: {:?}", contract_addr); + println!("MsgInstantiateContractRes: {:?}", res); + let contract_addr = res.data.address; let res = QueryContractInfoRequest { address: contract_addr.clone(), @@ -541,6 +541,8 @@ mod tests { .query(&app.app.wrap()) .unwrap(); + println!("QueryContractInfoRes: {:?}", res); + assert_eq!(res.address, contract_addr); let info = res.contract_info.unwrap(); assert_eq!(info.code_id, 1); @@ -551,33 +553,9 @@ mod tests { #[test] fn bank_send() { let app = MultiTestRunner::new("osmo"); - let bank: Bank = Bank::new(&app); let alice = app.init_account(&[coin(1000, "uatom")]).unwrap(); let bob = app.init_account(&[]).unwrap(); - let mock_api_bech = MockApiBech32::new("osmo"); - let alice_address = mock_api_bech.addr_make(&alice.address()).to_string(); - let bob_address = mock_api_bech.addr_make(&bob.address()).to_string(); - let bank_query = bank - .query_all_balances(&QueryAllBalancesRequest { - address: alice_address.clone(), - pagination: None, - }) - .unwrap(); - - println!("alice_address bank_query: {:?}", bank_query); - - let bank_query = bank - .query_all_balances(&QueryAllBalancesRequest { - address: bob_address.clone(), - pagination: None, - }) - .unwrap(); - - println!("bob_address bank_query: {:?}", bank_query); - - println!("alice_address {}", alice_address); - println!("bob_address {}", bob_address); let msgs = vec![cosmwasm_std::CosmosMsg::Bank(cosmwasm_std::BankMsg::Send { to_address: bob.address(), amount: vec![cosmwasm_std::Coin { @@ -585,8 +563,6 @@ mod tests { amount: 100u128.into(), }], })]; - println!("alice.address(): {:?}", alice.address()); - let res = app .execute_cosmos_msgs::(&msgs, &alice) @@ -596,9 +572,9 @@ mod tests { assert_eq!( res.events[0], Event::new("transfer") - .add_attribute("recipient", bob.address()) - .add_attribute("sender", alice.address()) - .add_attribute("amount", "100uatom") + .add_attribute("recipient", bob.address()) + .add_attribute("sender", alice.address()) + .add_attribute("amount", "100uatom") ); let bank = Bank::new(&app); @@ -616,9 +592,9 @@ mod tests { assert_eq!( res.events[0], Event::new("transfer") - .add_attribute("recipient", bob.address()) - .add_attribute("sender", alice.address()) - .add_attribute("amount", "100uatom") + .add_attribute("recipient", bob.address()) + .add_attribute("sender", alice.address()) + .add_attribute("amount", "100uatom") ); } @@ -627,9 +603,8 @@ mod tests { let app = MultiTestRunner::new("osmo"); let alice = app.init_account(&[coin(1000, "uatom")]).unwrap(); - let mock_api_bech = MockApiBech32::new("osmo"); - let bank: Bank = Bank::new(&app); - let alice_address = mock_api_bech.addr_make(&alice.address()); + let bank = Bank::new(&app); + // Query all balances let res = bank .query_all_balances(&QueryAllBalancesRequest { diff --git a/src/multi_test/test_addresses.rs b/src/multi_test/test_addresses.rs new file mode 100644 index 0000000..7bfa681 --- /dev/null +++ b/src/multi_test/test_addresses.rs @@ -0,0 +1,52 @@ +use anyhow::Result; +use apollo_cw_multi_test::AddressGenerator; +use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; +use sha2::digest::Update; +use sha2::{Digest, Sha256}; +#[derive(Default)] +pub struct MockAddressGenerator; + +impl AddressGenerator for MockAddressGenerator { + fn contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + code_id: u64, + instance_id: u64, + ) -> Result { + let canonical_addr = Self::instantiate_address(code_id, instance_id); + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } + + fn predictable_contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + _code_id: u64, + _instance_id: u64, + checksum: &[u8], + creator: &CanonicalAddr, + salt: &[u8], + ) -> Result { + let canonical_addr = instantiate2_address(checksum, creator, salt)?; + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } +} + +impl MockAddressGenerator { + // non-predictable contract address generator, see `BuildContractAddressClassic` + // implementation in wasmd: https://github.com/CosmWasm/wasmd/blob/main/x/wasm/keeper/addresses.go#L35-L42 + fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { + let mut key = Vec::::new(); + key.extend_from_slice(b"wasm\0"); + key.extend_from_slice(&code_id.to_be_bytes()); + key.extend_from_slice(&instance_id.to_be_bytes()); + let module = Sha256::digest("module".as_bytes()); + Sha256::new() + .chain(module) + .chain(key) + .finalize() + .to_vec() + .into() + } +}