From 2216c70b4886d9afacfc016d11bed0bab2c4f4f6 Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Fri, 12 Jul 2024 12:41:17 -0500 Subject: [PATCH 1/9] started adding instantiate2 support to admin factory --- .../external/cw-admin-factory/Cargo.toml | 4 +- .../external/cw-admin-factory/src/contract.rs | 72 +++++++++++++++++-- .../external/cw-admin-factory/src/error.rs | 3 + .../external/cw-admin-factory/src/msg.rs | 17 ++++- .../external/cw-admin-factory/src/state.rs | 3 + 5 files changed, 91 insertions(+), 8 deletions(-) diff --git a/contracts/external/cw-admin-factory/Cargo.toml b/contracts/external/cw-admin-factory/Cargo.toml index f7f0034ea..150026c88 100644 --- a/contracts/external/cw-admin-factory/Cargo.toml +++ b/contracts/external/cw-admin-factory/Cargo.toml @@ -1,5 +1,5 @@ [package] -name ="cw-admin-factory" +name = "cw-admin-factory" authors = ["Jake Hartnell", "blue-note", "ekez "] description = "A CosmWasm factory contract for instantiating a contract as its own admin." edition = { workspace = true } @@ -17,7 +17,7 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] [dependencies] -cosmwasm-std = { workspace = true } +cosmwasm-std = { workspace = true, features = ["cosmwasm_1_2"] } cosmwasm-schema = { workspace = true } cw-storage-plus = { workspace = true } cw2 = { workspace = true } diff --git a/contracts/external/cw-admin-factory/src/contract.rs b/contracts/external/cw-admin-factory/src/contract.rs index 00eaf73cb..68bc4f9f6 100644 --- a/contracts/external/cw-admin-factory/src/contract.rs +++ b/contracts/external/cw-admin-factory/src/contract.rs @@ -10,11 +10,13 @@ use cw_utils::parse_reply_instantiate_data; use crate::error::ContractError; use crate::msg::{AdminResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; -use crate::state::ADMIN; +use crate::state::{ADMIN, EXPECT}; pub(crate) const CONTRACT_NAME: &str = "crates.io:cw-admin-factory"; pub(crate) const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + pub const INSTANTIATE_CONTRACT_REPLY_ID: u64 = 0; +pub const INSTANTIATE2_CONTRACT_REPLY_ID: u64 = 2; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( @@ -46,6 +48,13 @@ pub fn execute( code_id, label, } => instantiate_contract(deps, env, info, msg, code_id, label), + ExecuteMsg::Instantiate2ContractWithSelfAdmin { + instantiate_msg: msg, + code_id, + label, + salt, + expect, + } => instantiate2_contract(deps, env, info, msg, code_id, label, salt, expect), } } @@ -75,7 +84,46 @@ pub fn instantiate_contract( let msg = SubMsg::reply_on_success(instantiate, INSTANTIATE_CONTRACT_REPLY_ID); Ok(Response::default() - .add_attribute("action", "instantiate_cw_core") + .add_attribute("action", "instantiate_contract_with_self_admin") + .add_submessage(msg)) +} + +#[allow(clippy::too_many_arguments)] +pub fn instantiate2_contract( + deps: DepsMut, + env: Env, + info: MessageInfo, + instantiate_msg: Binary, + code_id: u64, + label: String, + salt: Binary, + expect: Option, +) -> Result { + // If admin set, require the sender to be the admin. + if let Some(admin) = ADMIN.load(deps.storage)? { + if admin != info.sender { + return Err(ContractError::Unauthorized {}); + } + } + + if let Some(expect) = expect { + let expect = deps.api.addr_validate(&expect)?; + EXPECT.save(deps.storage, &expect)?; + } + + // Instantiate the specified contract with factory as the admin. + let instantiate = WasmMsg::Instantiate2 { + admin: Some(env.contract.address.to_string()), + code_id, + msg: instantiate_msg, + funds: info.funds, + label, + salt, + }; + + let msg = SubMsg::reply_on_success(instantiate, INSTANTIATE_CONTRACT_REPLY_ID); + Ok(Response::default() + .add_attribute("action", "instantiate2_contract_with_self_admin") .add_submessage(msg)) } @@ -90,10 +138,26 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { #[cfg_attr(not(feature = "library"), entry_point)] pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result { - match msg.id { - INSTANTIATE_CONTRACT_REPLY_ID => { + let msg_id = msg.id; + match msg_id { + INSTANTIATE_CONTRACT_REPLY_ID | INSTANTIATE2_CONTRACT_REPLY_ID => { let res = parse_reply_instantiate_data(msg)?; let contract_addr = deps.api.addr_validate(&res.contract_address)?; + + if msg_id == INSTANTIATE2_CONTRACT_REPLY_ID { + // If saved an expected address, verify it matches and clear it. + let expect = EXPECT.may_load(deps.storage)?; + if let Some(expect) = expect { + EXPECT.remove(deps.storage); + if contract_addr != expect { + return Err(ContractError::UnexpectedContractAddress { + expected: expect.to_string(), + actual: contract_addr.to_string(), + }); + } + } + } + // Make the contract its own admin. let msg = WasmMsg::UpdateAdmin { contract_addr: contract_addr.to_string(), diff --git a/contracts/external/cw-admin-factory/src/error.rs b/contracts/external/cw-admin-factory/src/error.rs index 299c8bfe1..83d9eac74 100644 --- a/contracts/external/cw-admin-factory/src/error.rs +++ b/contracts/external/cw-admin-factory/src/error.rs @@ -15,4 +15,7 @@ pub enum ContractError { #[error("An unknown reply ID was received.")] UnknownReplyID {}, + + #[error("Expected contract address {expected} but instantiated {actual}.")] + UnexpectedContractAddress { expected: String, actual: String }, } diff --git a/contracts/external/cw-admin-factory/src/msg.rs b/contracts/external/cw-admin-factory/src/msg.rs index 35a472783..13016fee1 100644 --- a/contracts/external/cw-admin-factory/src/msg.rs +++ b/contracts/external/cw-admin-factory/src/msg.rs @@ -10,13 +10,26 @@ pub struct InstantiateMsg { #[cw_serde] pub enum ExecuteMsg { - /// Instantiates the target contract with the provided instantiate message and code id and - /// updates the contract's admin to be itself. + /// Instantiates the target contract with the provided instantiate message, + /// code ID, and label and updates the contract's admin to be itself. InstantiateContractWithSelfAdmin { instantiate_msg: Binary, code_id: u64, label: String, }, + /// Instantiates the target contract with the provided instantiate message, + /// code ID, label, and salt, via instantiate2 to give a predictable + /// address, and updates the contract's admin to be itself. + Instantiate2ContractWithSelfAdmin { + instantiate_msg: Binary, + code_id: u64, + label: String, + salt: Binary, + /// Optionally specify the expected address and fail if it doesn't match + /// the instantiated contract. This makes it easy for a consumer to + /// validate that they are using the correct address elsewhere. + expect: Option, + }, } #[cw_serde] diff --git a/contracts/external/cw-admin-factory/src/state.rs b/contracts/external/cw-admin-factory/src/state.rs index 218223e2c..9957a9623 100644 --- a/contracts/external/cw-admin-factory/src/state.rs +++ b/contracts/external/cw-admin-factory/src/state.rs @@ -3,3 +3,6 @@ use cw_storage_plus::Item; /// The account allowed to execute the contract. If None, anyone is allowed. pub const ADMIN: Item> = Item::new("admin"); + +/// The expected instantiate2 address to validate in the reply. +pub const EXPECT: Item = Item::new("expect"); From 72c72fd48752b71bffa08241c4a5af98cfb14a1d Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Wed, 17 Jul 2024 16:01:10 -0400 Subject: [PATCH 2/9] added test tube tests for instantiate2 --- Cargo.lock | 8 + .../external/cw-admin-factory/Cargo.toml | 14 +- .../cw-admin-factory/src/integration_tests.rs | 214 ++++++++++++++++++ .../external/cw-admin-factory/src/lib.rs | 7 + packages/dao-testing/Cargo.toml | 1 + .../dao-testing/src/test_tube/cw4_group.rs | 128 +++++++++++ .../src/test_tube/cw_admin_factory.rs | 128 +++++++++++ .../src/test_tube/dao_voting_cw4.rs | 128 +++++++++++ packages/dao-testing/src/test_tube/mod.rs | 10 + 9 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 contracts/external/cw-admin-factory/src/integration_tests.rs create mode 100644 packages/dao-testing/src/test_tube/cw4_group.rs create mode 100644 packages/dao-testing/src/test_tube/cw_admin_factory.rs create mode 100644 packages/dao-testing/src/test_tube/dao_voting_cw4.rs diff --git a/Cargo.lock b/Cargo.lock index c04a23a82..933144536 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -692,13 +692,20 @@ version = "2.5.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", + "cw-admin-factory", "cw-multi-test", "cw-storage-plus 1.2.0", "cw-utils 1.0.3", "cw2 1.1.2", "cw20-base 1.1.2", + "cw4 1.1.2", "dao-dao-core", "dao-interface", + "dao-proposal-single", + "dao-testing", + "dao-voting 2.5.0", + "dao-voting-cw4", + "osmosis-test-tube", "thiserror", ] @@ -2013,6 +2020,7 @@ version = "2.5.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", + "cw-admin-factory", "cw-core", "cw-hooks", "cw-multi-test", diff --git a/contracts/external/cw-admin-factory/Cargo.toml b/contracts/external/cw-admin-factory/Cargo.toml index 150026c88..59836f97f 100644 --- a/contracts/external/cw-admin-factory/Cargo.toml +++ b/contracts/external/cw-admin-factory/Cargo.toml @@ -15,6 +15,11 @@ crate-type = ["cdylib", "rlib"] backtraces = ["cosmwasm-std/backtraces"] # use library feature to disable all instantiate/execute/query exports library = [] +# use test tube feature to enable test-tube integration tests, for example +# cargo test --features "test-tube" +test-tube = [] +# when writing tests you may wish to enable test-tube as a default feature +# default = ["test-tube"] [dependencies] cosmwasm-std = { workspace = true, features = ["cosmwasm_1_2"] } @@ -26,7 +31,14 @@ cw-utils = { workspace = true } [dev-dependencies] cosmwasm-schema = { workspace = true } +cw-admin-factory = { workspace = true } cw-multi-test = { workspace = true } +cw20-base = { workspace = true, features = ["library"] } +cw4 = { workspace = true } dao-dao-core = { workspace = true, features = ["library"] } dao-interface = { workspace = true } -cw20-base = { workspace = true, features = ["library"] } +dao-proposal-single = { workspace = true } +dao-testing = { workspace = true } +dao-voting = { workspace = true } +dao-voting-cw4 = { workspace = true } +osmosis-test-tube = { workspace = true } diff --git a/contracts/external/cw-admin-factory/src/integration_tests.rs b/contracts/external/cw-admin-factory/src/integration_tests.rs new file mode 100644 index 000000000..8e9133f02 --- /dev/null +++ b/contracts/external/cw-admin-factory/src/integration_tests.rs @@ -0,0 +1,214 @@ +use cosmwasm_std::{ + instantiate2_address, testing::mock_dependencies, to_json_binary, Api, Binary, Coin, Decimal, +}; +use cw_utils::Duration; +use dao_interface::state::{Admin, ModuleInstantiateInfo}; +use dao_testing::test_tube::{ + cw4_group::Cw4Group, cw_admin_factory::CwAdminFactory, dao_dao_core::DaoCore, + dao_proposal_single::DaoProposalSingle, dao_voting_cw4::DaoVotingCw4, +}; +use dao_voting::{ + pre_propose::PreProposeInfo, + threshold::{PercentageThreshold, Threshold}, +}; +use osmosis_test_tube::{ + osmosis_std::types::cosmwasm::wasm::v1::{ + QueryCodeRequest, QueryCodeResponse, QueryContractInfoRequest, QueryContractInfoResponse, + }, + Account, OsmosisTestApp, Runner, RunnerError, +}; + +use cw_admin_factory::msg::ExecuteMsg; + +use crate::ContractError; + +#[test] +fn test_set_self_admin_instantiate2() { + let app = OsmosisTestApp::new(); + let accounts = app + .init_accounts(&[Coin::new(1000000000000000u128, "uosmo")], 10) + .unwrap(); + + let cw_admin_factory = CwAdminFactory::new(&app, None, &accounts[0], &[]).unwrap(); + let dao_dao_core_id = DaoCore::upload(&app, &accounts[0]).unwrap(); + let cw4_group_id = Cw4Group::upload(&app, &accounts[0]).unwrap(); + let dao_voting_cw4_id = DaoVotingCw4::upload(&app, &accounts[0]).unwrap(); + let proposal_single_id = DaoProposalSingle::upload(&app, &accounts[0]).unwrap(); + + // Get DAO core checksum + let dao_core_checksum = app + .query::( + "/cosmwasm.wasm.v1.Query/Code", + &QueryCodeRequest { + code_id: dao_dao_core_id, + }, + ) + .unwrap() + .code_info + .unwrap() + .data_hash; + + let msg = dao_interface::msg::InstantiateMsg { + dao_uri: None, + admin: None, + name: "DAO DAO".to_string(), + description: "A DAO that makes DAO tooling".to_string(), + image_url: None, + automatically_add_cw20s: false, + automatically_add_cw721s: false, + voting_module_instantiate_info: ModuleInstantiateInfo { + code_id: dao_voting_cw4_id, + msg: to_json_binary(&dao_voting_cw4::msg::InstantiateMsg { + group_contract: dao_voting_cw4::msg::GroupContract::New { + cw4_group_code_id: cw4_group_id, + initial_members: vec![cw4::Member { + addr: accounts[0].address(), + weight: 1, + }], + }, + }) + .unwrap(), + admin: Some(Admin::CoreModule {}), + funds: vec![], + label: "DAO DAO Voting Module".to_string(), + }, + proposal_modules_instantiate_info: vec![ModuleInstantiateInfo { + code_id: proposal_single_id, + msg: to_json_binary(&dao_proposal_single::msg::InstantiateMsg { + min_voting_period: None, + threshold: Threshold::ThresholdQuorum { + threshold: PercentageThreshold::Majority {}, + quorum: PercentageThreshold::Percent(Decimal::percent(35)), + }, + max_voting_period: Duration::Time(432000), + allow_revoting: false, + only_members_execute: true, + close_proposal_on_execution_failure: false, + pre_propose_info: PreProposeInfo::AnyoneMayPropose {}, + veto: None, + }) + .unwrap(), + admin: Some(Admin::CoreModule {}), + funds: vec![], + label: "DAO DAO Proposal Module".to_string(), + }], + initial_items: None, + }; + + let salt = Binary::from("salt".as_bytes()); + let res = cw_admin_factory + .execute( + &ExecuteMsg::Instantiate2ContractWithSelfAdmin { + instantiate_msg: to_json_binary(&msg).unwrap(), + code_id: dao_dao_core_id, + label: "first".to_string(), + salt: salt.clone(), + expect: None, + }, + &[], + &accounts[0], + ) + .unwrap(); + let instantiate_event = &res.events[2]; + assert_eq!(instantiate_event.ty, "instantiate"); + let core_addr = instantiate_event.attributes[0].value.clone(); + + // Check that admin of core address is itself + let core_admin = app + .query::( + "/cosmwasm.wasm.v1.Query/ContractInfo", + &QueryContractInfoRequest { + address: core_addr.clone(), + }, + ) + .unwrap() + .contract_info + .unwrap() + .admin; + assert_eq!(core_admin, core_addr.clone()); + + let deps = mock_dependencies(); + + // Check that the address matches the predicted address + let canonical_factory = deps + .api + .addr_canonicalize(&cw_admin_factory.contract_addr) + .unwrap(); + let expected_addr = + instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(); + let canonical_core = deps.api.addr_canonicalize(&core_addr).unwrap(); + assert_eq!(canonical_core, expected_addr); + + // Check that it succeeds when expect matches. + let salt = Binary::from("salt_two".as_bytes()); + let expected_addr = deps + .api + .addr_humanize( + &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), + ) + .unwrap(); + let res = cw_admin_factory + .execute( + &ExecuteMsg::Instantiate2ContractWithSelfAdmin { + instantiate_msg: to_json_binary(&msg).unwrap(), + code_id: dao_dao_core_id, + label: "second".to_string(), + salt: salt.clone(), + expect: Some(expected_addr.to_string()), + }, + &[], + &accounts[0], + ) + .unwrap(); + let instantiate_event = &res.events[2]; + assert_eq!(instantiate_event.ty, "instantiate"); + let core_addr = instantiate_event.attributes[0].value.clone(); + assert_eq!(core_addr, expected_addr); + + // Check that admin of core address is itself + let core_admin = app + .query::( + "/cosmwasm.wasm.v1.Query/ContractInfo", + &QueryContractInfoRequest { + address: core_addr.clone(), + }, + ) + .unwrap() + .contract_info + .unwrap() + .admin; + assert_eq!(core_admin, core_addr.clone()); + + // Check that it fails when expect does not match. + let salt = Binary::from("salt_mismatch".as_bytes()); + let actual_addr = deps + .api + .addr_humanize( + &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), + ) + .unwrap(); + let err = cw_admin_factory + .execute( + &ExecuteMsg::Instantiate2ContractWithSelfAdmin { + instantiate_msg: to_json_binary(&msg).unwrap(), + code_id: dao_dao_core_id, + label: "third".to_string(), + salt: salt.clone(), + expect: Some("wrong".to_string()), + }, + &[], + &accounts[0], + ) + .unwrap_err(); + + assert_eq!( + err, + RunnerError::ExecuteError { + msg: ContractError::UnexpectedContractAddress { + expected: "wrong".to_string(), + actual: actual_addr.to_string(), + } + .to_string() + }, + ); +} diff --git a/contracts/external/cw-admin-factory/src/lib.rs b/contracts/external/cw-admin-factory/src/lib.rs index d1800adbc..6ea49d00c 100644 --- a/contracts/external/cw-admin-factory/src/lib.rs +++ b/contracts/external/cw-admin-factory/src/lib.rs @@ -8,4 +8,11 @@ pub mod state; #[cfg(test)] mod tests; +// Integrationg tests using an actual chain binary, requires +// the "test-tube" feature to be enabled +// cargo test --features test-tube +#[cfg(test)] +#[cfg(feature = "test-tube")] +mod integration_tests; + pub use crate::error::ContractError; diff --git a/packages/dao-testing/Cargo.toml b/packages/dao-testing/Cargo.toml index f75a81335..65f881db2 100644 --- a/packages/dao-testing/Cargo.toml +++ b/packages/dao-testing/Cargo.toml @@ -34,6 +34,7 @@ rand = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +cw-admin-factory = { workspace = true } cw-core-v1 = { workspace = true, features = ["library"] } cw-hooks = { workspace = true } cw-proposal-single-v1 = { workspace = true } diff --git a/packages/dao-testing/src/test_tube/cw4_group.rs b/packages/dao-testing/src/test_tube/cw4_group.rs new file mode 100644 index 000000000..a40d407c7 --- /dev/null +++ b/packages/dao-testing/src/test_tube/cw4_group.rs @@ -0,0 +1,128 @@ +use cosmwasm_std::Coin; +use cw4_group::{ + msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, + ContractError, +}; +use osmosis_test_tube::{ + osmosis_std::types::cosmwasm::wasm::v1::MsgExecuteContractResponse, Account, Module, + OsmosisTestApp, RunnerError, RunnerExecuteResult, SigningAccount, Wasm, +}; +use serde::de::DeserializeOwned; +use std::fmt::Debug; +use std::path::PathBuf; + +#[derive(Debug)] +pub struct Cw4Group<'a> { + pub app: &'a OsmosisTestApp, + pub code_id: u64, + pub contract_addr: String, +} + +impl<'a> Cw4Group<'a> { + pub fn new( + app: &'a OsmosisTestApp, + instantiate_msg: &InstantiateMsg, + signer: &SigningAccount, + ) -> Result { + let wasm = Wasm::new(app); + + let code_id = wasm + .store_code(&Self::get_wasm_byte_code(), None, signer)? + .data + .code_id; + + let contract_addr = wasm + .instantiate( + code_id, + &instantiate_msg, + Some(&signer.address()), + None, + &[], + signer, + )? + .data + .address; + + Ok(Self { + app, + code_id, + contract_addr, + }) + } + + pub fn new_with_values( + app: &'a OsmosisTestApp, + code_id: u64, + contract_addr: String, + ) -> Result { + Ok(Self { + app, + code_id, + contract_addr, + }) + } + + /// uploads contract and returns a code ID + pub fn upload(app: &OsmosisTestApp, signer: &SigningAccount) -> Result { + let wasm = Wasm::new(app); + + let code_id = wasm + .store_code(&Self::get_wasm_byte_code(), None, signer)? + .data + .code_id; + + Ok(code_id) + } + + // executes + pub fn execute( + &self, + execute_msg: &ExecuteMsg, + funds: &[Coin], + signer: &SigningAccount, + ) -> RunnerExecuteResult { + let wasm = Wasm::new(self.app); + wasm.execute(&self.contract_addr, execute_msg, funds, signer) + } + + // queries + pub fn query(&self, query_msg: &QueryMsg) -> Result + where + T: DeserializeOwned, + { + let wasm = Wasm::new(self.app); + wasm.query(&self.contract_addr, query_msg) + } + + fn get_wasm_byte_code() -> Vec { + let manifest_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let byte_code = std::fs::read( + manifest_path + .join("..") + .join("..") + .join("artifacts") + .join("cw4_group.wasm"), + ); + match byte_code { + Ok(byte_code) => byte_code, + // On arm processors, the above path is not found, so we try the following path + Err(_) => std::fs::read( + manifest_path + .join("..") + .join("..") + .join("artifacts") + .join("cw4_group-aarch64.wasm"), + ) + .unwrap(), + } + } + + pub fn execute_error(err: ContractError) -> RunnerError { + RunnerError::ExecuteError { + msg: format!( + "failed to execute message; message index: 0: {}: execute wasm contract failed", + err + ), + } + } +} diff --git a/packages/dao-testing/src/test_tube/cw_admin_factory.rs b/packages/dao-testing/src/test_tube/cw_admin_factory.rs new file mode 100644 index 000000000..17675f5b2 --- /dev/null +++ b/packages/dao-testing/src/test_tube/cw_admin_factory.rs @@ -0,0 +1,128 @@ +use cosmwasm_std::Coin; +use cw_admin_factory::{ + msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, + ContractError, +}; +use osmosis_test_tube::{ + osmosis_std::types::cosmwasm::wasm::v1::MsgExecuteContractResponse, Account, Module, + OsmosisTestApp, RunnerError, RunnerExecuteResult, SigningAccount, Wasm, +}; +use serde::de::DeserializeOwned; +use std::fmt::Debug; +use std::path::PathBuf; + +#[derive(Debug)] +pub struct CwAdminFactory<'a> { + pub app: &'a OsmosisTestApp, + pub code_id: u64, + pub contract_addr: String, +} + +impl<'a> CwAdminFactory<'a> { + pub fn new( + app: &'a OsmosisTestApp, + admin: Option, + signer: &SigningAccount, + funds: &[Coin], + ) -> Result { + let wasm = Wasm::new(app); + let code_id = wasm + .store_code(&Self::get_wasm_byte_code(), None, signer)? + .data + .code_id; + + let contract_addr = wasm + .instantiate( + code_id, + &InstantiateMsg { admin }, + Some(&signer.address()), + None, + funds, + signer, + )? + .data + .address; + + Ok(Self { + app, + code_id, + contract_addr, + }) + } + + pub fn new_with_values( + app: &'a OsmosisTestApp, + code_id: u64, + contract_addr: String, + ) -> Result { + Ok(Self { + app, + code_id, + contract_addr, + }) + } + + /// uploads contract and returns a code ID + pub fn upload(app: &OsmosisTestApp, signer: &SigningAccount) -> Result { + let wasm = Wasm::new(app); + + let code_id = wasm + .store_code(&Self::get_wasm_byte_code(), None, signer)? + .data + .code_id; + + Ok(code_id) + } + + // executes + pub fn execute( + &self, + execute_msg: &ExecuteMsg, + funds: &[Coin], + signer: &SigningAccount, + ) -> RunnerExecuteResult { + let wasm = Wasm::new(self.app); + wasm.execute(&self.contract_addr, execute_msg, funds, signer) + } + + // queries + pub fn query(&self, query_msg: &QueryMsg) -> Result + where + T: DeserializeOwned, + { + let wasm = Wasm::new(self.app); + wasm.query(&self.contract_addr, query_msg) + } + + fn get_wasm_byte_code() -> Vec { + let manifest_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let byte_code = std::fs::read( + manifest_path + .join("..") + .join("..") + .join("artifacts") + .join("cw_admin_factory.wasm"), + ); + match byte_code { + Ok(byte_code) => byte_code, + // On arm processors, the above path is not found, so we try the following path + Err(_) => std::fs::read( + manifest_path + .join("..") + .join("..") + .join("artifacts") + .join("cw_admin_factory-aarch64.wasm"), + ) + .unwrap(), + } + } + + pub fn execute_error(err: ContractError) -> RunnerError { + RunnerError::ExecuteError { + msg: format!( + "failed to execute message; message index: 0: {}: execute wasm contract failed", + err + ), + } + } +} diff --git a/packages/dao-testing/src/test_tube/dao_voting_cw4.rs b/packages/dao-testing/src/test_tube/dao_voting_cw4.rs new file mode 100644 index 000000000..aa4974a3b --- /dev/null +++ b/packages/dao-testing/src/test_tube/dao_voting_cw4.rs @@ -0,0 +1,128 @@ +use cosmwasm_std::Coin; +use cw_admin_factory::{ + msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, + ContractError, +}; +use osmosis_test_tube::{ + osmosis_std::types::cosmwasm::wasm::v1::MsgExecuteContractResponse, Account, Module, + OsmosisTestApp, RunnerError, RunnerExecuteResult, SigningAccount, Wasm, +}; +use serde::de::DeserializeOwned; +use std::fmt::Debug; +use std::path::PathBuf; + +#[derive(Debug)] +pub struct DaoVotingCw4<'a> { + pub app: &'a OsmosisTestApp, + pub code_id: u64, + pub contract_addr: String, +} + +impl<'a> DaoVotingCw4<'a> { + pub fn new( + app: &'a OsmosisTestApp, + instantiate_msg: &InstantiateMsg, + signer: &SigningAccount, + funds: &[Coin], + ) -> Result { + let wasm = Wasm::new(app); + let code_id = wasm + .store_code(&Self::get_wasm_byte_code(), None, signer)? + .data + .code_id; + + let contract_addr = wasm + .instantiate( + code_id, + &instantiate_msg, + Some(&signer.address()), + None, + funds, + signer, + )? + .data + .address; + + Ok(Self { + app, + code_id, + contract_addr, + }) + } + + pub fn new_with_values( + app: &'a OsmosisTestApp, + code_id: u64, + contract_addr: String, + ) -> Result { + Ok(Self { + app, + code_id, + contract_addr, + }) + } + + /// uploads contract and returns a code ID + pub fn upload(app: &OsmosisTestApp, signer: &SigningAccount) -> Result { + let wasm = Wasm::new(app); + + let code_id = wasm + .store_code(&Self::get_wasm_byte_code(), None, signer)? + .data + .code_id; + + Ok(code_id) + } + + // executes + pub fn execute( + &self, + execute_msg: &ExecuteMsg, + funds: &[Coin], + signer: &SigningAccount, + ) -> RunnerExecuteResult { + let wasm = Wasm::new(self.app); + wasm.execute(&self.contract_addr, execute_msg, funds, signer) + } + + // queries + pub fn query(&self, query_msg: &QueryMsg) -> Result + where + T: DeserializeOwned, + { + let wasm = Wasm::new(self.app); + wasm.query(&self.contract_addr, query_msg) + } + + fn get_wasm_byte_code() -> Vec { + let manifest_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let byte_code = std::fs::read( + manifest_path + .join("..") + .join("..") + .join("artifacts") + .join("cw_admin_factory.wasm"), + ); + match byte_code { + Ok(byte_code) => byte_code, + // On arm processors, the above path is not found, so we try the following path + Err(_) => std::fs::read( + manifest_path + .join("..") + .join("..") + .join("artifacts") + .join("cw_admin_factory-aarch64.wasm"), + ) + .unwrap(), + } + } + + pub fn execute_error(err: ContractError) -> RunnerError { + RunnerError::ExecuteError { + msg: format!( + "failed to execute message; message index: 0: {}: execute wasm contract failed", + err + ), + } + } +} diff --git a/packages/dao-testing/src/test_tube/mod.rs b/packages/dao-testing/src/test_tube/mod.rs index 0af2999a4..c764df4d1 100644 --- a/packages/dao-testing/src/test_tube/mod.rs +++ b/packages/dao-testing/src/test_tube/mod.rs @@ -5,9 +5,16 @@ // Integrationg tests using an actual chain binary, requires // the "test-tube" feature to be enabled // cargo test --features test-tube + +#[cfg(feature = "test-tube")] +pub mod cw_admin_factory; + #[cfg(feature = "test-tube")] pub mod cw_tokenfactory_issuer; +#[cfg(feature = "test-tube")] +pub mod cw4_group; + #[cfg(feature = "test-tube")] pub mod cw721_base; @@ -19,3 +26,6 @@ pub mod dao_proposal_single; #[cfg(feature = "test-tube")] pub mod dao_test_custom_factory; + +#[cfg(feature = "test-tube")] +pub mod dao_voting_cw4; From 544b66ac84a62b9c5ebf74613febfc92462840de Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Wed, 17 Jul 2024 16:23:43 -0400 Subject: [PATCH 3/9] updated schema --- .../schema/cw-admin-factory.json | 45 +- .../dao-pre-propose-approval-single.json | 103 +++++ .../schema/dao-pre-propose-multiple.json | 103 +++++ .../schema/dao-pre-propose-single.json | 103 +++++ .../schema/dao-proposal-condorcet.json | 198 +++++++++ .../schema/dao-proposal-multiple.json | 396 ++++++++++++++++++ .../schema/dao-proposal-single.json | 396 ++++++++++++++++++ 7 files changed, 1343 insertions(+), 1 deletion(-) diff --git a/contracts/external/cw-admin-factory/schema/cw-admin-factory.json b/contracts/external/cw-admin-factory/schema/cw-admin-factory.json index efba62576..d6f3ebcd9 100644 --- a/contracts/external/cw-admin-factory/schema/cw-admin-factory.json +++ b/contracts/external/cw-admin-factory/schema/cw-admin-factory.json @@ -22,7 +22,7 @@ "title": "ExecuteMsg", "oneOf": [ { - "description": "Instantiates the target contract with the provided instantiate message and code id and updates the contract's admin to be itself.", + "description": "Instantiates the target contract with the provided instantiate message, code ID, and label and updates the contract's admin to be itself.", "type": "object", "required": [ "instantiate_contract_with_self_admin" @@ -52,6 +52,49 @@ } }, "additionalProperties": false + }, + { + "description": "Instantiates the target contract with the provided instantiate message, code ID, label, and salt, via instantiate2 to give a predictable address, and updates the contract's admin to be itself.", + "type": "object", + "required": [ + "instantiate2_contract_with_self_admin" + ], + "properties": { + "instantiate2_contract_with_self_admin": { + "type": "object", + "required": [ + "code_id", + "instantiate_msg", + "label", + "salt" + ], + "properties": { + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "expect": { + "description": "Optionally specify the expected address and fail if it doesn't match the instantiated contract. This makes it easy for a consumer to validate that they are using the correct address elsewhere.", + "type": [ + "string", + "null" + ] + }, + "instantiate_msg": { + "$ref": "#/definitions/Binary" + }, + "label": { + "type": "string" + }, + "salt": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ], "definitions": { diff --git a/contracts/pre-propose/dao-pre-propose-approval-single/schema/dao-pre-propose-approval-single.json b/contracts/pre-propose/dao-pre-propose-approval-single/schema/dao-pre-propose-approval-single.json index c46026da1..9ea6e7bde 100644 --- a/contracts/pre-propose/dao-pre-propose-approval-single/schema/dao-pre-propose-approval-single.json +++ b/contracts/pre-propose/dao-pre-propose-approval-single/schema/dao-pre-propose-approval-single.json @@ -720,6 +720,10 @@ } ] }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, "DepositRefundPolicy": { "oneOf": [ { @@ -1002,6 +1006,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -1675,6 +1709,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -1759,6 +1847,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, diff --git a/contracts/pre-propose/dao-pre-propose-multiple/schema/dao-pre-propose-multiple.json b/contracts/pre-propose/dao-pre-propose-multiple/schema/dao-pre-propose-multiple.json index f55f6359e..a13061598 100644 --- a/contracts/pre-propose/dao-pre-propose-multiple/schema/dao-pre-propose-multiple.json +++ b/contracts/pre-propose/dao-pre-propose-multiple/schema/dao-pre-propose-multiple.json @@ -712,6 +712,10 @@ } ] }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, "DepositRefundPolicy": { "oneOf": [ { @@ -920,6 +924,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -1620,6 +1654,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -1704,6 +1792,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, diff --git a/contracts/pre-propose/dao-pre-propose-single/schema/dao-pre-propose-single.json b/contracts/pre-propose/dao-pre-propose-single/schema/dao-pre-propose-single.json index 578fe5634..507c69ae8 100644 --- a/contracts/pre-propose/dao-pre-propose-single/schema/dao-pre-propose-single.json +++ b/contracts/pre-propose/dao-pre-propose-single/schema/dao-pre-propose-single.json @@ -712,6 +712,10 @@ } ] }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, "DepositRefundPolicy": { "oneOf": [ { @@ -920,6 +924,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -1594,6 +1628,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -1678,6 +1766,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, diff --git a/contracts/proposal/dao-proposal-condorcet/schema/dao-proposal-condorcet.json b/contracts/proposal/dao-proposal-condorcet/schema/dao-proposal-condorcet.json index ab82db9c5..31094252c 100644 --- a/contracts/proposal/dao-proposal-condorcet/schema/dao-proposal-condorcet.json +++ b/contracts/proposal/dao-proposal-condorcet/schema/dao-proposal-condorcet.json @@ -555,6 +555,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -972,6 +1002,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -1056,6 +1140,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, @@ -1696,6 +1795,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -2266,6 +2395,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -2351,6 +2534,21 @@ } ] }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } + }, "Winner": { "oneOf": [ { diff --git a/contracts/proposal/dao-proposal-multiple/schema/dao-proposal-multiple.json b/contracts/proposal/dao-proposal-multiple/schema/dao-proposal-multiple.json index 5f6a884d0..75729fda4 100644 --- a/contracts/proposal/dao-proposal-multiple/schema/dao-proposal-multiple.json +++ b/contracts/proposal/dao-proposal-multiple/schema/dao-proposal-multiple.json @@ -1063,6 +1063,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -1722,6 +1752,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -1806,6 +1890,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, @@ -3120,6 +3219,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -3806,6 +3935,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -3890,6 +4073,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, @@ -4409,6 +4607,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -5076,6 +5304,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -5160,6 +5442,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, @@ -5656,6 +5953,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -6342,6 +6669,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -6426,6 +6807,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, diff --git a/contracts/proposal/dao-proposal-single/schema/dao-proposal-single.json b/contracts/proposal/dao-proposal-single/schema/dao-proposal-single.json index 0d247d3cc..9738cadec 100644 --- a/contracts/proposal/dao-proposal-single/schema/dao-proposal-single.json +++ b/contracts/proposal/dao-proposal-single/schema/dao-proposal-single.json @@ -1116,6 +1116,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -1793,6 +1823,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -1877,6 +1961,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, @@ -3226,6 +3325,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -3949,6 +4078,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -4033,6 +4216,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, @@ -4526,6 +4724,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -5229,6 +5457,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -5313,6 +5595,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, @@ -5772,6 +6069,36 @@ } }, "additionalProperties": false + }, + { + "description": "This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote_weighted" + ], + "properties": { + "vote_weighted": { + "type": "object", + "required": [ + "options", + "proposal_id" + ], + "properties": { + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/WeightedVoteOption" + } + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false } ] }, @@ -6495,6 +6822,60 @@ }, "additionalProperties": false }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code using a predictable address derivation algorithm implemented in [`cosmwasm_std::instantiate2_address`].\n\nThis is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). `sender` is automatically filled with the current contract's address. `fix_msg` is automatically set to false.", + "type": "object", + "required": [ + "instantiate2" + ], + "properties": { + "instantiate2": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg", + "salt" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readable label for the contract.\n\nValid values should: - not be empty - not be bigger than 128 bytes (or some chain-specific limit) - not start / end with whitespace", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "salt": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", "type": "object", @@ -6579,6 +6960,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, From e61d2863c0f39cb850eb16d0d83d126da3c4c76f Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Wed, 17 Jul 2024 17:09:09 -0400 Subject: [PATCH 4/9] fixed typo --- packages/dao-testing/src/test_tube/dao_voting_cw4.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dao-testing/src/test_tube/dao_voting_cw4.rs b/packages/dao-testing/src/test_tube/dao_voting_cw4.rs index aa4974a3b..ce0fdac33 100644 --- a/packages/dao-testing/src/test_tube/dao_voting_cw4.rs +++ b/packages/dao-testing/src/test_tube/dao_voting_cw4.rs @@ -101,7 +101,7 @@ impl<'a> DaoVotingCw4<'a> { .join("..") .join("..") .join("artifacts") - .join("cw_admin_factory.wasm"), + .join("dao_voting_cw4.wasm"), ); match byte_code { Ok(byte_code) => byte_code, @@ -111,7 +111,7 @@ impl<'a> DaoVotingCw4<'a> { .join("..") .join("..") .join("artifacts") - .join("cw_admin_factory-aarch64.wasm"), + .join("dao_voting_cw4-aarch64.wasm"), ) .unwrap(), } From 4667142a6c291abef1a13920eddbc9051ad08cf8 Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Wed, 17 Jul 2024 17:57:29 -0400 Subject: [PATCH 5/9] fixed event contract address getters --- .../cw-admin-factory/src/integration_tests.rs | 56 ++++++++++++++----- packages/dao-testing/Cargo.toml | 2 + 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/contracts/external/cw-admin-factory/src/integration_tests.rs b/contracts/external/cw-admin-factory/src/integration_tests.rs index 8e9133f02..ca0b1f698 100644 --- a/contracts/external/cw-admin-factory/src/integration_tests.rs +++ b/contracts/external/cw-admin-factory/src/integration_tests.rs @@ -1,5 +1,6 @@ use cosmwasm_std::{ - instantiate2_address, testing::mock_dependencies, to_json_binary, Api, Binary, Coin, Decimal, + instantiate2_address, testing::mock_dependencies, to_json_binary, Addr, Api, Binary, Coin, + Decimal, }; use cw_utils::Duration; use dao_interface::state::{Admin, ModuleInstantiateInfo}; @@ -13,9 +14,10 @@ use dao_voting::{ }; use osmosis_test_tube::{ osmosis_std::types::cosmwasm::wasm::v1::{ - QueryCodeRequest, QueryCodeResponse, QueryContractInfoRequest, QueryContractInfoResponse, + MsgExecuteContractResponse, QueryCodeRequest, QueryCodeResponse, QueryContractInfoRequest, + QueryContractInfoResponse, }, - Account, OsmosisTestApp, Runner, RunnerError, + Account, ExecuteResponse, OsmosisTestApp, Runner, RunnerError, }; use cw_admin_factory::msg::ExecuteMsg; @@ -96,7 +98,7 @@ fn test_set_self_admin_instantiate2() { }; let salt = Binary::from("salt".as_bytes()); - let res = cw_admin_factory + let res: ExecuteResponse = cw_admin_factory .execute( &ExecuteMsg::Instantiate2ContractWithSelfAdmin { instantiate_msg: to_json_binary(&msg).unwrap(), @@ -109,23 +111,35 @@ fn test_set_self_admin_instantiate2() { &accounts[0], ) .unwrap(); - let instantiate_event = &res.events[2]; - assert_eq!(instantiate_event.ty, "instantiate"); - let core_addr = instantiate_event.attributes[0].value.clone(); + let core_addr = &res + .events + .iter() + .find(|e| { + e.ty == "instantiate" + && e.attributes + .iter() + .any(|a| a.key == "code_id" && a.value == dao_dao_core_id.to_string()) + }) + .unwrap() + .attributes + .iter() + .find(|a| a.key == "_contract_address") + .unwrap() + .value; // Check that admin of core address is itself let core_admin = app .query::( "/cosmwasm.wasm.v1.Query/ContractInfo", &QueryContractInfoRequest { - address: core_addr.clone(), + address: core_addr.to_string(), }, ) .unwrap() .contract_info .unwrap() .admin; - assert_eq!(core_admin, core_addr.clone()); + assert_eq!(core_admin, core_addr.to_string()); let deps = mock_dependencies(); @@ -136,7 +150,7 @@ fn test_set_self_admin_instantiate2() { .unwrap(); let expected_addr = instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(); - let canonical_core = deps.api.addr_canonicalize(&core_addr).unwrap(); + let canonical_core = deps.api.addr_canonicalize(core_addr).unwrap(); assert_eq!(canonical_core, expected_addr); // Check that it succeeds when expect matches. @@ -147,7 +161,7 @@ fn test_set_self_admin_instantiate2() { &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), ) .unwrap(); - let res = cw_admin_factory + let res: ExecuteResponse = cw_admin_factory .execute( &ExecuteMsg::Instantiate2ContractWithSelfAdmin { instantiate_msg: to_json_binary(&msg).unwrap(), @@ -160,10 +174,22 @@ fn test_set_self_admin_instantiate2() { &accounts[0], ) .unwrap(); - let instantiate_event = &res.events[2]; - assert_eq!(instantiate_event.ty, "instantiate"); - let core_addr = instantiate_event.attributes[0].value.clone(); - assert_eq!(core_addr, expected_addr); + let core_addr = &res + .events + .iter() + .find(|e| { + e.ty == "instantiate" + && e.attributes + .iter() + .any(|a| a.key == "code_id" && a.value == dao_dao_core_id.to_string()) + }) + .unwrap() + .attributes + .iter() + .find(|a| a.key == "_contract_address") + .unwrap() + .value; + assert_eq!(Addr::unchecked(core_addr), expected_addr); // Check that admin of core address is itself let core_admin = app diff --git a/packages/dao-testing/Cargo.toml b/packages/dao-testing/Cargo.toml index 65f881db2..9b191be86 100644 --- a/packages/dao-testing/Cargo.toml +++ b/packages/dao-testing/Cargo.toml @@ -11,6 +11,8 @@ version = { workspace = true } # use test tube feature to enable test-tube integration tests, for example # cargo test --features "test-tube" test-tube = [] +# when writing tests you may wish to enable test-tube as a default feature +# default = ["test-tube"] # This crate depends on multi-test and rand. These are not features in # wasm builds of cosmwasm. Despite this crate only being used as a dev From c8f6d80c7c9641fac6fc34bccc5a44d0b246f83b Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Wed, 17 Jul 2024 23:03:53 -0400 Subject: [PATCH 6/9] humanize instead of canonicalize to check equality --- .../cw-admin-factory/src/integration_tests.rs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/contracts/external/cw-admin-factory/src/integration_tests.rs b/contracts/external/cw-admin-factory/src/integration_tests.rs index ca0b1f698..66a56fd0f 100644 --- a/contracts/external/cw-admin-factory/src/integration_tests.rs +++ b/contracts/external/cw-admin-factory/src/integration_tests.rs @@ -1,6 +1,5 @@ use cosmwasm_std::{ - instantiate2_address, testing::mock_dependencies, to_json_binary, Addr, Api, Binary, Coin, - Decimal, + instantiate2_address, testing::mock_dependencies, to_json_binary, Api, Binary, Coin, Decimal, }; use cw_utils::Duration; use dao_interface::state::{Admin, ModuleInstantiateInfo}; @@ -139,7 +138,7 @@ fn test_set_self_admin_instantiate2() { .contract_info .unwrap() .admin; - assert_eq!(core_admin, core_addr.to_string()); + assert_eq!(&core_admin, core_addr); let deps = mock_dependencies(); @@ -148,10 +147,13 @@ fn test_set_self_admin_instantiate2() { .api .addr_canonicalize(&cw_admin_factory.contract_addr) .unwrap(); - let expected_addr = - instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(); - let canonical_core = deps.api.addr_canonicalize(core_addr).unwrap(); - assert_eq!(canonical_core, expected_addr); + let expected_addr = deps + .api + .addr_humanize( + &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), + ) + .unwrap(); + assert_eq!(core_addr, expected_addr.as_str()); // Check that it succeeds when expect matches. let salt = Binary::from("salt_two".as_bytes()); @@ -189,7 +191,7 @@ fn test_set_self_admin_instantiate2() { .find(|a| a.key == "_contract_address") .unwrap() .value; - assert_eq!(Addr::unchecked(core_addr), expected_addr); + assert_eq!(core_addr, expected_addr.as_str()); // Check that admin of core address is itself let core_admin = app @@ -203,7 +205,7 @@ fn test_set_self_admin_instantiate2() { .contract_info .unwrap() .admin; - assert_eq!(core_admin, core_addr.clone()); + assert_eq!(&core_admin, core_addr); // Check that it fails when expect does not match. let salt = Binary::from("salt_mismatch".as_bytes()); From c9e9e9dca2f4b506361afc5b549e2d08dec6a9ab Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Thu, 18 Jul 2024 00:12:06 -0400 Subject: [PATCH 7/9] use correct bech32 addr encoders/decoders --- Cargo.lock | 1 + Cargo.toml | 1 + .../external/cw-admin-factory/Cargo.toml | 1 + .../cw-admin-factory/src/integration_tests.rs | 56 ++++++++++--------- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 933144536..d0dedb404 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,6 +690,7 @@ dependencies = [ name = "cw-admin-factory" version = "2.5.0" dependencies = [ + "bech32", "cosmwasm-schema", "cosmwasm-std", "cw-admin-factory", diff --git a/Cargo.toml b/Cargo.toml index 52032a9ed..c9a716f76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ overflow-checks = true [workspace.dependencies] anyhow = { version = "1.0" } assert_matches = "1.5" +bech32 = "0.9.1" cosm-orc = { version = "4.0" } cosm-tome = "0.2" cosmos-sdk-proto = "0.19" diff --git a/contracts/external/cw-admin-factory/Cargo.toml b/contracts/external/cw-admin-factory/Cargo.toml index 59836f97f..394f859fb 100644 --- a/contracts/external/cw-admin-factory/Cargo.toml +++ b/contracts/external/cw-admin-factory/Cargo.toml @@ -30,6 +30,7 @@ thiserror = { workspace = true } cw-utils = { workspace = true } [dev-dependencies] +bech32 = { workspace = true } cosmwasm-schema = { workspace = true } cw-admin-factory = { workspace = true } cw-multi-test = { workspace = true } diff --git a/contracts/external/cw-admin-factory/src/integration_tests.rs b/contracts/external/cw-admin-factory/src/integration_tests.rs index 66a56fd0f..3e7d6d698 100644 --- a/contracts/external/cw-admin-factory/src/integration_tests.rs +++ b/contracts/external/cw-admin-factory/src/integration_tests.rs @@ -1,5 +1,6 @@ +use bech32::{decode, encode, FromBase32, ToBase32, Variant}; use cosmwasm_std::{ - instantiate2_address, testing::mock_dependencies, to_json_binary, Api, Binary, Coin, Decimal, + instantiate2_address, to_json_binary, Addr, Binary, CanonicalAddr, Coin, Decimal, }; use cw_utils::Duration; use dao_interface::state::{Admin, ModuleInstantiateInfo}; @@ -30,6 +31,9 @@ fn test_set_self_admin_instantiate2() { .init_accounts(&[Coin::new(1000000000000000u128, "uosmo")], 10) .unwrap(); + // get bech32 prefix from created account + let prefix = decode(&accounts[0].address()).unwrap().0; + let cw_admin_factory = CwAdminFactory::new(&app, None, &accounts[0], &[]).unwrap(); let dao_dao_core_id = DaoCore::upload(&app, &accounts[0]).unwrap(); let cw4_group_id = Cw4Group::upload(&app, &accounts[0]).unwrap(); @@ -140,29 +144,20 @@ fn test_set_self_admin_instantiate2() { .admin; assert_eq!(&core_admin, core_addr); - let deps = mock_dependencies(); - // Check that the address matches the predicted address - let canonical_factory = deps - .api - .addr_canonicalize(&cw_admin_factory.contract_addr) - .unwrap(); - let expected_addr = deps - .api - .addr_humanize( - &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), - ) - .unwrap(); + let canonical_factory = addr_canonicalize(&prefix, &cw_admin_factory.contract_addr); + let expected_addr = addr_humanize( + &prefix, + &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), + ); assert_eq!(core_addr, expected_addr.as_str()); // Check that it succeeds when expect matches. let salt = Binary::from("salt_two".as_bytes()); - let expected_addr = deps - .api - .addr_humanize( - &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), - ) - .unwrap(); + let expected_addr = addr_humanize( + &prefix, + &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), + ); let res: ExecuteResponse = cw_admin_factory .execute( &ExecuteMsg::Instantiate2ContractWithSelfAdmin { @@ -209,12 +204,10 @@ fn test_set_self_admin_instantiate2() { // Check that it fails when expect does not match. let salt = Binary::from("salt_mismatch".as_bytes()); - let actual_addr = deps - .api - .addr_humanize( - &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), - ) - .unwrap(); + let actual_addr = addr_humanize( + &prefix, + &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), + ); let err = cw_admin_factory .execute( &ExecuteMsg::Instantiate2ContractWithSelfAdmin { @@ -240,3 +233,16 @@ fn test_set_self_admin_instantiate2() { }, ); } + +fn addr_canonicalize(prefix: &str, input: &str) -> CanonicalAddr { + let (p, decoded, variant) = decode(input).unwrap(); + if p == prefix && variant == Variant::Bech32 { + return Vec::::from_base32(&decoded).unwrap().into(); + } + panic!("Invalid address: {}", input); +} + +fn addr_humanize(prefix: &str, canonical: &CanonicalAddr) -> Addr { + let encoded = encode(prefix, canonical.as_slice().to_base32(), Variant::Bech32).unwrap(); + return Addr::unchecked(encoded); +} From 1a8b34bbeb5108006b2700e9700c70d3205608ef Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Thu, 18 Jul 2024 00:51:48 -0400 Subject: [PATCH 8/9] fixed instantiate2 expect test --- contracts/external/cw-admin-factory/src/contract.rs | 2 +- .../external/cw-admin-factory/src/integration_tests.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/contracts/external/cw-admin-factory/src/contract.rs b/contracts/external/cw-admin-factory/src/contract.rs index 68bc4f9f6..d0ac8fc95 100644 --- a/contracts/external/cw-admin-factory/src/contract.rs +++ b/contracts/external/cw-admin-factory/src/contract.rs @@ -121,7 +121,7 @@ pub fn instantiate2_contract( salt, }; - let msg = SubMsg::reply_on_success(instantiate, INSTANTIATE_CONTRACT_REPLY_ID); + let msg = SubMsg::reply_on_success(instantiate, INSTANTIATE2_CONTRACT_REPLY_ID); Ok(Response::default() .add_attribute("action", "instantiate2_contract_with_self_admin") .add_submessage(msg)) diff --git a/contracts/external/cw-admin-factory/src/integration_tests.rs b/contracts/external/cw-admin-factory/src/integration_tests.rs index 3e7d6d698..285be7d6d 100644 --- a/contracts/external/cw-admin-factory/src/integration_tests.rs +++ b/contracts/external/cw-admin-factory/src/integration_tests.rs @@ -215,18 +215,17 @@ fn test_set_self_admin_instantiate2() { code_id: dao_dao_core_id, label: "third".to_string(), salt: salt.clone(), - expect: Some("wrong".to_string()), + expect: Some(cw_admin_factory.contract_addr.clone()), }, &[], &accounts[0], ) .unwrap_err(); - assert_eq!( err, RunnerError::ExecuteError { msg: ContractError::UnexpectedContractAddress { - expected: "wrong".to_string(), + expected: cw_admin_factory.contract_addr.clone(), actual: actual_addr.to_string(), } .to_string() @@ -244,5 +243,5 @@ fn addr_canonicalize(prefix: &str, input: &str) -> CanonicalAddr { fn addr_humanize(prefix: &str, canonical: &CanonicalAddr) -> Addr { let encoded = encode(prefix, canonical.as_slice().to_base32(), Variant::Bech32).unwrap(); - return Addr::unchecked(encoded); + Addr::unchecked(encoded) } From c39ec7c950f29f27697e376209a403415a4cfd64 Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Thu, 18 Jul 2024 01:39:52 -0400 Subject: [PATCH 9/9] fixed error format --- .../cw-admin-factory/src/integration_tests.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/contracts/external/cw-admin-factory/src/integration_tests.rs b/contracts/external/cw-admin-factory/src/integration_tests.rs index 285be7d6d..f5533e0bd 100644 --- a/contracts/external/cw-admin-factory/src/integration_tests.rs +++ b/contracts/external/cw-admin-factory/src/integration_tests.rs @@ -224,11 +224,13 @@ fn test_set_self_admin_instantiate2() { assert_eq!( err, RunnerError::ExecuteError { - msg: ContractError::UnexpectedContractAddress { - expected: cw_admin_factory.contract_addr.clone(), - actual: actual_addr.to_string(), - } - .to_string() + msg: format!( + "failed to execute message; message index: 0: dispatch: submessages: reply: {}: execute wasm contract failed", + ContractError::UnexpectedContractAddress { + expected: cw_admin_factory.contract_addr.clone(), + actual: actual_addr.to_string(), + } + ) }, ); }