diff --git a/Cargo.lock b/Cargo.lock index c04a23a82..d0dedb404 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,15 +690,23 @@ dependencies = [ name = "cw-admin-factory" version = "2.5.0" dependencies = [ + "bech32", "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 +2021,7 @@ version = "2.5.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", + "cw-admin-factory", "cw-core", "cw-hooks", "cw-multi-test", 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 f7f0034ea..394f859fb 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 } @@ -15,9 +15,14 @@ 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 } +cosmwasm-std = { workspace = true, features = ["cosmwasm_1_2"] } cosmwasm-schema = { workspace = true } cw-storage-plus = { workspace = true } cw2 = { workspace = true } @@ -25,8 +30,16 @@ 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 } +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/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/external/cw-admin-factory/src/contract.rs b/contracts/external/cw-admin-factory/src/contract.rs index 00eaf73cb..d0ac8fc95 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, INSTANTIATE2_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/integration_tests.rs b/contracts/external/cw-admin-factory/src/integration_tests.rs new file mode 100644 index 000000000..f5533e0bd --- /dev/null +++ b/contracts/external/cw-admin-factory/src/integration_tests.rs @@ -0,0 +1,249 @@ +use bech32::{decode, encode, FromBase32, ToBase32, Variant}; +use cosmwasm_std::{ + instantiate2_address, to_json_binary, Addr, Binary, CanonicalAddr, 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::{ + MsgExecuteContractResponse, QueryCodeRequest, QueryCodeResponse, QueryContractInfoRequest, + QueryContractInfoResponse, + }, + Account, ExecuteResponse, 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(); + + // 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(); + 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: ExecuteResponse = 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 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.to_string(), + }, + ) + .unwrap() + .contract_info + .unwrap() + .admin; + assert_eq!(&core_admin, core_addr); + + // Check that the address matches the predicted address + 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 = addr_humanize( + &prefix, + &instantiate2_address(&dao_core_checksum, &canonical_factory, salt.as_slice()).unwrap(), + ); + let res: ExecuteResponse = 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 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!(core_addr, expected_addr.as_str()); + + // 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); + + // Check that it fails when expect does not match. + let salt = Binary::from("salt_mismatch".as_bytes()); + 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 { + instantiate_msg: to_json_binary(&msg).unwrap(), + code_id: dao_dao_core_id, + label: "third".to_string(), + salt: salt.clone(), + expect: Some(cw_admin_factory.contract_addr.clone()), + }, + &[], + &accounts[0], + ) + .unwrap_err(); + assert_eq!( + err, + RunnerError::ExecuteError { + 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(), + } + ) + }, + ); +} + +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(); + Addr::unchecked(encoded) +} 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/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"); 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" + } + } } } }, diff --git a/packages/dao-testing/Cargo.toml b/packages/dao-testing/Cargo.toml index f75a81335..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 @@ -34,6 +36,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..ce0fdac33 --- /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("dao_voting_cw4.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("dao_voting_cw4-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;