diff --git a/Cargo.lock b/Cargo.lock index b1e7d67d1..8a4bde71e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -698,7 +698,6 @@ dependencies = [ "cw2 1.1.2", "cw20-base 1.1.2", "cw4 1.1.2", - "dao-dao-core 2.5.0", "dao-interface 2.5.0", "dao-proposal-single 2.5.0", "dao-testing", @@ -839,6 +838,7 @@ dependencies = [ "cw-multi-test", "cw20 1.1.2", "cw20-base 1.1.2", + "dao-testing", "thiserror", ] @@ -848,6 +848,7 @@ version = "2.5.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", + "cw-fund-distributor", "cw-multi-test", "cw-paginate-storage 2.5.0", "cw-storage-plus 1.2.0", @@ -858,6 +859,7 @@ dependencies = [ "cw20-stake 2.5.0", "dao-dao-core 2.5.0", "dao-interface 2.5.0", + "dao-testing", "dao-voting-cw20-staked", "thiserror", ] @@ -972,12 +974,14 @@ dependencies = [ "cw-denom 2.5.0", "cw-multi-test", "cw-ownable", + "cw-payroll-factory", "cw-storage-plus 1.2.0", "cw-utils 1.0.3", "cw-vesting", "cw2 1.1.2", "cw20 1.1.2", "cw20-base 1.1.2", + "dao-testing", "thiserror", "wynd-utils", ] @@ -1068,10 +1072,12 @@ dependencies = [ "cosmwasm-std", "cw-multi-test", "cw-storage-plus 1.2.0", + "cw-token-swap", "cw-utils 1.0.3", "cw2 1.1.2", "cw20 1.1.2", "cw20-base 1.1.2", + "dao-testing", "thiserror", ] @@ -1181,6 +1187,7 @@ dependencies = [ "cw-stake-tracker", "cw-storage-plus 1.2.0", "cw-utils 1.0.3", + "cw-vesting", "cw-wormhole", "cw2 1.1.2", "cw20 1.1.2", @@ -1377,7 +1384,9 @@ dependencies = [ "cw20 1.1.2", "cw20-base 1.1.2", "cw20-stake 0.2.6", + "cw20-stake 2.5.0", "dao-hooks 2.5.0", + "dao-testing", "dao-voting 2.5.0", "thiserror", ] @@ -1399,7 +1408,9 @@ dependencies = [ "cw20 1.1.2", "cw20-base 1.1.2", "cw20-stake 2.5.0", + "cw20-stake-external-rewards", "dao-hooks 2.5.0", + "dao-testing", "stake-cw20-external-rewards", "thiserror", ] @@ -1418,6 +1429,8 @@ dependencies = [ "cw20 1.1.2", "cw20-base 1.1.2", "cw20-stake 2.5.0", + "cw20-stake-reward-distributor", + "dao-testing", "stake-cw20-reward-distributor", "thiserror", ] @@ -1687,9 +1700,11 @@ dependencies = [ "cw20-base 1.1.2", "cw721 0.18.0", "cw721-base 0.18.0", + "dao-dao-core 2.5.0", "dao-dao-macros 2.5.0", "dao-interface 2.5.0", "dao-proposal-sudo", + "dao-testing", "dao-voting-cw20-balance", "thiserror", ] @@ -1799,6 +1814,7 @@ dependencies = [ "cw4-voting", "dao-dao-core 2.5.0", "dao-interface 2.5.0", + "dao-migrator", "dao-proposal-single 2.5.0", "dao-testing", "dao-voting 0.1.0", @@ -2054,6 +2070,7 @@ dependencies = [ "dao-hooks 2.5.0", "dao-interface 2.5.0", "dao-proposal-single 2.5.0", + "dao-testing", "dao-voting 2.5.0", "dao-voting-cw20-balance", "thiserror", @@ -2106,6 +2123,7 @@ dependencies = [ "dao-interface 2.5.0", "dao-pre-propose-base 2.5.0", "dao-pre-propose-multiple 2.5.0", + "dao-proposal-multiple 2.5.0", "dao-testing", "dao-voting 0.1.0", "dao-voting 2.5.0", @@ -2170,6 +2188,7 @@ dependencies = [ "dao-interface 2.5.0", "dao-pre-propose-base 2.5.0", "dao-pre-propose-single 2.5.0", + "dao-proposal-single 2.5.0", "dao-testing", "dao-voting 0.1.0", "dao-voting 2.5.0", @@ -2216,6 +2235,7 @@ dependencies = [ "cw721-base 0.18.0", "dao-hooks 2.5.0", "dao-interface 2.5.0", + "dao-rewards-distributor", "dao-testing", "dao-voting 2.5.0", "dao-voting-cw20-staked", @@ -2250,35 +2270,59 @@ dependencies = [ name = "dao-testing" version = "2.5.0" dependencies = [ + "btsg-ft-factory", "cosmwasm-schema", "cosmwasm-std", "cw-admin-factory", "cw-core", + "cw-fund-distributor", "cw-hooks 2.5.0", "cw-multi-test", + "cw-payroll-factory", "cw-proposal-single", + "cw-token-swap", "cw-tokenfactory-issuer", "cw-utils 1.0.3", "cw-vesting", "cw2 1.1.2", "cw20 1.1.2", "cw20-base 1.1.2", + "cw20-stake 0.2.6", "cw20-stake 2.5.0", + "cw20-stake-external-rewards", + "cw20-stake-reward-distributor", "cw4 1.1.2", "cw4-group 1.1.2", + "cw4-voting", "cw721-base 0.18.0", "cw721-roles", + "dao-dao-core 2.4.1", "dao-dao-core 2.5.0", + "dao-interface 2.4.1", "dao-interface 2.5.0", + "dao-migrator", + "dao-pre-propose-approval-single 2.4.1", + "dao-pre-propose-approval-single 2.5.0", + "dao-pre-propose-approver", + "dao-pre-propose-multiple 2.4.1", "dao-pre-propose-multiple 2.5.0", + "dao-pre-propose-single 2.4.1", "dao-pre-propose-single 2.5.0", "dao-proposal-condorcet", + "dao-proposal-hook-counter", + "dao-proposal-multiple 2.4.1", + "dao-proposal-multiple 2.5.0", + "dao-proposal-single 2.4.1", "dao-proposal-single 2.5.0", + "dao-proposal-sudo", + "dao-rewards-distributor", "dao-test-custom-factory", "dao-voting 0.1.0", + "dao-voting 2.4.1", "dao-voting 2.5.0", "dao-voting-cw20-balance", "dao-voting-cw20-staked", + "dao-voting-cw4 2.4.1", "dao-voting-cw4 2.5.0", "dao-voting-cw721-roles", "dao-voting-cw721-staked", @@ -2290,6 +2334,8 @@ dependencies = [ "serde", "serde_json", "stake-cw20", + "stake-cw20-external-rewards", + "stake-cw20-reward-distributor", ] [[package]] @@ -2350,6 +2396,7 @@ dependencies = [ "cw20-base 1.1.2", "dao-dao-macros 2.5.0", "dao-interface 2.5.0", + "dao-testing", "thiserror", ] @@ -2368,6 +2415,7 @@ dependencies = [ "cw20-stake 2.5.0", "dao-dao-macros 2.5.0", "dao-interface 2.5.0", + "dao-testing", "dao-voting 2.5.0", "thiserror", ] @@ -2404,6 +2452,8 @@ dependencies = [ "cw4-group 1.1.2", "dao-dao-macros 2.5.0", "dao-interface 2.5.0", + "dao-testing", + "dao-voting-cw4 2.5.0", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 1d98d3a94..ab164d07e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,7 @@ wynd-utils = "0.4" # optional owner. cw-ownable = "0.5" +btsg-ft-factory = { path = "./contracts/external/btsg-ft-factory", version = "2.5.0" } cw-admin-factory = { path = "./contracts/external/cw-admin-factory", version = "2.5.0" } cw-denom = { path = "./packages/cw-denom", version = "2.5.0" } cw-fund-distributor = { path = "./contracts/distribution/cw-fund-distributor", version = "2.5.0" } @@ -92,11 +93,14 @@ cw-hooks = { path = "./packages/cw-hooks", version = "2.5.0" } cw-paginate-storage = { path = "./packages/cw-paginate-storage", version = "2.5.0" } cw-payroll-factory = { path = "./contracts/external/cw-payroll-factory", version = "2.5.0" } cw-stake-tracker = { path = "./packages/cw-stake-tracker", version = "2.5.0" } +cw-token-swap = { path = "./contracts/external/cw-token-swap", version = "2.5.0" } cw-tokenfactory-issuer = { path = "./contracts/external/cw-tokenfactory-issuer", version = "2.5.0", default-features = false } cw-tokenfactory-types = { path = "./packages/cw-tokenfactory-types", version = "2.5.0", default-features = false } cw-vesting = { path = "./contracts/external/cw-vesting", version = "2.5.0" } cw-wormhole = { path = "./packages/cw-wormhole", version = "2.5.0" } cw20-stake = { path = "./contracts/staking/cw20-stake", version = "2.5.0" } +cw20-stake-external-rewards = { path = "./contracts/staking/cw20-stake-external-rewards", version = "2.5.0" } +cw20-stake-reward-distributor = { path = "./contracts/staking/cw20-stake-reward-distributor", version = "2.5.0" } cw721-controllers = { path = "./packages/cw721-controllers", version = "2.5.0" } cw721-roles = { path = "./contracts/external/cw721-roles", version = "2.5.0" } dao-cw721-extensions = { path = "./packages/dao-cw721-extensions", version = "2.5.0" } @@ -104,6 +108,7 @@ dao-dao-core = { path = "./contracts/dao-dao-core", version = "2.5.0" } dao-dao-macros = { path = "./packages/dao-dao-macros", version = "2.5.0" } dao-hooks = { path = "./packages/dao-hooks", version = "2.5.0" } dao-interface = { path = "./packages/dao-interface", version = "2.5.0" } +dao-migrator = { path = "./contracts/external/dao-migrator", version = "2.5.0" } dao-pre-propose-approval-single = { path = "./contracts/pre-propose/dao-pre-propose-approval-single", version = "2.5.0" } dao-pre-propose-approver = { path = "./contracts/pre-propose/dao-pre-propose-approver", version = "2.5.0" } dao-pre-propose-base = { path = "./packages/dao-pre-propose-base", version = "2.5.0" } @@ -134,9 +139,12 @@ cw20-stake-external-rewards-v1 = { package = "stake-cw20-external-rewards", vers cw20-stake-reward-distributor-v1 = { package = "stake-cw20-reward-distributor", version = "0.1.0" } cw20-stake-v1 = { package = "cw20-stake", version = "0.2.6" } cw20-staked-balance-voting-v1 = { package = "cw20-staked-balance-voting", version = "0.1.0" } -cw4-voting-v1 = { package = "cw4-voting", version = "0.1.0" } stake-cw20-v03 = { package = "stake-cw20", version = "0.2.6" } +cw4-voting-v1 = { package = "cw4-voting", version = "0.1.0", git = "https://github.com/DA0-DA0/dao-contracts.git", tag = "v1.0.0" } +cw-core-interface-v1 = { package = "cw-core-interface", version = "0.1.0", git = "https://github.com/DA0-DA0/dao-contracts.git", tag = "v1.0.0" } voting-v1 = { package = "dao-voting", version = "0.1.0" } +cw20-v1 = { version = "0.13", package = "cw20" } +cw4-v1 = { version = "0.13", package = "cw4" } # v2.4.1 dependencies. used for state migrations. cw-denom-v241 = { package = "cw-denom", version = "=2.4.1" } diff --git a/contracts/dao-dao-core/Cargo.toml b/contracts/dao-dao-core/Cargo.toml index a9ac8dae6..fe9b3f2b7 100644 --- a/contracts/dao-dao-core/Cargo.toml +++ b/contracts/dao-dao-core/Cargo.toml @@ -31,8 +31,10 @@ cw-paginate-storage = { workspace = true } cw-core-v1 = { workspace = true, features = ["library"] } [dev-dependencies] +dao-dao-core = { workspace = true } cw-multi-test = { workspace = true } cw20-base = { workspace = true } cw721-base = { workspace = true } dao-proposal-sudo = { workspace = true } +dao-testing = { workspace = true } dao-voting-cw20-balance = { workspace = true } diff --git a/contracts/dao-dao-core/schema/dao-dao-core.json b/contracts/dao-dao-core/schema/dao-dao-core.json index b1cca4f3d..7bf2418c2 100644 --- a/contracts/dao-dao-core/schema/dao-dao-core.json +++ b/contracts/dao-dao-core/schema/dao-dao-core.json @@ -918,6 +918,10 @@ }, "additionalProperties": false }, + "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" + }, "DistributionMsg": { "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", "oneOf": [ @@ -1039,6 +1043,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 } ] }, @@ -1463,6 +1497,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", @@ -1547,6 +1635,21 @@ "additionalProperties": false } ] + }, + "WeightedVoteOption": { + "type": "object", + "required": [ + "option", + "weight" + ], + "properties": { + "option": { + "$ref": "#/definitions/VoteOption" + }, + "weight": { + "$ref": "#/definitions/Decimal" + } + } } } }, diff --git a/contracts/dao-dao-core/src/tests.rs b/contracts/dao-dao-core/src/tests.rs index 81dd040cb..4c04f8cc3 100644 --- a/contracts/dao-dao-core/src/tests.rs +++ b/contracts/dao-dao-core/src/tests.rs @@ -5,7 +5,7 @@ use cosmwasm_std::{ to_json_binary, Addr, CosmosMsg, Empty, Storage, Uint128, WasmMsg, }; use cw2::{set_contract_version, ContractVersion}; -use cw_multi_test::{App, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, Executor}; use cw_storage_plus::{Item, Map}; use cw_utils::{Duration, Expiration}; use dao_interface::{ @@ -17,71 +17,19 @@ use dao_interface::{ state::{Admin, Config, ModuleInstantiateInfo, ProposalModule, ProposalModuleStatus}, voting::{InfoResponse, VotingPowerAtHeightResponse}, }; +use dao_testing::contracts::{ + cw20_base_contract, cw721_base_contract, dao_dao_core_contract, dao_proposal_sudo_contract, + dao_voting_cw20_balance_contract, v1::cw_core_v1_contract, +}; use crate::{ contract::{derive_proposal_module_prefix, migrate, CONTRACT_NAME, CONTRACT_VERSION}, state::PROPOSAL_MODULES, - ContractError, }; +use dao_dao_core::ContractError; const CREATOR_ADDR: &str = "creator"; -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn cw721_contract() -> Box> { - let contract = ContractWrapper::new( - cw721_base::entry::execute, - cw721_base::entry::instantiate, - cw721_base::entry::query, - ); - Box::new(contract) -} - -fn sudo_proposal_contract() -> Box> { - let contract = ContractWrapper::new( - dao_proposal_sudo::contract::execute, - dao_proposal_sudo::contract::instantiate, - dao_proposal_sudo::contract::query, - ); - Box::new(contract) -} - -fn cw20_balances_voting() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_balance::contract::execute, - dao_voting_cw20_balance::contract::instantiate, - dao_voting_cw20_balance::contract::query, - ) - .with_reply(dao_voting_cw20_balance::contract::reply); - Box::new(contract) -} - -fn cw_core_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - -fn v1_cw_core_contract() -> Box> { - use cw_core_v1::contract; - let contract = ContractWrapper::new(contract::execute, contract::instantiate, contract::query) - .with_reply(contract::reply) - .with_migrate(contract::migrate); - Box::new(contract) -} - fn instantiate_gov(app: &mut App, code_id: u64, msg: InstantiateMsg) -> Addr { app.instantiate_contract( code_id, @@ -96,8 +44,8 @@ fn instantiate_gov(app: &mut App, code_id: u64, msg: InstantiateMsg) -> Addr { fn test_instantiate_with_n_gov_modules(n: usize) { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let gov_id = app.store_code(cw_core_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let cw20_instantiate = cw20_base::msg::InstantiateMsg { name: "DAO".to_string(), @@ -176,8 +124,8 @@ fn test_valid_instantiate() { #[should_panic(expected = "Error parsing into type cw20_base::msg::InstantiateMsg: Invalid type")] fn test_instantiate_with_submessage_failure() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let gov_id = app.store_code(cw_core_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let cw20_instantiate = cw20_base::msg::InstantiateMsg { name: "DAO".to_string(), @@ -239,8 +187,8 @@ makes wickedness." #[test] fn test_update_config() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let gov_id = app.store_code(cw_core_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -338,8 +286,8 @@ fn test_update_config() { fn test_swap_governance(swaps: Vec<(u32, u32)>) { let mut app = App::default(); - let propmod_id = app.store_code(sudo_proposal_contract()); - let core_id = app.store_code(cw_core_contract()); + let propmod_id = app.store_code(dao_proposal_sudo_contract()); + let core_id = app.store_code(dao_dao_core_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -517,8 +465,8 @@ fn test_swap_governance_bad() { #[test] fn test_removed_modules_can_not_execute() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let gov_id = app.store_code(cw_core_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -680,8 +628,8 @@ fn test_removed_modules_can_not_execute() { #[test] fn test_module_already_disabled() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let gov_id = app.store_code(cw_core_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -782,8 +730,8 @@ fn test_module_already_disabled() { #[test] fn test_swap_voting_module() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let gov_id = app.store_code(cw_core_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -888,8 +836,8 @@ fn test_unauthorized(app: &mut App, gov_addr: Addr, msg: ExecuteMsg) { #[test] fn test_permissions() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let gov_id = app.store_code(cw_core_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -972,10 +920,10 @@ fn test_permissions() { fn do_standard_instantiate(auto_add: bool, admin: Option) -> (Addr, App) { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let voting_id = app.store_code(cw20_balances_voting()); - let gov_id = app.store_code(cw_core_contract()); - let cw20_id = app.store_code(cw20_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -1689,10 +1637,10 @@ fn test_remove_missing_key() { #[test] fn test_list_items() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let voting_id = app.store_code(cw20_balances_voting()); - let gov_id = app.store_code(cw_core_contract()); - let cw20_id = app.store_code(cw20_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -1808,10 +1756,10 @@ fn test_list_items() { #[test] fn test_instantiate_with_items() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let voting_id = app.store_code(cw20_balances_voting()); - let gov_id = app.store_code(cw_core_contract()); - let cw20_id = app.store_code(cw20_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -1927,7 +1875,7 @@ fn test_instantiate_with_items() { fn test_cw20_receive_auto_add() { let (gov_addr, mut app) = do_standard_instantiate(true, None); - let cw20_id = app.store_code(cw20_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let another_cw20 = app .instantiate_contract( cw20_id, @@ -2074,7 +2022,7 @@ fn test_cw20_receive_auto_add() { fn test_cw20_receive_no_auto_add() { let (gov_addr, mut app) = do_standard_instantiate(false, None); - let cw20_id = app.store_code(cw20_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let another_cw20 = app .instantiate_contract( cw20_id, @@ -2159,7 +2107,7 @@ fn test_cw20_receive_no_auto_add() { fn test_cw721_receive() { let (gov_addr, mut app) = do_standard_instantiate(true, None); - let cw721_id = app.store_code(cw721_contract()); + let cw721_id = app.store_code(cw721_base_contract()); let cw721_addr = app .instantiate_contract( @@ -2289,7 +2237,7 @@ fn test_cw721_receive() { fn test_cw721_receive_no_auto_add() { let (gov_addr, mut app) = do_standard_instantiate(false, None); - let cw721_id = app.store_code(cw721_contract()); + let cw721_id = app.store_code(cw721_base_contract()); let cw721_addr = app .instantiate_contract( @@ -2651,10 +2599,10 @@ fn test_dump_state_proposal_modules() { #[test] fn test_migrate_from_compatible() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let voting_id = app.store_code(cw20_balances_voting()); - let gov_id = app.store_code(cw_core_contract()); - let cw20_id = app.store_code(cw20_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -2739,11 +2687,11 @@ fn test_migrate_from_beta() { use cw_core_v1 as v1; let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let voting_id = app.store_code(cw20_balances_voting()); - let core_id = app.store_code(cw_core_contract()); - let v1_core_id = app.store_code(v1_cw_core_contract()); - let cw20_id = app.store_code(cw20_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let v1_core_id = app.store_code(cw_core_v1_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let proposal_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), @@ -2953,8 +2901,8 @@ fn test_execute_stargate_msg() { #[test] fn test_module_prefixes() { let mut app = App::default(); - let govmod_id = app.store_code(sudo_proposal_contract()); - let gov_id = app.store_code(cw_core_contract()); + let govmod_id = app.store_code(dao_proposal_sudo_contract()); + let gov_id = app.store_code(dao_dao_core_contract()); let govmod_instantiate = dao_proposal_sudo::msg::InstantiateMsg { root: CREATOR_ADDR.to_string(), diff --git a/contracts/distribution/cw-fund-distributor/Cargo.toml b/contracts/distribution/cw-fund-distributor/Cargo.toml index f73aba4df..6d67b634d 100644 --- a/contracts/distribution/cw-fund-distributor/Cargo.toml +++ b/contracts/distribution/cw-fund-distributor/Cargo.toml @@ -30,6 +30,8 @@ dao-interface = { workspace = true } cw-paginate-storage = { workspace = true } [dev-dependencies] +cw-fund-distributor = { workspace = true } dao-dao-core = { workspace = true, features = ["library"] } +dao-testing = { workspace = true } cw-multi-test = { workspace = true } cw20-base = { workspace = true, features = ["library"] } diff --git a/contracts/distribution/cw-fund-distributor/src/testing/adversarial_tests.rs b/contracts/distribution/cw-fund-distributor/src/testing/adversarial_tests.rs index 8df033529..cc0e0c865 100644 --- a/contracts/distribution/cw-fund-distributor/src/testing/adversarial_tests.rs +++ b/contracts/distribution/cw-fund-distributor/src/testing/adversarial_tests.rs @@ -1,9 +1,13 @@ use crate::msg::ExecuteMsg::ClaimAll; use crate::msg::{ExecuteMsg, InstantiateMsg}; -use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Empty, Uint128}; +use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Uint128}; use cw20::{BalanceResponse, Cw20Coin}; -use cw_multi_test::{next_block, App, BankSudo, Contract, ContractWrapper, Executor, SudoMsg}; +use cw_multi_test::{next_block, App, BankSudo, Executor, SudoMsg}; use cw_utils::Duration; +use dao_testing::contracts::{ + cw20_base_contract, cw20_stake_contract, cw_fund_distributor_contract, + dao_voting_cw20_staked_contract, +}; const CREATOR_ADDR: &str = "creator"; const FEE_DENOM: &str = "ujuno"; @@ -13,44 +17,6 @@ struct BaseTest { distributor_address: Addr, } -fn distributor_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn staked_balances_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_staked::contract::execute, - dao_voting_cw20_staked::contract::instantiate, - dao_voting_cw20_staked::contract::query, - ) - .with_reply(dao_voting_cw20_staked::contract::reply); - Box::new(contract) -} - -fn cw20_staking_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ); - Box::new(contract) -} - fn instantiate_cw20( app: &mut App, sender: Addr, @@ -58,7 +24,7 @@ fn instantiate_cw20( name: String, symbol: String, ) -> Addr { - let cw20_id = app.store_code(cw20_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let msg = cw20_base::msg::InstantiateMsg { name, symbol, @@ -74,10 +40,10 @@ fn instantiate_cw20( fn setup_test(initial_balances: Vec) -> BaseTest { let mut app = App::default(); - let distributor_id = app.store_code(distributor_contract()); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balances_voting_contract()); - let stake_cw20_id = app.store_code(cw20_staking_contract()); + let distributor_id = app.store_code(cw_fund_distributor_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let stake_cw20_id = app.store_code(cw20_stake_contract()); let voting_address = app .instantiate_contract( diff --git a/contracts/distribution/cw-fund-distributor/src/testing/tests.rs b/contracts/distribution/cw-fund-distributor/src/testing/tests.rs index f3269dd3f..d86ca86a0 100644 --- a/contracts/distribution/cw-fund-distributor/src/testing/tests.rs +++ b/contracts/distribution/cw-fund-distributor/src/testing/tests.rs @@ -2,10 +2,14 @@ use crate::msg::{ CW20EntitlementResponse, CW20Response, DenomResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, NativeEntitlementResponse, QueryMsg, TotalPowerResponse, VotingContractResponse, }; -use crate::ContractError; -use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Empty, Uint128, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Uint128, WasmMsg}; use cw20::Cw20Coin; -use cw_multi_test::{next_block, App, BankSudo, Contract, ContractWrapper, Executor, SudoMsg}; +use cw_fund_distributor::ContractError; +use cw_multi_test::{next_block, App, BankSudo, Executor, SudoMsg}; +use dao_testing::contracts::{ + cw20_base_contract, cw20_stake_contract, cw_fund_distributor_contract, + dao_voting_cw20_staked_contract, +}; use crate::msg::ExecuteMsg::{ClaimAll, ClaimCW20, ClaimNatives}; use crate::msg::QueryMsg::TotalPower; @@ -15,44 +19,6 @@ use cw_utils::Duration; const CREATOR_ADDR: &str = "creator"; const FEE_DENOM: &str = "ujuno"; -fn distributor_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn staked_balances_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_staked::contract::execute, - dao_voting_cw20_staked::contract::instantiate, - dao_voting_cw20_staked::contract::query, - ) - .with_reply(dao_voting_cw20_staked::contract::reply); - Box::new(contract) -} - -fn cw20_staking_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ); - Box::new(contract) -} - struct BaseTest { app: App, distributor_address: Addr, @@ -61,10 +27,10 @@ struct BaseTest { fn setup_test(initial_balances: Vec) -> BaseTest { let mut app = App::default(); - let distributor_id = app.store_code(distributor_contract()); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balances_voting_contract()); - let stake_cw20_id = app.store_code(cw20_staking_contract()); + let distributor_id = app.store_code(cw_fund_distributor_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let stake_cw20_id = app.store_code(cw20_stake_contract()); let voting_address = app .instantiate_contract( @@ -196,7 +162,7 @@ pub fn mint_natives(app: &mut App, recipient: Addr, amount: Uint128) { .unwrap(); } -pub fn fund_distributor_contract_cw20( +pub fn fund_cw_fund_distributor_contract_cw20( app: &mut App, distributor_address: Addr, token_address: Addr, @@ -216,7 +182,7 @@ pub fn fund_distributor_contract_cw20( .unwrap(); } -pub fn fund_distributor_contract_natives( +pub fn fund_cw_fund_distributor_contract_natives( app: &mut App, distributor_address: Addr, amount: Uint128, @@ -237,7 +203,7 @@ pub fn fund_distributor_contract_natives( #[test] fn test_instantiate_fails_given_invalid_voting_contract_address() { let mut app = App::default(); - let distributor_id = app.store_code(distributor_contract()); + let distributor_id = app.store_code(cw_fund_distributor_contract()); let expected_error: ContractError = app .instantiate_contract( @@ -265,10 +231,10 @@ fn test_instantiate_fails_given_invalid_voting_contract_address() { #[test] fn test_instantiate_fails_zero_voting_power() { let mut app = App::default(); - let distributor_id = app.store_code(distributor_contract()); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balances_voting_contract()); - let stake_cw20_id = app.store_code(cw20_staking_contract()); + let distributor_id = app.store_code(cw_fund_distributor_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let stake_cw20_id = app.store_code(cw20_stake_contract()); let initial_balances = vec![Cw20Coin { address: "bekauz".to_string(), @@ -376,7 +342,7 @@ fn test_fund_cw20() { let first_fund_amount = Uint128::new(20000); // fund the contract for the first time - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -391,7 +357,7 @@ fn test_fund_cw20() { let second_fund_amount = amount.checked_sub(first_fund_amount).unwrap(); // fund the remaining part - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -464,7 +430,7 @@ pub fn test_fund_natives() { let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -476,7 +442,7 @@ pub fn test_fund_natives() { // fund again with an existing balance with an existing balance, fund mint_natives(&mut app, Addr::unchecked("bekauz"), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -571,7 +537,7 @@ pub fn test_claim_cw20() { ); // fund the contract - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -641,7 +607,7 @@ pub fn test_claim_cw20_twice() { ); // fund the contract - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -715,7 +681,7 @@ pub fn test_claim_cw20s_empty_list() { ); // fund the contract - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address, @@ -760,7 +726,7 @@ pub fn test_claim_natives_twice() { let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -823,7 +789,7 @@ pub fn test_claim_natives() { let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -876,7 +842,7 @@ pub fn test_claim_all() { let amount = Uint128::new(500000); // mint and fund the distributor with native & cw20 tokens mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -889,7 +855,7 @@ pub fn test_claim_all() { amount, Addr::unchecked(CREATOR_ADDR), ); - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -956,7 +922,7 @@ pub fn test_claim_natives_empty_list_of_denoms() { let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -1002,11 +968,11 @@ pub fn test_redistribute_unclaimed_funds() { amount: Uint128::new(20), }, ]); - let distributor_id = app.store_code(distributor_contract()); + let distributor_id = app.store_code(cw_fund_distributor_contract()); let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -1103,14 +1069,14 @@ pub fn test_unauthorized_redistribute_unclaimed_funds() { mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, Addr::unchecked(CREATOR_ADDR), ); - let distributor_id = app.store_code(distributor_contract()); + let distributor_id = app.store_code(cw_fund_distributor_contract()); let migrate_msg = &MigrateMsg::RedistributeUnclaimedFunds { distribution_height: app.block_info().height, }; @@ -1149,7 +1115,7 @@ pub fn test_claim_cw20_during_funding_period() { ); // fund the contract - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -1197,7 +1163,7 @@ pub fn test_claim_natives_during_funding_period() { mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); // fund the contract - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -1241,7 +1207,7 @@ pub fn test_claim_all_during_funding_period() { let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -1377,7 +1343,7 @@ fn test_query_cw20_entitlements() { amount, Addr::unchecked(CREATOR_ADDR), ); - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -1431,7 +1397,7 @@ fn test_query_native_entitlements() { // fund the contract with some native tokens let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -1476,7 +1442,7 @@ fn test_query_cw20_entitlement() { amount, Addr::unchecked(CREATOR_ADDR), ); - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address.clone(), @@ -1539,7 +1505,7 @@ fn test_query_native_entitlement() { // fund the contract with some native tokens let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, @@ -1585,7 +1551,7 @@ fn test_query_cw20_tokens() { amount, Addr::unchecked(CREATOR_ADDR), ); - fund_distributor_contract_cw20( + fund_cw_fund_distributor_contract_cw20( &mut app, distributor_address.clone(), token_address, @@ -1628,7 +1594,7 @@ fn test_query_native_denoms() { // mint and fund the distributor with a native token let amount = Uint128::new(500000); mint_natives(&mut app, Addr::unchecked(CREATOR_ADDR), amount); - fund_distributor_contract_natives( + fund_cw_fund_distributor_contract_natives( &mut app, distributor_address.clone(), amount, diff --git a/contracts/distribution/dao-rewards-distributor/Cargo.toml b/contracts/distribution/dao-rewards-distributor/Cargo.toml index 4d38cbc3b..035aba996 100644 --- a/contracts/distribution/dao-rewards-distributor/Cargo.toml +++ b/contracts/distribution/dao-rewards-distributor/Cargo.toml @@ -33,6 +33,7 @@ semver = { workspace = true } thiserror = { workspace = true } [dev-dependencies] +dao-rewards-distributor = { workspace = true } cw-multi-test = { workspace = true } anyhow = { workspace = true } cw20-stake = { workspace = true, features = ["library"] } diff --git a/contracts/distribution/dao-rewards-distributor/src/testing/mod.rs b/contracts/distribution/dao-rewards-distributor/src/testing/mod.rs index e84477456..836069a0a 100644 --- a/contracts/distribution/dao-rewards-distributor/src/testing/mod.rs +++ b/contracts/distribution/dao-rewards-distributor/src/testing/mod.rs @@ -1,299 +1,2 @@ -use cosmwasm_std::Empty; -use cw_multi_test::{Contract, ContractWrapper}; - pub mod suite; pub mod tests; - -pub const DENOM: &str = "ujuno"; -pub const ALT_DENOM: &str = "unotjuno"; -pub const OWNER: &str = "owner"; -pub const ADDR1: &str = "addr1"; -pub const ADDR2: &str = "addr2"; -pub const ADDR3: &str = "addr3"; -pub const ADDR4: &str = "addr4"; - -pub fn contract_rewards() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ); - Box::new(contract) -} - -mod cw4_setup { - use cosmwasm_std::Addr; - use cw4::Member; - use cw_multi_test::{App, Executor}; - use dao_testing::contracts::{cw4_group_contract, dao_voting_cw4_contract}; - - use super::OWNER; - - pub fn setup_cw4_test(app: &mut App, initial_members: Vec) -> (Addr, Addr) { - let cw4_group_code_id = app.store_code(cw4_group_contract()); - let vp_code_id = app.store_code(dao_voting_cw4_contract()); - - let msg = dao_voting_cw4::msg::InstantiateMsg { - group_contract: dao_voting_cw4::msg::GroupContract::New { - cw4_group_code_id, - initial_members, - }, - }; - - let vp_addr = app - .instantiate_contract( - vp_code_id, - Addr::unchecked(OWNER), - &msg, - &[], - "cw4-vp", - None, - ) - .unwrap(); - - let cw4_addr: Addr = app - .wrap() - .query_wasm_smart( - vp_addr.clone(), - &dao_voting_cw4::msg::QueryMsg::GroupContract {}, - ) - .unwrap(); - - (vp_addr, cw4_addr) - } -} - -mod native_setup { - use cosmwasm_std::{coins, Addr}; - use cw_multi_test::{App, Executor}; - use dao_testing::contracts::native_staked_balances_voting_contract; - - use super::{DENOM, OWNER}; - - pub fn stake_tokenfactory_tokens( - app: &mut App, - staking_addr: &Addr, - address: &str, - amount: u128, - ) { - let msg = dao_voting_token_staked::msg::ExecuteMsg::Stake {}; - app.execute_contract( - Addr::unchecked(address), - staking_addr.clone(), - &msg, - &coins(amount, DENOM), - ) - .unwrap(); - } - - pub fn unstake_tokenfactory_tokens( - app: &mut App, - staking_addr: &Addr, - address: &str, - amount: u128, - ) { - let msg = dao_voting_token_staked::msg::ExecuteMsg::Unstake { - amount: amount.into(), - }; - app.execute_contract(Addr::unchecked(address), staking_addr.clone(), &msg, &[]) - .unwrap(); - } - - pub fn setup_native_token_test(app: &mut App) -> Addr { - let vp_code_id = app.store_code(native_staked_balances_voting_contract()); - - let msg = dao_voting_token_staked::msg::InstantiateMsg { - active_threshold: None, - unstaking_duration: None, - token_info: dao_voting_token_staked::msg::TokenInfo::Existing { - denom: DENOM.to_string(), - }, - }; - - app.instantiate_contract( - vp_code_id, - Addr::unchecked(OWNER), - &msg, - &[], - "native-vp", - None, - ) - .unwrap() - } -} - -mod cw20_setup { - use cosmwasm_std::{to_json_binary, Addr, Uint128}; - use cw20::Cw20Coin; - use cw_multi_test::{App, Executor}; - use cw_utils::Duration; - use dao_testing::contracts::{ - cw20_base_contract, cw20_stake_contract, cw20_staked_balances_voting_contract, - }; - - use super::OWNER; - - pub fn instantiate_cw20(app: &mut App, name: &str, initial_balances: Vec) -> Addr { - let cw20_id = app.store_code(cw20_base_contract()); - let msg = cw20_base::msg::InstantiateMsg { - name: name.to_string(), - symbol: name.to_string(), - decimals: 6, - initial_balances, - mint: None, - marketing: None, - }; - - app.instantiate_contract(cw20_id, Addr::unchecked(OWNER), &msg, &[], "cw20", None) - .unwrap() - } - - pub fn instantiate_cw20_staking( - app: &mut App, - cw20: Addr, - unstaking_duration: Option, - ) -> Addr { - let staking_code_id = app.store_code(cw20_stake_contract()); - let msg = cw20_stake::msg::InstantiateMsg { - owner: Some(OWNER.to_string()), - token_address: cw20.to_string(), - unstaking_duration, - }; - app.instantiate_contract( - staking_code_id, - Addr::unchecked(OWNER), - &msg, - &[], - "staking", - None, - ) - .unwrap() - } - - pub fn instantiate_cw20_vp_contract(app: &mut App, cw20: Addr, staking_contract: Addr) -> Addr { - let vp_code_id = app.store_code(cw20_staked_balances_voting_contract()); - let msg = dao_voting_cw20_staked::msg::InstantiateMsg { - token_info: dao_voting_cw20_staked::msg::TokenInfo::Existing { - address: cw20.to_string(), - staking_contract: dao_voting_cw20_staked::msg::StakingInfo::Existing { - staking_contract_address: staking_contract.to_string(), - }, - }, - active_threshold: None, - }; - app.instantiate_contract(vp_code_id, Addr::unchecked(OWNER), &msg, &[], "vp", None) - .unwrap() - } - - pub fn setup_cw20_test(app: &mut App, initial_balances: Vec) -> (Addr, Addr, Addr) { - // Instantiate cw20 contract - let cw20_addr = instantiate_cw20(app, "test", initial_balances.clone()); - - // Instantiate staking contract - let staking_addr = instantiate_cw20_staking(app, cw20_addr.clone(), None); - - // Instantiate vp contract - let vp_addr = instantiate_cw20_vp_contract(app, cw20_addr.clone(), staking_addr.clone()); - - (staking_addr, cw20_addr, vp_addr) - } - - #[allow(dead_code)] - pub fn stake_cw20_tokens>( - app: &mut App, - staking_addr: &Addr, - cw20_addr: &Addr, - sender: T, - amount: u128, - ) { - let msg = cw20::Cw20ExecuteMsg::Send { - contract: staking_addr.to_string(), - amount: Uint128::new(amount), - msg: to_json_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(), - }; - app.execute_contract(Addr::unchecked(sender), cw20_addr.clone(), &msg, &[]) - .unwrap(); - } -} - -mod cw721_setup { - - use cosmwasm_std::{to_json_binary, Addr, Binary, Empty}; - use cw_multi_test::{App, Executor}; - use dao_testing::contracts::{cw721_base_contract, cw721_staked_voting_contract}; - use dao_voting_cw721_staked::state::Config; - - use super::OWNER; - - pub fn stake_cw721( - app: &mut App, - vp_addr: &Addr, - cw721_addr: &Addr, - address: &str, - token_id: &str, - ) { - let msg = cw721_base::msg::ExecuteMsg::::SendNft { - contract: vp_addr.to_string(), - token_id: token_id.to_string(), - msg: Binary::default(), - }; - - app.execute_contract(Addr::unchecked(address), cw721_addr.clone(), &msg, &[]) - .unwrap(); - } - - pub fn unstake_cw721(app: &mut App, vp_addr: &Addr, address: &str, token_id: &str) { - app.execute_contract( - Addr::unchecked(address), - vp_addr.clone(), - &dao_voting_cw721_staked::msg::ExecuteMsg::Unstake { - token_ids: vec![token_id.to_string()], - }, - &[], - ) - .unwrap(); - } - - pub fn setup_cw721_test(app: &mut App, initial_nfts: Vec) -> (Addr, Addr) { - let cw721_code_id = app.store_code(cw721_base_contract()); - let vp_code_id = app.store_code(cw721_staked_voting_contract()); - - let msg = dao_voting_cw721_staked::msg::InstantiateMsg { - nft_contract: dao_voting_cw721_staked::msg::NftContract::New { - code_id: cw721_code_id, - label: "Test NFT contract".to_string(), - msg: to_json_binary(&cw721_base::msg::InstantiateMsg { - name: "Test NFT".to_string(), - symbol: "TEST".to_string(), - minter: OWNER.to_string(), - }) - .unwrap(), - initial_nfts, - }, - active_threshold: None, - unstaking_duration: None, - }; - - let vp_addr = app - .instantiate_contract( - vp_code_id, - Addr::unchecked(OWNER), - &msg, - &[], - "cw721-vp", - None, - ) - .unwrap(); - - let cw721_addr = app - .wrap() - .query_wasm_smart::( - vp_addr.clone(), - &dao_voting_cw721_staked::msg::QueryMsg::Config {}, - ) - .unwrap() - .nft_address; - - (vp_addr, cw721_addr) - } -} diff --git a/contracts/distribution/dao-rewards-distributor/src/testing/suite.rs b/contracts/distribution/dao-rewards-distributor/src/testing/suite.rs index ed01a2256..749e1cd38 100644 --- a/contracts/distribution/dao-rewards-distributor/src/testing/suite.rs +++ b/contracts/distribution/dao-rewards-distributor/src/testing/suite.rs @@ -1,13 +1,15 @@ -use std::borrow::BorrowMut; - use cosmwasm_schema::cw_serde; -use cosmwasm_std::{coin, coins, to_json_binary, Addr, Coin, Empty, Timestamp, Uint128}; +use cosmwasm_std::{coin, to_json_binary, Addr, Coin, Timestamp, Uint128}; use cw20::{Cw20Coin, Expiration, UncheckedDenom}; use cw4::{Member, MemberListResponse}; -use cw_multi_test::{App, BankSudo, Executor, SudoMsg}; +use cw_multi_test::{BankSudo, Executor, SudoMsg}; use cw_ownable::Action; use cw_utils::Duration; -use dao_interface::voting::InfoResponse; +use dao_interface::{token::InitialBalance, voting::InfoResponse}; +use dao_testing::{ + Cw20TestDao, Cw4TestDao, Cw721TestDao, DaoTestingSuite, DaoTestingSuiteBase, InitialNft, + TokenTestDao, GOV_DENOM, MEMBER1, MEMBER2, MEMBER3, OWNER, +}; use crate::{ msg::{ @@ -15,26 +17,13 @@ use crate::{ PendingRewardsResponse, QueryMsg, ReceiveCw20Msg, }, state::{DistributionState, EmissionRate}, - testing::cw20_setup::instantiate_cw20, - ContractError, -}; - -use super::{ - contract_rewards, - cw20_setup::{self, setup_cw20_test}, - cw4_setup::setup_cw4_test, - cw721_setup::{setup_cw721_test, stake_cw721, unstake_cw721}, - native_setup::{ - setup_native_token_test, stake_tokenfactory_tokens, unstake_tokenfactory_tokens, - }, - ADDR1, ADDR2, ADDR3, DENOM, OWNER, }; - +use dao_rewards_distributor::ContractError; pub enum DaoType { CW20, + CW4, CW721, Native, - CW4, } #[cw_serde] @@ -47,7 +36,6 @@ pub struct RewardsConfig { } pub struct SuiteBuilder { - pub _instantiate: InstantiateMsg, pub dao_type: DaoType, pub rewards_config: RewardsConfig, pub cw4_members: Vec, @@ -56,28 +44,25 @@ pub struct SuiteBuilder { impl SuiteBuilder { pub fn base(dao_type: DaoType) -> Self { Self { - _instantiate: InstantiateMsg { - owner: Some(OWNER.to_string()), - }, dao_type, rewards_config: RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Height(10), destination: None, continuous: true, }, cw4_members: vec![ Member { - addr: ADDR1.to_string(), + addr: MEMBER1.to_string(), weight: 2, }, Member { - addr: ADDR2.to_string(), + addr: MEMBER2.to_string(), weight: 1, }, Member { - addr: ADDR3.to_string(), + addr: MEMBER3.to_string(), weight: 1, }, ], @@ -102,150 +87,133 @@ impl SuiteBuilder { impl SuiteBuilder { pub fn build(mut self) -> Suite { - let owner = Addr::unchecked(OWNER); - let mut suite_built = Suite { - app: App::default(), - owner: Some(owner.clone()), + base: DaoTestingSuiteBase::base(), + core_addr: Addr::unchecked(""), staking_addr: Addr::unchecked(""), voting_power_addr: Addr::unchecked(""), reward_code_id: 0, distribution_contract: Addr::unchecked(""), cw20_addr: Addr::unchecked(""), - reward_denom: DENOM.to_string(), + reward_denom: GOV_DENOM.to_string(), + cw20_dao: None, + cw4_dao: None, + cw721_dao: None, + token_dao: None, }; - // start at 0 height and time - suite_built.app.borrow_mut().update_block(|b| b.height = 0); - suite_built - .app - .borrow_mut() - .update_block(|b| b.time = Timestamp::from_seconds(0)); - match self.dao_type { DaoType::CW4 => { - let (voting_power_addr, dao_voting_addr) = - setup_cw4_test(suite_built.app.borrow_mut(), self.cw4_members); - suite_built.voting_power_addr = voting_power_addr.clone(); - suite_built.staking_addr = dao_voting_addr.clone(); + let dao = suite_built.base.cw4().with_members(self.cw4_members).dao(); + suite_built.core_addr = dao.core_addr.clone(); + suite_built.voting_power_addr = dao.voting_module_addr.clone(); + suite_built.staking_addr = dao.x.group_addr.clone(); + suite_built.cw4_dao = Some(dao); } DaoType::CW20 => { - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - - let (staking_addr, cw20_addr, vp_addr) = - setup_cw20_test(suite_built.app.borrow_mut(), initial_balances.clone()); - - suite_built.voting_power_addr = vp_addr.clone(); - suite_built.cw20_addr = cw20_addr.clone(); - suite_built.staking_addr = staking_addr.clone(); - - for coin in initial_balances.clone() { - suite_built.stake_cw20_tokens(coin.amount.u128(), coin.address.as_str()); - } + let dao = suite_built + .base + .cw20() + .with_initial_balances(vec![ + Cw20Coin { + address: MEMBER1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: MEMBER2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: MEMBER3.to_string(), + amount: Uint128::new(50), + }, + ]) + .dao(); + + suite_built.core_addr = dao.core_addr.clone(); + suite_built.voting_power_addr = dao.voting_module_addr.clone(); + suite_built.cw20_addr = dao.x.cw20_addr.clone(); + suite_built.staking_addr = dao.x.staking_addr.clone(); + suite_built.cw20_dao = Some(dao); } DaoType::CW721 => { - let initial_nfts = vec![ - to_json_binary(&cw721_base::msg::ExecuteMsg::::Mint { - token_id: "1".to_string(), - owner: ADDR1.to_string(), - token_uri: Some("https://jpegs.com".to_string()), - extension: Empty {}, - }) - .unwrap(), - to_json_binary(&cw721_base::msg::ExecuteMsg::::Mint { - token_id: "2".to_string(), - owner: ADDR1.to_string(), - token_uri: Some("https://jpegs.com".to_string()), - extension: Empty {}, - }) - .unwrap(), - to_json_binary(&cw721_base::msg::ExecuteMsg::::Mint { - token_id: "3".to_string(), - owner: ADDR2.to_string(), - token_uri: Some("https://jpegs.com".to_string()), - extension: Empty {}, - }) - .unwrap(), - to_json_binary(&cw721_base::msg::ExecuteMsg::::Mint { - token_id: "4".to_string(), - owner: ADDR3.to_string(), - token_uri: Some("https://jpegs.com".to_string()), - extension: Empty {}, - }) - .unwrap(), - ]; - - let (vp_addr, cw721) = setup_cw721_test(suite_built.app.borrow_mut(), initial_nfts); - - suite_built.voting_power_addr = vp_addr.clone(); - suite_built.staking_addr = cw721.clone(); - - suite_built.stake_nft(ADDR1, 1); - suite_built.stake_nft(ADDR1, 2); - suite_built.stake_nft(ADDR2, 3); - suite_built.stake_nft(ADDR3, 4); + let dao = suite_built + .base + .cw721() + .with_initial_nfts(vec![ + InitialNft { + token_id: "1".to_string(), + owner: MEMBER1.to_string(), + }, + InitialNft { + token_id: "2".to_string(), + owner: MEMBER1.to_string(), + }, + InitialNft { + token_id: "3".to_string(), + owner: MEMBER2.to_string(), + }, + InitialNft { + token_id: "4".to_string(), + owner: MEMBER3.to_string(), + }, + ]) + .dao(); + + suite_built.core_addr = dao.core_addr.clone(); + suite_built.voting_power_addr = dao.voting_module_addr.clone(); + suite_built.staking_addr = dao.x.cw721_addr.clone(); + suite_built.cw721_dao = Some(dao); } DaoType::Native => { - let initial_balances = vec![ - (ADDR1, coins(100, DENOM)), - (ADDR2, coins(50, DENOM)), - (ADDR3, coins(50, DENOM)), - ]; - - // Mint tokens for initial balances - for init_bal in initial_balances { - suite_built - .app - .borrow_mut() - .sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: init_bal.0.to_string(), - amount: init_bal.1, - } - })) - .unwrap(); - } - - // Create Native token staking contract - let vp_addr = setup_native_token_test(suite_built.app.borrow_mut()); - suite_built.voting_power_addr = vp_addr.clone(); - suite_built.staking_addr = vp_addr.clone(); - suite_built.stake_native_tokens(ADDR1, 100); - suite_built.stake_native_tokens(ADDR2, 50); - suite_built.stake_native_tokens(ADDR3, 50); + let dao = suite_built + .base + .token() + .with_initial_balances(vec![ + InitialBalance { + address: MEMBER1.to_string(), + amount: Uint128::new(100), + }, + InitialBalance { + address: MEMBER2.to_string(), + amount: Uint128::new(50), + }, + InitialBalance { + address: MEMBER3.to_string(), + amount: Uint128::new(50), + }, + ]) + .dao(); + + suite_built.core_addr = dao.core_addr.clone(); + suite_built.voting_power_addr = dao.voting_module_addr.clone(); + suite_built.staking_addr = dao.voting_module_addr.clone(); + suite_built.token_dao = Some(dao); } }; + // start at 0 height and time + suite_built.base.app.update_block(|b| { + b.height = 0; + b.time = Timestamp::from_seconds(0); + }); + // initialize the rewards distributor - suite_built.reward_code_id = suite_built.app.borrow_mut().store_code(contract_rewards()); - let reward_addr = suite_built + suite_built.reward_code_id = suite_built.base.rewards_distributor_id; + suite_built.distribution_contract = suite_built + .base .app - .borrow_mut() .instantiate_contract( suite_built.reward_code_id, - owner.clone(), + Addr::unchecked(OWNER), &InstantiateMsg { - owner: Some(owner.clone().into_string()), + owner: Some(OWNER.to_string()), }, &[], "reward", None, ) .unwrap(); - suite_built.distribution_contract = reward_addr.clone(); // depending on the dao type we register rewards differently match self.dao_type { @@ -258,7 +226,7 @@ impl SuiteBuilder { ); match self.rewards_config.denom { UncheckedDenom::Native(_) => { - suite_built.fund_native(1, coin(100_000_000, DENOM.to_string())); + suite_built.fund_native(1, coin(100_000_000, GOV_DENOM.to_string())); } UncheckedDenom::Cw20(_) => { suite_built.fund_cw20( @@ -275,15 +243,16 @@ impl SuiteBuilder { self.rewards_config.denom = match self.rewards_config.denom { UncheckedDenom::Native(denom) => UncheckedDenom::Native(denom), UncheckedDenom::Cw20(_) => UncheckedDenom::Cw20( - instantiate_cw20( - suite_built.app.borrow_mut(), - "rewardcw", - vec![Cw20Coin { - address: OWNER.to_string(), - amount: Uint128::new(1_000_000_000), - }], - ) - .to_string(), + suite_built + .base + .instantiate_cw20( + "rewardcw", + vec![Cw20Coin { + address: OWNER.to_string(), + amount: Uint128::new(1_000_000_000), + }], + ) + .to_string(), ), }; suite_built.reward_denom = match self.rewards_config.denom.clone() { @@ -299,7 +268,7 @@ impl SuiteBuilder { ); match &self.rewards_config.denom { UncheckedDenom::Native(_) => { - suite_built.fund_native(1, coin(100_000_000, DENOM.to_string())); + suite_built.fund_native(1, coin(100_000_000, GOV_DENOM.to_string())); } UncheckedDenom::Cw20(addr) => { suite_built.fund_cw20( @@ -321,9 +290,9 @@ impl SuiteBuilder { } pub struct Suite { - pub app: App, - pub owner: Option, + pub base: DaoTestingSuiteBase, + pub core_addr: Addr, pub staking_addr: Addr, pub voting_power_addr: Addr, pub reward_denom: String, @@ -333,13 +302,19 @@ pub struct Suite { // cw20 type fields pub cw20_addr: Addr, + + // DAO types + pub cw20_dao: Option, + pub cw4_dao: Option, + pub cw721_dao: Option, + pub token_dao: Option, } // SUITE QUERIES impl Suite { pub fn get_time_until_rewards_expiration(&mut self) -> u64 { let distribution = &self.get_distributions().distributions[0]; - let current_block = self.app.block_info(); + let current_block = self.base.app.block_info(); let (expiration_unit, current_unit) = match distribution.active_epoch.ends_at { cw20::Expiration::AtHeight(h) => (h, current_block.height), cw20::Expiration::AtTime(t) => (t.seconds(), current_block.time.seconds()), @@ -358,7 +333,8 @@ impl Suite { address: T, denom: U, ) -> u128 { - self.app + self.base + .app .wrap() .query_balance(address, denom) .unwrap() @@ -375,6 +351,7 @@ impl Suite { address: address.into(), }; let result: cw20::BalanceResponse = self + .base .app .wrap() .query_wasm_smart(contract_addr, &msg) @@ -383,7 +360,8 @@ impl Suite { } pub fn get_distributions(&mut self) -> DistributionsResponse { - self.app + self.base + .app .wrap() .query_wasm_smart( self.distribution_contract.clone(), @@ -397,6 +375,7 @@ impl Suite { pub fn get_distribution(&mut self, id: u64) -> DistributionState { let resp: DistributionState = self + .base .app .wrap() .query_wasm_smart( @@ -409,8 +388,8 @@ impl Suite { pub fn get_undistributed_rewards(&mut self, id: u64) -> Uint128 { let undistributed_rewards: Uint128 = self + .base .app - .borrow_mut() .wrap() .query_wasm_smart( self.distribution_contract.clone(), @@ -422,8 +401,8 @@ impl Suite { pub fn get_owner(&mut self) -> Addr { let ownable_response: cw_ownable::Ownership = self + .base .app - .borrow_mut() .wrap() .query_wasm_smart(self.distribution_contract.clone(), &QueryMsg::Ownership {}) .unwrap(); @@ -431,8 +410,8 @@ impl Suite { } pub fn get_info(&mut self) -> InfoResponse { - self.app - .borrow_mut() + self.base + .app .wrap() .query_wasm_smart(self.distribution_contract.clone(), &QueryMsg::Info {}) .unwrap() @@ -477,8 +456,8 @@ impl Suite { pub fn assert_pending_rewards(&mut self, address: &str, id: u64, expected: u128) { let res: PendingRewardsResponse = self + .base .app - .borrow_mut() .wrap() .query_wasm_smart( self.distribution_contract.clone(), @@ -532,7 +511,8 @@ impl Suite { impl Suite { pub fn withdraw(&mut self, id: u64) { let msg = ExecuteMsg::Withdraw { id }; - self.app + self.base + .app .execute_contract( Addr::unchecked(OWNER), self.distribution_contract.clone(), @@ -544,7 +524,8 @@ impl Suite { pub fn withdraw_error(&mut self, id: u64) -> ContractError { let msg = ExecuteMsg::Withdraw { id }; - self.app + self.base + .app .execute_contract( Addr::unchecked(OWNER), self.distribution_contract.clone(), @@ -560,8 +541,9 @@ impl Suite { let msg = cw4_group::msg::ExecuteMsg::AddHook { addr: self.distribution_contract.to_string(), }; - self.app - .execute_contract(Addr::unchecked(OWNER), addr, &msg, &[]) + self.base + .app + .execute_contract(self.core_addr.clone(), addr, &msg, &[]) .unwrap(); } @@ -594,10 +576,10 @@ impl Suite { vec![] }; - self.app - .borrow_mut() + self.base + .app .execute_contract( - self.owner.clone().unwrap(), + Addr::unchecked(OWNER), self.distribution_contract.clone(), &execute_create_msg, &send_funds, @@ -607,8 +589,8 @@ impl Suite { pub fn mint_native(&mut self, coin: Coin, dest: &str) { // mint the tokens to be funded - self.app - .borrow_mut() + self.base + .app .sudo(SudoMsg::Bank({ BankSudo::Mint { to_address: dest.to_string(), @@ -619,13 +601,13 @@ impl Suite { } pub fn mint_cw20(&mut self, coin: Cw20Coin, name: &str) -> Addr { - cw20_setup::instantiate_cw20(self.app.borrow_mut(), name, vec![coin]) + self.base.instantiate_cw20(name, vec![coin]) } pub fn fund_native(&mut self, id: u64, coin: Coin) { self.mint_native(coin.clone(), OWNER); - self.app - .borrow_mut() + self.base + .app .execute_contract( Addr::unchecked(OWNER), self.distribution_contract.clone(), @@ -637,8 +619,8 @@ impl Suite { pub fn fund_latest_native(&mut self, coin: Coin) { self.mint_native(coin.clone(), OWNER); - self.app - .borrow_mut() + self.base + .app .execute_contract( Addr::unchecked(OWNER), self.distribution_contract.clone(), @@ -650,7 +632,8 @@ impl Suite { pub fn fund_cw20(&mut self, id: u64, coin: Cw20Coin) { let fund_sub_msg = to_json_binary(&ReceiveCw20Msg::Fund(FundMsg { id })).unwrap(); - self.app + self.base + .app .execute_contract( Addr::unchecked(OWNER), Addr::unchecked(coin.address), @@ -666,7 +649,8 @@ impl Suite { pub fn fund_latest_cw20(&mut self, coin: Cw20Coin) { let fund_sub_msg = to_json_binary(&ReceiveCw20Msg::FundLatest {}).unwrap(); - self.app + self.base + .app .execute_contract( Addr::unchecked(OWNER), Addr::unchecked(coin.address), @@ -681,14 +665,14 @@ impl Suite { } pub fn skip_blocks(&mut self, blocks: u64) { - self.app.borrow_mut().update_block(|b| { + self.base.app.update_block(|b| { println!("skipping blocks {:?} -> {:?}", b.height, b.height + blocks); b.height += blocks }); } pub fn skip_seconds(&mut self, seconds: u64) { - self.app.borrow_mut().update_block(|b| { + self.base.app.update_block(|b| { let new_block_time = b.time.plus_seconds(seconds); println!( "skipping seconds {:?} -> {:?}", @@ -707,7 +691,8 @@ impl Suite { pub fn claim_rewards(&mut self, address: &str, id: u64) { let msg = ExecuteMsg::Claim { id }; - self.app + self.base + .app .execute_contract( Addr::unchecked(address), self.distribution_contract.clone(), @@ -724,7 +709,8 @@ impl Suite { amount: Uint128::new(amount), msg: to_json_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(), }; - self.app + self.base + .app .execute_contract(Addr::unchecked(sender), self.cw20_addr.clone(), &msg, &[]) .unwrap(); } @@ -733,7 +719,8 @@ impl Suite { let msg = cw20_stake::msg::ExecuteMsg::Unstake { amount: Uint128::new(amount), }; - self.app + self.base + .app .execute_contract( Addr::unchecked(sender), self.staking_addr.clone(), @@ -744,30 +731,31 @@ impl Suite { } pub fn stake_nft(&mut self, sender: &str, token_id: u64) { - stake_cw721( - self.app.borrow_mut(), - &self.voting_power_addr, - &self.staking_addr, + self.base.cw721().stake( + &self.cw721_dao.clone().unwrap(), sender, - &token_id.to_string(), + token_id.to_string(), ) } pub fn unstake_nft(&mut self, sender: &str, token_id: u64) { - unstake_cw721( - self.app.borrow_mut(), - &self.voting_power_addr, + self.base.cw721().unstake( + &self.cw721_dao.clone().unwrap(), sender, - &token_id.to_string(), + token_id.to_string(), ) } pub fn stake_native_tokens(&mut self, address: &str, amount: u128) { - stake_tokenfactory_tokens(self.app.borrow_mut(), &self.staking_addr, address, amount) + self.base + .token() + .stake(&self.token_dao.clone().unwrap(), address, amount) } pub fn unstake_native_tokens(&mut self, address: &str, amount: u128) { - unstake_tokenfactory_tokens(self.app.borrow_mut(), &self.staking_addr, address, amount) + self.base + .token() + .unstake(&self.token_dao.clone().unwrap(), address, amount) } pub fn update_emission_rate( @@ -791,6 +779,7 @@ impl Suite { }; let _resp = self + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -812,6 +801,7 @@ impl Suite { }; let _resp = self + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -833,6 +823,7 @@ impl Suite { }; let _resp = self + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -854,6 +845,7 @@ impl Suite { }; let _resp = self + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -875,6 +867,7 @@ impl Suite { }; let _resp = self + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -896,6 +889,7 @@ impl Suite { }; let _resp = self + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -917,6 +911,7 @@ impl Suite { }; let _resp = self + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -930,13 +925,15 @@ impl Suite { pub fn update_members(&mut self, add: Vec, remove: Vec) { let msg = cw4_group::msg::ExecuteMsg::UpdateMembers { remove, add }; - self.app - .execute_contract(Addr::unchecked(OWNER), self.staking_addr.clone(), &msg, &[]) + self.base + .app + .execute_contract(self.core_addr.clone(), self.staking_addr.clone(), &msg, &[]) .unwrap(); } pub fn query_members(&mut self) -> Vec { let members: MemberListResponse = self + .base .app .wrap() .query_wasm_smart( @@ -957,7 +954,8 @@ impl Suite { expiry: None, }); - self.app + self.base + .app .execute_contract( Addr::unchecked(OWNER), self.distribution_contract.clone(), @@ -966,7 +964,8 @@ impl Suite { ) .unwrap(); - self.app + self.base + .app .execute_contract( Addr::unchecked(new_owner), self.distribution_contract.clone(), diff --git a/contracts/distribution/dao-rewards-distributor/src/testing/tests.rs b/contracts/distribution/dao-rewards-distributor/src/testing/tests.rs index 673e8c9ba..b40752e97 100644 --- a/contracts/distribution/dao-rewards-distributor/src/testing/tests.rs +++ b/contracts/distribution/dao-rewards-distributor/src/testing/tests.rs @@ -1,5 +1,3 @@ -use std::borrow::BorrowMut; - use cosmwasm_std::testing::{mock_dependencies, mock_env}; use cosmwasm_std::{coin, coins, to_json_binary, Addr, Timestamp}; use cosmwasm_std::{Uint128, Uint256}; @@ -10,21 +8,17 @@ use cw_multi_test::Executor; use cw_ownable::OwnershipError; use cw_utils::Duration; use dao_interface::voting::InfoResponse; +use dao_testing::{DaoTestingSuite, GOV_DENOM, MEMBER1, MEMBER2, MEMBER3, MEMBER4, OWNER}; use crate::contract::{CONTRACT_NAME, CONTRACT_VERSION}; +use crate::msg::ExecuteMsg; use crate::msg::{CreateMsg, FundMsg, InstantiateMsg, MigrateMsg}; use crate::state::{EmissionRate, Epoch}; -use crate::testing::native_setup::setup_native_token_test; -use crate::ContractError; -use crate::{ - msg::ExecuteMsg, - testing::{ADDR1, ADDR2, ADDR3, ADDR4, DENOM}, -}; - -use super::{ - suite::{RewardsConfig, SuiteBuilder}, - ALT_DENOM, OWNER, -}; +use dao_rewards_distributor::ContractError; + +use super::suite::{RewardsConfig, SuiteBuilder}; + +const ALT_DENOM: &str = "ualtgovtoken"; // By default, the tests are set up to distribute rewards over 1_000_000 units of time. // Over that time, 100_000_000 token rewards will be distributed. @@ -34,7 +28,7 @@ use super::{ fn test_fund_native_404() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); - let mint_coin = coin(100, DENOM); + let mint_coin = coin(100, GOV_DENOM); suite.mint_native(mint_coin.clone(), OWNER); suite.fund_native(3, mint_coin); @@ -80,24 +74,24 @@ fn test_native_dao_rewards_update_reward_rate() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); suite.assert_undistributed_rewards(1, 90_000_000); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); suite.assert_undistributed_rewards(1, 80_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_pending_rewards(MEMBER1, 1, 0); // set the rewards rate to half of the current one // now there will be 5_000_000 tokens distributed over 100_000 blocks @@ -106,9 +100,9 @@ fn test_native_dao_rewards_update_reward_rate() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 2_500_000); - suite.assert_pending_rewards(ADDR2, 1, 6_250_000); - suite.assert_pending_rewards(ADDR3, 1, 6_250_000); + suite.assert_pending_rewards(MEMBER1, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 6_250_000); + suite.assert_pending_rewards(MEMBER3, 1, 6_250_000); suite.assert_undistributed_rewards(1, 75_000_000); @@ -119,18 +113,18 @@ fn test_native_dao_rewards_update_reward_rate() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 7_500_000); - suite.assert_pending_rewards(ADDR2, 1, 8_750_000); - suite.assert_pending_rewards(ADDR3, 1, 8_750_000); + suite.assert_pending_rewards(MEMBER1, 1, 7_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 8_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 8_750_000); suite.assert_undistributed_rewards(1, 65_000_000); // skip 2/10ths of the time suite.skip_blocks(200_000); - suite.assert_pending_rewards(ADDR1, 1, 17_500_000); - suite.assert_pending_rewards(ADDR2, 1, 13_750_000); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER1, 1, 17_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000); suite.assert_undistributed_rewards(1, 45_000_000); @@ -141,44 +135,44 @@ fn test_native_dao_rewards_update_reward_rate() { suite.skip_blocks(100_000); // assert no pending rewards changed - suite.assert_pending_rewards(ADDR1, 1, 17_500_000); - suite.assert_pending_rewards(ADDR2, 1, 13_750_000); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER1, 1, 17_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000); suite.assert_undistributed_rewards(1, 45_000_000); - // assert ADDR1 pre-claim balance - suite.assert_native_balance(ADDR1, DENOM, 10_000_000); - // ADDR1 claims their rewards - suite.claim_rewards(ADDR1, 1); - // assert ADDR1 post-claim balance to be pre-claim + pending - suite.assert_native_balance(ADDR1, DENOM, 10_000_000 + 17_500_000); - // assert ADDR1 is now entitled to 0 pending rewards - suite.assert_pending_rewards(ADDR1, 1, 0); + // assert MEMBER1 pre-claim balance + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000); + // MEMBER1 claims their rewards + suite.claim_rewards(MEMBER1, 1); + // assert MEMBER1 post-claim balance to be pre-claim + pending + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000 + 17_500_000); + // assert MEMBER1 is now entitled to 0 pending rewards + suite.assert_pending_rewards(MEMBER1, 1, 0); // user 2 unstakes their stake - suite.unstake_native_tokens(ADDR2, 50); + suite.unstake_native_tokens(MEMBER2, 50); // skip 1/10th of the time suite.skip_blocks(100_000); - // only the ADDR1 pending rewards should have changed - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 13_750_000); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000); + // only the MEMBER1 pending rewards should have changed + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000); suite.assert_undistributed_rewards(1, 45_000_000); - // ADDR2 claims their rewards (has 50 to begin with as they unstaked) - suite.assert_native_balance(ADDR2, DENOM, 50); - suite.claim_rewards(ADDR2, 1); - // assert ADDR2 post-claim balance to be pre-claim + pending and has 0 pending rewards - suite.assert_native_balance(ADDR2, DENOM, 13_750_000 + 50); - suite.assert_pending_rewards(ADDR2, 1, 0); + // MEMBER2 claims their rewards (has 50 to begin with as they unstaked) + suite.assert_native_balance(MEMBER2, GOV_DENOM, 50); + suite.claim_rewards(MEMBER2, 1); + // assert MEMBER2 post-claim balance to be pre-claim + pending and has 0 pending rewards + suite.assert_native_balance(MEMBER2, GOV_DENOM, 13_750_000 + 50); + suite.assert_pending_rewards(MEMBER2, 1, 0); // update the reward rate back to 1_000 / 10blocks // this should now distribute 10_000_000 tokens over 100_000 blocks - // between ADDR1 (2/3rds) and ADDR3 (1/3rd) + // between MEMBER1 (2/3rds) and MEMBER3 (1/3rd) suite.update_emission_rate(1, Duration::Height(10), 1000, true); // update with the same rate does nothing @@ -188,37 +182,37 @@ fn test_native_dao_rewards_update_reward_rate() { suite.skip_blocks(100_000); // assert that rewards are being distributed at the expected rate - suite.assert_pending_rewards(ADDR1, 1, 6_666_666); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000 + 3_333_333); + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000 + 3_333_333); suite.assert_undistributed_rewards(1, 35_000_000); - // ADDR3 claims their rewards - suite.assert_native_balance(ADDR3, DENOM, 0); - suite.claim_rewards(ADDR3, 1); - suite.assert_pending_rewards(ADDR3, 1, 0); - suite.assert_native_balance(ADDR3, DENOM, 13_750_000 + 3_333_333); + // MEMBER3 claims their rewards + suite.assert_native_balance(MEMBER3, GOV_DENOM, 0); + suite.claim_rewards(MEMBER3, 1); + suite.assert_pending_rewards(MEMBER3, 1, 0); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 13_750_000 + 3_333_333); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 6_666_666 + 6_666_666 + 1); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 3_333_333); + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666 + 6_666_666 + 1); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 3_333_333); suite.assert_undistributed_rewards(1, 25_000_000); // claim everything so that there are 0 pending rewards - suite.claim_rewards(ADDR3, 1); - suite.claim_rewards(ADDR1, 1); + suite.claim_rewards(MEMBER3, 1); + suite.claim_rewards(MEMBER1, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 0); // update the rewards rate to 40_000_000 per 100_000 blocks. - // split is still 2/3rds to ADDR1 and 1/3rd to ADDR3 + // split is still 2/3rds to MEMBER1 and 1/3rd to MEMBER3 suite.update_emission_rate(1, Duration::Height(10), 4000, true); suite.assert_ends_at(Expiration::AtHeight(1_062_500)); @@ -226,40 +220,41 @@ fn test_native_dao_rewards_update_reward_rate() { let addr1_pending = 20_000_000 * 2 / 3; let addr3_pending = 20_000_000 / 3; - suite.assert_pending_rewards(ADDR1, 1, addr1_pending); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, addr3_pending); + suite.assert_pending_rewards(MEMBER1, 1, addr1_pending); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, addr3_pending); suite.assert_undistributed_rewards(1, 5_000_000); - // ADDR2 wakes up to the increased staking rate and stakes 50 tokens - // this brings new split to: [ADDR1: 50%, ADDR2: 25%, ADDR3: 25%] - suite.stake_native_tokens(ADDR2, 50); + // MEMBER2 wakes up to the increased staking rate and stakes 50 tokens + // this brings new split to: [MEMBER1: 50%, MEMBER2: 25%, MEMBER3: 25%] + suite.stake_native_tokens(MEMBER2, 50); suite.skip_blocks(10_000); // allocates 4_000_000 tokens - suite.assert_pending_rewards(ADDR1, 1, addr1_pending + 4_000_000 * 2 / 4); - suite.assert_pending_rewards(ADDR2, 1, 4_000_000 / 4); - suite.assert_pending_rewards(ADDR3, 1, addr3_pending + 4_000_000 / 4); + suite.assert_pending_rewards(MEMBER1, 1, addr1_pending + 4_000_000 * 2 / 4); + suite.assert_pending_rewards(MEMBER2, 1, 4_000_000 / 4); + suite.assert_pending_rewards(MEMBER3, 1, addr3_pending + 4_000_000 / 4); suite.assert_undistributed_rewards(1, 1_000_000); - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER3, 1); let addr1_pending = 0; let addr3_pending = 0; suite.skip_blocks(10_000); // skips from 1,060,000 to 1,070,000, and the end is 1,062,500, so this allocates only 1_000_000 tokens instead of 4_000_000 - suite.assert_pending_rewards(ADDR1, 1, addr1_pending + 1_000_000 * 2 / 4); - suite.assert_pending_rewards(ADDR2, 1, 4_000_000 / 4 + 1_000_000 / 4); - suite.assert_pending_rewards(ADDR3, 1, addr3_pending + 1_000_000 / 4); + suite.assert_pending_rewards(MEMBER1, 1, addr1_pending + 1_000_000 * 2 / 4); + suite.assert_pending_rewards(MEMBER2, 1, 4_000_000 / 4 + 1_000_000 / 4); + suite.assert_pending_rewards(MEMBER3, 1, addr3_pending + 1_000_000 / 4); - suite.claim_rewards(ADDR2, 1); + suite.claim_rewards(MEMBER2, 1); suite.assert_undistributed_rewards(1, 0); // TODO: there's a few denoms remaining here, ensure such cases are handled properly - let remaining_rewards = suite.get_balance_native(suite.distribution_contract.clone(), DENOM); + let remaining_rewards = + suite.get_balance_native(suite.distribution_contract.clone(), GOV_DENOM); println!("Remaining rewards: {}", remaining_rewards); } @@ -268,7 +263,7 @@ fn test_native_dao_rewards_reward_rate_switch_unit() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Height(10), destination: None, continuous: true, @@ -282,20 +277,20 @@ fn test_native_dao_rewards_reward_rate_switch_unit() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_pending_rewards(MEMBER1, 1, 0); // set the rewards rate to time-based rewards suite.update_emission_rate(1, Duration::Time(10), 500, true); @@ -303,9 +298,9 @@ fn test_native_dao_rewards_reward_rate_switch_unit() { // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 2_500_000); - suite.assert_pending_rewards(ADDR2, 1, 6_250_000); - suite.assert_pending_rewards(ADDR3, 1, 6_250_000); + suite.assert_pending_rewards(MEMBER1, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 6_250_000); + suite.assert_pending_rewards(MEMBER3, 1, 6_250_000); // double the rewards rate // now there will be 10_000_000 tokens distributed over 100_000 seconds @@ -314,16 +309,16 @@ fn test_native_dao_rewards_reward_rate_switch_unit() { // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 7_500_000); - suite.assert_pending_rewards(ADDR2, 1, 8_750_000); - suite.assert_pending_rewards(ADDR3, 1, 8_750_000); + suite.assert_pending_rewards(MEMBER1, 1, 7_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 8_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 8_750_000); // skip 2/10ths of the time suite.skip_seconds(200_000); - suite.assert_pending_rewards(ADDR1, 1, 17_500_000); - suite.assert_pending_rewards(ADDR2, 1, 13_750_000); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER1, 1, 17_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000); // pause the rewards distribution suite.pause_emission(1); @@ -332,73 +327,73 @@ fn test_native_dao_rewards_reward_rate_switch_unit() { suite.skip_blocks(100_000); // assert no pending rewards changed - suite.assert_pending_rewards(ADDR1, 1, 17_500_000); - suite.assert_pending_rewards(ADDR2, 1, 13_750_000); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000); - - // assert ADDR1 pre-claim balance - suite.assert_native_balance(ADDR1, DENOM, 10_000_000); - // ADDR1 claims their rewards - suite.claim_rewards(ADDR1, 1); - // assert ADDR1 post-claim balance to be pre-claim + pending - suite.assert_native_balance(ADDR1, DENOM, 10_000_000 + 17_500_000); - // assert ADDR1 is now entitled to 0 pending rewards - suite.assert_pending_rewards(ADDR1, 1, 0); + suite.assert_pending_rewards(MEMBER1, 1, 17_500_000); + suite.assert_pending_rewards(MEMBER2, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000); + + // assert MEMBER1 pre-claim balance + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000); + // MEMBER1 claims their rewards + suite.claim_rewards(MEMBER1, 1); + // assert MEMBER1 post-claim balance to be pre-claim + pending + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000 + 17_500_000); + // assert MEMBER1 is now entitled to 0 pending rewards + suite.assert_pending_rewards(MEMBER1, 1, 0); // user 2 unstakes their stake - suite.unstake_native_tokens(ADDR2, 50); + suite.unstake_native_tokens(MEMBER2, 50); // skip 1/10th of the time suite.skip_blocks(100_000); - // only the ADDR1 pending rewards should have changed - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 13_750_000); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000); + // only the MEMBER1 pending rewards should have changed + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 13_750_000); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000); - // ADDR2 claims their rewards (has 50 to begin with as they unstaked) - suite.assert_native_balance(ADDR2, DENOM, 50); - suite.claim_rewards(ADDR2, 1); - // assert ADDR2 post-claim balance to be pre-claim + pending and has 0 pending rewards - suite.assert_native_balance(ADDR2, DENOM, 13_750_000 + 50); - suite.assert_pending_rewards(ADDR2, 1, 0); + // MEMBER2 claims their rewards (has 50 to begin with as they unstaked) + suite.assert_native_balance(MEMBER2, GOV_DENOM, 50); + suite.claim_rewards(MEMBER2, 1); + // assert MEMBER2 post-claim balance to be pre-claim + pending and has 0 pending rewards + suite.assert_native_balance(MEMBER2, GOV_DENOM, 13_750_000 + 50); + suite.assert_pending_rewards(MEMBER2, 1, 0); // update the reward rate back to 1_000 / 10blocks // this should now distribute 10_000_000 tokens over 100_000 blocks - // between ADDR1 (2/3rds) and ADDR3 (1/3rd) + // between MEMBER1 (2/3rds) and MEMBER3 (1/3rd) suite.update_emission_rate(1, Duration::Height(10), 1000, true); // skip 1/10th of the time suite.skip_blocks(100_000); // assert that rewards are being distributed at the expected rate - suite.assert_pending_rewards(ADDR1, 1, 6_666_666); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 13_750_000 + 3_333_333); + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 13_750_000 + 3_333_333); - // ADDR3 claims their rewards - suite.assert_native_balance(ADDR3, DENOM, 0); - suite.claim_rewards(ADDR3, 1); - suite.assert_pending_rewards(ADDR3, 1, 0); - suite.assert_native_balance(ADDR3, DENOM, 13_750_000 + 3_333_333); + // MEMBER3 claims their rewards + suite.assert_native_balance(MEMBER3, GOV_DENOM, 0); + suite.claim_rewards(MEMBER3, 1); + suite.assert_pending_rewards(MEMBER3, 1, 0); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 13_750_000 + 3_333_333); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 6_666_666 + 6_666_666 + 1); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 3_333_333); + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666 + 6_666_666 + 1); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 3_333_333); // claim everything so that there are 0 pending rewards - suite.claim_rewards(ADDR3, 1); - suite.claim_rewards(ADDR1, 1); + suite.claim_rewards(MEMBER3, 1); + suite.claim_rewards(MEMBER1, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 0); // update the rewards rate to 40_000_000 per 100_000 seconds. - // split is still 2/3rds to ADDR1 and 1/3rd to ADDR3 + // split is still 2/3rds to MEMBER1 and 1/3rd to MEMBER3 suite.update_emission_rate(1, Duration::Time(10), 4000, true); suite.assert_ends_at(Expiration::AtTime(Timestamp::from_seconds(462_500))); @@ -406,34 +401,35 @@ fn test_native_dao_rewards_reward_rate_switch_unit() { let addr1_pending = 20_000_000 * 2 / 3; let addr3_pending = 20_000_000 / 3; - suite.assert_pending_rewards(ADDR1, 1, addr1_pending); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, addr3_pending); + suite.assert_pending_rewards(MEMBER1, 1, addr1_pending); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, addr3_pending); - // ADDR2 wakes up to the increased staking rate and stakes 50 tokens - // this brings new split to: [ADDR1: 50%, ADDR2: 25%, ADDR3: 25%] - suite.stake_native_tokens(ADDR2, 50); + // MEMBER2 wakes up to the increased staking rate and stakes 50 tokens + // this brings new split to: [MEMBER1: 50%, MEMBER2: 25%, MEMBER3: 25%] + suite.stake_native_tokens(MEMBER2, 50); suite.skip_seconds(10_000); // allocates 4_000_000 tokens - suite.assert_pending_rewards(ADDR1, 1, addr1_pending + 4_000_000 * 2 / 4); - suite.assert_pending_rewards(ADDR2, 1, 4_000_000 / 4); - suite.assert_pending_rewards(ADDR3, 1, addr3_pending + 4_000_000 / 4); + suite.assert_pending_rewards(MEMBER1, 1, addr1_pending + 4_000_000 * 2 / 4); + suite.assert_pending_rewards(MEMBER2, 1, 4_000_000 / 4); + suite.assert_pending_rewards(MEMBER3, 1, addr3_pending + 4_000_000 / 4); - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER3, 1); let addr1_pending = 0; let addr3_pending = 0; suite.skip_seconds(10_000); // skips from 460,000 to 470,000, and the end is 462,500, so this allocates only 1_000_000 tokens instead of 4_000_000 - suite.assert_pending_rewards(ADDR1, 1, addr1_pending + 1_000_000 * 2 / 4); - suite.assert_pending_rewards(ADDR2, 1, 4_000_000 / 4 + 1_000_000 / 4); - suite.assert_pending_rewards(ADDR3, 1, addr3_pending + 1_000_000 / 4); + suite.assert_pending_rewards(MEMBER1, 1, addr1_pending + 1_000_000 * 2 / 4); + suite.assert_pending_rewards(MEMBER2, 1, 4_000_000 / 4 + 1_000_000 / 4); + suite.assert_pending_rewards(MEMBER3, 1, addr3_pending + 1_000_000 / 4); - suite.claim_rewards(ADDR2, 1); + suite.claim_rewards(MEMBER2, 1); // TODO: there's a few denoms remaining here, ensure such cases are handled properly - let remaining_rewards = suite.get_balance_native(suite.distribution_contract.clone(), DENOM); + let remaining_rewards = + suite.get_balance_native(suite.distribution_contract.clone(), GOV_DENOM); println!("Remaining rewards: {}", remaining_rewards); } @@ -448,80 +444,80 @@ fn test_cw20_dao_native_rewards_block_height_based() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 10_000_000); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 0); - // ADDR2 and ADDR3 unstake their rewards - suite.unstake_cw20_tokens(50, ADDR2); - suite.unstake_cw20_tokens(50, ADDR3); + // MEMBER2 and MEMBER3 unstake their rewards + suite.unstake_cw20_tokens(50, MEMBER2); + suite.unstake_cw20_tokens(50, MEMBER3); // skip 1/10th of the time suite.skip_blocks(100_000); - // because ADDR2 and ADDR3 are not staking, ADDR1 receives all the rewards. - // ADDR2 and ADDR3 should have the same amount of pending rewards as before. - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + // because MEMBER2 and MEMBER3 are not staking, MEMBER1 receives all the rewards. + // MEMBER2 and MEMBER3 should have the same amount of pending rewards as before. + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR2 and ADDR3 wake up, claim and restake their rewards - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + // MEMBER2 and MEMBER3 wake up, claim and restake their rewards + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); - suite.stake_cw20_tokens(50, ADDR2); + suite.stake_cw20_tokens(50, MEMBER2); // skip 3/10th of the time suite.skip_blocks(300_000); - suite.stake_cw20_tokens(50, ADDR3); + suite.stake_cw20_tokens(50, MEMBER3); - suite.assert_pending_rewards(ADDR1, 1, 30_000_000); - suite.assert_pending_rewards(ADDR2, 1, 10_000_000); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.assert_pending_rewards(MEMBER1, 1, 30_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 0); - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 0); let remaining_time = suite.get_time_until_rewards_expiration(); suite.skip_blocks(remaining_time - 100_000); - suite.claim_rewards(ADDR1, 1); - suite.unstake_cw20_tokens(100, ADDR1); - suite.assert_pending_rewards(ADDR1, 1, 0); + suite.claim_rewards(MEMBER1, 1); + suite.unstake_cw20_tokens(100, MEMBER1); + suite.assert_pending_rewards(MEMBER1, 1, 0); suite.skip_blocks(100_000); - suite.unstake_cw20_tokens(50, ADDR2); + suite.unstake_cw20_tokens(50, MEMBER2); suite.skip_blocks(100_000); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 0); - let addr1_bal = suite.get_balance_native(ADDR1, DENOM); - let addr2_bal = suite.get_balance_native(ADDR2, DENOM); - let addr3_bal = suite.get_balance_native(ADDR3, DENOM); + let addr1_bal = suite.get_balance_native(MEMBER1, GOV_DENOM); + let addr2_bal = suite.get_balance_native(MEMBER2, GOV_DENOM); + let addr3_bal = suite.get_balance_native(MEMBER3, GOV_DENOM); println!("Balances: {}, {}, {}", addr1_bal, addr2_bal, addr3_bal); } @@ -537,41 +533,41 @@ fn test_cw721_dao_rewards() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 10_000_000); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 0); - // ADDR2 and ADDR3 unstake their nfts - suite.unstake_nft(ADDR2, 3); - suite.unstake_nft(ADDR3, 4); + // MEMBER2 and MEMBER3 unstake their nfts + suite.unstake_nft(MEMBER2, 3); + suite.unstake_nft(MEMBER3, 4); // skip 1/10th of the time suite.skip_blocks(100_000); - // because ADDR2 and ADDR3 are not staking, ADDR1 receives all the rewards. - // ADDR2 and ADDR3 should have the same amount of pending rewards as before. - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + // because MEMBER2 and MEMBER3 are not staking, MEMBER1 receives all the rewards. + // MEMBER2 and MEMBER3 should have the same amount of pending rewards as before. + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR2 and ADDR3 wake up, claim and restake their nfts - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + // MEMBER2 and MEMBER3 wake up, claim and restake their nfts + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); - suite.stake_nft(ADDR2, 3); - suite.stake_nft(ADDR3, 4); + suite.stake_nft(MEMBER2, 3); + suite.stake_nft(MEMBER3, 4); } #[test] @@ -582,13 +578,13 @@ fn test_claim_zero_rewards() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); - // ADDR1 attempts to claim again - suite.claim_rewards(ADDR1, 1); + // MEMBER1 attempts to claim again + suite.claim_rewards(MEMBER1, 1); } #[test] @@ -598,7 +594,7 @@ fn test_native_dao_cw20_rewards_time_based() { let mut suite = SuiteBuilder::base(super::suite::DaoType::CW20) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Cw20(DENOM.to_string()), + denom: UncheckedDenom::Cw20(GOV_DENOM.to_string()), duration: Duration::Time(10), destination: None, continuous: true, @@ -614,41 +610,41 @@ fn test_native_dao_cw20_rewards_time_based() { // skip 1/10th of the time suite.skip_seconds(100_000); - // suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + // suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_cw20_balance(cw20_denom, ADDR1, 10_000_000); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_cw20_balance(cw20_denom, MEMBER1, 10_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 0); - // ADDR2 and ADDR3 unstake their stake - suite.unstake_cw20_tokens(50, ADDR2); - suite.unstake_cw20_tokens(50, ADDR3); + // MEMBER2 and MEMBER3 unstake their stake + suite.unstake_cw20_tokens(50, MEMBER2); + suite.unstake_cw20_tokens(50, MEMBER3); // skip 1/10th of the time suite.skip_seconds(100_000); - // because ADDR2 and ADDR3 are not staking, ADDR1 receives all the rewards. - // ADDR2 and ADDR3 should have the same amount of pending rewards as before. - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + // because MEMBER2 and MEMBER3 are not staking, MEMBER1 receives all the rewards. + // MEMBER2 and MEMBER3 should have the same amount of pending rewards as before. + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR2 and ADDR3 wake up and claim their rewards - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + // MEMBER2 and MEMBER3 wake up and claim their rewards + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); - suite.assert_cw20_balance(cw20_denom, ADDR1, 10_000_000); - suite.assert_cw20_balance(cw20_denom, ADDR2, 5_000_000); + suite.assert_cw20_balance(cw20_denom, MEMBER1, 10_000_000); + suite.assert_cw20_balance(cw20_denom, MEMBER2, 5_000_000); } #[test] @@ -658,7 +654,7 @@ fn test_native_dao_rewards_time_based() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Time(10), destination: None, continuous: true, @@ -672,44 +668,44 @@ fn test_native_dao_rewards_time_based() { // skip 1/10th of the time suite.skip_seconds(100_000); - // suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + // suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 10_000_000); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 0); - // ADDR2 and ADDR3 unstake their stake - suite.unstake_native_tokens(ADDR2, 50); - suite.unstake_native_tokens(ADDR3, 50); + // MEMBER2 and MEMBER3 unstake their stake + suite.unstake_native_tokens(MEMBER2, 50); + suite.unstake_native_tokens(MEMBER3, 50); // skip 1/10th of the time suite.skip_seconds(100_000); - // because ADDR2 and ADDR3 are not staking, ADDR1 receives all the rewards. - // ADDR2 and ADDR3 should have the same amount of pending rewards as before. - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + // because MEMBER2 and MEMBER3 are not staking, MEMBER1 receives all the rewards. + // MEMBER2 and MEMBER3 should have the same amount of pending rewards as before. + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR2 and ADDR3 wake up, claim and restake their rewards - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + // MEMBER2 and MEMBER3 wake up, claim and restake their rewards + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); - let addr1_balance = suite.get_balance_native(ADDR1, DENOM); - let addr2_balance = suite.get_balance_native(ADDR2, DENOM); + let addr1_balance = suite.get_balance_native(MEMBER1, GOV_DENOM); + let addr2_balance = suite.get_balance_native(MEMBER2, GOV_DENOM); - suite.stake_native_tokens(ADDR1, addr1_balance); - suite.stake_native_tokens(ADDR2, addr2_balance); + suite.stake_native_tokens(MEMBER1, addr1_balance); + suite.stake_native_tokens(MEMBER2, addr2_balance); } // all of the `+1` corrections highlight rounding @@ -720,22 +716,22 @@ fn test_native_dao_rewards_time_based_with_rounding() { let mut suite = SuiteBuilder::base(super::suite::DaoType::CW4) .with_rewards_config(RewardsConfig { amount: 100, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Time(100), destination: None, continuous: true, }) .with_cw4_members(vec![ Member { - addr: ADDR1.to_string(), + addr: MEMBER1.to_string(), weight: 140, }, Member { - addr: ADDR2.to_string(), + addr: MEMBER2.to_string(), weight: 40, }, Member { - addr: ADDR3.to_string(), + addr: MEMBER3.to_string(), weight: 20, }, ]) @@ -748,99 +744,99 @@ fn test_native_dao_rewards_time_based_with_rounding() { // skip 1 interval suite.skip_seconds(100); - suite.assert_pending_rewards(ADDR1, 1, 70); - suite.assert_pending_rewards(ADDR2, 1, 20); - suite.assert_pending_rewards(ADDR3, 1, 10); + suite.assert_pending_rewards(MEMBER1, 1, 70); + suite.assert_pending_rewards(MEMBER2, 1, 20); + suite.assert_pending_rewards(MEMBER3, 1, 10); // change voting power of one of the members and claim suite.update_members( vec![Member { - addr: ADDR2.to_string(), + addr: MEMBER2.to_string(), weight: 60, }], vec![], ); - suite.claim_rewards(ADDR2, 1); - suite.assert_native_balance(ADDR2, DENOM, 20); - suite.assert_pending_rewards(ADDR2, 1, 0); + suite.claim_rewards(MEMBER2, 1); + suite.assert_native_balance(MEMBER2, GOV_DENOM, 20); + suite.assert_pending_rewards(MEMBER2, 1, 0); // skip 1 interval suite.skip_seconds(100); - suite.assert_pending_rewards(ADDR1, 1, 70 + 63); - suite.assert_pending_rewards(ADDR2, 1, 27); - suite.assert_pending_rewards(ADDR3, 1, 10 + 9); + suite.assert_pending_rewards(MEMBER1, 1, 70 + 63); + suite.assert_pending_rewards(MEMBER2, 1, 27); + suite.assert_pending_rewards(MEMBER3, 1, 10 + 9); // increase reward rate and claim suite.update_emission_rate(1, Duration::Time(100), 150, true); - suite.claim_rewards(ADDR3, 1); - suite.assert_native_balance(ADDR3, DENOM, 10 + 9); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.claim_rewards(MEMBER3, 1); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 10 + 9); + suite.assert_pending_rewards(MEMBER3, 1, 0); // skip 1 interval suite.skip_seconds(100); - suite.assert_pending_rewards(ADDR1, 1, 70 + 63 + 95 + 1); - suite.assert_pending_rewards(ADDR2, 1, 27 + 40 + 1); - suite.assert_pending_rewards(ADDR3, 1, 13); + suite.assert_pending_rewards(MEMBER1, 1, 70 + 63 + 95 + 1); + suite.assert_pending_rewards(MEMBER2, 1, 27 + 40 + 1); + suite.assert_pending_rewards(MEMBER3, 1, 13); // claim rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 70 + 63 + 95 + 1); - suite.assert_pending_rewards(ADDR1, 1, 0); + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 70 + 63 + 95 + 1); + suite.assert_pending_rewards(MEMBER1, 1, 0); // skip 3 intervals suite.skip_seconds(300); - suite.assert_pending_rewards(ADDR1, 1, 3 * 95 + 1); - suite.assert_pending_rewards(ADDR2, 1, 27 + 4 * 40 + 1 + 1 + 1); - suite.assert_pending_rewards(ADDR3, 1, 4 * 13 + 1 + 1); + suite.assert_pending_rewards(MEMBER1, 1, 3 * 95 + 1); + suite.assert_pending_rewards(MEMBER2, 1, 27 + 4 * 40 + 1 + 1 + 1); + suite.assert_pending_rewards(MEMBER3, 1, 4 * 13 + 1 + 1); // change voting power for all suite.update_members( vec![ Member { - addr: ADDR1.to_string(), + addr: MEMBER1.to_string(), weight: 100, }, Member { - addr: ADDR2.to_string(), + addr: MEMBER2.to_string(), weight: 80, }, Member { - addr: ADDR3.to_string(), + addr: MEMBER3.to_string(), weight: 40, }, ], vec![], ); - suite.claim_rewards(ADDR2, 1); - suite.assert_native_balance(ADDR2, DENOM, 20 + 27 + 4 * 40 + 1 + 1 + 1); - suite.assert_pending_rewards(ADDR2, 1, 0); + suite.claim_rewards(MEMBER2, 1); + suite.assert_native_balance(MEMBER2, GOV_DENOM, 20 + 27 + 4 * 40 + 1 + 1 + 1); + suite.assert_pending_rewards(MEMBER2, 1, 0); // skip 1 interval suite.skip_seconds(100); - suite.assert_pending_rewards(ADDR1, 1, 3 * 95 + 1 + 68); - suite.assert_pending_rewards(ADDR2, 1, 54); - suite.assert_pending_rewards(ADDR3, 1, 4 * 13 + 1 + 1 + 27); + suite.assert_pending_rewards(MEMBER1, 1, 3 * 95 + 1 + 68); + suite.assert_pending_rewards(MEMBER2, 1, 54); + suite.assert_pending_rewards(MEMBER3, 1, 4 * 13 + 1 + 1 + 27); // claim all - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); - suite.assert_native_balance(ADDR1, DENOM, 70 + 63 + 95 + 1 + 3 * 95 + 1 + 68); - suite.assert_native_balance(ADDR2, DENOM, 20 + 27 + 4 * 40 + 1 + 1 + 1 + 54); - suite.assert_native_balance(ADDR3, DENOM, 10 + 9 + 4 * 13 + 1 + 1 + 27); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 70 + 63 + 95 + 1 + 3 * 95 + 1 + 68); + suite.assert_native_balance(MEMBER2, GOV_DENOM, 20 + 27 + 4 * 40 + 1 + 1 + 1 + 54); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 10 + 9 + 4 * 13 + 1 + 1 + 27); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 0); // TODO: fix this rug of 3 udenom by the distribution contract suite.assert_native_balance( suite.distribution_contract.as_str(), - DENOM, + GOV_DENOM, 100_000_000 - (100 * 2 + 150 * 5) + 3, ); } @@ -868,6 +864,7 @@ fn test_immediate_emission() { // create distribution suite + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -878,9 +875,9 @@ fn test_immediate_emission() { .unwrap(); // users immediately have access to rewards - suite.assert_pending_rewards(ADDR1, 2, 50_000_000); - suite.assert_pending_rewards(ADDR2, 2, 25_000_000); - suite.assert_pending_rewards(ADDR3, 2, 25_000_000); + suite.assert_pending_rewards(MEMBER1, 2, 50_000_000); + suite.assert_pending_rewards(MEMBER2, 2, 25_000_000); + suite.assert_pending_rewards(MEMBER3, 2, 25_000_000); // ensure undistributed rewards are immediately 0 suite.assert_undistributed_rewards(2, 0); @@ -889,16 +886,16 @@ fn test_immediate_emission() { suite.fund_native(2, coin(100_000_000, ALT_DENOM)); // users immediately have access to new rewards - suite.assert_pending_rewards(ADDR1, 2, 2 * 50_000_000); - suite.assert_pending_rewards(ADDR2, 2, 2 * 25_000_000); - suite.assert_pending_rewards(ADDR3, 2, 2 * 25_000_000); + suite.assert_pending_rewards(MEMBER1, 2, 2 * 50_000_000); + suite.assert_pending_rewards(MEMBER2, 2, 2 * 25_000_000); + suite.assert_pending_rewards(MEMBER3, 2, 2 * 25_000_000); // ensure undistributed rewards are immediately 0 suite.assert_undistributed_rewards(2, 0); // a new user stakes tokens - suite.mint_native(coin(200, DENOM), ADDR4); - suite.stake_native_tokens(ADDR4, 200); + suite.mint_native(coin(200, GOV_DENOM), MEMBER4); + suite.stake_native_tokens(MEMBER4, 200); // skip 2 blocks so stake takes effect suite.skip_blocks(2); @@ -906,22 +903,22 @@ fn test_immediate_emission() { // another fund takes into account new voting power suite.fund_native(2, coin(100_000_000, ALT_DENOM)); - suite.assert_pending_rewards(ADDR1, 2, 2 * 50_000_000 + 25_000_000); - suite.assert_pending_rewards(ADDR2, 2, 2 * 25_000_000 + 12_500_000); - suite.assert_pending_rewards(ADDR3, 2, 2 * 25_000_000 + 12_500_000); - suite.assert_pending_rewards(ADDR4, 2, 50_000_000); + suite.assert_pending_rewards(MEMBER1, 2, 2 * 50_000_000 + 25_000_000); + suite.assert_pending_rewards(MEMBER2, 2, 2 * 25_000_000 + 12_500_000); + suite.assert_pending_rewards(MEMBER3, 2, 2 * 25_000_000 + 12_500_000); + suite.assert_pending_rewards(MEMBER4, 2, 50_000_000); // ensure undistributed rewards are immediately 0 suite.assert_undistributed_rewards(2, 0); - suite.claim_rewards(ADDR1, 2); - suite.claim_rewards(ADDR2, 2); - suite.claim_rewards(ADDR3, 2); - suite.claim_rewards(ADDR4, 2); + suite.claim_rewards(MEMBER1, 2); + suite.claim_rewards(MEMBER2, 2); + suite.claim_rewards(MEMBER3, 2); + suite.claim_rewards(MEMBER4, 2); - suite.unstake_native_tokens(ADDR1, 100); - suite.unstake_native_tokens(ADDR2, 50); - suite.unstake_native_tokens(ADDR3, 50); + suite.unstake_native_tokens(MEMBER1, 100); + suite.unstake_native_tokens(MEMBER2, 50); + suite.unstake_native_tokens(MEMBER3, 50); // skip 2 blocks so stake takes effect suite.skip_blocks(2); @@ -929,10 +926,10 @@ fn test_immediate_emission() { // another fund takes into account new voting power suite.fund_native(2, coin(100_000_000, ALT_DENOM)); - suite.assert_pending_rewards(ADDR1, 2, 0); - suite.assert_pending_rewards(ADDR2, 2, 0); - suite.assert_pending_rewards(ADDR3, 2, 0); - suite.assert_pending_rewards(ADDR4, 2, 100_000_000); + suite.assert_pending_rewards(MEMBER1, 2, 0); + suite.assert_pending_rewards(MEMBER2, 2, 0); + suite.assert_pending_rewards(MEMBER3, 2, 0); + suite.assert_pending_rewards(MEMBER4, 2, 100_000_000); // ensure undistributed rewards are immediately 0 suite.assert_undistributed_rewards(2, 0); @@ -946,9 +943,9 @@ fn test_immediate_emission_fails_if_no_voting_power() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); // all users unstake - suite.unstake_native_tokens(ADDR1, 100); - suite.unstake_native_tokens(ADDR2, 50); - suite.unstake_native_tokens(ADDR3, 50); + suite.unstake_native_tokens(MEMBER1, 100); + suite.unstake_native_tokens(MEMBER2, 50); + suite.unstake_native_tokens(MEMBER3, 50); // skip 2 blocks since the contract depends on the previous block's total // voting power, and voting power takes 1 block to take effect. so if voting @@ -969,6 +966,7 @@ fn test_immediate_emission_fails_if_no_voting_power() { // create and fund distribution suite + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -990,78 +988,78 @@ fn test_transition_to_immediate() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 10_000_000); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 0); - // ADDR2 unstakes their stake - suite.unstake_native_tokens(ADDR2, 50); + // MEMBER2 unstakes their stake + suite.unstake_native_tokens(MEMBER2, 50); // skip 1/10th of the time suite.skip_blocks(100_000); - // because ADDR2 is not staking, ADDR1 and ADDR3 receive the rewards. ADDR2 + // because MEMBER2 is not staking, MEMBER1 and MEMBER3 receive the rewards. MEMBER2 // should have the same amount of pending rewards as before. - suite.assert_pending_rewards(ADDR1, 1, 6_666_666); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000 + 3_333_333); + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000 + 3_333_333); - // ADDR2 claims their rewards - suite.claim_rewards(ADDR2, 1); - suite.assert_pending_rewards(ADDR2, 1, 0); + // MEMBER2 claims their rewards + suite.claim_rewards(MEMBER2, 1); + suite.assert_pending_rewards(MEMBER2, 1, 0); // switching to immediate emission instantly distributes the remaining 70M suite.set_immediate_emission(1); - // ADDR1 and ADDR3 split the rewards, and ADDR2 gets none - suite.assert_pending_rewards(ADDR1, 1, 6_666_666 + 46_666_666 + 1); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000 + 3_333_333 + 23_333_333); + // MEMBER1 and MEMBER3 split the rewards, and MEMBER2 gets none + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666 + 46_666_666 + 1); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000 + 3_333_333 + 23_333_333); // claim all rewards - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER3, 1); - // ADDR3 unstakes their stake, leaving only ADDR1 staked - suite.unstake_native_tokens(ADDR3, 50); + // MEMBER3 unstakes their stake, leaving only MEMBER1 staked + suite.unstake_native_tokens(MEMBER3, 50); // skip 2 blocks so unstake takes effect suite.skip_blocks(2); // another fund immediately adds to the pending rewards - suite.mint_native(coin(100_000_000, DENOM), OWNER); - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.mint_native(coin(100_000_000, GOV_DENOM), OWNER); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); - // ADDR1 gets all - suite.assert_pending_rewards(ADDR1, 1, 100_000_000); + // MEMBER1 gets all + suite.assert_pending_rewards(MEMBER1, 1, 100_000_000); // change back to linear emission suite.update_emission_rate(1, Duration::Height(10), 1000, true); // fund with 100M again - suite.mint_native(coin(100_000_000, DENOM), OWNER); - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.mint_native(coin(100_000_000, GOV_DENOM), OWNER); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); - // ADDR1 has same pending as before - suite.assert_pending_rewards(ADDR1, 1, 100_000_000); + // MEMBER1 has same pending as before + suite.assert_pending_rewards(MEMBER1, 1, 100_000_000); // skip 1/10th of the time suite.skip_blocks(100_000); - // ADDR1 has new linearly distributed rewards - suite.assert_pending_rewards(ADDR1, 1, 100_000_000 + 10_000_000); + // MEMBER1 has new linearly distributed rewards + suite.assert_pending_rewards(MEMBER1, 1, 100_000_000 + 10_000_000); } #[test] @@ -1075,44 +1073,44 @@ fn test_native_dao_rewards() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 10_000_000); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 10_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 0); - // ADDR2 and ADDR3 unstake their stake - suite.unstake_native_tokens(ADDR2, 50); - suite.unstake_native_tokens(ADDR3, 50); + // MEMBER2 and MEMBER3 unstake their stake + suite.unstake_native_tokens(MEMBER2, 50); + suite.unstake_native_tokens(MEMBER3, 50); // skip 1/10th of the time suite.skip_blocks(100_000); - // because ADDR2 and ADDR3 are not staking, ADDR1 receives all the rewards. - // ADDR2 and ADDR3 should have the same amount of pending rewards as before. - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 5_000_000); - suite.assert_pending_rewards(ADDR3, 1, 5_000_000); + // because MEMBER2 and MEMBER3 are not staking, MEMBER1 receives all the rewards. + // MEMBER2 and MEMBER3 should have the same amount of pending rewards as before. + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 5_000_000); - // ADDR2 and ADDR3 wake up, claim and restake their rewards - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + // MEMBER2 and MEMBER3 wake up, claim and restake their rewards + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); - let addr1_balance = suite.get_balance_native(ADDR1, DENOM); - let addr2_balance = suite.get_balance_native(ADDR2, DENOM); + let addr1_balance = suite.get_balance_native(MEMBER1, GOV_DENOM); + let addr2_balance = suite.get_balance_native(MEMBER2, GOV_DENOM); - suite.stake_native_tokens(ADDR1, addr1_balance); - suite.stake_native_tokens(ADDR2, addr2_balance); + suite.stake_native_tokens(MEMBER1, addr1_balance); + suite.stake_native_tokens(MEMBER2, addr2_balance); } #[test] @@ -1126,39 +1124,39 @@ fn test_continuous_backfill_latest_voting_power() { // skip all of the time suite.skip_blocks(1_000_000); - suite.assert_pending_rewards(ADDR1, 1, 50_000_000); - suite.assert_pending_rewards(ADDR2, 1, 25_000_000); - suite.assert_pending_rewards(ADDR3, 1, 25_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 25_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 25_000_000); - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); // skip 1/10th of the time suite.skip_blocks(100_000); // change voting powers (1 = 200, 2 = 50, 3 = 50) - suite.stake_native_tokens(ADDR1, 100); + suite.stake_native_tokens(MEMBER1, 100); // skip 1/10th of the time suite.skip_blocks(100_000); // change voting powers again (1 = 50, 2 = 100, 3 = 100) - suite.unstake_native_tokens(ADDR1, 150); - suite.stake_native_tokens(ADDR2, 50); - suite.stake_native_tokens(ADDR3, 50); + suite.unstake_native_tokens(MEMBER1, 150); + suite.stake_native_tokens(MEMBER2, 50); + suite.stake_native_tokens(MEMBER3, 50); // skip 1/10th of the time suite.skip_blocks(100_000); // fund with 100M - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); // since this is continuous, rewards should backfill based on the latest // voting powers. we skipped 30% of the time, so 30M should be distributed - suite.assert_pending_rewards(ADDR1, 1, 6_000_000); - suite.assert_pending_rewards(ADDR2, 1, 12_000_000); - suite.assert_pending_rewards(ADDR3, 1, 12_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 6_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 12_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 12_000_000); } #[test] @@ -1172,124 +1170,128 @@ fn test_cw4_dao_rewards() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // remove the second member - suite.update_members(vec![], vec![ADDR2.to_string()]); + suite.update_members(vec![], vec![MEMBER2.to_string()]); suite.query_members(); // skip 1/10th of the time suite.skip_blocks(100_000); - // now that ADDR2 is no longer a member, ADDR1 and ADDR3 will split the rewards - suite.assert_pending_rewards(ADDR1, 1, 5_000_000 + 6_666_666); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 3_333_333 + 2_500_000); + // now that MEMBER2 is no longer a member, MEMBER1 and MEMBER3 will split the rewards + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000 + 6_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 3_333_333 + 2_500_000); // reintroduce the 2nd member with double the vp let add_member_2 = Member { - addr: ADDR2.to_string(), + addr: MEMBER2.to_string(), weight: 2, }; suite.update_members(vec![add_member_2], vec![]); suite.query_members(); - // now the vp split is [ADDR1: 40%, ADDR2: 40%, ADDR3: 20%] + // now the vp split is [MEMBER1: 40%, MEMBER2: 40%, MEMBER3: 20%] // meaning the token reward per 100k blocks is 4mil, 4mil, 2mil - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 5_000_000 + 6_666_666); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 5_000_000 + 6_666_666); - // assert pending rewards are still the same (other than ADDR1) - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 3_333_333 + 2_500_000); + // assert pending rewards are still the same (other than MEMBER1) + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 3_333_333 + 2_500_000); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 4_000_000); - suite.assert_pending_rewards(ADDR2, 1, 6_500_000); - suite.assert_pending_rewards(ADDR3, 1, 7_833_333); + suite.assert_pending_rewards(MEMBER1, 1, 4_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 6_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 7_833_333); // skip 1/2 of time, leaving 200k blocks left suite.skip_blocks(500_000); - suite.assert_pending_rewards(ADDR1, 1, 24_000_000); - suite.assert_pending_rewards(ADDR2, 1, 26_500_000); - suite.assert_pending_rewards(ADDR3, 1, 17_833_333); + suite.assert_pending_rewards(MEMBER1, 1, 24_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 26_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 17_833_333); // remove all members suite.update_members( vec![], - vec![ADDR1.to_string(), ADDR2.to_string(), ADDR3.to_string()], + vec![ + MEMBER1.to_string(), + MEMBER2.to_string(), + MEMBER3.to_string(), + ], ); - suite.assert_pending_rewards(ADDR1, 1, 24_000_000); - suite.assert_pending_rewards(ADDR2, 1, 26_500_000); - suite.assert_pending_rewards(ADDR3, 1, 17_833_333); + suite.assert_pending_rewards(MEMBER1, 1, 24_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 26_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 17_833_333); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 24_000_000); - suite.assert_pending_rewards(ADDR2, 1, 26_500_000); - suite.assert_pending_rewards(ADDR3, 1, 17_833_333); + suite.assert_pending_rewards(MEMBER1, 1, 24_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 26_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 17_833_333); suite.update_members( vec![ Member { - addr: ADDR1.to_string(), + addr: MEMBER1.to_string(), weight: 2, }, Member { - addr: ADDR2.to_string(), + addr: MEMBER2.to_string(), weight: 2, }, Member { - addr: ADDR3.to_string(), + addr: MEMBER3.to_string(), weight: 1, }, ], vec![], ); - suite.assert_pending_rewards(ADDR1, 1, 24_000_000); - suite.assert_pending_rewards(ADDR2, 1, 26_500_000); - suite.assert_pending_rewards(ADDR3, 1, 17_833_333); + suite.assert_pending_rewards(MEMBER1, 1, 24_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 26_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 17_833_333); - suite.claim_rewards(ADDR1, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_native_balance(ADDR1, DENOM, 35_666_666); + suite.claim_rewards(MEMBER1, 1); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 35_666_666); // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 4_000_000); - suite.assert_pending_rewards(ADDR2, 1, 30_500_000); - suite.assert_pending_rewards(ADDR3, 1, 19_833_333); + suite.assert_pending_rewards(MEMBER1, 1, 4_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 30_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 19_833_333); // at the very expiration block, claim rewards - suite.claim_rewards(ADDR2, 1); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_native_balance(ADDR2, DENOM, 30_500_000); + suite.claim_rewards(MEMBER2, 1); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_native_balance(MEMBER2, GOV_DENOM, 30_500_000); suite.skip_blocks(100_000); - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER3, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 0); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 0); let contract = suite.distribution_contract.clone(); // for 100k blocks there were no members so some rewards are remaining in the contract. - let contract_token_balance = suite.get_balance_native(contract.clone(), DENOM); + let contract_token_balance = suite.get_balance_native(contract.clone(), GOV_DENOM); assert!(contract_token_balance > 0); } @@ -1299,7 +1301,7 @@ fn test_fund_multiple_denoms() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); let alt_coin = coin(100_000_000, ALT_DENOM); - let coin = coin(100_000_000, DENOM); + let coin = coin(100_000_000, GOV_DENOM); suite.mint_native(alt_coin.clone(), OWNER); suite.mint_native(coin.clone(), OWNER); let hook_caller = suite.staking_addr.to_string(); @@ -1316,8 +1318,8 @@ fn test_fund_multiple_denoms() { ); suite + .base .app - .borrow_mut() .execute_contract( Addr::unchecked(OWNER), suite.distribution_contract.clone(), @@ -1363,7 +1365,7 @@ fn test_fund_cw20_with_invalid_cw20_receive_msg() { let mut suite = SuiteBuilder::base(super::suite::DaoType::CW20).build(); let unregistered_cw20_coin = Cw20Coin { - address: ADDR1.to_string(), + address: MEMBER1.to_string(), amount: Uint128::new(1_000_000), }; @@ -1371,9 +1373,10 @@ fn test_fund_cw20_with_invalid_cw20_receive_msg() { let fund_sub_msg = to_json_binary(&"not_the_fund: {}").unwrap(); suite + .base .app .execute_contract( - Addr::unchecked(ADDR1), + Addr::unchecked(MEMBER1), new_cw20_mint.clone(), &cw20::Cw20ExecuteMsg::Send { contract: suite.distribution_contract.to_string(), @@ -1392,7 +1395,7 @@ fn test_fund_invalid_cw20_denom() { let mut suite = SuiteBuilder::base(super::suite::DaoType::CW20).build(); let unregistered_cw20_coin = Cw20Coin { - address: ADDR1.to_string(), + address: MEMBER1.to_string(), amount: Uint128::new(1_000_000), }; @@ -1420,30 +1423,30 @@ fn test_withdraw_alternative_destination_address() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // user 1 and 2 claim their rewards - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); // user 2 unstakes - suite.unstake_native_tokens(ADDR2, 50); + suite.unstake_native_tokens(MEMBER2, 50); suite.skip_blocks(100_000); let distribution_contract = suite.distribution_contract.to_string(); - suite.assert_native_balance(subdao_addr.as_str(), DENOM, 0); + suite.assert_native_balance(subdao_addr.as_str(), GOV_DENOM, 0); let pre_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); suite.withdraw(1); let post_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); - let post_withdraw_subdao_balance = suite.get_balance_native(subdao_addr.to_string(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); + let post_withdraw_subdao_balance = suite.get_balance_native(subdao_addr.to_string(), GOV_DENOM); // after withdraw the balance of the subdao should be the same // as pre-withdraw-distributor-bal minus post-withdraw-distributor-bal @@ -1460,30 +1463,30 @@ fn test_withdraw_block_based() { // skip 1/10th of the time suite.skip_blocks(100_000); - // suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - // suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - // suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + // suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + // suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + // suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // user 1 and 2 claim their rewards - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); // user 2 unstakes - suite.unstake_native_tokens(ADDR2, 50); + suite.unstake_native_tokens(MEMBER2, 50); suite.skip_blocks(100_000); let distribution_contract = suite.distribution_contract.to_string(); let pre_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); - suite.assert_native_balance(suite.owner.clone().unwrap().as_str(), DENOM, 0); + suite.assert_native_balance(OWNER, GOV_DENOM, 0); suite.withdraw(1); let post_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); - let post_withdraw_owner_balance = suite.get_balance_native(suite.owner.clone().unwrap(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); + let post_withdraw_owner_balance = suite.get_balance_native(OWNER, GOV_DENOM); // after withdraw the balance of the owner should be the same // as pre-withdraw-distributor-bal minus post-withdraw-distributor-bal @@ -1505,25 +1508,25 @@ fn test_withdraw_block_based() { ); // we assert that pending rewards did not change - suite.assert_pending_rewards(ADDR1, 1, 6_666_666); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 3_333_333 + 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 3_333_333 + 2_500_000); // user 1 can claim their rewards - suite.claim_rewards(ADDR1, 1); - // suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_native_balance(ADDR1, DENOM, 11_666_666); + suite.claim_rewards(MEMBER1, 1); + // suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 11_666_666); // user 3 can unstake and claim their rewards - suite.unstake_native_tokens(ADDR3, 50); + suite.unstake_native_tokens(MEMBER3, 50); suite.skip_blocks(100_000); - suite.assert_native_balance(ADDR3, DENOM, 50); - suite.claim_rewards(ADDR3, 1); - // suite.assert_pending_rewards(ADDR3, 1, 0); - suite.assert_native_balance(ADDR3, DENOM, 3_333_333 + 2_500_000 + 50); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 50); + suite.claim_rewards(MEMBER3, 1); + // suite.assert_pending_rewards(MEMBER3, 1, 0); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 3_333_333 + 2_500_000 + 50); // TODO: fix this rug of 1 udenom by the distribution contract - suite.assert_native_balance(&distribution_contract, DENOM, 1); + suite.assert_native_balance(&distribution_contract, GOV_DENOM, 1); } #[test] @@ -1531,7 +1534,7 @@ fn test_withdraw_time_based() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Time(10), destination: None, continuous: true, @@ -1541,30 +1544,30 @@ fn test_withdraw_time_based() { // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // user 1 and 2 claim their rewards - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); // user 2 unstakes - suite.unstake_native_tokens(ADDR2, 50); + suite.unstake_native_tokens(MEMBER2, 50); suite.skip_seconds(100_000); let distribution_contract = suite.distribution_contract.to_string(); let pre_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); - suite.assert_native_balance(suite.owner.clone().unwrap().as_str(), DENOM, 0); + suite.assert_native_balance(OWNER, GOV_DENOM, 0); suite.withdraw(1); let post_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); - let post_withdraw_owner_balance = suite.get_balance_native(suite.owner.clone().unwrap(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); + let post_withdraw_owner_balance = suite.get_balance_native(OWNER, GOV_DENOM); // after withdraw the balance of the owner should be the same // as pre-withdraw-distributor-bal minus post-withdraw-distributor-bal @@ -1586,25 +1589,25 @@ fn test_withdraw_time_based() { ); // we assert that pending rewards did not change - suite.assert_pending_rewards(ADDR1, 1, 6_666_666); - suite.assert_pending_rewards(ADDR2, 1, 0); - suite.assert_pending_rewards(ADDR3, 1, 3_333_333 + 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 6_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 0); + suite.assert_pending_rewards(MEMBER3, 1, 3_333_333 + 2_500_000); // user 1 can claim their rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_pending_rewards(ADDR1, 1, 0); - suite.assert_native_balance(ADDR1, DENOM, 11_666_666); + suite.claim_rewards(MEMBER1, 1); + suite.assert_pending_rewards(MEMBER1, 1, 0); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 11_666_666); // user 3 can unstake and claim their rewards - suite.unstake_native_tokens(ADDR3, 50); + suite.unstake_native_tokens(MEMBER3, 50); suite.skip_seconds(100_000); - suite.assert_native_balance(ADDR3, DENOM, 50); - suite.claim_rewards(ADDR3, 1); - suite.assert_pending_rewards(ADDR3, 1, 0); - suite.assert_native_balance(ADDR3, DENOM, 3_333_333 + 2_500_000 + 50); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 50); + suite.claim_rewards(MEMBER3, 1); + suite.assert_pending_rewards(MEMBER3, 1, 0); + suite.assert_native_balance(MEMBER3, GOV_DENOM, 3_333_333 + 2_500_000 + 50); // TODO: fix this rug of 1 udenom by the distribution contract - suite.assert_native_balance(&distribution_contract, DENOM, 1); + suite.assert_native_balance(&distribution_contract, GOV_DENOM, 1); } #[test] @@ -1612,7 +1615,7 @@ fn test_withdraw_and_restart_with_continuous() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Time(10), destination: None, continuous: true, @@ -1622,14 +1625,14 @@ fn test_withdraw_and_restart_with_continuous() { // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // users claim their rewards - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); // skip 1/10th of the time suite.skip_seconds(100_000); @@ -1637,14 +1640,14 @@ fn test_withdraw_and_restart_with_continuous() { let distribution_contract = suite.distribution_contract.to_string(); let pre_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); - suite.assert_native_balance(suite.owner.clone().unwrap().as_str(), DENOM, 0); + suite.assert_native_balance(OWNER, GOV_DENOM, 0); suite.withdraw(1); let post_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); - let post_withdraw_owner_balance = suite.get_balance_native(suite.owner.clone().unwrap(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); + let post_withdraw_owner_balance = suite.get_balance_native(OWNER, GOV_DENOM); // after withdraw the balance of the owner should be the same // as pre-withdraw-distributor-bal minus post-withdraw-distributor-bal @@ -1667,22 +1670,22 @@ fn test_withdraw_and_restart_with_continuous() { ); // we assert that pending rewards did not change - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); // fund again - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); // check that pending rewards did not restart. since we skipped 1/10th the // time after the withdraw occurred, everyone should already have 10% of the // new amount pending. - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); } #[test] @@ -1690,7 +1693,7 @@ fn test_withdraw_and_restart_not_continuous() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Time(10), destination: None, continuous: false, @@ -1700,14 +1703,14 @@ fn test_withdraw_and_restart_not_continuous() { // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // users claim their rewards - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); // skip 1/10th of the time suite.skip_seconds(100_000); @@ -1715,14 +1718,14 @@ fn test_withdraw_and_restart_not_continuous() { let distribution_contract = suite.distribution_contract.to_string(); let pre_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); - suite.assert_native_balance(suite.owner.clone().unwrap().as_str(), DENOM, 0); + suite.assert_native_balance(OWNER, GOV_DENOM, 0); suite.withdraw(1); let post_withdraw_distributor_balance = - suite.get_balance_native(distribution_contract.clone(), DENOM); - let post_withdraw_owner_balance = suite.get_balance_native(suite.owner.clone().unwrap(), DENOM); + suite.get_balance_native(distribution_contract.clone(), GOV_DENOM); + let post_withdraw_owner_balance = suite.get_balance_native(OWNER, GOV_DENOM); // after withdraw the balance of the owner should be the same // as pre-withdraw-distributor-bal minus post-withdraw-distributor-bal @@ -1745,15 +1748,15 @@ fn test_withdraw_and_restart_not_continuous() { ); // we assert that pending rewards did not change - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); // fund again - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); // skip 1/10th of the time suite.skip_seconds(100_000); @@ -1761,9 +1764,9 @@ fn test_withdraw_and_restart_not_continuous() { // check that pending rewards restarted from the funding date. since we // skipped 1/10th the time after the funding occurred, everyone should // have 10% of the new amount pending - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); } #[test] @@ -1775,10 +1778,10 @@ fn test_withdraw_unauthorized() { suite.skip_blocks(100_000); suite + .base .app - .borrow_mut() .execute_contract( - Addr::unchecked(ADDR1), + Addr::unchecked(MEMBER1), suite.distribution_contract.clone(), &ExecuteMsg::Withdraw { id: 1 }, &[], @@ -1803,7 +1806,7 @@ fn test_claim_404() { suite.skip_blocks(100_000); - suite.claim_rewards(ADDR1, 3); + suite.claim_rewards(MEMBER1, 3); } #[test] @@ -1813,8 +1816,8 @@ fn test_fund_latest_404() { // make new rewards contract let reward_addr = suite + .base .app - .borrow_mut() .instantiate_contract( suite.reward_code_id, Addr::unchecked(OWNER), @@ -1828,15 +1831,15 @@ fn test_fund_latest_404() { .unwrap(); // try to fund latest before creating a distribution - suite.mint_native(coin(100_000_000, DENOM), OWNER); + suite.mint_native(coin(100_000_000, GOV_DENOM), OWNER); suite + .base .app - .borrow_mut() .execute_contract( Addr::unchecked(OWNER), reward_addr, &ExecuteMsg::FundLatest {}, - &[coin(100_000_000, DENOM)], + &[coin(100_000_000, GOV_DENOM)], ) .unwrap(); } @@ -1867,8 +1870,8 @@ fn test_fund_invalid_native_denom() { suite.mint_native(coin(100_000_000, ALT_DENOM), OWNER); suite + .base .app - .borrow_mut() .execute_contract( Addr::unchecked(OWNER), suite.distribution_contract.clone(), @@ -1883,7 +1886,7 @@ fn test_fund_native_block_based_post_expiration_not_continuous() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Height(10), destination: None, continuous: false, @@ -1901,22 +1904,22 @@ fn test_fund_native_block_based_post_expiration_not_continuous() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); - // ADDR2 unstake their stake - suite.unstake_native_tokens(ADDR2, 50); + // MEMBER2 unstake their stake + suite.unstake_native_tokens(MEMBER2, 50); // addr3 claims their rewards - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER3, 1); // skip to 100_000 blocks past the expiration suite.skip_blocks(1_000_000); - suite.assert_pending_rewards(ADDR1, 1, 65_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 30_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 65_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 30_000_000); suite.assert_ends_at(expiration_date); suite.assert_started_at(started_at); @@ -1924,9 +1927,9 @@ fn test_fund_native_block_based_post_expiration_not_continuous() { // we fund the distributor with the same amount of coins as // during setup, meaning that the rewards distribution duration // should be the same. - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); - let current_block = suite.app.block_info(); + let current_block = suite.base.app.block_info(); // funding after the reward period had expired should // reset the start date to that of the funding. @@ -1943,7 +1946,7 @@ fn test_fund_cw20_time_based_post_expiration_not_continuous() { let mut suite = SuiteBuilder::base(super::suite::DaoType::CW20) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Cw20(DENOM.to_string()), + denom: UncheckedDenom::Cw20(GOV_DENOM.to_string()), duration: Duration::Time(10), destination: None, continuous: false, @@ -1963,23 +1966,23 @@ fn test_fund_cw20_time_based_post_expiration_not_continuous() { // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); - // ADDR2 unstake their stake - suite.unstake_cw20_tokens(50, ADDR2); + // MEMBER2 unstake their stake + suite.unstake_cw20_tokens(50, MEMBER2); // addr3 claims their rewards - suite.claim_rewards(ADDR3, 1); - suite.assert_cw20_balance(cw20_denom, ADDR3, 2_500_000); + suite.claim_rewards(MEMBER3, 1); + suite.assert_cw20_balance(cw20_denom, MEMBER3, 2_500_000); // skip to 100_000 blocks past the expiration suite.skip_seconds(1_000_000); - suite.assert_pending_rewards(ADDR1, 1, 65_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 30_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 65_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 30_000_000); suite.assert_ends_at(expiration_date); suite.assert_started_at(started_at); @@ -1994,7 +1997,7 @@ fn test_fund_cw20_time_based_post_expiration_not_continuous() { suite.fund_cw20(1, funding_denom.clone()); - let current_block = suite.app.block_info(); + let current_block = suite.base.app.block_info(); // funding after the reward period had expired should // reset the start date to that of the funding. @@ -2013,7 +2016,7 @@ fn test_fund_cw20_time_based_pre_expiration() { let mut suite = SuiteBuilder::base(super::suite::DaoType::CW20) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Cw20(DENOM.to_string()), + denom: UncheckedDenom::Cw20(GOV_DENOM.to_string()), duration: Duration::Time(10), destination: None, continuous: true, @@ -2031,22 +2034,22 @@ fn test_fund_cw20_time_based_pre_expiration() { // skip 1/10th of the time suite.skip_seconds(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); - // ADDR2 unstake their stake - suite.unstake_cw20_tokens(50, ADDR2); + // MEMBER2 unstake their stake + suite.unstake_cw20_tokens(50, MEMBER2); // addr3 claims their rewards - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER3, 1); // skip to 100_000 blocks before the expiration suite.skip_seconds(800_000); - suite.assert_pending_rewards(ADDR1, 1, 58_333_333); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 26_666_666); + suite.assert_pending_rewards(MEMBER1, 1, 58_333_333); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 26_666_666); suite.assert_ends_at(expiration_date); suite.assert_started_at(started_at); @@ -2087,22 +2090,22 @@ fn test_fund_native_height_based_pre_expiration() { // skip 1/10th of the time suite.skip_blocks(100_000); - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); - // ADDR2 unstake their stake - suite.unstake_native_tokens(ADDR2, 50); + // MEMBER2 unstake their stake + suite.unstake_native_tokens(MEMBER2, 50); // addr3 claims their rewards - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER3, 1); // skip to 100_000 blocks before the expiration suite.skip_blocks(800_000); - suite.assert_pending_rewards(ADDR1, 1, 58_333_333); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 26_666_666); + suite.assert_pending_rewards(MEMBER1, 1, 58_333_333); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 26_666_666); suite.assert_ends_at(expiration_date); suite.assert_started_at(started_at); @@ -2110,7 +2113,7 @@ fn test_fund_native_height_based_pre_expiration() { // we fund the distributor with the same amount of coins as // during setup, meaning that the rewards distribution duration // should be the same. - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); // funding before the reward period expires should // not reset the existing rewards cycle @@ -2127,7 +2130,7 @@ fn test_native_dao_rewards_entry_edge_case() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); // we start with the following staking power split: - // [ADDR1: 100, ADDR2: 50, ADDR3: 50], or [ADDR1: 50%, ADDR2: 25%, ADDR3: 25% + // [MEMBER1: 100, MEMBER2: 50, MEMBER3: 50], or [MEMBER1: 50%, MEMBER2: 25%, MEMBER3: 25% suite.assert_amount(1_000); suite.assert_ends_at(Expiration::AtHeight(1_000_000)); suite.assert_duration(10); @@ -2135,63 +2138,63 @@ fn test_native_dao_rewards_entry_edge_case() { // skip 1/10th of the time suite.skip_blocks(100_000); - // ADDR1 stakes additional 100 tokens, bringing the new staking power split to - // [ADDR1: 200, ADDR2: 50, ADDR3: 50], or [ADDR1: 66.6%, ADDR2: 16.6%, ADDR3: 16.6%] - // this means that per 100_000 blocks, ADDR1 should receive 6_666_666, while - // ADDR2 and ADDR3 should receive 1_666_666 each. - suite.mint_native(coin(100, DENOM), ADDR1); - suite.stake_native_tokens(ADDR1, 100); + // MEMBER1 stakes additional 100 tokens, bringing the new staking power split to + // [MEMBER1: 200, MEMBER2: 50, MEMBER3: 50], or [MEMBER1: 66.6%, MEMBER2: 16.6%, MEMBER3: 16.6%] + // this means that per 100_000 blocks, MEMBER1 should receive 6_666_666, while + // MEMBER2 and MEMBER3 should receive 1_666_666 each. + suite.mint_native(coin(100, GOV_DENOM), MEMBER1); + suite.stake_native_tokens(MEMBER1, 100); // rewards here should not be affected by the new stake, - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip 1/10th of the time suite.skip_blocks(100_000); // here we should see the new stake affecting the rewards split. - suite.assert_pending_rewards(ADDR1, 1, 5_000_000 + 6_666_666); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000 + 1_666_666); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000 + 1_666_666); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000 + 6_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000 + 1_666_666); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000 + 1_666_666); - // ADDR1 claims rewards - suite.claim_rewards(ADDR1, 1); - suite.assert_native_balance(ADDR1, DENOM, 5_000_000 + 6_666_666); - suite.assert_pending_rewards(ADDR1, 1, 0); + // MEMBER1 claims rewards + suite.claim_rewards(MEMBER1, 1); + suite.assert_native_balance(MEMBER1, GOV_DENOM, 5_000_000 + 6_666_666); + suite.assert_pending_rewards(MEMBER1, 1, 0); - // ADDR2 and ADDR3 unstake their stake - // new voting power split is [ADDR1: 100%, ADDR2: 0%, ADDR3: 0%] - suite.unstake_native_tokens(ADDR2, 50); - suite.unstake_native_tokens(ADDR3, 50); + // MEMBER2 and MEMBER3 unstake their stake + // new voting power split is [MEMBER1: 100%, MEMBER2: 0%, MEMBER3: 0%] + suite.unstake_native_tokens(MEMBER2, 50); + suite.unstake_native_tokens(MEMBER3, 50); - // we assert that by unstaking, ADDR2 and ADDR3 do not forfeit their earned but unclaimed rewards - suite.assert_pending_rewards(ADDR2, 1, 2_500_000 + 1_666_666); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000 + 1_666_666); + // we assert that by unstaking, MEMBER2 and MEMBER3 do not forfeit their earned but unclaimed rewards + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000 + 1_666_666); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000 + 1_666_666); // skip a block and assert that nothing changes suite.skip_blocks(1); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000 + 1_666_666); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000 + 1_666_666); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000 + 1_666_666); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000 + 1_666_666); // skip the remaining blocks to reach 1/10th of the time suite.skip_blocks(99_999); - // because ADDR2 and ADDR3 are not staking, ADDR1 receives all the rewards. - // ADDR2 and ADDR3 should have the same amount of pending rewards as before. - suite.assert_pending_rewards(ADDR1, 1, 10_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000 + 1_666_666); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000 + 1_666_666); + // because MEMBER2 and MEMBER3 are not staking, MEMBER1 receives all the rewards. + // MEMBER2 and MEMBER3 should have the same amount of pending rewards as before. + suite.assert_pending_rewards(MEMBER1, 1, 10_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000 + 1_666_666); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000 + 1_666_666); - // ADDR2 and ADDR3 wake up, claim and restake their rewards - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + // MEMBER2 and MEMBER3 wake up, claim and restake their rewards + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); - let addr1_balance = suite.get_balance_native(ADDR1, DENOM); - let addr2_balance = suite.get_balance_native(ADDR2, DENOM); + let addr1_balance = suite.get_balance_native(MEMBER1, GOV_DENOM); + let addr2_balance = suite.get_balance_native(MEMBER2, GOV_DENOM); - suite.stake_native_tokens(ADDR1, addr1_balance); - suite.stake_native_tokens(ADDR2, addr2_balance); + suite.stake_native_tokens(MEMBER1, addr1_balance); + suite.stake_native_tokens(MEMBER2, addr2_balance); } #[test] @@ -2233,20 +2236,20 @@ fn test_fund_native_on_create() { suite.skip_blocks(1_000_000); // skip 1/10th of the time - suite.assert_pending_rewards(ADDR1, 2, 5_000_000); - suite.assert_pending_rewards(ADDR2, 2, 2_500_000); - suite.assert_pending_rewards(ADDR3, 2, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 2, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 2, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 2, 2_500_000); } #[test] -#[should_panic(expected = "Must send reserve token 'ujuno'")] +#[should_panic(expected = "Must send reserve token 'ugovtoken'")] fn test_fund_native_with_other_denom() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); suite.mint_native(coin(100, ALT_DENOM), OWNER); let execute_create_msg = ExecuteMsg::Create(CreateMsg { - denom: cw20::UncheckedDenom::Native(DENOM.to_string()), + denom: cw20::UncheckedDenom::Native(GOV_DENOM.to_string()), emission_rate: EmissionRate::Linear { amount: Uint128::new(1000), duration: Duration::Height(100), @@ -2260,6 +2263,7 @@ fn test_fund_native_with_other_denom() { // create distribution with other denom provided suite + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -2275,11 +2279,11 @@ fn test_fund_native_with_other_denom() { fn test_fund_native_multiple_denoms() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); - suite.mint_native(coin(100, DENOM), OWNER); + suite.mint_native(coin(100, GOV_DENOM), OWNER); suite.mint_native(coin(100, ALT_DENOM), OWNER); let execute_create_msg = ExecuteMsg::Create(CreateMsg { - denom: cw20::UncheckedDenom::Native(DENOM.to_string()), + denom: cw20::UncheckedDenom::Native(GOV_DENOM.to_string()), emission_rate: EmissionRate::Linear { amount: Uint128::new(1000), duration: Duration::Height(100), @@ -2293,12 +2297,13 @@ fn test_fund_native_multiple_denoms() { // create distribution with 0 amount suite + .base .app .execute_contract( Addr::unchecked(OWNER), suite.distribution_contract.clone(), &execute_create_msg, - &[coin(100, DENOM), coin(100, ALT_DENOM)], + &[coin(100, GOV_DENOM), coin(100, ALT_DENOM)], ) .unwrap(); } @@ -2308,7 +2313,7 @@ fn test_fund_native_multiple_denoms() { fn test_fund_native_on_create_cw20() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); - suite.mint_native(coin(100, DENOM), OWNER); + suite.mint_native(coin(100, GOV_DENOM), OWNER); let cw20_denom = suite .mint_cw20( @@ -2335,12 +2340,13 @@ fn test_fund_native_on_create_cw20() { // create cw20 distribution with native funds provided suite + .base .app .execute_contract( Addr::unchecked(OWNER), suite.distribution_contract.clone(), &execute_create_msg, - &coins(100, DENOM), + &coins(100, GOV_DENOM), ) .unwrap(); } @@ -2381,7 +2387,7 @@ fn test_update_owner() { fn test_update_vp_contract() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native).build(); - let new_vp_contract = setup_native_token_test(suite.app.borrow_mut()); + let new_vp_contract = suite.base.cw4().dao().voting_module_addr; suite.update_vp_contract(1, new_vp_contract.as_str()); @@ -2462,7 +2468,7 @@ fn test_rewards_not_lost_after_discontinuous_restart() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 3_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Height(1), destination: None, continuous: false, @@ -2477,17 +2483,17 @@ fn test_rewards_not_lost_after_discontinuous_restart() { suite.skip_blocks(33_333); // check pending rewards - suite.assert_pending_rewards(ADDR1, 1, 49999500); - suite.assert_pending_rewards(ADDR2, 1, 24999750); - suite.assert_pending_rewards(ADDR3, 1, 24999750); + suite.assert_pending_rewards(MEMBER1, 1, 49999500); + suite.assert_pending_rewards(MEMBER2, 1, 24999750); + suite.assert_pending_rewards(MEMBER3, 1, 24999750); // before user claim rewards, someone funded - suite.fund_native(1, coin(1u128, DENOM)); + suite.fund_native(1, coin(1u128, GOV_DENOM)); // pending rewards should still exist - suite.assert_pending_rewards(ADDR1, 1, 49999500); - suite.assert_pending_rewards(ADDR2, 1, 24999750); - suite.assert_pending_rewards(ADDR3, 1, 24999750); + suite.assert_pending_rewards(MEMBER1, 1, 49999500); + suite.assert_pending_rewards(MEMBER2, 1, 24999750); + suite.assert_pending_rewards(MEMBER3, 1, 24999750); } #[test] @@ -2502,20 +2508,20 @@ fn test_fund_while_paused() { suite.skip_blocks(100_000); // check pending rewards - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // pause suite.pause_emission(1); // pending rewards should still exist - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // fund during pause the amount that's already been distributed - suite.fund_native(1, coin(10_000_000, DENOM)); + suite.fund_native(1, coin(10_000_000, GOV_DENOM)); // restart suite.update_emission_rate(1, Duration::Height(10), 1_000, true); @@ -2527,13 +2533,13 @@ fn test_fund_while_paused() { suite.skip_blocks(100_000); // check pending rewards - suite.assert_pending_rewards(ADDR1, 1, 2 * 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2 * 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2 * 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 2 * 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2 * 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2 * 2_500_000); // pause and fund more suite.pause_emission(1); - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); // restart suite.update_emission_rate(1, Duration::Height(10), 1_000, true); @@ -2555,9 +2561,9 @@ fn test_pause_expired() { suite.skip_blocks(100_000); // check pending rewards - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // check undistributed rewards suite.assert_undistributed_rewards(1, 90_000_000); @@ -2572,9 +2578,9 @@ fn test_pause_expired() { suite.update_emission_rate(1, Duration::Height(10), 1_000, false); // check pending rewards are the same - suite.assert_pending_rewards(ADDR1, 1, 5_000_000); - suite.assert_pending_rewards(ADDR2, 1, 2_500_000); - suite.assert_pending_rewards(ADDR3, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER1, 1, 5_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 2_500_000); + suite.assert_pending_rewards(MEMBER3, 1, 2_500_000); // skip all and more, expiring suite.skip_blocks(1_100_000); @@ -2583,9 +2589,9 @@ fn test_pause_expired() { suite.assert_undistributed_rewards(1, 0); // check pending rewards - suite.assert_pending_rewards(ADDR1, 1, 50_000_000); - suite.assert_pending_rewards(ADDR2, 1, 25_000_000); - suite.assert_pending_rewards(ADDR3, 1, 25_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 25_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 25_000_000); // pause suite.pause_emission(1); @@ -2594,12 +2600,12 @@ fn test_pause_expired() { suite.assert_undistributed_rewards(1, 0); // pending rewards should still exist - suite.assert_pending_rewards(ADDR1, 1, 50_000_000); - suite.assert_pending_rewards(ADDR2, 1, 25_000_000); - suite.assert_pending_rewards(ADDR3, 1, 25_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 25_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 25_000_000); // fund - suite.fund_native(1, coin(100_000_000, DENOM)); + suite.fund_native(1, coin(100_000_000, GOV_DENOM)); // resume suite.update_emission_rate(1, Duration::Height(10), 1_000, false); @@ -2614,9 +2620,9 @@ fn test_pause_expired() { suite.assert_undistributed_rewards(1, 0); // check pending rewards - suite.assert_pending_rewards(ADDR1, 1, 100_000_000); - suite.assert_pending_rewards(ADDR2, 1, 50_000_000); - suite.assert_pending_rewards(ADDR3, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 100_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 50_000_000); } #[test] @@ -2624,7 +2630,7 @@ fn test_large_stake_before_claim() { let mut suite = SuiteBuilder::base(super::suite::DaoType::Native) .with_rewards_config(RewardsConfig { amount: 3_000, - denom: UncheckedDenom::Native(DENOM.to_string()), + denom: UncheckedDenom::Native(GOV_DENOM.to_string()), duration: Duration::Height(1), destination: None, continuous: true, @@ -2635,22 +2641,22 @@ fn test_large_stake_before_claim() { suite.assert_ends_at(Expiration::AtHeight(33_333)); suite.assert_duration(1); - // ADDR1 stake big amount of tokens + // MEMBER1 stake big amount of tokens suite.skip_blocks(33_000); - suite.mint_native(coin(10_000, &suite.reward_denom), ADDR1); - suite.stake_native_tokens(ADDR1, 10_000); + suite.mint_native(coin(10_000, &suite.reward_denom), MEMBER1); + suite.stake_native_tokens(MEMBER1, 10_000); // ADD1 claims rewards in the next block suite.skip_blocks(1); - suite.claim_rewards(ADDR1, 1); + suite.claim_rewards(MEMBER1, 1); // skip to end suite.skip_blocks(100_000_000); // all users should be able to claim rewards - suite.claim_rewards(ADDR1, 1); - suite.claim_rewards(ADDR2, 1); - suite.claim_rewards(ADDR3, 1); + suite.claim_rewards(MEMBER1, 1); + suite.claim_rewards(MEMBER2, 1); + suite.claim_rewards(MEMBER3, 1); } #[test] @@ -2662,14 +2668,14 @@ fn test_fund_latest_native() { suite.assert_duration(10); // double duration by 1_000_000 blocks - suite.fund_latest_native(coin(100_000_000, DENOM)); + suite.fund_latest_native(coin(100_000_000, GOV_DENOM)); // skip all of the time suite.skip_blocks(2_000_000); - suite.assert_pending_rewards(ADDR1, 1, 100_000_000); - suite.assert_pending_rewards(ADDR2, 1, 50_000_000); - suite.assert_pending_rewards(ADDR3, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 100_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 50_000_000); } #[test] @@ -2677,7 +2683,7 @@ fn test_fund_latest_cw20() { let mut suite = SuiteBuilder::base(super::suite::DaoType::CW20) .with_rewards_config(RewardsConfig { amount: 1_000, - denom: UncheckedDenom::Cw20(DENOM.to_string()), + denom: UncheckedDenom::Cw20(GOV_DENOM.to_string()), duration: Duration::Height(10), destination: None, continuous: true, @@ -2697,9 +2703,9 @@ fn test_fund_latest_cw20() { // skip all of the time suite.skip_blocks(2_000_000); - suite.assert_pending_rewards(ADDR1, 1, 100_000_000); - suite.assert_pending_rewards(ADDR2, 1, 50_000_000); - suite.assert_pending_rewards(ADDR3, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER1, 1, 100_000_000); + suite.assert_pending_rewards(MEMBER2, 1, 50_000_000); + suite.assert_pending_rewards(MEMBER3, 1, 50_000_000); } #[test] @@ -2715,7 +2721,7 @@ fn test_fund_latest_cw20_invalid_native() { }) .build(); - suite.fund_latest_native(coin(100, DENOM)); + suite.fund_latest_native(coin(100, GOV_DENOM)); } #[test] @@ -2761,6 +2767,7 @@ fn test_closed_funding() { // create distribution suite + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -2778,12 +2785,12 @@ fn test_closed_funding() { ); // test fund from non-owner - suite.mint_native(coin(100, ALT_DENOM), ADDR1); + suite.mint_native(coin(100, ALT_DENOM), MEMBER1); let err: ContractError = suite + .base .app - .borrow_mut() .execute_contract( - Addr::unchecked(ADDR1), + Addr::unchecked(MEMBER1), suite.distribution_contract.clone(), &ExecuteMsg::Fund(FundMsg { id: 2 }), &[coin(100, ALT_DENOM)], @@ -2798,9 +2805,10 @@ fn test_closed_funding() { // test fund from non-owner suite + .base .app .execute_contract( - Addr::unchecked(ADDR1), + Addr::unchecked(MEMBER1), suite.distribution_contract.clone(), &ExecuteMsg::Fund(FundMsg { id: 2 }), &[coin(100, ALT_DENOM)], @@ -2837,6 +2845,7 @@ fn test_queries_before_funded() { // create distribution with no funds suite + .base .app .execute_contract( Addr::unchecked(OWNER), @@ -2847,9 +2856,9 @@ fn test_queries_before_funded() { .unwrap(); // users have no rewards - suite.assert_pending_rewards(ADDR1, 2, 0); - suite.assert_pending_rewards(ADDR2, 2, 0); - suite.assert_pending_rewards(ADDR3, 2, 0); + suite.assert_pending_rewards(MEMBER1, 2, 0); + suite.assert_pending_rewards(MEMBER2, 2, 0); + suite.assert_pending_rewards(MEMBER3, 2, 0); // ensure undistributed rewards are immediately 0 suite.assert_undistributed_rewards(2, 0); @@ -2862,11 +2871,11 @@ fn test_migrate() { cw2::set_contract_version(&mut deps.storage, "test", "0.0.1").unwrap(); // wrong contract name errors - let err: ContractError = + let err: crate::ContractError = crate::contract::migrate(deps.as_mut(), mock_env(), MigrateMsg {}).unwrap_err(); assert_eq!( err, - ContractError::MigrationErrorIncorrectContract { + crate::ContractError::MigrationErrorIncorrectContract { expected: CONTRACT_NAME.to_string(), actual: "test".to_string(), } @@ -2877,11 +2886,11 @@ fn test_migrate() { crate::contract::migrate(deps.as_mut(), mock_env(), MigrateMsg {}).unwrap(); // same-version migration errors - let err: ContractError = + let err: crate::ContractError = crate::contract::migrate(deps.as_mut(), mock_env(), MigrateMsg {}).unwrap_err(); assert_eq!( err, - ContractError::MigrationErrorInvalidVersion { + crate::ContractError::MigrationErrorInvalidVersion { new: CONTRACT_VERSION.to_string(), current: CONTRACT_VERSION.to_string(), } @@ -2889,11 +2898,11 @@ fn test_migrate() { // future version errors cw2::set_contract_version(&mut deps.storage, CONTRACT_NAME, "9.9.9").unwrap(); - let err: ContractError = + let err: crate::ContractError = crate::contract::migrate(deps.as_mut(), mock_env(), MigrateMsg {}).unwrap_err(); assert_eq!( err, - ContractError::MigrationErrorInvalidVersion { + crate::ContractError::MigrationErrorInvalidVersion { new: CONTRACT_VERSION.to_string(), current: "9.9.9".to_string(), } diff --git a/contracts/external/btsg-ft-factory/src/testing/mod.rs b/contracts/external/btsg-ft-factory/src/testing/mod.rs index 2282ac98d..53e84f356 100644 --- a/contracts/external/btsg-ft-factory/src/testing/mod.rs +++ b/contracts/external/btsg-ft-factory/src/testing/mod.rs @@ -3,26 +3,15 @@ mod bitsong_stargate; mod tests; use app::BitsongApp; -use cosmwasm_std::{Addr, Empty}; -use cw_multi_test::{Contract, ContractWrapper, Executor}; -use dao_testing::contracts::native_staked_balances_voting_contract; +use cosmwasm_std::Addr; +use cw_multi_test::Executor; +use dao_testing::contracts::{btsg_ft_factory_contract, dao_voting_token_staked_contract}; use crate::msg::InstantiateMsg; /// Address used to stake stuff. pub(crate) const STAKER: &str = "staker"; -pub(crate) fn btsg_ft_factory_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - pub(crate) struct CommonTest { app: BitsongApp, module_id: u64, @@ -32,7 +21,7 @@ pub(crate) struct CommonTest { pub(crate) fn setup_test() -> CommonTest { let mut app = BitsongApp::new(); let factory_id = app.store_code(btsg_ft_factory_contract()); - let module_id = app.store_code(native_staked_balances_voting_contract()); + let module_id = app.store_code(dao_voting_token_staked_contract()); let factory = app .instantiate_contract( diff --git a/contracts/external/btsg-ft-factory/src/testing/tests.rs b/contracts/external/btsg-ft-factory/src/testing/tests.rs index 21cb4f58a..02d456659 100644 --- a/contracts/external/btsg-ft-factory/src/testing/tests.rs +++ b/contracts/external/btsg-ft-factory/src/testing/tests.rs @@ -9,7 +9,7 @@ use dao_interface::{ state::{Admin, ModuleInstantiateInfo}, token::InitialBalance, }; -use dao_testing::contracts::{dao_dao_contract, proposal_single_contract}; +use dao_testing::contracts::{dao_dao_core_contract, dao_proposal_single_contract}; use crate::{ bitsong::{Coin, MsgMint, MsgSetUri}, @@ -30,8 +30,8 @@ fn test_issue_fantoken() -> anyhow::Result<()> { .. } = setup_test(); - let core_id = app.store_code(dao_dao_contract()); - let proposal_single_id = app.store_code(proposal_single_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let proposal_single_id = app.store_code(dao_proposal_single_contract()); let initial_balances = vec![InitialBalance { amount: Uint128::new(100), @@ -132,8 +132,8 @@ fn test_initial_fantoken_balances() -> anyhow::Result<()> { .. } = setup_test(); - let core_id = app.store_code(dao_dao_contract()); - let proposal_single_id = app.store_code(proposal_single_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let proposal_single_id = app.store_code(dao_proposal_single_contract()); let initial_balances = vec![InitialBalance { amount: Uint128::new(100), @@ -239,8 +239,8 @@ fn test_fantoken_minter_and_authority_set_to_dao() -> anyhow::Result<()> { .. } = setup_test(); - let core_id = app.store_code(dao_dao_contract()); - let proposal_single_id = app.store_code(proposal_single_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let proposal_single_id = app.store_code(dao_proposal_single_contract()); let initial_balances = vec![InitialBalance { amount: Uint128::new(100), @@ -396,8 +396,8 @@ fn test_fantoken_can_be_staked() -> anyhow::Result<()> { .. } = setup_test(); - let core_id = app.store_code(dao_dao_contract()); - let proposal_single_id = app.store_code(proposal_single_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let proposal_single_id = app.store_code(dao_proposal_single_contract()); let initial_balances = vec![InitialBalance { amount: Uint128::new(100), diff --git a/contracts/external/cw-admin-factory/Cargo.toml b/contracts/external/cw-admin-factory/Cargo.toml index 394f859fb..4b268d4b6 100644 --- a/contracts/external/cw-admin-factory/Cargo.toml +++ b/contracts/external/cw-admin-factory/Cargo.toml @@ -30,13 +30,12 @@ thiserror = { workspace = true } cw-utils = { workspace = true } [dev-dependencies] +cw-admin-factory = { workspace = true } bech32 = { workspace = true } cosmwasm-schema = { workspace = true } -cw-admin-factory = { workspace = true } cw-multi-test = { workspace = true } -cw20-base = { workspace = true, features = ["library"] } +cw20-base = { workspace = true } cw4 = { workspace = true } -dao-dao-core = { workspace = true, features = ["library"] } dao-interface = { workspace = true } dao-proposal-single = { workspace = true } dao-testing = { workspace = true } diff --git a/contracts/external/cw-admin-factory/src/tests.rs b/contracts/external/cw-admin-factory/src/tests.rs index 7e6dbfbed..45b009979 100644 --- a/contracts/external/cw-admin-factory/src/tests.rs +++ b/contracts/external/cw-admin-factory/src/tests.rs @@ -2,57 +2,29 @@ use std::vec; use cosmwasm_std::{ testing::{mock_dependencies, mock_env, mock_info}, - to_json_binary, Addr, Binary, Empty, Reply, SubMsg, SubMsgResponse, SubMsgResult, WasmMsg, + to_json_binary, Addr, Binary, Reply, SubMsg, SubMsgResponse, SubMsgResult, WasmMsg, }; - -use cw_multi_test::{App, AppResponse, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, AppResponse, Executor}; use dao_interface::state::{Admin, ModuleInstantiateInfo}; +use dao_testing::contracts::{ + cw20_base_contract, cw_admin_factory_contract, dao_dao_core_contract, +}; use crate::{ contract::{ instantiate, migrate, reply, CONTRACT_NAME, CONTRACT_VERSION, INSTANTIATE_CONTRACT_REPLY_ID, }, msg::{AdminResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, - ContractError, }; +use cw_admin_factory::ContractError; const ADMIN_ADDR: &str = "admin"; -fn factory_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply); - Box::new(contract) -} - -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn cw_core_contract() -> Box> { - let contract = ContractWrapper::new( - dao_dao_core::contract::execute, - dao_dao_core::contract::instantiate, - dao_dao_core::contract::query, - ) - .with_reply(dao_dao_core::contract::reply) - .with_migrate(dao_dao_core::contract::migrate); - Box::new(contract) -} - #[test] pub fn test_set_self_admin() { let mut app = App::default(); - let code_id = app.store_code(factory_contract()); - let cw20_code_id = app.store_code(cw20_contract()); + let code_id = app.store_code(cw_admin_factory_contract()); + let cw20_code_id = app.store_code(cw20_base_contract()); let cw20_instantiate = cw20_base::msg::InstantiateMsg { name: "DAO".to_string(), symbol: "DAO".to_string(), @@ -75,7 +47,7 @@ pub fn test_set_self_admin() { .unwrap(); // Instantiate core contract using factory. - let cw_core_code_id = app.store_code(cw_core_contract()); + let cw_core_code_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { dao_uri: None, admin: None, @@ -136,8 +108,8 @@ pub fn test_set_self_admin() { #[test] pub fn test_authorized_set_self_admin() { let mut app = App::default(); - let code_id = app.store_code(factory_contract()); - let cw20_code_id = app.store_code(cw20_contract()); + let code_id = app.store_code(cw_admin_factory_contract()); + let cw20_code_id = app.store_code(cw20_base_contract()); let cw20_instantiate = cw20_base::msg::InstantiateMsg { name: "DAO".to_string(), symbol: "DAO".to_string(), @@ -169,7 +141,7 @@ pub fn test_authorized_set_self_admin() { assert_eq!(current_admin.admin, Some(Addr::unchecked(ADMIN_ADDR))); // Instantiate core contract using factory. - let cw_core_code_id = app.store_code(cw_core_contract()); + let cw_core_code_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { dao_uri: None, admin: None, diff --git a/contracts/external/cw-payroll-factory/Cargo.toml b/contracts/external/cw-payroll-factory/Cargo.toml index 9b89969a5..be8010582 100644 --- a/contracts/external/cw-payroll-factory/Cargo.toml +++ b/contracts/external/cw-payroll-factory/Cargo.toml @@ -1,5 +1,5 @@ [package] -name ="cw-payroll-factory" +name = "cw-payroll-factory" authors = ["Jake Hartnell"] description = "A CosmWasm factory contract for instantiating a payroll contract." edition = { workspace = true } @@ -29,6 +29,8 @@ cw-vesting = { workspace = true, features = ["library"] } cw-utils = { workspace = true } [dev-dependencies] +cw-payroll-factory = { workspace = true } cw-multi-test = { workspace = true } cw20-base = { workspace = true, features = ["library"] } +dao-testing = { workspace = true } wynd-utils = { workspace = true } diff --git a/contracts/external/cw-payroll-factory/src/tests.rs b/contracts/external/cw-payroll-factory/src/tests.rs index 1feffd463..a341a9158 100644 --- a/contracts/external/cw-payroll-factory/src/tests.rs +++ b/contracts/external/cw-payroll-factory/src/tests.rs @@ -1,56 +1,31 @@ -use cosmwasm_std::{coins, to_json_binary, Addr, Empty, Uint128}; +use cosmwasm_std::{coins, to_json_binary, Addr, Uint128}; use cw20::{Cw20Coin, Cw20ExecuteMsg}; use cw_denom::UncheckedDenom; -use cw_multi_test::{App, BankSudo, Contract, ContractWrapper, Executor, SudoMsg}; +use cw_multi_test::{App, BankSudo, Executor, SudoMsg}; use cw_ownable::OwnershipError; use cw_vesting::{ msg::{InstantiateMsg as PayrollInstantiateMsg, QueryMsg as PayrollQueryMsg}, vesting::{Schedule, Status, Vest}, }; +use dao_testing::contracts::{ + cw20_base_contract, cw_payroll_factory_contract, cw_vesting_contract, +}; use crate::{ msg::{ExecuteMsg, InstantiateMsg, QueryMsg, ReceiveMsg}, state::VestingContract, - ContractError, }; +use cw_payroll_factory::ContractError; const ALICE: &str = "alice"; const BOB: &str = "bob"; const INITIAL_BALANCE: u128 = 1000000000; const NATIVE_DENOM: &str = "denom"; -fn factory_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply); - Box::new(contract) -} - -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -pub fn cw_vesting_contract() -> Box> { - let contract = ContractWrapper::new( - cw_vesting::contract::execute, - cw_vesting::contract::instantiate, - cw_vesting::contract::query, - ); - Box::new(contract) -} - #[test] pub fn test_instantiate_native_payroll_contract() { let mut app = App::default(); - let code_id = app.store_code(factory_contract()); + let code_id = app.store_code(cw_payroll_factory_contract()); let cw_vesting_code_id = app.store_code(cw_vesting_contract()); // Instantiate factory with only Alice allowed to instantiate payroll contracts @@ -211,8 +186,8 @@ pub fn test_instantiate_native_payroll_contract() { #[test] pub fn test_instantiate_cw20_payroll_contract() { let mut app = App::default(); - let code_id = app.store_code(factory_contract()); - let cw20_code_id = app.store_code(cw20_contract()); + let code_id = app.store_code(cw_payroll_factory_contract()); + let cw20_code_id = app.store_code(cw20_base_contract()); let cw_vesting_code_id = app.store_code(cw_vesting_contract()); // Instantiate cw20 contract with balances for Alice @@ -343,7 +318,7 @@ pub fn test_instantiate_cw20_payroll_contract() { #[test] fn test_instantiate_wrong_ownership_native() { let mut app = App::default(); - let code_id = app.store_code(factory_contract()); + let code_id = app.store_code(cw_payroll_factory_contract()); let cw_vesting_code_id = app.store_code(cw_vesting_contract()); let amount = Uint128::new(1000000); @@ -413,7 +388,7 @@ fn test_instantiate_wrong_ownership_native() { #[test] fn test_update_vesting_code_id() { let mut app = App::default(); - let code_id = app.store_code(factory_contract()); + let code_id = app.store_code(cw_payroll_factory_contract()); let cw_vesting_code_id = app.store_code(cw_vesting_contract()); let cw_vesting_code_two = app.store_code(cw_vesting_contract()); @@ -512,8 +487,8 @@ fn test_update_vesting_code_id() { #[test] pub fn test_inconsistent_cw20_amount() { let mut app = App::default(); - let code_id = app.store_code(factory_contract()); - let cw20_code_id = app.store_code(cw20_contract()); + let code_id = app.store_code(cw_payroll_factory_contract()); + let cw20_code_id = app.store_code(cw20_base_contract()); let cw_vesting_code_id = app.store_code(cw_vesting_contract()); // Instantiate cw20 contract with balances for Alice let cw20_addr = app diff --git a/contracts/external/cw-token-swap/Cargo.toml b/contracts/external/cw-token-swap/Cargo.toml index e974d5453..2c879dae8 100644 --- a/contracts/external/cw-token-swap/Cargo.toml +++ b/contracts/external/cw-token-swap/Cargo.toml @@ -26,6 +26,8 @@ cw20 = { workspace = true } thiserror = { workspace = true } [dev-dependencies] +cw-token-swap = { workspace = true } cosmwasm-schema = { workspace = true } cw-multi-test = { workspace = true } cw20-base = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/external/cw-token-swap/src/error.rs b/contracts/external/cw-token-swap/src/error.rs index df3961398..82519383b 100644 --- a/contracts/external/cw-token-swap/src/error.rs +++ b/contracts/external/cw-token-swap/src/error.rs @@ -1,8 +1,7 @@ use cosmwasm_std::{StdError, Uint128}; use thiserror::Error; -#[derive(Error, Debug)] -#[cfg_attr(test, derive(PartialEq))] // Only neeed while testing. +#[derive(Error, Debug, PartialEq)] pub enum ContractError { #[error("{0}")] Std(#[from] StdError), diff --git a/contracts/external/cw-token-swap/src/tests.rs b/contracts/external/cw-token-swap/src/tests.rs index e2d2a9913..fdc475dd6 100644 --- a/contracts/external/cw-token-swap/src/tests.rs +++ b/contracts/external/cw-token-swap/src/tests.rs @@ -1,9 +1,10 @@ use cosmwasm_std::{ testing::{mock_dependencies, mock_env}, - to_json_binary, Addr, Coin, Empty, Uint128, + to_json_binary, Addr, Coin, Uint128, }; use cw20::Cw20Coin; -use cw_multi_test::{App, BankSudo, Contract, ContractWrapper, Executor, SudoMsg}; +use cw_multi_test::{App, BankSudo, Executor, SudoMsg}; +use dao_testing::contracts::{cw20_base_contract, cw_token_swap_contract}; use crate::{ contract::{migrate, CONTRACT_NAME, CONTRACT_VERSION}, @@ -11,36 +12,18 @@ use crate::{ Counterparty, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, StatusResponse, TokenInfo, }, state::{CheckedCounterparty, CheckedTokenInfo}, - ContractError, }; +use cw_token_swap::ContractError; const DAO1: &str = "dao1"; const DAO2: &str = "dao2"; -fn escrow_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ); - Box::new(contract) -} - -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - #[test] fn test_simple_escrow() { let mut app = App::default(); - let cw20_code = app.store_code(cw20_contract()); - let escrow_code = app.store_code(escrow_contract()); + let cw20_code = app.store_code(cw20_base_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let cw20 = app .instantiate_contract( @@ -140,8 +123,8 @@ fn test_simple_escrow() { fn test_withdraw() { let mut app = App::default(); - let cw20_code = app.store_code(cw20_contract()); - let escrow_code = app.store_code(escrow_contract()); + let cw20_code = app.store_code(cw20_base_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let cw20 = app .instantiate_contract( @@ -324,8 +307,8 @@ fn test_withdraw() { fn test_withdraw_post_completion() { let mut app = App::default(); - let cw20_code = app.store_code(cw20_contract()); - let escrow_code = app.store_code(escrow_contract()); + let cw20_code = app.store_code(cw20_base_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let cw20 = app .instantiate_contract( @@ -432,8 +415,8 @@ fn test_withdraw_post_completion() { fn test_invalid_instantiate() { let mut app = App::default(); - let cw20_code = app.store_code(cw20_contract()); - let escrow_code = app.store_code(escrow_contract()); + let cw20_code = app.store_code(cw20_base_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let cw20 = app .instantiate_contract( @@ -523,7 +506,7 @@ fn test_invalid_instantiate() { fn test_non_distincy_counterparties() { let mut app = App::default(); - let escrow_code = app.store_code(escrow_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); // Zero amount not allowed for native tokens. let err: ContractError = app @@ -561,8 +544,8 @@ fn test_non_distincy_counterparties() { fn test_fund_non_counterparty() { let mut app = App::default(); - let cw20_code = app.store_code(cw20_contract()); - let escrow_code = app.store_code(escrow_contract()); + let cw20_code = app.store_code(cw20_base_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let cw20 = app .instantiate_contract( @@ -658,8 +641,8 @@ fn test_fund_non_counterparty() { fn test_fund_twice() { let mut app = App::default(); - let cw20_code = app.store_code(cw20_contract()); - let escrow_code = app.store_code(escrow_contract()); + let cw20_code = app.store_code(cw20_base_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let cw20 = app .instantiate_contract( @@ -778,8 +761,8 @@ fn test_fund_twice() { fn test_fund_invalid_amount() { let mut app = App::default(); - let cw20_code = app.store_code(cw20_contract()); - let escrow_code = app.store_code(escrow_contract()); + let cw20_code = app.store_code(cw20_base_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let cw20 = app .instantiate_contract( @@ -883,7 +866,7 @@ fn test_fund_invalid_amount() { fn test_fund_invalid_denom() { let mut app = App::default(); - let escrow_code = app.store_code(escrow_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); let escrow = app .instantiate_contract( @@ -943,8 +926,8 @@ fn test_fund_invalid_denom() { fn test_fund_invalid_cw20() { let mut app = App::default(); - let escrow_code = app.store_code(escrow_contract()); - let cw20_code = app.store_code(cw20_contract()); + let escrow_code = app.store_code(cw_token_swap_contract()); + let cw20_code = app.store_code(cw20_base_contract()); let cw20 = app .instantiate_contract( diff --git a/contracts/external/cw-vesting/Cargo.toml b/contracts/external/cw-vesting/Cargo.toml index 2689de7de..1d9829424 100644 --- a/contracts/external/cw-vesting/Cargo.toml +++ b/contracts/external/cw-vesting/Cargo.toml @@ -36,6 +36,7 @@ thiserror = { workspace = true } wynd-utils = { workspace = true } [dev-dependencies] +cw-vesting = { workspace = true } anyhow = { workspace = true } cw-multi-test = { workspace = true } cw20-base = { workspace = true } diff --git a/contracts/external/cw-vesting/src/tests.rs b/contracts/external/cw-vesting/src/tests.rs index 9a55807b5..9bbaa30d4 100644 --- a/contracts/external/cw-vesting/src/tests.rs +++ b/contracts/external/cw-vesting/src/tests.rs @@ -1,12 +1,10 @@ use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; -use cosmwasm_std::{coins, to_json_binary, Addr, Coin, Decimal, Empty, Uint128, Validator}; +use cosmwasm_std::{coins, to_json_binary, Addr, Coin, Decimal, Uint128, Validator}; use cw20::{Cw20Coin, Cw20ExecuteMsg, Cw20ReceiveMsg}; use cw_denom::{CheckedDenom, UncheckedDenom}; -use cw_multi_test::{ - App, AppBuilder, BankSudo, Contract, ContractWrapper, Executor, StakingInfo, SudoMsg, -}; +use cw_multi_test::{App, AppBuilder, BankSudo, Executor, StakingInfo, SudoMsg}; use cw_ownable::Action; -use dao_testing::contracts::cw20_base_contract; +use dao_testing::contracts::{cw20_base_contract, cw_vesting_contract}; use crate::contract::{execute, execute_receive_cw20}; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg, ReceiveMsg}; @@ -21,15 +19,6 @@ const TOTAL_VEST: u128 = 1000000; const OWNER: &str = "owner"; const NATIVE_DENOM: &str = "ujuno"; -fn cw_vesting_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ); - Box::new(contract) -} - fn get_vesting_payment(app: &App, cw_vesting_addr: Addr) -> Vest { app.wrap() .query_wasm_smart(cw_vesting_addr, &QueryMsg::Info {}) @@ -214,7 +203,7 @@ fn test_happy_cw20_path() { ); // No time has passed, so nothing is withdrawable. - let err: ContractError = app + let err: cw_vesting::ContractError = app .execute_contract( bob.clone(), cw_vesting_addr.clone(), @@ -226,7 +215,7 @@ fn test_happy_cw20_path() { .unwrap(); assert_eq!( err, - ContractError::InvalidWithdrawal { + cw_vesting::ContractError::InvalidWithdrawal { request: Uint128::zero(), claimable: Uint128::zero() } @@ -283,7 +272,7 @@ fn test_happy_native_path() { ); // No time has passed, so nothing is withdrawable. - let err: ContractError = app + let err: cw_vesting::ContractError = app .execute_contract( bob.clone(), cw_vesting_addr.clone(), @@ -295,7 +284,7 @@ fn test_happy_native_path() { .unwrap(); assert_eq!( err, - ContractError::InvalidWithdrawal { + cw_vesting::ContractError::InvalidWithdrawal { request: Uint128::zero(), claimable: Uint128::zero() } @@ -420,7 +409,7 @@ fn test_cancel_vesting() { } = setup_test_case(&mut app, InstantiateMsg::default(), &[]); // Non-owner can't cancel - let err: ContractError = app + let err: cw_vesting::ContractError = app .execute_contract( Addr::unchecked(ALICE), cw_vesting_addr.clone(), @@ -432,7 +421,7 @@ fn test_cancel_vesting() { .unwrap(); assert_eq!( err, - ContractError::Ownable(cw_ownable::OwnershipError::NotOwner) + cw_vesting::ContractError::Ownable(cw_ownable::OwnershipError::NotOwner) ); // Advance the clock by 1/2 the vesting period. @@ -451,7 +440,7 @@ fn test_cancel_vesting() { .unwrap(); // Can't distribute as tokens are already distributed. - let err: ContractError = app + let err: cw_vesting::ContractError = app .execute_contract( Addr::unchecked(BOB), cw_vesting_addr, @@ -461,7 +450,10 @@ fn test_cancel_vesting() { .unwrap_err() .downcast() .unwrap(); - assert!(matches!(err, ContractError::InvalidWithdrawal { .. })); + assert!(matches!( + err, + cw_vesting::ContractError::InvalidWithdrawal { .. } + )); // Unvested funds have been returned to contract owner assert_eq!( @@ -513,7 +505,7 @@ fn test_catch_imposter_cw20() { }; // Errors that cw20 does not match what was expected - let error: ContractError = app + let error: cw_vesting::ContractError = app .execute_contract( Addr::unchecked(OWNER), Addr::unchecked(cw20_imposter_addr), @@ -523,7 +515,7 @@ fn test_catch_imposter_cw20() { .unwrap_err() .downcast() .unwrap(); - assert_eq!(error, ContractError::WrongCw20); + assert_eq!(error, cw_vesting::ContractError::WrongCw20); } #[test] @@ -542,7 +534,7 @@ fn test_incorrect_native_funding_amount() { let (_, _, cw_vesting_code_id) = setup_contracts(&mut app); // Instantiate cw-vesting contract errors with incorrect amount - let error: ContractError = app + let error: cw_vesting::ContractError = app .instantiate_contract( cw_vesting_code_id, alice, @@ -556,7 +548,7 @@ fn test_incorrect_native_funding_amount() { .unwrap(); assert_eq!( error, - ContractError::WrongFundAmount { + cw_vesting::ContractError::WrongFundAmount { sent: Uint128::new(100), expected: Uint128::new(TOTAL_VEST) } diff --git a/contracts/external/cw721-roles/src/tests.rs b/contracts/external/cw721-roles/src/tests.rs index 41c559413..365772b9b 100644 --- a/contracts/external/cw721-roles/src/tests.rs +++ b/contracts/external/cw721-roles/src/tests.rs @@ -3,7 +3,7 @@ use cw4::{HooksResponse, Member, MemberListResponse, MemberResponse, TotalWeight use cw721::{NftInfoResponse, OwnerOfResponse}; use cw_multi_test::{App, Executor}; use dao_cw721_extensions::roles::{ExecuteExt, MetadataExt, QueryExt}; -use dao_testing::contracts::{cw721_roles_contract, cw721_staked_voting_contract}; +use dao_testing::contracts::{cw721_roles_contract, dao_voting_cw721_staked_contract}; use dao_voting_cw721_staked::msg::{InstantiateMsg as Cw721StakedInstantiateMsg, NftContract}; use crate::error::RolesContractError; @@ -254,7 +254,7 @@ fn test_send_permissions() { .unwrap(); // Instantiate an NFT staking voting contract for testing SendNft - let dao_voting_cw721_staked_id = app.store_code(cw721_staked_voting_contract()); + let dao_voting_cw721_staked_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_staked_addr = app .instantiate_contract( dao_voting_cw721_staked_id, diff --git a/contracts/external/dao-migrator/Cargo.toml b/contracts/external/dao-migrator/Cargo.toml index 4d2b48cb8..429ebaaab 100644 --- a/contracts/external/dao-migrator/Cargo.toml +++ b/contracts/external/dao-migrator/Cargo.toml @@ -40,12 +40,13 @@ cw-core-v1 = { workspace = true, features = ["library"] } cw-proposal-single-v1 = { workspace = true, features = ["library"] } cw20-staked-balance-voting-v1 = { workspace = true, features = ["library"] } cw20-stake-v1 = { workspace = true, features = ["library"] } -cw-core-interface-v1 = { package = "cw-core-interface", version = "0.1.0", git = "https://github.com/DA0-DA0/dao-contracts.git", tag = "v1.0.0" } -cw4-voting-v1 = { package = "cw4-voting", version = "0.1.0", git = "https://github.com/DA0-DA0/dao-contracts.git", tag = "v1.0.0" } -cw20-v1 = { version = "0.13", package = "cw20" } -cw4-v1 = { version = "0.13", package = "cw4" } +cw-core-interface-v1 = { workspace = true } +cw4-voting-v1 = { workspace = true } +cw20-v1 = { workspace = true } +cw4-v1 = { workspace = true } [dev-dependencies] +dao-migrator = { workspace = true } cosmwasm-schema = { workspace = true } cw-multi-test = { workspace = true } dao-testing = { workspace = true } diff --git a/contracts/external/dao-migrator/src/testing/helpers.rs b/contracts/external/dao-migrator/src/testing/helpers.rs index c25d13507..a65d5b753 100644 --- a/contracts/external/dao-migrator/src/testing/helpers.rs +++ b/contracts/external/dao-migrator/src/testing/helpers.rs @@ -5,8 +5,12 @@ use cosmwasm_std::{ use cw_multi_test::{next_block, App, Contract, ContractWrapper, Executor}; use dao_interface::query::SubDao; use dao_testing::contracts::{ - cw20_base_contract, cw20_staked_balances_voting_contract, cw4_group_contract, dao_dao_contract, - proposal_single_contract, v1_dao_dao_contract, v1_proposal_single_contract, + cw20_base_contract, cw20_stake_contract, cw4_group_contract, dao_dao_core_contract, + dao_proposal_single_contract, dao_voting_cw20_staked_contract, dao_voting_cw4_contract, + v1::{ + cw20_stake_v1_contract, cw4_voting_v1_contract, cw_core_v1_contract, + cw_proposal_single_v1_contract, + }, }; use crate::{ @@ -50,13 +54,13 @@ pub enum VotingType { pub fn get_v1_code_ids(app: &mut App) -> (CodeIds, V1CodeIds) { let code_ids = CodeIds { - core: app.store_code(v1_dao_dao_contract()), - proposal_single: app.store_code(v1_proposal_single_contract()), + core: app.store_code(cw_core_v1_contract()), + proposal_single: app.store_code(cw_proposal_single_v1_contract()), cw20_base: app.store_code(cw20_base_contract()), - cw20_stake: app.store_code(v1_cw20_stake_contract()), - cw20_voting: app.store_code(cw20_staked_balances_voting_contract()), + cw20_stake: app.store_code(cw20_stake_v1_contract()), + cw20_voting: app.store_code(dao_voting_cw20_staked_contract()), cw4_group: app.store_code(cw4_group_contract()), - cw4_voting: app.store_code(v1_cw4_voting_contract()), + cw4_voting: app.store_code(cw4_voting_v1_contract()), }; let v1_code_ids = V1CodeIds { @@ -70,10 +74,10 @@ pub fn get_v1_code_ids(app: &mut App) -> (CodeIds, V1CodeIds) { pub fn get_v2_code_ids(app: &mut App) -> (CodeIds, V2CodeIds) { let code_ids = CodeIds { - core: app.store_code(dao_dao_contract()), - proposal_single: app.store_code(proposal_single_contract()), + core: app.store_code(dao_dao_core_contract()), + proposal_single: app.store_code(dao_proposal_single_contract()), cw20_base: app.store_code(cw20_base_contract()), - cw20_stake: app.store_code(v2_cw20_stake_contract()), + cw20_stake: app.store_code(cw20_stake_contract()), cw20_voting: app.store_code(dao_voting_cw20_staked_contract()), cw4_group: app.store_code(cw4_group_contract()), cw4_voting: app.store_code(dao_voting_cw4_contract()), @@ -267,67 +271,6 @@ pub fn set_cw20_to_dao(app: &mut App, sender: Addr, addrs: ModuleAddrs) { ); } -pub fn dao_voting_cw20_staked_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_staked::contract::execute, - dao_voting_cw20_staked::contract::instantiate, - dao_voting_cw20_staked::contract::query, - ) - .with_reply(dao_voting_cw20_staked::contract::reply) - .with_migrate(dao_voting_cw20_staked::contract::migrate); - Box::new(contract) -} - -pub fn migrator_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply); - Box::new(contract) -} - -pub fn v1_cw20_stake_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake_v1::contract::execute, - cw20_stake_v1::contract::instantiate, - cw20_stake_v1::contract::query, - ); - Box::new(contract) -} - -pub fn v2_cw20_stake_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ) - .with_migrate(cw20_stake::contract::migrate); - Box::new(contract) -} - -pub fn v1_cw4_voting_contract() -> Box> { - let contract = ContractWrapper::new( - cw4_voting_v1::contract::execute, - cw4_voting_v1::contract::instantiate, - cw4_voting_v1::contract::query, - ) - .with_reply(cw4_voting_v1::contract::reply); - Box::new(contract) -} - -pub fn dao_voting_cw4_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw4::contract::execute, - dao_voting_cw4::contract::instantiate, - dao_voting_cw4::contract::query, - ) - .with_reply(dao_voting_cw4::contract::reply) - .with_migrate(dao_voting_cw4::contract::migrate); - Box::new(contract) -} - fn some_init( _deps: DepsMut, _env: Env, diff --git a/contracts/external/dao-migrator/src/testing/setup.rs b/contracts/external/dao-migrator/src/testing/setup.rs index becb49522..4b039a502 100644 --- a/contracts/external/dao-migrator/src/testing/setup.rs +++ b/contracts/external/dao-migrator/src/testing/setup.rs @@ -3,7 +3,7 @@ use std::borrow::BorrowMut; use cosmwasm_std::{to_json_binary, Addr, WasmMsg}; use cw_multi_test::{next_block, App, AppResponse, Executor}; use dao_interface::state::{Admin, ModuleInstantiateInfo}; -use dao_testing::contracts::stake_cw20_v03_contract; +use dao_testing::contracts::{dao_migrator_contract, v1::stake_cw20_v03_contract}; use crate::{ testing::helpers::get_module_addrs, @@ -11,8 +11,8 @@ use crate::{ }; use super::helpers::{ - get_cw20_init_msg, get_cw4_init_msg, get_v1_code_ids, get_v2_code_ids, migrator_contract, - set_cw20_to_dao, set_dummy_proposal, ExecuteParams, ModuleAddrs, VotingType, SENDER_ADDR, + get_cw20_init_msg, get_cw4_init_msg, get_v1_code_ids, get_v2_code_ids, set_cw20_to_dao, + set_dummy_proposal, ExecuteParams, ModuleAddrs, VotingType, SENDER_ADDR, }; pub fn init_v1(app: &mut App, sender: Addr, voting_type: VotingType) -> (Addr, V1CodeIds) { @@ -255,7 +255,7 @@ pub fn execute_migration( custom_proposal_params: Option>, ) -> Result { let sender = Addr::unchecked(SENDER_ADDR); - let migrator_code_id = app.store_code(migrator_contract()); + let migrator_code_id = app.store_code(dao_migrator_contract()); let (new_code_ids, v2_code_ids) = get_v2_code_ids(app); let params = params.unwrap_or_else(|| ExecuteParams { sub_daos: Some(vec![]), @@ -368,7 +368,7 @@ pub fn execute_migration_from_core( params: Option, ) -> Result { let sender = Addr::unchecked(SENDER_ADDR); - let migrator_code_id = app.store_code(migrator_contract()); + let migrator_code_id = app.store_code(dao_migrator_contract()); let (new_code_ids, v2_code_ids) = get_v2_code_ids(app); let params = params.unwrap_or_else(|| ExecuteParams { sub_daos: Some(vec![]), diff --git a/contracts/external/dao-migrator/src/testing/test_migration.rs b/contracts/external/dao-migrator/src/testing/test_migration.rs index 691e00c9f..514216fa4 100644 --- a/contracts/external/dao-migrator/src/testing/test_migration.rs +++ b/contracts/external/dao-migrator/src/testing/test_migration.rs @@ -14,8 +14,8 @@ use crate::{ }, }, types::ProposalParams, - ContractError, }; +use dao_migrator::ContractError; use super::{helpers::demo_contract, setup::setup_dao_v1_multiple_proposals}; diff --git a/contracts/pre-propose/dao-pre-propose-approval-single/src/tests.rs b/contracts/pre-propose/dao-pre-propose-approval-single/src/tests.rs index 2e3f3e324..fe4cacd04 100644 --- a/contracts/pre-propose/dao-pre-propose-approval-single/src/tests.rs +++ b/contracts/pre-propose/dao-pre-propose-approval-single/src/tests.rs @@ -1,17 +1,25 @@ -use cosmwasm_std::{ - coins, from_json, to_json_binary, Addr, Coin, CosmosMsg, Empty, Uint128, WasmMsg, -}; +use cosmwasm_std::{coins, from_json, to_json_binary, Addr, Coin, CosmosMsg, Uint128, WasmMsg}; use cw2::ContractVersion; use cw20::Cw20Coin; use cw_denom::UncheckedDenom; -use cw_multi_test::{App, BankSudo, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, BankSudo, Executor}; use cw_utils::Duration; use dao_interface::proposal::InfoResponse; use dao_interface::state::ProposalModule; use dao_interface::state::{Admin, ModuleInstantiateInfo}; use dao_pre_propose_base::{error::PreProposeError, msg::DepositInfoResponse, state::Config}; use dao_proposal_single::query::ProposalResponse; -use dao_testing::{contracts::cw4_group_contract, helpers::instantiate_with_cw4_groups_governance}; +use dao_testing::{ + contracts::{ + cw20_base_contract, cw4_group_contract, dao_pre_propose_approval_single_contract, + dao_proposal_single_contract, + v241::{ + dao_dao_core_v241_contract, dao_pre_propose_approval_single_v241_contract, + dao_proposal_single_v241_contract, dao_voting_cw4_v241_contract, + }, + }, + helpers::instantiate_with_cw4_groups_governance, +}; use dao_voting::pre_propose::{PreProposeSubmissionPolicy, PreProposeSubmissionPolicyError}; use dao_voting::{ deposit::{CheckedDepositInfo, DepositRefundPolicy, DepositToken, UncheckedDepositInfo}, @@ -22,7 +30,6 @@ use dao_voting::{ }; // test v2.4.1 migration -use dao_dao_core_v241 as core_v241; use dao_interface_v241 as di_v241; use dao_pre_propose_approval_single_v241 as dppas_v241; use dao_proposal_single_v241 as dps_v241; @@ -32,31 +39,6 @@ use dao_voting_v241 as dv_v241; use crate::state::{Proposal, ProposalStatus}; use crate::{contract::*, msg::*}; -fn dao_proposal_single_contract() -> Box> { - let contract = ContractWrapper::new( - dao_proposal_single::contract::execute, - dao_proposal_single::contract::instantiate, - dao_proposal_single::contract::query, - ) - .with_migrate(dao_proposal_single::contract::migrate) - .with_reply(dao_proposal_single::contract::reply); - Box::new(contract) -} - -fn dao_pre_propose_approval_single_contract() -> Box> { - let contract = ContractWrapper::new(execute, instantiate, query).with_migrate(migrate); - Box::new(contract) -} - -fn cw20_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - fn get_default_proposal_module_instantiate( app: &mut App, deposit_info: Option, @@ -2492,41 +2474,11 @@ fn test_withdraw() { fn test_migrate_from_v241() { let app = &mut App::default(); - let core_v241_contract = Box::new( - ContractWrapper::new( - core_v241::contract::execute, - core_v241::contract::instantiate, - core_v241::contract::query, - ) - .with_reply(core_v241::contract::reply), - ); - let dvcw4_v241_contract = Box::new( - ContractWrapper::new( - dvcw4_v241::contract::execute, - dvcw4_v241::contract::instantiate, - dvcw4_v241::contract::query, - ) - .with_reply(dvcw4_v241::contract::reply), - ); - let dpps_v241_contract = Box::new(ContractWrapper::new( - dppas_v241::contract::execute, - dppas_v241::contract::instantiate, - dppas_v241::contract::query, - )); - let dps_v241_contract = Box::new( - ContractWrapper::new( - dps_v241::contract::execute, - dps_v241::contract::instantiate, - dps_v241::contract::query, - ) - .with_reply(dps_v241::contract::reply), - ); - - let core_id = app.store_code(core_v241_contract); + let core_id = app.store_code(dao_dao_core_v241_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let dvcw4_v241_id = app.store_code(dvcw4_v241_contract); - let dpps_v241_id = app.store_code(dpps_v241_contract); - let dps_v241_id = app.store_code(dps_v241_contract); + let dvcw4_v241_id = app.store_code(dao_voting_cw4_v241_contract()); + let dpps_v241_id = app.store_code(dao_pre_propose_approval_single_v241_contract()); + let dps_v241_id = app.store_code(dao_proposal_single_v241_contract()); let governance_instantiate = di_v241::msg::InstantiateMsg { dao_uri: None, @@ -2848,41 +2800,11 @@ fn test_migrate_from_v241() { fn test_migrate_from_v241_with_policy_update() { let app = &mut App::default(); - let core_v241_contract = Box::new( - ContractWrapper::new( - core_v241::contract::execute, - core_v241::contract::instantiate, - core_v241::contract::query, - ) - .with_reply(core_v241::contract::reply), - ); - let dvcw4_v241_contract = Box::new( - ContractWrapper::new( - dvcw4_v241::contract::execute, - dvcw4_v241::contract::instantiate, - dvcw4_v241::contract::query, - ) - .with_reply(dvcw4_v241::contract::reply), - ); - let dpps_v241_contract = Box::new(ContractWrapper::new( - dppas_v241::contract::execute, - dppas_v241::contract::instantiate, - dppas_v241::contract::query, - )); - let dps_v241_contract = Box::new( - ContractWrapper::new( - dps_v241::contract::execute, - dps_v241::contract::instantiate, - dps_v241::contract::query, - ) - .with_reply(dps_v241::contract::reply), - ); - - let core_id = app.store_code(core_v241_contract); + let core_id = app.store_code(dao_dao_core_v241_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let dvcw4_v241_id = app.store_code(dvcw4_v241_contract); - let dpps_v241_id = app.store_code(dpps_v241_contract); - let dps_v241_id = app.store_code(dps_v241_contract); + let dvcw4_v241_id = app.store_code(dao_voting_cw4_v241_contract()); + let dpps_v241_id = app.store_code(dao_pre_propose_approval_single_v241_contract()); + let dps_v241_id = app.store_code(dao_proposal_single_v241_contract()); let governance_instantiate = di_v241::msg::InstantiateMsg { dao_uri: None, diff --git a/contracts/pre-propose/dao-pre-propose-approver/src/tests.rs b/contracts/pre-propose/dao-pre-propose-approver/src/tests.rs index c1475939a..8dc569995 100644 --- a/contracts/pre-propose/dao-pre-propose-approver/src/tests.rs +++ b/contracts/pre-propose/dao-pre-propose-approver/src/tests.rs @@ -1,8 +1,8 @@ -use cosmwasm_std::{coins, from_json, to_json_binary, Addr, Coin, Empty, Uint128}; +use cosmwasm_std::{coins, from_json, to_json_binary, Addr, Coin, Uint128}; use cw2::ContractVersion; use cw20::Cw20Coin; use cw_denom::UncheckedDenom; -use cw_multi_test::{App, BankSudo, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, BankSudo, Executor}; use dao_interface::proposal::InfoResponse; use dao_voting::pre_propose::{PreProposeSubmissionPolicy, PreProposeSubmissionPolicyError}; use dps::query::{ProposalListResponse, ProposalResponse}; @@ -17,6 +17,10 @@ use dao_pre_propose_approval_single::{ }; use dao_pre_propose_base::{error::PreProposeError, msg::DepositInfoResponse, state::Config}; use dao_proposal_single as dps; +use dao_testing::contracts::{ + cw20_base_contract, dao_pre_propose_approval_single_contract, + dao_pre_propose_approver_contract, dao_proposal_single_contract, +}; use dao_testing::helpers::instantiate_with_cw4_groups_governance; use dao_voting::{ deposit::{CheckedDepositInfo, DepositRefundPolicy, DepositToken, UncheckedDepositInfo}, @@ -36,50 +40,12 @@ use crate::msg::{ // The approver dao contract is the 6th contract instantiated const APPROVER: &str = "contract6"; -fn cw_dao_proposal_single_contract() -> Box> { - let contract = ContractWrapper::new( - dps::contract::execute, - dps::contract::instantiate, - dps::contract::query, - ) - .with_migrate(dps::contract::migrate) - .with_reply(dps::contract::reply); - Box::new(contract) -} - -fn cw_pre_propose_base_proposal_single() -> Box> { - let contract = ContractWrapper::new( - dao_pre_propose_approval_single::contract::execute, - dao_pre_propose_approval_single::contract::instantiate, - dao_pre_propose_approval_single::contract::query, - ); - Box::new(contract) -} - -fn cw20_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn pre_propose_approver_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ); - Box::new(contract) -} - fn get_proposal_module_approval_single_instantiate( app: &mut App, deposit_info: Option, open_proposal_submission: bool, ) -> dps::msg::InstantiateMsg { - let pre_propose_id = app.store_code(cw_pre_propose_base_proposal_single()); + let pre_propose_id = app.store_code(dao_pre_propose_approval_single_contract()); let submission_policy = if open_proposal_submission { PreProposeSubmissionPolicy::Anyone { denylist: vec![] } @@ -126,7 +92,7 @@ fn get_proposal_module_approver_instantiate( _open_proposal_submission: bool, pre_propose_approval_contract: String, ) -> dps::msg::InstantiateMsg { - let pre_propose_id = app.store_code(pre_propose_approver_contract()); + let pre_propose_id = app.store_code(dao_pre_propose_approver_contract()); dps::msg::InstantiateMsg { threshold: Threshold::AbsolutePercentage { @@ -191,7 +157,7 @@ fn setup_default_test( deposit_info: Option, open_proposal_submission: bool, ) -> DefaultTestSetup { - let dps_id = app.store_code(cw_dao_proposal_single_contract()); + let dps_id = app.store_code(dao_proposal_single_contract()); // Instantiate SubDAO with pre-propose-approval-single let proposal_module_instantiate = get_proposal_module_approval_single_instantiate( diff --git a/contracts/pre-propose/dao-pre-propose-multiple/src/tests.rs b/contracts/pre-propose/dao-pre-propose-multiple/src/tests.rs index f949702c2..e27c14e17 100644 --- a/contracts/pre-propose/dao-pre-propose-multiple/src/tests.rs +++ b/contracts/pre-propose/dao-pre-propose-multiple/src/tests.rs @@ -5,14 +5,24 @@ use cpm::query::ProposalResponse; use cw2::ContractVersion; use cw20::Cw20Coin; use cw_denom::UncheckedDenom; -use cw_multi_test::{App, BankSudo, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, BankSudo, Executor}; use cw_utils::Duration; use dao_interface::proposal::InfoResponse; use dao_interface::state::ProposalModule; use dao_interface::state::{Admin, ModuleInstantiateInfo}; use dao_pre_propose_base::{error::PreProposeError, msg::DepositInfoResponse, state::Config}; use dao_proposal_multiple as cpm; -use dao_testing::{contracts::cw4_group_contract, helpers::instantiate_with_cw4_groups_governance}; +use dao_testing::{ + contracts::{ + cw20_base_contract, cw4_group_contract, dao_pre_propose_multiple_contract, + dao_proposal_multiple_contract, + v241::{ + dao_dao_core_v241_contract, dao_pre_propose_multiple_v241_contract, + dao_proposal_multiple_v241_contract, dao_voting_cw4_v241_contract, + }, + }, + helpers::instantiate_with_cw4_groups_governance, +}; use dao_voting::multiple_choice::MultipleChoiceAutoVote; use dao_voting::pre_propose::{PreProposeSubmissionPolicy, PreProposeSubmissionPolicyError}; use dao_voting::{ @@ -27,7 +37,6 @@ use dao_voting::{ }; // test v2.4.1 migration -use dao_dao_core_v241 as core_v241; use dao_interface_v241 as di_v241; use dao_pre_propose_multiple_v241 as dppm_v241; use dao_proposal_multiple_v241 as dpm_v241; @@ -36,30 +45,6 @@ use dao_voting_v241 as dv_v241; use crate::contract::*; -fn dao_proposal_multiple_contract() -> Box> { - let contract = ContractWrapper::new( - cpm::contract::execute, - cpm::contract::instantiate, - cpm::contract::query, - ) - .with_reply(cpm::contract::reply); - Box::new(contract) -} - -fn dao_pre_propose_multiple_contract() -> Box> { - let contract = ContractWrapper::new(execute, instantiate, query).with_migrate(migrate); - Box::new(contract) -} - -fn cw20_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - fn get_default_proposal_module_instantiate( app: &mut App, deposit_info: Option, @@ -2247,41 +2232,11 @@ fn test_withdraw() { fn test_migrate_from_v241() { let app = &mut App::default(); - let core_v241_contract = Box::new( - ContractWrapper::new( - core_v241::contract::execute, - core_v241::contract::instantiate, - core_v241::contract::query, - ) - .with_reply(core_v241::contract::reply), - ); - let dvcw4_v241_contract = Box::new( - ContractWrapper::new( - dvcw4_v241::contract::execute, - dvcw4_v241::contract::instantiate, - dvcw4_v241::contract::query, - ) - .with_reply(dvcw4_v241::contract::reply), - ); - let dppm_v241_contract = Box::new(ContractWrapper::new( - dppm_v241::contract::execute, - dppm_v241::contract::instantiate, - dppm_v241::contract::query, - )); - let dpm_v241_contract = Box::new( - ContractWrapper::new( - dpm_v241::contract::execute, - dpm_v241::contract::instantiate, - dpm_v241::contract::query, - ) - .with_reply(dpm_v241::contract::reply), - ); - - let core_id = app.store_code(core_v241_contract); + let core_id = app.store_code(dao_dao_core_v241_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let dvcw4_v241_id = app.store_code(dvcw4_v241_contract); - let dppm_v241_id = app.store_code(dppm_v241_contract); - let dpm_v241_id = app.store_code(dpm_v241_contract); + let dvcw4_v241_id = app.store_code(dao_voting_cw4_v241_contract()); + let dppm_v241_id = app.store_code(dao_pre_propose_multiple_v241_contract()); + let dpm_v241_id = app.store_code(dao_proposal_multiple_v241_contract()); let governance_instantiate = di_v241::msg::InstantiateMsg { dao_uri: None, @@ -2629,41 +2584,11 @@ fn test_migrate_from_v241() { fn test_migrate_from_v241_with_policy_update() { let app = &mut App::default(); - let core_v241_contract = Box::new( - ContractWrapper::new( - core_v241::contract::execute, - core_v241::contract::instantiate, - core_v241::contract::query, - ) - .with_reply(core_v241::contract::reply), - ); - let dvcw4_v241_contract = Box::new( - ContractWrapper::new( - dvcw4_v241::contract::execute, - dvcw4_v241::contract::instantiate, - dvcw4_v241::contract::query, - ) - .with_reply(dvcw4_v241::contract::reply), - ); - let dppm_v241_contract = Box::new(ContractWrapper::new( - dppm_v241::contract::execute, - dppm_v241::contract::instantiate, - dppm_v241::contract::query, - )); - let dpm_v241_contract = Box::new( - ContractWrapper::new( - dpm_v241::contract::execute, - dpm_v241::contract::instantiate, - dpm_v241::contract::query, - ) - .with_reply(dpm_v241::contract::reply), - ); - - let core_id = app.store_code(core_v241_contract); + let core_id = app.store_code(dao_dao_core_v241_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let dvcw4_v241_id = app.store_code(dvcw4_v241_contract); - let dppm_v241_id = app.store_code(dppm_v241_contract); - let dpm_v241_id = app.store_code(dpm_v241_contract); + let dvcw4_v241_id = app.store_code(dao_voting_cw4_v241_contract()); + let dppm_v241_id = app.store_code(dao_pre_propose_multiple_v241_contract()); + let dpm_v241_id = app.store_code(dao_proposal_multiple_v241_contract()); let governance_instantiate = di_v241::msg::InstantiateMsg { dao_uri: None, diff --git a/contracts/pre-propose/dao-pre-propose-single/src/tests.rs b/contracts/pre-propose/dao-pre-propose-single/src/tests.rs index a8eef5e3e..8c037240c 100644 --- a/contracts/pre-propose/dao-pre-propose-single/src/tests.rs +++ b/contracts/pre-propose/dao-pre-propose-single/src/tests.rs @@ -4,14 +4,24 @@ use cosmwasm_std::{ use cw2::ContractVersion; use cw20::Cw20Coin; use cw_denom::UncheckedDenom; -use cw_multi_test::{App, BankSudo, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, BankSudo, Executor}; use cw_utils::Duration; use dao_interface::proposal::InfoResponse; use dao_interface::state::ProposalModule; use dao_interface::state::{Admin, ModuleInstantiateInfo}; use dao_pre_propose_base::{error::PreProposeError, msg::DepositInfoResponse, state::Config}; use dao_proposal_single as dps; -use dao_testing::{contracts::cw4_group_contract, helpers::instantiate_with_cw4_groups_governance}; +use dao_testing::{ + contracts::{ + cw20_base_contract, cw4_group_contract, dao_pre_propose_single_contract, + dao_proposal_single_contract, + v241::{ + dao_dao_core_v241_contract, dao_pre_propose_single_v241_contract, + dao_proposal_single_v241_contract, dao_voting_cw4_v241_contract, + }, + }, + helpers::instantiate_with_cw4_groups_governance, +}; use dao_voting::pre_propose::{PreProposeSubmissionPolicy, PreProposeSubmissionPolicyError}; use dao_voting::{ deposit::{CheckedDepositInfo, DepositRefundPolicy, DepositToken, UncheckedDepositInfo}, @@ -23,7 +33,6 @@ use dao_voting::{ use dps::query::ProposalResponse; // test v2.4.1 migration -use dao_dao_core_v241 as core_v241; use dao_interface_v241 as di_v241; use dao_pre_propose_single_v241 as dpps_v241; use dao_proposal_single_v241 as dps_v241; @@ -32,31 +41,6 @@ use dao_voting_v241 as dv_v241; use crate::contract::*; -fn dao_proposal_single_contract() -> Box> { - let contract = ContractWrapper::new( - dps::contract::execute, - dps::contract::instantiate, - dps::contract::query, - ) - .with_migrate(dps::contract::migrate) - .with_reply(dps::contract::reply); - Box::new(contract) -} - -fn dao_pre_propose_single_contract() -> Box> { - let contract = ContractWrapper::new(execute, instantiate, query).with_migrate(migrate); - Box::new(contract) -} - -fn cw20_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - fn get_default_proposal_module_instantiate( app: &mut App, deposit_info: Option, @@ -2186,41 +2170,11 @@ fn test_hook_management() { fn test_migrate_from_v241() { let app = &mut App::default(); - let core_v241_contract = Box::new( - ContractWrapper::new( - core_v241::contract::execute, - core_v241::contract::instantiate, - core_v241::contract::query, - ) - .with_reply(core_v241::contract::reply), - ); - let dvcw4_v241_contract = Box::new( - ContractWrapper::new( - dvcw4_v241::contract::execute, - dvcw4_v241::contract::instantiate, - dvcw4_v241::contract::query, - ) - .with_reply(dvcw4_v241::contract::reply), - ); - let dpps_v241_contract = Box::new(ContractWrapper::new( - dpps_v241::contract::execute, - dpps_v241::contract::instantiate, - dpps_v241::contract::query, - )); - let dps_v241_contract = Box::new( - ContractWrapper::new( - dps_v241::contract::execute, - dps_v241::contract::instantiate, - dps_v241::contract::query, - ) - .with_reply(dps_v241::contract::reply), - ); - - let core_id = app.store_code(core_v241_contract); + let core_id = app.store_code(dao_dao_core_v241_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let dvcw4_v241_id = app.store_code(dvcw4_v241_contract); - let dpps_v241_id = app.store_code(dpps_v241_contract); - let dps_v241_id = app.store_code(dps_v241_contract); + let dvcw4_v241_id = app.store_code(dao_voting_cw4_v241_contract()); + let dpps_v241_id = app.store_code(dao_pre_propose_single_v241_contract()); + let dps_v241_id = app.store_code(dao_proposal_single_v241_contract()); let governance_instantiate = di_v241::msg::InstantiateMsg { dao_uri: None, @@ -2513,41 +2467,11 @@ fn test_migrate_from_v241() { fn test_migrate_from_v241_with_policy_update() { let app = &mut App::default(); - let core_v241_contract = Box::new( - ContractWrapper::new( - core_v241::contract::execute, - core_v241::contract::instantiate, - core_v241::contract::query, - ) - .with_reply(core_v241::contract::reply), - ); - let dvcw4_v241_contract = Box::new( - ContractWrapper::new( - dvcw4_v241::contract::execute, - dvcw4_v241::contract::instantiate, - dvcw4_v241::contract::query, - ) - .with_reply(dvcw4_v241::contract::reply), - ); - let dpps_v241_contract = Box::new(ContractWrapper::new( - dpps_v241::contract::execute, - dpps_v241::contract::instantiate, - dpps_v241::contract::query, - )); - let dps_v241_contract = Box::new( - ContractWrapper::new( - dps_v241::contract::execute, - dps_v241::contract::instantiate, - dps_v241::contract::query, - ) - .with_reply(dps_v241::contract::reply), - ); - - let core_id = app.store_code(core_v241_contract); + let core_id = app.store_code(dao_dao_core_v241_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let dvcw4_v241_id = app.store_code(dvcw4_v241_contract); - let dpps_v241_id = app.store_code(dpps_v241_contract); - let dps_v241_id = app.store_code(dps_v241_contract); + let dvcw4_v241_id = app.store_code(dao_voting_cw4_v241_contract()); + let dpps_v241_id = app.store_code(dao_pre_propose_single_v241_contract()); + let dps_v241_id = app.store_code(dao_proposal_single_v241_contract()); let governance_instantiate = di_v241::msg::InstantiateMsg { dao_uri: None, diff --git a/contracts/proposal/dao-proposal-condorcet/src/testing/suite.rs b/contracts/proposal/dao-proposal-condorcet/src/testing/suite.rs index c268bc5c1..7ab46d511 100644 --- a/contracts/proposal/dao-proposal-condorcet/src/testing/suite.rs +++ b/contracts/proposal/dao-proposal-condorcet/src/testing/suite.rs @@ -6,7 +6,8 @@ use dao_interface::{ voting::InfoResponse, }; use dao_testing::contracts::{ - cw4_group_contract, dao_dao_contract, dao_voting_cw4_contract, proposal_condorcet_contract, + cw4_group_contract, dao_dao_core_contract, dao_proposal_condorcet_contract, + dao_voting_cw4_contract, }; use dao_voting::threshold::PercentageThreshold; use dao_voting_cw4::msg::GroupContract; @@ -74,8 +75,8 @@ impl SuiteBuilder { let sender = Addr::unchecked(&initial_members[0].addr); let mut app = App::default(); - let condorcet_id = app.store_code(proposal_condorcet_contract()); - let core_id = app.store_code(dao_dao_contract()); + let condorcet_id = app.store_code(dao_proposal_condorcet_contract()); + let core_id = app.store_code(dao_dao_core_contract()); let cw4_id = app.store_code(cw4_group_contract()); let cw4_voting_id = app.store_code(dao_voting_cw4_contract()); diff --git a/contracts/proposal/dao-proposal-multiple/Cargo.toml b/contracts/proposal/dao-proposal-multiple/Cargo.toml index 5eca7e2df..b37648976 100644 --- a/contracts/proposal/dao-proposal-multiple/Cargo.toml +++ b/contracts/proposal/dao-proposal-multiple/Cargo.toml @@ -41,6 +41,7 @@ dao-pre-propose-multiple = { workspace = true } voting-v1 = { workspace = true } [dev-dependencies] +dao-proposal-multiple = { workspace = true } anyhow = { workspace = true } cw-multi-test = { workspace = true } dao-voting-cw4 = { workspace = true } diff --git a/contracts/proposal/dao-proposal-multiple/src/testing/adversarial_tests.rs b/contracts/proposal/dao-proposal-multiple/src/testing/adversarial_tests.rs index 8f3b593ea..0ffc0ccb1 100644 --- a/contracts/proposal/dao-proposal-multiple/src/testing/adversarial_tests.rs +++ b/contracts/proposal/dao-proposal-multiple/src/testing/adversarial_tests.rs @@ -8,11 +8,11 @@ use crate::testing::queries::{ query_balance_cw20, query_dao_token, query_multiple_proposal_module, query_proposal, }; use crate::testing::tests::{get_pre_propose_info, ALTERNATIVE_ADDR, CREATOR_ADDR}; -use crate::ContractError; use cosmwasm_std::{to_json_binary, Addr, CosmosMsg, Decimal, Uint128, WasmMsg}; use cw20::Cw20Coin; use cw_multi_test::{next_block, App, Executor}; use cw_utils::Duration; +use dao_proposal_multiple::ContractError; use dao_voting::{ deposit::{DepositRefundPolicy, UncheckedDepositInfo, VotingModuleTokenType}, multiple_choice::{ diff --git a/contracts/proposal/dao-proposal-multiple/src/testing/do_votes.rs b/contracts/proposal/dao-proposal-multiple/src/testing/do_votes.rs index 51a0747b8..959c96da3 100644 --- a/contracts/proposal/dao-proposal-multiple/src/testing/do_votes.rs +++ b/contracts/proposal/dao-proposal-multiple/src/testing/do_votes.rs @@ -3,7 +3,7 @@ use cw20::Cw20Coin; use cw_denom::CheckedDenom; use cw_multi_test::{App, BankSudo, Executor}; use dao_interface::state::ProposalModule; -use dao_testing::ShouldExecute; +use dao_testing::{contracts::dao_proposal_multiple_contract, ShouldExecute}; use dao_voting::{ deposit::{CheckedDepositInfo, UncheckedDepositInfo}, multiple_choice::{ @@ -23,7 +23,7 @@ use crate::{ instantiate_with_cw20_balances_governance, instantiate_with_staked_balances_governance, }, queries::query_deposit_config_and_pre_propose_module, - tests::{get_pre_propose_info, proposal_multiple_contract, TestMultipleChoiceVote}, + tests::{get_pre_propose_info, TestMultipleChoiceVote}, }, }; use dao_pre_propose_multiple as cppm; @@ -96,7 +96,7 @@ where F: Fn(&mut App, InstantiateMsg, Option>) -> Addr, { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let mut initial_balances = votes .iter() diff --git a/contracts/proposal/dao-proposal-multiple/src/testing/instantiate.rs b/contracts/proposal/dao-proposal-multiple/src/testing/instantiate.rs index 693edfbb0..bb0eacb29 100644 --- a/contracts/proposal/dao-proposal-multiple/src/testing/instantiate.rs +++ b/contracts/proposal/dao-proposal-multiple/src/testing/instantiate.rs @@ -1,13 +1,14 @@ use cosmwasm_std::{to_json_binary, Addr, Coin, Empty, Uint128}; use cw20::Cw20Coin; -use cw_multi_test::{next_block, App, BankSudo, ContractWrapper, Executor, SudoMsg}; +use cw_multi_test::{next_block, App, BankSudo, Executor, SudoMsg}; use cw_utils::Duration; use dao_interface::state::{Admin, ModuleInstantiateInfo}; use dao_pre_propose_multiple as cppm; use dao_testing::contracts::{ - cw20_balances_voting_contract, cw20_base_contract, cw20_stake_contract, - cw20_staked_balances_voting_contract, cw4_group_contract, cw721_base_contract, - dao_dao_contract, native_staked_balances_voting_contract, pre_propose_multiple_contract, + cw20_base_contract, cw20_stake_contract, cw4_group_contract, cw721_base_contract, + dao_dao_core_contract, dao_pre_propose_multiple_contract, dao_proposal_multiple_contract, + dao_voting_cw20_balance_contract, dao_voting_cw20_staked_contract, + dao_voting_cw721_staked_contract, dao_voting_token_staked_contract, }; use dao_voting::{ deposit::{DepositRefundPolicy, UncheckedDepositInfo, VotingModuleTokenType}, @@ -21,9 +22,7 @@ use dao_voting::{ use dao_voting_cw4::msg::GroupContract; use crate::testing::tests::ALTERNATIVE_ADDR; -use crate::{ - msg::InstantiateMsg, testing::tests::proposal_multiple_contract, testing::tests::CREATOR_ADDR, -}; +use crate::{msg::InstantiateMsg, testing::tests::CREATOR_ADDR}; #[allow(dead_code)] fn get_pre_propose_info( @@ -31,7 +30,7 @@ fn get_pre_propose_info( deposit_info: Option, open_proposal_submission: bool, ) -> PreProposeInfo { - let pre_propose_contract = app.store_code(pre_propose_multiple_contract()); + let pre_propose_contract = app.store_code(dao_pre_propose_multiple_contract()); let submission_policy = if open_proposal_submission { PreProposeSubmissionPolicy::Anyone { denylist: vec![] } @@ -107,7 +106,7 @@ pub fn _instantiate_with_staked_cw721_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_multiple_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_multiple_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -132,15 +131,8 @@ pub fn _instantiate_with_staked_cw721_governance( }; let cw721_id = app.store_code(cw721_base_contract()); - let cw721_stake_id = app.store_code({ - let contract = ContractWrapper::new( - dao_voting_cw721_staked::contract::execute, - dao_voting_cw721_staked::contract::instantiate, - dao_voting_cw721_staked::contract::query, - ); - Box::new(contract) - }); - let core_contract_id = app.store_code(dao_dao_contract()); + let cw721_stake_id = app.store_code(dao_voting_cw721_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let nft_address = app .instantiate_contract( @@ -248,7 +240,7 @@ pub fn instantiate_with_native_staked_balances_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_multiple_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_multiple_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -273,8 +265,8 @@ pub fn instantiate_with_native_staked_balances_governance( .collect() }; - let native_stake_id = app.store_code(native_staked_balances_voting_contract()); - let core_contract_id = app.store_code(dao_dao_contract()); + let native_stake_id = app.store_code(dao_voting_token_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { admin: None, @@ -360,11 +352,11 @@ pub fn instantiate_with_cw20_balances_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_multiple_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_multiple_contract()); let cw20_id = app.store_code(cw20_base_contract()); - let core_id = app.store_code(dao_dao_contract()); - let votemod_id = app.store_code(cw20_balances_voting_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let votemod_id = app.store_code(dao_voting_cw20_balance_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -441,7 +433,7 @@ pub fn instantiate_with_staked_balances_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_multiple_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_multiple_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -468,8 +460,8 @@ pub fn instantiate_with_staked_balances_governance( let cw20_id = app.store_code(cw20_base_contract()); let cw20_stake_id = app.store_code(cw20_stake_contract()); - let staked_balances_voting_id = app.store_code(cw20_staked_balances_voting_contract()); - let core_contract_id = app.store_code(dao_dao_contract()); + let staked_balances_voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { admin: None, @@ -572,7 +564,7 @@ pub fn instantiate_with_multiple_staked_balances_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_multiple_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_multiple_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![ @@ -605,8 +597,8 @@ pub fn instantiate_with_multiple_staked_balances_governance( let cw20_id = app.store_code(cw20_base_contract()); let cw20_stake_id = app.store_code(cw20_stake_contract()); - let staked_balances_voting_id = app.store_code(cw20_staked_balances_voting_contract()); - let core_contract_id = app.store_code(dao_dao_contract()); + let staked_balances_voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { admin: None, @@ -712,11 +704,11 @@ pub fn instantiate_with_staking_active_threshold( initial_balances: Option>, active_threshold: Option, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_multiple_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_multiple_contract()); let cw20_id = app.store_code(cw20_base_contract()); let cw20_staking_id = app.store_code(cw20_stake_contract()); - let core_id = app.store_code(dao_dao_contract()); - let votemod_id = app.store_code(cw20_staked_balances_voting_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let votemod_id = app.store_code(dao_voting_cw20_staked_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -781,9 +773,9 @@ pub fn _instantiate_with_cw4_groups_governance( proposal_module_instantiate: InstantiateMsg, initial_weights: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_multiple_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_multiple_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let core_id = app.store_code(dao_dao_contract()); + let core_id = app.store_code(dao_dao_core_contract()); let votemod_id = app.store_code(cw4_group_contract()); let initial_weights = initial_weights.unwrap_or_else(|| { diff --git a/contracts/proposal/dao-proposal-multiple/src/testing/tests.rs b/contracts/proposal/dao-proposal-multiple/src/testing/tests.rs index 2b82b7ce7..5dab858ff 100644 --- a/contracts/proposal/dao-proposal-multiple/src/testing/tests.rs +++ b/contracts/proposal/dao-proposal-multiple/src/testing/tests.rs @@ -4,7 +4,7 @@ use cosmwasm_std::{ use cw20::Cw20Coin; use cw_denom::{CheckedDenom, UncheckedDenom}; use cw_hooks::HooksResponse; -use cw_multi_test::{next_block, App, BankSudo, Contract, ContractWrapper, Executor, SudoMsg}; +use cw_multi_test::{next_block, App, BankSudo, Executor, SudoMsg}; use cw_utils::Duration; use dao_interface::state::ProposalModule; use dao_interface::state::{Admin, ModuleInstantiateInfo}; @@ -49,12 +49,15 @@ use crate::{ query_proposal_config, query_proposal_hooks, query_vote_hooks, }, }, - ContractError, }; use dao_pre_propose_multiple as cppm; +use dao_proposal_multiple::ContractError; use dao_testing::{ - contracts::{cw20_balances_voting_contract, cw20_base_contract}, + contracts::{ + cw20_base_contract, dao_pre_propose_multiple_contract, dao_proposal_multiple_contract, + dao_voting_cw20_balance_contract, + }, ShouldExecute, }; @@ -72,31 +75,12 @@ pub struct TestMultipleChoiceVote { pub should_execute: ShouldExecute, } -pub fn proposal_multiple_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply); - Box::new(contract) -} - -pub fn pre_propose_multiple_contract() -> Box> { - let contract = ContractWrapper::new( - cppm::contract::execute, - cppm::contract::instantiate, - cppm::contract::query, - ); - Box::new(contract) -} - pub fn get_pre_propose_info( app: &mut App, deposit_info: Option, open_proposal_submission: bool, ) -> PreProposeInfo { - let pre_propose_contract = app.store_code(pre_propose_multiple_contract()); + let pre_propose_contract = app.store_code(dao_pre_propose_multiple_contract()); let submission_policy = if open_proposal_submission { PreProposeSubmissionPolicy::Anyone { denylist: vec![] } @@ -127,7 +111,7 @@ pub fn get_pre_propose_info( #[test] fn test_propose() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = Duration::Height(6); let quorum = PercentageThreshold::Majority {}; @@ -209,7 +193,7 @@ fn test_propose() { #[test] fn test_propose_wrong_num_choices() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = cw_utils::Duration::Height(6); let quorum = PercentageThreshold::Majority {}; @@ -293,7 +277,7 @@ fn test_propose_wrong_num_choices() { #[test] fn test_proposal_count_initialized_to_zero() { let mut app = App::default(); - let _proposal_id = app.store_code(proposal_multiple_contract()); + let _proposal_id = app.store_code(dao_proposal_multiple_contract()); let msg = InstantiateMsg { voting_strategy: VotingStrategy::SingleChoice { quorum: PercentageThreshold::Percent(Decimal::percent(10)), @@ -328,7 +312,7 @@ fn test_proposal_count_initialized_to_zero() { #[test] fn test_propose_auto_vote_winner() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = Duration::Height(6); let quorum = PercentageThreshold::Majority {}; @@ -419,7 +403,7 @@ fn test_propose_auto_vote_winner() { #[test] fn test_propose_auto_vote_reject() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = Duration::Height(6); let quorum = PercentageThreshold::Majority {}; @@ -511,7 +495,7 @@ fn test_propose_auto_vote_reject() { #[should_panic(expected = "Not registered to vote (no voting power) at time of proposal creation")] fn test_propose_non_member_auto_vote_fail() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = Duration::Height(6); let quorum = PercentageThreshold::Majority {}; @@ -577,7 +561,7 @@ fn test_propose_non_member_auto_vote_fail() { #[test] fn test_no_early_pass_with_min_duration() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let msg = InstantiateMsg { voting_strategy: VotingStrategy::SingleChoice { quorum: PercentageThreshold::Percent(Decimal::percent(10)), @@ -673,7 +657,7 @@ fn test_no_early_pass_with_min_duration() { #[test] fn test_propose_with_messages() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let msg = InstantiateMsg { voting_strategy: VotingStrategy::SingleChoice { quorum: PercentageThreshold::Percent(Decimal::percent(10)), @@ -795,7 +779,7 @@ fn test_propose_with_messages() { )] fn test_min_duration_units_missmatch() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let msg = InstantiateMsg { voting_strategy: VotingStrategy::SingleChoice { quorum: PercentageThreshold::Percent(Decimal::percent(10)), @@ -828,7 +812,7 @@ fn test_min_duration_units_missmatch() { #[should_panic(expected = "Min voting period must be less than or equal to max voting period")] fn test_min_duration_larger_than_proposal_duration() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let msg = InstantiateMsg { voting_strategy: VotingStrategy::SingleChoice { quorum: PercentageThreshold::Percent(Decimal::percent(10)), @@ -860,7 +844,7 @@ fn test_min_duration_larger_than_proposal_duration() { #[test] fn test_min_duration_same_as_proposal_duration() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let msg = InstantiateMsg { voting_strategy: VotingStrategy::SingleChoice { quorum: PercentageThreshold::Percent(Decimal::percent(10)), @@ -971,7 +955,7 @@ fn test_min_duration_same_as_proposal_duration() { #[test] fn test_voting_module_token_proposal_deposit_instantiate() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Majority {}; let voting_strategy = VotingStrategy::SingleChoice { quorum }; @@ -1030,7 +1014,7 @@ fn test_voting_module_token_proposal_deposit_instantiate() { #[test] fn test_different_token_proposal_deposit() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let cw20_id = app.store_code(cw20_base_contract()); let cw20_addr = app .instantiate_contract( @@ -1084,9 +1068,9 @@ fn test_different_token_proposal_deposit() { #[should_panic(expected = "Error parsing into type dao_voting_cw20_balance::msg::QueryMsg")] fn test_bad_token_proposal_deposit() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let cw20_id = app.store_code(cw20_base_contract()); - let votemod_id = app.store_code(cw20_balances_voting_contract()); + let votemod_id = app.store_code(dao_voting_cw20_balance_contract()); let votemod_addr = app .instantiate_contract( @@ -1142,7 +1126,7 @@ fn test_bad_token_proposal_deposit() { #[test] fn test_take_proposal_deposit() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Percent(Decimal::percent(10)); let voting_strategy = VotingStrategy::SingleChoice { quorum }; @@ -1250,7 +1234,7 @@ fn test_take_proposal_deposit() { #[test] fn test_take_native_proposal_deposit() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Percent(Decimal::percent(10)); let voting_strategy = VotingStrategy::SingleChoice { quorum }; @@ -1345,7 +1329,7 @@ fn test_take_native_proposal_deposit() { #[test] fn test_native_proposal_deposit() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = cw_utils::Duration::Height(6); let instantiate = InstantiateMsg { @@ -1777,7 +1761,7 @@ fn test_cant_vote_executed_or_closed() { #[test] fn test_cant_propose_zero_power() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Percent(Decimal::percent(10)); let voting_strategy = VotingStrategy::SingleChoice { quorum }; let max_voting_period = cw_utils::Duration::Height(6); @@ -1953,7 +1937,7 @@ fn test_cant_vote_not_registered() { fn test_cant_execute_not_member() { // Create proposal with only_members_execute: true let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = cw_utils::Duration::Height(6); let quorum = PercentageThreshold::Majority {}; @@ -2045,7 +2029,7 @@ fn test_cant_execute_not_member_when_proposal_created() { // Create proposal with only_members_execute: true and ensure member cannot // execute if they were not a member when the proposal was created let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = cw_utils::Duration::Height(6); let quorum = PercentageThreshold::Majority {}; @@ -2164,7 +2148,7 @@ fn test_cant_execute_not_member_when_proposal_created() { #[test] fn test_open_proposal_submission() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let max_voting_period = cw_utils::Duration::Height(6); @@ -2469,7 +2453,7 @@ fn test_deposit_return_on_close() { #[test] fn test_execute_expired_proposal() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Percent(Decimal::percent(10)); let voting_strategy = VotingStrategy::SingleChoice { quorum }; let max_voting_period = cw_utils::Duration::Height(6); @@ -2768,7 +2752,7 @@ fn test_no_return_if_no_refunds() { #[test] fn test_query_list_proposals() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Majority {}; let voting_strategy = VotingStrategy::SingleChoice { quorum }; let max_voting_period = cw_utils::Duration::Height(6); @@ -2904,7 +2888,7 @@ fn test_query_list_proposals() { #[test] fn test_hooks() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Majority {}; let voting_strategy = VotingStrategy::SingleChoice { quorum }; @@ -3031,7 +3015,7 @@ fn test_hooks() { #[test] fn test_active_threshold_absolute() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Majority {}; let voting_strategy = VotingStrategy::SingleChoice { quorum }; @@ -3163,7 +3147,7 @@ fn test_active_threshold_absolute() { #[test] fn test_active_threshold_percent() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Majority {}; let voting_strategy = VotingStrategy::SingleChoice { quorum }; let max_voting_period = cw_utils::Duration::Height(6); @@ -3295,7 +3279,7 @@ fn test_active_threshold_percent() { #[test] fn test_active_threshold_none() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Majority {}; let voting_strategy = VotingStrategy::SingleChoice { quorum }; let max_voting_period = cw_utils::Duration::Height(6); @@ -3407,7 +3391,7 @@ fn test_active_threshold_none() { #[test] fn test_revoting() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let core_addr = instantiate_with_staked_balances_governance( &mut app, InstantiateMsg { @@ -3541,7 +3525,7 @@ fn test_revoting() { #[test] fn test_allow_revoting_config_changes() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let core_addr = instantiate_with_staked_balances_governance( &mut app, InstantiateMsg { @@ -3696,7 +3680,7 @@ fn test_allow_revoting_config_changes() { #[test] fn test_revoting_same_vote_twice() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let core_addr = instantiate_with_staked_balances_governance( &mut app, InstantiateMsg { @@ -3792,7 +3776,7 @@ fn test_revoting_same_vote_twice() { #[test] fn test_invalid_revote_does_not_invalidate_initial_vote() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let core_addr = instantiate_with_staked_balances_governance( &mut app, InstantiateMsg { @@ -3987,7 +3971,7 @@ fn test_return_deposit_to_dao_on_proposal_failure() { #[test] fn test_close_failed_proposal() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let quorum = PercentageThreshold::Majority {}; let voting_strategy = VotingStrategy::SingleChoice { quorum }; @@ -4228,7 +4212,7 @@ fn test_close_failed_proposal() { #[test] fn test_no_double_refund_on_execute_fail_and_close() { let mut app = App::default(); - let _proposal_module_id = app.store_code(proposal_multiple_contract()); + let _proposal_module_id = app.store_code(dao_proposal_multiple_contract()); let voting_strategy = VotingStrategy::SingleChoice { quorum: PercentageThreshold::Majority {}, @@ -4424,7 +4408,7 @@ fn test_no_double_refund_on_execute_fail_and_close() { #[test] pub fn test_not_allow_voting_on_expired_proposal() { let mut app = App::default(); - let _govmod_id = app.store_code(proposal_multiple_contract()); + let _govmod_id = app.store_code(dao_proposal_multiple_contract()); let instantiate = InstantiateMsg { max_voting_period: Duration::Height(6), only_members_execute: false, diff --git a/contracts/proposal/dao-proposal-single/Cargo.toml b/contracts/proposal/dao-proposal-single/Cargo.toml index 06170dd00..142bd57dc 100644 --- a/contracts/proposal/dao-proposal-single/Cargo.toml +++ b/contracts/proposal/dao-proposal-single/Cargo.toml @@ -36,6 +36,7 @@ voting-v1 = { workspace = true } cw-proposal-single-v1 = { workspace = true, features = ["library"] } [dev-dependencies] +dao-proposal-single = { workspace = true } anyhow = { workspace = true } cosmwasm-schema = { workspace = true } cw-multi-test = { workspace = true } diff --git a/contracts/proposal/dao-proposal-single/src/testing/adversarial_tests.rs b/contracts/proposal/dao-proposal-single/src/testing/adversarial_tests.rs index beed03604..40b5fcd1c 100644 --- a/contracts/proposal/dao-proposal-single/src/testing/adversarial_tests.rs +++ b/contracts/proposal/dao-proposal-single/src/testing/adversarial_tests.rs @@ -23,7 +23,8 @@ use dao_voting::{ }; use super::CREATOR_ADDR; -use crate::{query::ProposalResponse, ContractError}; +use crate::query::ProposalResponse; +use dao_proposal_single::ContractError; struct CommonTest { app: App, diff --git a/contracts/proposal/dao-proposal-single/src/testing/contracts.rs b/contracts/proposal/dao-proposal-single/src/testing/contracts.rs deleted file mode 100644 index d222acbc5..000000000 --- a/contracts/proposal/dao-proposal-single/src/testing/contracts.rs +++ /dev/null @@ -1,108 +0,0 @@ -use cosmwasm_std::Empty; - -use cw_multi_test::{Contract, ContractWrapper}; -use dao_pre_propose_single as cppbps; - -pub(crate) fn cw20_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -pub(crate) fn cw4_group_contract() -> Box> { - let contract = ContractWrapper::new( - cw4_group::contract::execute, - cw4_group::contract::instantiate, - cw4_group::contract::query, - ); - Box::new(contract) -} - -pub(crate) fn cw721_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw721_base::entry::execute, - cw721_base::entry::instantiate, - cw721_base::entry::query, - ); - Box::new(contract) -} - -pub(crate) fn cw20_stake_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ); - Box::new(contract) -} - -pub(crate) fn proposal_single_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - -pub(crate) fn pre_propose_single_contract() -> Box> { - let contract = ContractWrapper::new( - cppbps::contract::execute, - cppbps::contract::instantiate, - cppbps::contract::query, - ); - Box::new(contract) -} - -pub(crate) fn cw20_staked_balances_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_staked::contract::execute, - dao_voting_cw20_staked::contract::instantiate, - dao_voting_cw20_staked::contract::query, - ) - .with_reply(dao_voting_cw20_staked::contract::reply); - Box::new(contract) -} - -pub(crate) fn native_staked_balances_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_token_staked::contract::execute, - dao_voting_token_staked::contract::instantiate, - dao_voting_token_staked::contract::query, - ); - Box::new(contract) -} - -pub(crate) fn cw721_stake_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw721_staked::contract::execute, - dao_voting_cw721_staked::contract::instantiate, - dao_voting_cw721_staked::contract::query, - ); - Box::new(contract) -} - -pub(crate) fn cw_core_contract() -> Box> { - let contract = ContractWrapper::new( - dao_dao_core::contract::execute, - dao_dao_core::contract::instantiate, - dao_dao_core::contract::query, - ) - .with_reply(dao_dao_core::contract::reply); - Box::new(contract) -} - -pub(crate) fn cw4_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw4::contract::execute, - dao_voting_cw4::contract::instantiate, - dao_voting_cw4::contract::query, - ) - .with_reply(dao_voting_cw4::contract::reply); - Box::new(contract) -} diff --git a/contracts/proposal/dao-proposal-single/src/testing/execute.rs b/contracts/proposal/dao-proposal-single/src/testing/execute.rs index c8511271f..d9b32acfd 100644 --- a/contracts/proposal/dao-proposal-single/src/testing/execute.rs +++ b/contracts/proposal/dao-proposal-single/src/testing/execute.rs @@ -3,6 +3,7 @@ use cw_multi_test::{App, BankSudo, Executor}; use cw_denom::CheckedDenom; use dao_pre_propose_single as cppbps; +use dao_testing::contracts::cw20_base_contract; use dao_voting::{ deposit::CheckedDepositInfo, pre_propose::ProposalCreationPolicy, @@ -14,12 +15,10 @@ use crate::{ msg::{ExecuteMsg, QueryMsg}, query::ProposalResponse, testing::queries::{query_creation_policy, query_next_proposal_id}, - ContractError, }; +use dao_proposal_single::ContractError; -use super::{ - contracts::cw20_base_contract, queries::query_pre_proposal_single_config, CREATOR_ADDR, -}; +use super::{queries::query_pre_proposal_single_config, CREATOR_ADDR}; // Creates a proposal then checks that the proposal was created with // the specified messages and returns the ID of the proposal. diff --git a/contracts/proposal/dao-proposal-single/src/testing/instantiate.rs b/contracts/proposal/dao-proposal-single/src/testing/instantiate.rs index 217ad740f..4f469476f 100644 --- a/contracts/proposal/dao-proposal-single/src/testing/instantiate.rs +++ b/contracts/proposal/dao-proposal-single/src/testing/instantiate.rs @@ -6,6 +6,12 @@ use cw_utils::Duration; use dao_interface::state::{Admin, ModuleInstantiateInfo}; use dao_pre_propose_single as cppbps; +use dao_testing::contracts::{ + cw20_base_contract, cw20_stake_contract, cw4_group_contract, cw721_base_contract, + dao_dao_core_contract, dao_pre_propose_single_contract, dao_proposal_single_contract, + dao_voting_cw20_staked_contract, dao_voting_cw4_contract, dao_voting_cw721_staked_contract, + dao_voting_token_staked_contract, +}; use dao_voting::{ deposit::{DepositRefundPolicy, UncheckedDepositInfo, VotingModuleTokenType}, pre_propose::{PreProposeInfo, PreProposeSubmissionPolicy}, @@ -15,22 +21,14 @@ use dao_voting_cw4::msg::GroupContract; use crate::msg::InstantiateMsg; -use super::{ - contracts::{ - cw20_base_contract, cw20_stake_contract, cw20_staked_balances_voting_contract, - cw4_group_contract, cw4_voting_contract, cw721_base_contract, cw721_stake_contract, - cw_core_contract, native_staked_balances_voting_contract, proposal_single_contract, - }, - CREATOR_ADDR, -}; +use super::CREATOR_ADDR; pub(crate) fn get_pre_propose_info( app: &mut App, deposit_info: Option, open_proposal_submission: bool, ) -> PreProposeInfo { - let pre_propose_contract = - app.store_code(crate::testing::contracts::pre_propose_single_contract()); + let pre_propose_contract = app.store_code(dao_pre_propose_single_contract()); let submission_policy = if open_proposal_submission { PreProposeSubmissionPolicy::Anyone { denylist: vec![] } @@ -108,7 +106,7 @@ pub(crate) fn instantiate_with_staked_cw721_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_single_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_single_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -133,8 +131,8 @@ pub(crate) fn instantiate_with_staked_cw721_governance( }; let cw721_id = app.store_code(cw721_base_contract()); - let cw721_stake_id = app.store_code(cw721_stake_contract()); - let core_contract_id = app.store_code(cw_core_contract()); + let cw721_stake_id = app.store_code(dao_voting_cw721_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let nft_address = app .instantiate_contract( @@ -242,7 +240,7 @@ pub(crate) fn instantiate_with_native_staked_balances_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_single_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_single_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -267,8 +265,8 @@ pub(crate) fn instantiate_with_native_staked_balances_governance( .collect() }; - let native_stake_id = app.store_code(native_staked_balances_voting_contract()); - let core_contract_id = app.store_code(cw_core_contract()); + let native_stake_id = app.store_code(dao_voting_token_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { admin: None, @@ -353,7 +351,7 @@ pub(crate) fn instantiate_with_staked_balances_governance( proposal_module_instantiate: InstantiateMsg, initial_balances: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_single_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_single_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -380,8 +378,8 @@ pub(crate) fn instantiate_with_staked_balances_governance( let cw20_id = app.store_code(cw20_base_contract()); let cw20_stake_id = app.store_code(cw20_stake_contract()); - let staked_balances_voting_id = app.store_code(cw20_staked_balances_voting_contract()); - let core_contract_id = app.store_code(cw_core_contract()); + let staked_balances_voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { admin: None, @@ -485,11 +483,11 @@ pub(crate) fn instantiate_with_staking_active_threshold( initial_balances: Option>, active_threshold: Option, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_single_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_single_contract()); let cw20_id = app.store_code(cw20_base_contract()); let cw20_staking_id = app.store_code(cw20_stake_contract()); - let core_id = app.store_code(cw_core_contract()); - let votemod_id = app.store_code(cw20_staked_balances_voting_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let votemod_id = app.store_code(dao_voting_cw20_staked_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -554,10 +552,10 @@ pub(crate) fn instantiate_with_cw4_groups_governance( proposal_module_instantiate: InstantiateMsg, initial_weights: Option>, ) -> Addr { - let proposal_module_code_id = app.store_code(proposal_single_contract()); + let proposal_module_code_id = app.store_code(dao_proposal_single_contract()); let cw4_id = app.store_code(cw4_group_contract()); - let core_id = app.store_code(cw_core_contract()); - let votemod_id = app.store_code(cw4_voting_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let votemod_id = app.store_code(dao_voting_cw4_contract()); let initial_weights = initial_weights.unwrap_or_else(|| { vec![Cw20Coin { diff --git a/contracts/proposal/dao-proposal-single/src/testing/migration_tests.rs b/contracts/proposal/dao-proposal-single/src/testing/migration_tests.rs index 83196d8cf..2aa4ce67e 100644 --- a/contracts/proposal/dao-proposal-single/src/testing/migration_tests.rs +++ b/contracts/proposal/dao-proposal-single/src/testing/migration_tests.rs @@ -4,8 +4,9 @@ use cw_multi_test::{next_block, App, Executor}; use cw_utils::Duration; use dao_interface::query::{GetItemResponse, ProposalModuleCountResponse}; use dao_testing::contracts::{ - cw20_base_contract, cw20_stake_contract, cw20_staked_balances_voting_contract, - dao_dao_contract, proposal_single_contract, v1_dao_dao_contract, v1_proposal_single_contract, + cw20_base_contract, cw20_stake_contract, dao_dao_core_contract, dao_proposal_single_contract, + dao_voting_cw20_staked_contract, + v1::{cw_core_v1_contract, cw_proposal_single_v1_contract}, }; use dao_voting::veto::VetoConfig; use dao_voting::{ @@ -47,14 +48,14 @@ fn test_v1_v2_full_migration() { // instantiate a v1 DAO // ---- - let proposal_code = app.store_code(v1_proposal_single_contract()); - let core_code = app.store_code(v1_dao_dao_contract()); + let proposal_code = app.store_code(cw_proposal_single_v1_contract()); + let core_code = app.store_code(cw_core_v1_contract()); // cw20 staking and voting module has not changed across v1->v2 so // we use the current edition. let cw20_code = app.store_code(cw20_base_contract()); let cw20_stake_code = app.store_code(cw20_stake_contract()); - let voting_code = app.store_code(cw20_staked_balances_voting_contract()); + let voting_code = app.store_code(dao_voting_cw20_staked_contract()); let initial_balances = vec![Cw20Coin { address: sender.to_string(), @@ -300,8 +301,8 @@ fn test_v1_v2_full_migration() { // create a proposal to migrate to v2 // ---- - let v2_core_code = app.store_code(dao_dao_contract()); - let v2_proposal_code = app.store_code(proposal_single_contract()); + let v2_core_code = app.store_code(dao_dao_core_contract()); + let v2_proposal_code = app.store_code(dao_proposal_single_contract()); let pre_propose_info = get_pre_propose_info( &mut app, diff --git a/contracts/proposal/dao-proposal-single/src/testing/mod.rs b/contracts/proposal/dao-proposal-single/src/testing/mod.rs index 12c9b9af0..0eede537c 100644 --- a/contracts/proposal/dao-proposal-single/src/testing/mod.rs +++ b/contracts/proposal/dao-proposal-single/src/testing/mod.rs @@ -1,5 +1,4 @@ mod adversarial_tests; -mod contracts; mod do_votes; mod execute; mod instantiate; diff --git a/contracts/proposal/dao-proposal-single/src/testing/queries.rs b/contracts/proposal/dao-proposal-single/src/testing/queries.rs index a246f1c64..0758fb27f 100644 --- a/contracts/proposal/dao-proposal-single/src/testing/queries.rs +++ b/contracts/proposal/dao-proposal-single/src/testing/queries.rs @@ -3,7 +3,7 @@ use cw_multi_test::App; use dao_interface::state::{ProposalModule, ProposalModuleStatus}; use cw_hooks::HooksResponse; -use dao_pre_propose_single as cppbps; +use dao_pre_propose_single as dpps; use dao_voting::pre_propose::ProposalCreationPolicy; use crate::{ @@ -15,7 +15,7 @@ use crate::{ pub(crate) fn query_deposit_config_and_pre_propose_module( app: &App, proposal_single: &Addr, -) -> (cppbps::Config, Addr) { +) -> (dpps::Config, Addr) { let proposal_creation_policy = query_creation_policy(app, proposal_single); if let ProposalCreationPolicy::Module { addr: module_addr } = proposal_creation_policy { @@ -118,9 +118,9 @@ pub(crate) fn query_list_proposals_reverse( .unwrap() } -pub(crate) fn query_pre_proposal_single_config(app: &App, pre_propose: &Addr) -> cppbps::Config { +pub(crate) fn query_pre_proposal_single_config(app: &App, pre_propose: &Addr) -> dpps::Config { app.wrap() - .query_wasm_smart(pre_propose, &cppbps::QueryMsg::Config {}) + .query_wasm_smart(pre_propose, &dpps::QueryMsg::Config {}) .unwrap() } @@ -128,9 +128,9 @@ pub(crate) fn query_pre_proposal_single_deposit_info( app: &App, pre_propose: &Addr, proposal_id: u64, -) -> cppbps::DepositInfoResponse { +) -> dpps::DepositInfoResponse { app.wrap() - .query_wasm_smart(pre_propose, &cppbps::QueryMsg::DepositInfo { proposal_id }) + .query_wasm_smart(pre_propose, &dpps::QueryMsg::DepositInfo { proposal_id }) .unwrap() } diff --git a/contracts/proposal/dao-proposal-single/src/testing/tests.rs b/contracts/proposal/dao-proposal-single/src/testing/tests.rs index 56bc68522..242b84cd7 100644 --- a/contracts/proposal/dao-proposal-single/src/testing/tests.rs +++ b/contracts/proposal/dao-proposal-single/src/testing/tests.rs @@ -16,7 +16,10 @@ use dao_interface::{ state::{Admin, ModuleInstantiateInfo}, voting::InfoResponse, }; -use dao_testing::{ShouldExecute, TestSingleChoiceVote}; +use dao_testing::{ + contracts::{dao_pre_propose_single_contract, dao_proposal_single_contract}, + ShouldExecute, TestSingleChoiceVote, +}; use dao_voting::{ deposit::{CheckedDepositInfo, UncheckedDepositInfo, VotingModuleTokenType}, pre_propose::{PreProposeInfo, PreProposeSubmissionPolicy, ProposalCreationPolicy}, @@ -38,7 +41,6 @@ use crate::{ query::{ProposalResponse, VoteInfo}, state::Config, testing::{ - contracts::{pre_propose_single_contract, proposal_single_contract}, execute::{ add_proposal_hook, add_proposal_hook_should_fail, add_vote_hook, add_vote_hook_should_fail, close_proposal, close_proposal_should_fail, @@ -62,8 +64,8 @@ use crate::{ query_voting_module, }, }, - ContractError, }; +use dao_proposal_single::ContractError; use super::{ do_votes::do_votes_staked_balances, @@ -3092,7 +3094,7 @@ fn test_migrate_from_compatible() { proposal_id: _, } = setup_test(vec![]); - let new_code_id = app.store_code(proposal_single_contract()); + let new_code_id = app.store_code(dao_proposal_single_contract()); let start_config = query_proposal_config(&app, &proposal_module); app.execute( @@ -3154,8 +3156,8 @@ pub fn test_migrate_updates_version() { // let cw20_id = app.store_code(cw20_base_contract()); // let cw20_stake_id = app.store_code(cw20_stake_contract()); -// let staked_balances_voting_id = app.store_code(cw20_staked_balances_voting_contract()); -// let core_contract_id = app.store_code(cw_core_contract()); +// let staked_balances_voting_id = app.store_code(dao_voting_cw20_staked_contract()); +// let core_contract_id = app.store_code(dao_dao_core_contract()); // let instantiate_core = dao_interface::msg::InstantiateMsg { // admin: None, @@ -3278,8 +3280,8 @@ pub fn test_migrate_updates_version() { // ) // .unwrap(); -// let v2_proposal_single = app.store_code(proposal_single_contract()); -// let pre_propose_single = app.store_code(pre_propose_single_contract()); +// let v2_proposal_single = app.store_code(dao_proposal_single_contract()); +// let pre_propose_single = app.store_code(dao_pre_propose_approval_single_contract()); // // Attempt to migrate. This will fail as there is a pending // // proposal. @@ -3754,7 +3756,10 @@ fn test_reply_hooks_mock() { // Do it again. This time, there is no module so this should error. let _id = failed_pre_propose_module_hook_id(); let err = reply(deps.as_mut(), env.clone(), prepropose_reply_msg).unwrap_err(); - assert!(matches!(err, ContractError::InvalidReplyID { id: _ })); + assert!(matches!( + err, + crate::ContractError::InvalidReplyID { id: _ } + )); // Check that we fail open. let status = CREATION_POLICY.load(deps.as_ref().storage).unwrap(); @@ -3933,7 +3938,7 @@ fn test_update_pre_propose_module() { ProposalCreationPolicy::Module { addr } => addr, }; - let pre_propose_id = app.store_code(pre_propose_single_contract()); + let pre_propose_id = app.store_code(dao_pre_propose_single_contract()); // Make a proposal to switch to a new pre-propose moudle. mint_cw20s(&mut app, &gov_token, &core_addr, CREATOR_ADDR, 10_000_000); diff --git a/contracts/staking/cw20-stake-external-rewards/Cargo.toml b/contracts/staking/cw20-stake-external-rewards/Cargo.toml index 9f59c261e..9b14e2bd4 100644 --- a/contracts/staking/cw20-stake-external-rewards/Cargo.toml +++ b/contracts/staking/cw20-stake-external-rewards/Cargo.toml @@ -22,10 +22,10 @@ cw-storage-plus = { workspace = true } cw-controllers = { workspace = true } cw20 = { workspace = true } cw-utils = { workspace = true } -cw20-base = { workspace = true, features = ["library"] } +cw20-base = { workspace = true, features = ["library"] } cw2 = { workspace = true } thiserror = { workspace = true } -cw20-stake = { workspace = true, features = ["library"]} +cw20-stake = { workspace = true, features = ["library"] } cw-ownable = { workspace = true } dao-hooks = { workspace = true } @@ -33,5 +33,7 @@ cw20-stake-external-rewards-v1 = { workspace = true } cw20-013 = { package = "cw20", version = "0.13" } [dev-dependencies] +cw20-stake-external-rewards = { workspace = true } cw-multi-test = { workspace = true } anyhow = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/staking/cw20-stake-external-rewards/src/contract.rs b/contracts/staking/cw20-stake-external-rewards/src/contract.rs index e92b0b6d9..2faa57121 100644 --- a/contracts/staking/cw20-stake-external-rewards/src/contract.rs +++ b/contracts/staking/cw20-stake-external-rewards/src/contract.rs @@ -455,1583 +455,3 @@ pub fn query_pending_rewards( last_update_block: LAST_UPDATE_BLOCK.load(deps.storage).unwrap_or_default(), }) } - -#[cfg(test)] -mod tests { - use std::borrow::BorrowMut; - - use crate::{msg::MigrateMsg, ContractError}; - - use cosmwasm_std::{coin, to_json_binary, Addr, Empty, Uint128, WasmMsg}; - use cw20::{Cw20Coin, Cw20ExecuteMsg, Denom}; - use cw_ownable::{Action, Ownership, OwnershipError}; - use cw_utils::Duration; - - use cw_multi_test::{next_block, App, BankSudo, Contract, ContractWrapper, Executor, SudoMsg}; - - use cw20_stake_external_rewards_v1 as v1; - - use crate::msg::{ExecuteMsg, InfoResponse, PendingRewardsResponse, QueryMsg, ReceiveMsg}; - - const OWNER: &str = "owner"; - const ADDR1: &str = "addr0001"; - const ADDR2: &str = "addr0002"; - const ADDR3: &str = "addr0003"; - - pub fn contract_rewards() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_migrate(crate::contract::migrate); - Box::new(contract) - } - - pub fn contract_rewards_v1() -> Box> { - let contract = ContractWrapper::new( - v1::contract::execute, - v1::contract::instantiate, - v1::contract::query, - ); - Box::new(contract) - } - - pub fn contract_staking() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ); - Box::new(contract) - } - - pub fn contract_cw20() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) - } - - fn mock_app() -> App { - App::default() - } - - fn instantiate_cw20(app: &mut App, initial_balances: Vec) -> Addr { - let cw20_id = app.store_code(contract_cw20()); - let msg = cw20_base::msg::InstantiateMsg { - name: String::from("Test"), - symbol: String::from("TEST"), - decimals: 6, - initial_balances, - mint: None, - marketing: None, - }; - - app.instantiate_contract(cw20_id, Addr::unchecked(ADDR1), &msg, &[], "cw20", None) - .unwrap() - } - - fn instantiate_staking( - app: &mut App, - cw20: Addr, - unstaking_duration: Option, - ) -> Addr { - let staking_code_id = app.store_code(contract_staking()); - let msg = cw20_stake::msg::InstantiateMsg { - owner: Some(OWNER.to_string()), - token_address: cw20.to_string(), - unstaking_duration, - }; - app.instantiate_contract( - staking_code_id, - Addr::unchecked(ADDR1), - &msg, - &[], - "staking", - None, - ) - .unwrap() - } - - fn stake_tokens>( - app: &mut App, - staking_addr: &Addr, - cw20_addr: &Addr, - sender: T, - amount: u128, - ) { - let msg = cw20::Cw20ExecuteMsg::Send { - contract: staking_addr.to_string(), - amount: Uint128::new(amount), - msg: to_json_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(), - }; - app.execute_contract(Addr::unchecked(sender), cw20_addr.clone(), &msg, &[]) - .unwrap(); - } - - fn unstake_tokens(app: &mut App, staking_addr: &Addr, address: &str, amount: u128) { - let msg = cw20_stake::msg::ExecuteMsg::Unstake { - amount: Uint128::new(amount), - }; - app.execute_contract(Addr::unchecked(address), staking_addr.clone(), &msg, &[]) - .unwrap(); - } - - fn setup_staking_contract(app: &mut App, initial_balances: Vec) -> (Addr, Addr) { - // Instantiate cw20 contract - let cw20_addr = instantiate_cw20(app, initial_balances.clone()); - app.update_block(next_block); - // Instantiate staking contract - let staking_addr = instantiate_staking(app, cw20_addr.clone(), None); - app.update_block(next_block); - for coin in initial_balances { - stake_tokens( - app, - &staking_addr, - &cw20_addr, - coin.address, - coin.amount.u128(), - ); - } - (staking_addr, cw20_addr) - } - - fn setup_reward_contract( - app: &mut App, - staking_contract: Addr, - reward_token: Denom, - owner: Addr, - ) -> Addr { - let reward_code_id = app.store_code(contract_rewards()); - let msg = crate::msg::InstantiateMsg { - owner: Some(owner.clone().into_string()), - staking_contract: staking_contract.clone().into_string(), - reward_token, - reward_duration: 100000, - }; - let reward_addr = app - .instantiate_contract(reward_code_id, owner, &msg, &[], "reward", None) - .unwrap(); - let msg = cw20_stake::msg::ExecuteMsg::AddHook { - addr: reward_addr.to_string(), - }; - let _result = app - .execute_contract(Addr::unchecked(OWNER), staking_contract, &msg, &[]) - .unwrap(); - reward_addr - } - - fn get_balance_cw20, U: Into>( - app: &App, - contract_addr: T, - address: U, - ) -> Uint128 { - let msg = cw20::Cw20QueryMsg::Balance { - address: address.into(), - }; - let result: cw20::BalanceResponse = - app.wrap().query_wasm_smart(contract_addr, &msg).unwrap(); - result.balance - } - - fn get_balance_native, U: Into>( - app: &App, - address: T, - denom: U, - ) -> Uint128 { - app.wrap().query_balance(address, denom).unwrap().amount - } - - fn get_ownership>(app: &App, address: T) -> Ownership { - app.wrap() - .query_wasm_smart(address, &QueryMsg::Ownership {}) - .unwrap() - } - - fn assert_pending_rewards(app: &mut App, reward_addr: &Addr, address: &str, expected: u128) { - let res: PendingRewardsResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart( - reward_addr, - &QueryMsg::GetPendingRewards { - address: address.to_string(), - }, - ) - .unwrap(); - assert_eq!(res.pending_rewards, Uint128::new(expected)); - } - - fn claim_rewards(app: &mut App, reward_addr: Addr, address: &str) { - let msg = ExecuteMsg::Claim {}; - app.borrow_mut() - .execute_contract(Addr::unchecked(address), reward_addr, &msg, &[]) - .unwrap(); - } - - fn fund_rewards_cw20( - app: &mut App, - admin: &Addr, - reward_token: Addr, - reward_addr: &Addr, - amount: u128, - ) { - let fund_sub_msg = to_json_binary(&ReceiveMsg::Fund {}).unwrap(); - let fund_msg = Cw20ExecuteMsg::Send { - contract: reward_addr.clone().into_string(), - amount: Uint128::new(amount), - msg: fund_sub_msg, - }; - let _res = app - .borrow_mut() - .execute_contract(admin.clone(), reward_token, &fund_msg, &[]) - .unwrap(); - } - - #[test] - fn test_zero_rewards_duration() { - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let denom = "utest".to_string(); - let (staking_addr, _) = setup_staking_contract(&mut app, vec![]); - let reward_funding = vec![coin(100000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding, - } - })) - .unwrap(); - - let reward_token = Denom::Native(denom); - let owner = admin; - let reward_code_id = app.store_code(contract_rewards()); - let msg = crate::msg::InstantiateMsg { - owner: Some(owner.clone().into_string()), - staking_contract: staking_addr.to_string(), - reward_token, - reward_duration: 0, - }; - let err: ContractError = app - .instantiate_contract(reward_code_id, owner, &msg, &[], "reward", None) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::ZeroRewardDuration {}) - } - - #[test] - fn test_native_rewards() { - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, cw20_addr) = setup_staking_contract(&mut app, initial_balances); - let reward_funding = vec![coin(100000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - let reward_addr = setup_reward_contract( - &mut app, - staking_addr.clone(), - Denom::Native(denom.clone()), - admin.clone(), - ); - - app.borrow_mut().update_block(|b| b.height = 1000); - - let fund_msg = ExecuteMsg::Fund {}; - - let _res = app - .borrow_mut() - .execute_contract( - admin.clone(), - reward_addr.clone(), - &fund_msg, - &reward_funding, - ) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(1000)); - assert_eq!(res.reward.period_finish, 101000); - assert_eq!(res.reward.reward_duration, 100000); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 500); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 250); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 250); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 500); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1500); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 750); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 750); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 2000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 1000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 1000); - - assert_eq!(get_balance_native(&app, ADDR1, &denom), Uint128::zero()); - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - assert_eq!(get_balance_native(&app, ADDR1, &denom), Uint128::new(2000)); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); - - app.borrow_mut().update_block(|b| b.height += 10); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); - - unstake_tokens(&mut app, &staking_addr, ADDR2, 50); - unstake_tokens(&mut app, &staking_addr, ADDR3, 50); - - app.borrow_mut().update_block(|b| b.height += 10); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 15000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - assert_eq!(get_balance_native(&app, ADDR1, &denom), Uint128::new(17000)); - - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - assert_eq!(get_balance_native(&app, ADDR2, &denom), Uint128::new(3500)); - - stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR2, 50); - stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 50); - - app.borrow_mut().update_block(|b| b.height += 10); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 2500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 6000); - - // Current height is 1034. ADDR1 is receiving 500 tokens/block - // and ADDR2 / ADDR3 are receiving 250. - // - // At height 101000 99966 additional blocks have passed. So we - // expect: - // - // ADDR1: 5000 + 99966 * 500 = 49,998,000 - // ADDR2: 2500 + 99966 * 250 = 24,994,000 - // ADDR3: 6000 + 99966 * 250 = 24,997,500 - app.borrow_mut().update_block(|b| b.height = 101000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 49988000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 24994000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 24997500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - assert_eq!( - get_balance_native(&app, ADDR1, &denom), - Uint128::new(50005000) - ); - assert_eq!( - get_balance_native(&app, ADDR2, &denom), - Uint128::new(24997500) - ); - assert_eq!(get_balance_native(&app, ADDR3, &denom), Uint128::new(0)); - assert_eq!( - get_balance_native(&app, &reward_addr, &denom), - Uint128::new(24997500) - ); - - app.borrow_mut().update_block(|b| b.height = 200000); - let fund_msg = ExecuteMsg::Fund {}; - - // Add more rewards - let reward_funding = vec![coin(200000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - - let _res = app - .borrow_mut() - .execute_contract( - admin.clone(), - reward_addr.clone(), - &fund_msg, - &reward_funding, - ) - .unwrap(); - - app.borrow_mut().update_block(|b| b.height = 300000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 74997500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - assert_eq!( - get_balance_native(&app, ADDR1, &denom), - Uint128::new(150005000) - ); - assert_eq!( - get_balance_native(&app, ADDR2, &denom), - Uint128::new(74997500) - ); - assert_eq!(get_balance_native(&app, ADDR3, &denom), Uint128::zero()); - assert_eq!( - get_balance_native(&app, &reward_addr, &denom), - Uint128::new(74997500) - ); - - // Add more rewards - let reward_funding = vec![coin(200000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - - let _res = app - .borrow_mut() - .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) - .unwrap(); - - app.borrow_mut().update_block(|b| b.height = 400000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 124997500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - claim_rewards(&mut app, reward_addr.clone(), ADDR3); - assert_eq!( - get_balance_native(&app, ADDR1, &denom), - Uint128::new(250005000) - ); - assert_eq!( - get_balance_native(&app, ADDR2, &denom), - Uint128::new(124997500) - ); - assert_eq!( - get_balance_native(&app, ADDR3, &denom), - Uint128::new(124997500) - ); - assert_eq!( - get_balance_native(&app, &reward_addr, &denom), - Uint128::zero() - ); - - app.borrow_mut().update_block(|b| b.height = 500000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 0); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 0); - - app.borrow_mut().update_block(|b| b.height = 1000000); - unstake_tokens(&mut app, &staking_addr, ADDR3, 1); - stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 1); - } - - #[test] - fn test_cw20_rewards() { - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, cw20_addr) = setup_staking_contract(&mut app, initial_balances); - let reward_token = instantiate_cw20( - &mut app, - vec![Cw20Coin { - address: OWNER.to_string(), - amount: Uint128::new(500000000), - }], - ); - let reward_addr = setup_reward_contract( - &mut app, - staking_addr.clone(), - Denom::Cw20(reward_token.clone()), - admin.clone(), - ); - - app.borrow_mut().update_block(|b| b.height = 1000); - - fund_rewards_cw20( - &mut app, - &admin, - reward_token.clone(), - &reward_addr, - 100000000, - ); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(1000)); - assert_eq!(res.reward.period_finish, 101000); - assert_eq!(res.reward.reward_duration, 100000); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 500); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 250); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 250); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 500); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1500); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 750); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 750); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 2000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 1000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 1000); - - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR1), - Uint128::zero() - ); - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR1), - Uint128::new(2000) - ); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); - - app.borrow_mut().update_block(|b| b.height += 10); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); - - unstake_tokens(&mut app, &staking_addr, ADDR2, 50); - unstake_tokens(&mut app, &staking_addr, ADDR3, 50); - - app.borrow_mut().update_block(|b| b.height += 10); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 15000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR1), - Uint128::new(17000) - ); - - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR2), - Uint128::new(3500) - ); - - stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR2, 50); - stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 50); - - app.borrow_mut().update_block(|b| b.height += 10); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 2500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 6000); - - app.borrow_mut().update_block(|b| b.height = 101000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 49988000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 24994000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 24997500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR1), - Uint128::new(50005000) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR2), - Uint128::new(24997500) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR3), - Uint128::new(0) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, &reward_addr), - Uint128::new(24997500) - ); - - app.borrow_mut().update_block(|b| b.height = 200000); - - let reward_funding = vec![coin(200000000, denom)]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding, - } - })) - .unwrap(); - - fund_rewards_cw20( - &mut app, - &admin, - reward_token.clone(), - &reward_addr, - 200000000, - ); - - app.borrow_mut().update_block(|b| b.height = 300000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 74997500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR1), - Uint128::new(150005000) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR2), - Uint128::new(74997500) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR3), - Uint128::zero() - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, &reward_addr), - Uint128::new(74997500) - ); - - // Add more rewards - fund_rewards_cw20( - &mut app, - &admin, - reward_token.clone(), - &reward_addr, - 200000000, - ); - - app.borrow_mut().update_block(|b| b.height = 400000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 124997500); - - claim_rewards(&mut app, reward_addr.clone(), ADDR1); - claim_rewards(&mut app, reward_addr.clone(), ADDR2); - claim_rewards(&mut app, reward_addr.clone(), ADDR3); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR1), - Uint128::new(250005000) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR2), - Uint128::new(124997500) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, ADDR3), - Uint128::new(124997500) - ); - assert_eq!( - get_balance_cw20(&app, &reward_token, &reward_addr), - Uint128::zero() - ); - - app.borrow_mut().update_block(|b| b.height = 500000); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 0); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 0); - - app.borrow_mut().update_block(|b| b.height = 1000000); - unstake_tokens(&mut app, &staking_addr, ADDR3, 1); - stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 1); - } - - #[test] - fn update_rewards() { - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); - let reward_funding = vec![coin(200000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - // Add funding to Addr1 to make sure it can't update staking contract - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: ADDR1.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - let reward_addr = setup_reward_contract( - &mut app, - staking_addr, - Denom::Native(denom.clone()), - admin.clone(), - ); - - app.borrow_mut().update_block(|b| b.height = 1000); - - let fund_msg = ExecuteMsg::Fund {}; - - // None admin cannot update rewards - let err: ContractError = app - .borrow_mut() - .execute_contract( - Addr::unchecked(ADDR1), - reward_addr.clone(), - &fund_msg, - &reward_funding, - ) - .unwrap_err() - .downcast() - .unwrap(); - - assert_eq!(err, ContractError::Ownable(OwnershipError::NotOwner)); - - let _res = app - .borrow_mut() - .execute_contract( - admin.clone(), - reward_addr.clone(), - &fund_msg, - &reward_funding, - ) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(2000)); - assert_eq!(res.reward.period_finish, 101000); - assert_eq!(res.reward.reward_duration, 100000); - - // Create new period after old period - app.borrow_mut().update_block(|b| b.height = 101000); - - let reward_funding = vec![coin(100000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - let _res = app - .borrow_mut() - .execute_contract( - admin.clone(), - reward_addr.clone(), - &fund_msg, - &reward_funding, - ) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(1000)); - assert_eq!(res.reward.period_finish, 201000); - assert_eq!(res.reward.reward_duration, 100000); - - // Add funds in middle of period returns an error - app.borrow_mut().update_block(|b| b.height = 151000); - - let reward_funding = vec![coin(200000000, denom)]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - let err = app - .borrow_mut() - .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) - .unwrap_err(); - assert_eq!( - ContractError::RewardPeriodNotFinished {}, - err.downcast().unwrap() - ); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(1000)); - assert_eq!(res.reward.period_finish, 201000); - assert_eq!(res.reward.reward_duration, 100000); - } - - #[test] - fn update_reward_duration() { - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); - - let reward_addr = setup_reward_contract( - &mut app, - staking_addr, - Denom::Native(denom.clone()), - admin.clone(), - ); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(0)); - assert_eq!(res.reward.period_finish, 0); - assert_eq!(res.reward.reward_duration, 100000); - - // Zero rewards durations are not allowed. - let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 0 }; - let err: ContractError = app - .borrow_mut() - .execute_contract(admin.clone(), reward_addr.clone(), &msg, &[]) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::ZeroRewardDuration {}); - - let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 10 }; - let _resp = app - .borrow_mut() - .execute_contract(admin.clone(), reward_addr.clone(), &msg, &[]) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(0)); - assert_eq!(res.reward.period_finish, 0); - assert_eq!(res.reward.reward_duration, 10); - - // Non-admin cannot update rewards - let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 100 }; - let err: ContractError = app - .borrow_mut() - .execute_contract(Addr::unchecked("non-admin"), reward_addr.clone(), &msg, &[]) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::Ownable(OwnershipError::NotOwner)); - - let reward_funding = vec![coin(1000, denom)]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - // Add funding to Addr1 to make sure it can't update staking contract - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: ADDR1.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - - app.borrow_mut().update_block(|b| b.height = 1000); - - let fund_msg = ExecuteMsg::Fund {}; - - let _res = app - .borrow_mut() - .execute_contract( - admin.clone(), - reward_addr.clone(), - &fund_msg, - &reward_funding, - ) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(100)); - assert_eq!(res.reward.period_finish, 1010); - assert_eq!(res.reward.reward_duration, 10); - - // Cannot update reward period before it finishes - let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 10 }; - let err: ContractError = app - .borrow_mut() - .execute_contract(admin.clone(), reward_addr.clone(), &msg, &[]) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::RewardPeriodNotFinished {}); - - // Update reward period once rewards are finished - app.borrow_mut().update_block(|b| b.height = 1010); - - let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 100 }; - let _resp = app - .borrow_mut() - .execute_contract(admin, reward_addr.clone(), &msg, &[]) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(100)); - assert_eq!(res.reward.period_finish, 1010); - assert_eq!(res.reward.reward_duration, 100); - } - - #[test] - fn test_update_owner() { - let mut app = mock_app(); - let addr_owner = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); - - let reward_addr = setup_reward_contract( - &mut app, - staking_addr, - Denom::Native(denom), - addr_owner.clone(), - ); - - let owner = get_ownership(&app, &reward_addr).owner; - assert_eq!(owner, Some(addr_owner.clone())); - - // random addr cannot update owner - let msg = ExecuteMsg::UpdateOwnership(Action::TransferOwnership { - new_owner: ADDR1.to_string(), - expiry: None, - }); - let err: ContractError = app - .borrow_mut() - .execute_contract(Addr::unchecked(ADDR1), reward_addr.clone(), &msg, &[]) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::Ownable(OwnershipError::NotOwner)); - - // owner nominates a new onwer. - app.borrow_mut() - .execute_contract(addr_owner.clone(), reward_addr.clone(), &msg, &[]) - .unwrap(); - - let ownership = get_ownership(&app, &reward_addr); - assert_eq!( - ownership, - Ownership:: { - owner: Some(addr_owner), - pending_owner: Some(Addr::unchecked(ADDR1)), - pending_expiry: None, - } - ); - - // new owner accepts the nomination. - app.execute_contract( - Addr::unchecked(ADDR1), - reward_addr.clone(), - &ExecuteMsg::UpdateOwnership(Action::AcceptOwnership), - &[], - ) - .unwrap(); - - let ownership = get_ownership(&app, &reward_addr); - assert_eq!( - ownership, - Ownership:: { - owner: Some(Addr::unchecked(ADDR1)), - pending_owner: None, - pending_expiry: None, - } - ); - - // new owner renounces ownership. - app.execute_contract( - Addr::unchecked(ADDR1), - reward_addr.clone(), - &ExecuteMsg::UpdateOwnership(Action::RenounceOwnership), - &[], - ) - .unwrap(); - - let ownership = get_ownership(&app, &reward_addr); - assert_eq!( - ownership, - Ownership:: { - owner: None, - pending_owner: None, - pending_expiry: None, - } - ); - } - - #[test] - fn test_cannot_fund_with_wrong_coin_native() { - let mut app = mock_app(); - let owner = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); - - let reward_addr = setup_reward_contract( - &mut app, - staking_addr, - Denom::Native(denom.clone()), - owner.clone(), - ); - - app.borrow_mut().update_block(|b| b.height = 1000); - - // No funding - let fund_msg = ExecuteMsg::Fund {}; - - let err: ContractError = app - .borrow_mut() - .execute_contract(owner.clone(), reward_addr.clone(), &fund_msg, &[]) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::InvalidFunds {}); - - // Invalid funding - let invalid_funding = vec![coin(100, "invalid")]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: owner.to_string(), - amount: invalid_funding.clone(), - } - })) - .unwrap(); - - let fund_msg = ExecuteMsg::Fund {}; - - let err: ContractError = app - .borrow_mut() - .execute_contract( - owner.clone(), - reward_addr.clone(), - &fund_msg, - &invalid_funding, - ) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::InvalidFunds {}); - - // Extra funding - let extra_funding = vec![coin(100, denom), coin(100, "extra")]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: owner.to_string(), - amount: extra_funding.clone(), - } - })) - .unwrap(); - - let fund_msg = ExecuteMsg::Fund {}; - - let err: ContractError = app - .borrow_mut() - .execute_contract( - owner.clone(), - reward_addr.clone(), - &fund_msg, - &extra_funding, - ) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::InvalidFunds {}); - - // Cw20 funding fails - let cw20_token = instantiate_cw20( - &mut app, - vec![Cw20Coin { - address: OWNER.to_string(), - amount: Uint128::new(500000000), - }], - ); - let fund_sub_msg = to_json_binary(&ReceiveMsg::Fund {}).unwrap(); - let fund_msg = Cw20ExecuteMsg::Send { - contract: reward_addr.into_string(), - amount: Uint128::new(100), - msg: fund_sub_msg, - }; - let err: ContractError = app - .borrow_mut() - .execute_contract(owner, cw20_token, &fund_msg, &[]) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::InvalidCw20 {}); - } - - #[test] - fn test_cannot_fund_with_wrong_coin_cw20() { - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let _denom = "utest".to_string(); - let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); - let reward_token = instantiate_cw20( - &mut app, - vec![Cw20Coin { - address: OWNER.to_string(), - amount: Uint128::new(500000000), - }], - ); - let reward_addr = setup_reward_contract( - &mut app, - staking_addr, - Denom::Cw20(Addr::unchecked("dummy_cw20")), - admin.clone(), - ); - - app.borrow_mut().update_block(|b| b.height = 1000); - - // Test with invalid token - let fund_sub_msg = to_json_binary(&ReceiveMsg::Fund {}).unwrap(); - let fund_msg = Cw20ExecuteMsg::Send { - contract: reward_addr.clone().into_string(), - amount: Uint128::new(100), - msg: fund_sub_msg, - }; - let err: ContractError = app - .borrow_mut() - .execute_contract(admin.clone(), reward_token, &fund_msg, &[]) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::InvalidCw20 {}); - - // Test does not work when funded with native - let invalid_funding = vec![coin(100, "invalid")]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: invalid_funding.clone(), - } - })) - .unwrap(); - - let fund_msg = ExecuteMsg::Fund {}; - - let err: ContractError = app - .borrow_mut() - .execute_contract(admin, reward_addr, &fund_msg, &invalid_funding) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::InvalidFunds {}) - } - - #[test] - fn test_rewards_with_zero_staked() { - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - // Instantiate cw20 contract - let cw20_addr = instantiate_cw20(&mut app, initial_balances.clone()); - app.update_block(next_block); - // Instantiate staking contract - let staking_addr = instantiate_staking(&mut app, cw20_addr.clone(), None); - app.update_block(next_block); - let reward_funding = vec![coin(100000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - let reward_addr = setup_reward_contract( - &mut app, - staking_addr.clone(), - Denom::Native(denom), - admin.clone(), - ); - - app.borrow_mut().update_block(|b| b.height = 1000); - - let fund_msg = ExecuteMsg::Fund {}; - - let _res = app - .borrow_mut() - .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(1000)); - assert_eq!(res.reward.period_finish, 101000); - assert_eq!(res.reward.reward_duration, 100000); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 0); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 0); - - for coin in initial_balances { - stake_tokens( - &mut app, - &staking_addr, - &cw20_addr, - coin.address, - coin.amount.u128(), - ); - } - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 500); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 250); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 250); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1000); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 500); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 500); - } - - #[test] - fn test_small_rewards() { - // This test was added due to a bug in the contract not properly paying out small reward - // amounts due to floor division - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, _) = setup_staking_contract(&mut app, initial_balances); - let reward_funding = vec![coin(1000000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - let reward_addr = - setup_reward_contract(&mut app, staking_addr, Denom::Native(denom), admin.clone()); - - app.borrow_mut().update_block(|b| b.height = 1000); - - let fund_msg = ExecuteMsg::Fund {}; - - let _res = app - .borrow_mut() - .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) - .unwrap(); - - let res: InfoResponse = app - .borrow_mut() - .wrap() - .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) - .unwrap(); - - assert_eq!(res.reward.reward_rate, Uint128::new(10)); - assert_eq!(res.reward.period_finish, 101000); - assert_eq!(res.reward.reward_duration, 100000); - - app.borrow_mut().update_block(next_block); - assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5); - assert_pending_rewards(&mut app, &reward_addr, ADDR2, 2); - assert_pending_rewards(&mut app, &reward_addr, ADDR3, 2); - } - - #[test] - fn test_zero_reward_rate_failed() { - // This test is due to a bug when funder provides rewards config that results in less then 1 - // reward per block which rounds down to zer0 - let mut app = mock_app(); - let admin = Addr::unchecked(OWNER); - app.borrow_mut().update_block(|b| b.height = 0); - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, _) = setup_staking_contract(&mut app, initial_balances); - let reward_funding = vec![coin(10000, denom.clone())]; - app.sudo(SudoMsg::Bank({ - BankSudo::Mint { - to_address: admin.to_string(), - amount: reward_funding.clone(), - } - })) - .unwrap(); - let reward_addr = - setup_reward_contract(&mut app, staking_addr, Denom::Native(denom), admin.clone()); - - app.borrow_mut().update_block(|b| b.height = 1000); - - let fund_msg = ExecuteMsg::Fund {}; - - let _res = app - .borrow_mut() - .execute_contract(admin, reward_addr, &fund_msg, &reward_funding) - .unwrap_err(); - } - - #[test] - fn test_migrate_from_v1() { - let mut app = App::default(); - - let v1_code = app.store_code(contract_rewards_v1()); - let v2_code = app.store_code(contract_rewards()); - - let initial_balances = vec![ - Cw20Coin { - address: ADDR1.to_string(), - amount: Uint128::new(100), - }, - Cw20Coin { - address: ADDR2.to_string(), - amount: Uint128::new(50), - }, - Cw20Coin { - address: ADDR3.to_string(), - amount: Uint128::new(50), - }, - ]; - let denom = "utest".to_string(); - let (staking_addr, _) = setup_staking_contract(&mut app, initial_balances); - - let rewards_addr = app - .instantiate_contract( - v1_code, - Addr::unchecked(OWNER), - &v1::msg::InstantiateMsg { - owner: Some(OWNER.to_string()), - manager: Some(ADDR1.to_string()), - staking_contract: staking_addr.into_string(), - reward_token: cw20_013::Denom::Native(denom), - reward_duration: 10000, - }, - &[], - "rewards".to_string(), - Some(OWNER.to_string()), - ) - .unwrap(); - - app.execute( - Addr::unchecked(OWNER), - WasmMsg::Migrate { - contract_addr: rewards_addr.to_string(), - new_code_id: v2_code, - msg: to_json_binary(&MigrateMsg::FromV1 {}).unwrap(), - } - .into(), - ) - .unwrap(); - - let ownership = get_ownership(&app, &rewards_addr); - assert_eq!( - ownership, - Ownership:: { - owner: Some(Addr::unchecked(OWNER)), - pending_owner: None, - pending_expiry: None, - } - ); - - let err: ContractError = app - .execute( - Addr::unchecked(OWNER), - WasmMsg::Migrate { - contract_addr: rewards_addr.to_string(), - new_code_id: v2_code, - msg: to_json_binary(&MigrateMsg::FromV1 {}).unwrap(), - } - .into(), - ) - .unwrap_err() - .downcast() - .unwrap(); - assert_eq!(err, ContractError::AlreadyMigrated {}); - } -} diff --git a/contracts/staking/cw20-stake-external-rewards/src/lib.rs b/contracts/staking/cw20-stake-external-rewards/src/lib.rs index 595daabe0..62c64328d 100644 --- a/contracts/staking/cw20-stake-external-rewards/src/lib.rs +++ b/contracts/staking/cw20-stake-external-rewards/src/lib.rs @@ -6,3 +6,6 @@ pub mod msg; pub mod state; pub use crate::error::ContractError; + +#[cfg(test)] +mod tests; diff --git a/contracts/staking/cw20-stake-external-rewards/src/tests.rs b/contracts/staking/cw20-stake-external-rewards/src/tests.rs new file mode 100644 index 000000000..a4f32ae0f --- /dev/null +++ b/contracts/staking/cw20-stake-external-rewards/src/tests.rs @@ -0,0 +1,1537 @@ +use std::borrow::BorrowMut; + +use cosmwasm_std::{coin, to_json_binary, Addr, Uint128, WasmMsg}; +use cw20::{Cw20Coin, Cw20ExecuteMsg, Denom}; +use cw20_stake_external_rewards_v1 as v1; +use cw_multi_test::{next_block, App, BankSudo, Executor, SudoMsg}; +use cw_ownable::{Action, Ownership, OwnershipError}; +use cw_utils::Duration; +use dao_testing::contracts::{ + cw20_base_contract, cw20_stake_contract, cw20_stake_external_rewards_contract, + v1::cw20_stake_external_rewards_v1_contract, +}; + +use crate::msg::{ + ExecuteMsg, InfoResponse, MigrateMsg, PendingRewardsResponse, QueryMsg, ReceiveMsg, +}; +use cw20_stake_external_rewards::ContractError; + +const OWNER: &str = "owner"; +const ADDR1: &str = "addr0001"; +const ADDR2: &str = "addr0002"; +const ADDR3: &str = "addr0003"; + +fn mock_app() -> App { + App::default() +} + +fn instantiate_cw20(app: &mut App, initial_balances: Vec) -> Addr { + let cw20_id = app.store_code(cw20_base_contract()); + let msg = cw20_base::msg::InstantiateMsg { + name: String::from("Test"), + symbol: String::from("TEST"), + decimals: 6, + initial_balances, + mint: None, + marketing: None, + }; + + app.instantiate_contract(cw20_id, Addr::unchecked(ADDR1), &msg, &[], "cw20", None) + .unwrap() +} + +fn instantiate_staking(app: &mut App, cw20: Addr, unstaking_duration: Option) -> Addr { + let staking_code_id = app.store_code(cw20_stake_contract()); + let msg = cw20_stake::msg::InstantiateMsg { + owner: Some(OWNER.to_string()), + token_address: cw20.to_string(), + unstaking_duration, + }; + app.instantiate_contract( + staking_code_id, + Addr::unchecked(ADDR1), + &msg, + &[], + "staking", + None, + ) + .unwrap() +} + +fn stake_tokens>( + app: &mut App, + staking_addr: &Addr, + cw20_addr: &Addr, + sender: T, + amount: u128, +) { + let msg = cw20::Cw20ExecuteMsg::Send { + contract: staking_addr.to_string(), + amount: Uint128::new(amount), + msg: to_json_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(), + }; + app.execute_contract(Addr::unchecked(sender), cw20_addr.clone(), &msg, &[]) + .unwrap(); +} + +fn unstake_tokens(app: &mut App, staking_addr: &Addr, address: &str, amount: u128) { + let msg = cw20_stake::msg::ExecuteMsg::Unstake { + amount: Uint128::new(amount), + }; + app.execute_contract(Addr::unchecked(address), staking_addr.clone(), &msg, &[]) + .unwrap(); +} + +fn setup_staking_contract(app: &mut App, initial_balances: Vec) -> (Addr, Addr) { + // Instantiate cw20 contract + let cw20_addr = instantiate_cw20(app, initial_balances.clone()); + app.update_block(next_block); + // Instantiate staking contract + let staking_addr = instantiate_staking(app, cw20_addr.clone(), None); + app.update_block(next_block); + for coin in initial_balances { + stake_tokens( + app, + &staking_addr, + &cw20_addr, + coin.address, + coin.amount.u128(), + ); + } + (staking_addr, cw20_addr) +} + +fn setup_reward_contract( + app: &mut App, + staking_contract: Addr, + reward_token: Denom, + owner: Addr, +) -> Addr { + let reward_code_id = app.store_code(cw20_stake_external_rewards_contract()); + let msg = crate::msg::InstantiateMsg { + owner: Some(owner.clone().into_string()), + staking_contract: staking_contract.clone().into_string(), + reward_token, + reward_duration: 100000, + }; + let reward_addr = app + .instantiate_contract(reward_code_id, owner, &msg, &[], "reward", None) + .unwrap(); + let msg = cw20_stake::msg::ExecuteMsg::AddHook { + addr: reward_addr.to_string(), + }; + let _result = app + .execute_contract(Addr::unchecked(OWNER), staking_contract, &msg, &[]) + .unwrap(); + reward_addr +} + +fn get_balance_cw20, U: Into>( + app: &App, + contract_addr: T, + address: U, +) -> Uint128 { + let msg = cw20::Cw20QueryMsg::Balance { + address: address.into(), + }; + let result: cw20::BalanceResponse = app.wrap().query_wasm_smart(contract_addr, &msg).unwrap(); + result.balance +} + +fn get_balance_native, U: Into>( + app: &App, + address: T, + denom: U, +) -> Uint128 { + app.wrap().query_balance(address, denom).unwrap().amount +} + +fn get_ownership>(app: &App, address: T) -> Ownership { + app.wrap() + .query_wasm_smart(address, &QueryMsg::Ownership {}) + .unwrap() +} + +fn assert_pending_rewards(app: &mut App, reward_addr: &Addr, address: &str, expected: u128) { + let res: PendingRewardsResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart( + reward_addr, + &QueryMsg::GetPendingRewards { + address: address.to_string(), + }, + ) + .unwrap(); + assert_eq!(res.pending_rewards, Uint128::new(expected)); +} + +fn claim_rewards(app: &mut App, reward_addr: Addr, address: &str) { + let msg = ExecuteMsg::Claim {}; + app.borrow_mut() + .execute_contract(Addr::unchecked(address), reward_addr, &msg, &[]) + .unwrap(); +} + +fn fund_rewards_cw20( + app: &mut App, + admin: &Addr, + reward_token: Addr, + reward_addr: &Addr, + amount: u128, +) { + let fund_sub_msg = to_json_binary(&ReceiveMsg::Fund {}).unwrap(); + let fund_msg = Cw20ExecuteMsg::Send { + contract: reward_addr.clone().into_string(), + amount: Uint128::new(amount), + msg: fund_sub_msg, + }; + let _res = app + .borrow_mut() + .execute_contract(admin.clone(), reward_token, &fund_msg, &[]) + .unwrap(); +} + +#[test] +fn test_zero_rewards_duration() { + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let denom = "utest".to_string(); + let (staking_addr, _) = setup_staking_contract(&mut app, vec![]); + let reward_funding = vec![coin(100000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding, + } + })) + .unwrap(); + + let reward_token = Denom::Native(denom); + let owner = admin; + let reward_code_id = app.store_code(cw20_stake_external_rewards_contract()); + let msg = crate::msg::InstantiateMsg { + owner: Some(owner.clone().into_string()), + staking_contract: staking_addr.to_string(), + reward_token, + reward_duration: 0, + }; + let err: ContractError = app + .instantiate_contract(reward_code_id, owner, &msg, &[], "reward", None) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::ZeroRewardDuration {}) +} + +#[test] +fn test_native_rewards() { + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, cw20_addr) = setup_staking_contract(&mut app, initial_balances); + let reward_funding = vec![coin(100000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + let reward_addr = setup_reward_contract( + &mut app, + staking_addr.clone(), + Denom::Native(denom.clone()), + admin.clone(), + ); + + app.borrow_mut().update_block(|b| b.height = 1000); + + let fund_msg = ExecuteMsg::Fund {}; + + let _res = app + .borrow_mut() + .execute_contract( + admin.clone(), + reward_addr.clone(), + &fund_msg, + &reward_funding, + ) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(1000)); + assert_eq!(res.reward.period_finish, 101000); + assert_eq!(res.reward.reward_duration, 100000); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 500); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 250); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 250); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 500); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1500); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 750); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 750); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 2000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 1000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 1000); + + assert_eq!(get_balance_native(&app, ADDR1, &denom), Uint128::zero()); + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + assert_eq!(get_balance_native(&app, ADDR1, &denom), Uint128::new(2000)); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); + + app.borrow_mut().update_block(|b| b.height += 10); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); + + unstake_tokens(&mut app, &staking_addr, ADDR2, 50); + unstake_tokens(&mut app, &staking_addr, ADDR3, 50); + + app.borrow_mut().update_block(|b| b.height += 10); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 15000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + assert_eq!(get_balance_native(&app, ADDR1, &denom), Uint128::new(17000)); + + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + assert_eq!(get_balance_native(&app, ADDR2, &denom), Uint128::new(3500)); + + stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR2, 50); + stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 50); + + app.borrow_mut().update_block(|b| b.height += 10); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 2500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 6000); + + // Current height is 1034. ADDR1 is receiving 500 tokens/block + // and ADDR2 / ADDR3 are receiving 250. + // + // At height 101000 99966 additional blocks have passed. So we + // expect: + // + // ADDR1: 5000 + 99966 * 500 = 49,998,000 + // ADDR2: 2500 + 99966 * 250 = 24,994,000 + // ADDR3: 6000 + 99966 * 250 = 24,997,500 + app.borrow_mut().update_block(|b| b.height = 101000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 49988000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 24994000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 24997500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + assert_eq!( + get_balance_native(&app, ADDR1, &denom), + Uint128::new(50005000) + ); + assert_eq!( + get_balance_native(&app, ADDR2, &denom), + Uint128::new(24997500) + ); + assert_eq!(get_balance_native(&app, ADDR3, &denom), Uint128::new(0)); + assert_eq!( + get_balance_native(&app, &reward_addr, &denom), + Uint128::new(24997500) + ); + + app.borrow_mut().update_block(|b| b.height = 200000); + let fund_msg = ExecuteMsg::Fund {}; + + // Add more rewards + let reward_funding = vec![coin(200000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + + let _res = app + .borrow_mut() + .execute_contract( + admin.clone(), + reward_addr.clone(), + &fund_msg, + &reward_funding, + ) + .unwrap(); + + app.borrow_mut().update_block(|b| b.height = 300000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 74997500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + assert_eq!( + get_balance_native(&app, ADDR1, &denom), + Uint128::new(150005000) + ); + assert_eq!( + get_balance_native(&app, ADDR2, &denom), + Uint128::new(74997500) + ); + assert_eq!(get_balance_native(&app, ADDR3, &denom), Uint128::zero()); + assert_eq!( + get_balance_native(&app, &reward_addr, &denom), + Uint128::new(74997500) + ); + + // Add more rewards + let reward_funding = vec![coin(200000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + + let _res = app + .borrow_mut() + .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) + .unwrap(); + + app.borrow_mut().update_block(|b| b.height = 400000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 124997500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + claim_rewards(&mut app, reward_addr.clone(), ADDR3); + assert_eq!( + get_balance_native(&app, ADDR1, &denom), + Uint128::new(250005000) + ); + assert_eq!( + get_balance_native(&app, ADDR2, &denom), + Uint128::new(124997500) + ); + assert_eq!( + get_balance_native(&app, ADDR3, &denom), + Uint128::new(124997500) + ); + assert_eq!( + get_balance_native(&app, &reward_addr, &denom), + Uint128::zero() + ); + + app.borrow_mut().update_block(|b| b.height = 500000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 0); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 0); + + app.borrow_mut().update_block(|b| b.height = 1000000); + unstake_tokens(&mut app, &staking_addr, ADDR3, 1); + stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 1); +} + +#[test] +fn test_cw20_rewards() { + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, cw20_addr) = setup_staking_contract(&mut app, initial_balances); + let reward_token = instantiate_cw20( + &mut app, + vec![Cw20Coin { + address: OWNER.to_string(), + amount: Uint128::new(500000000), + }], + ); + let reward_addr = setup_reward_contract( + &mut app, + staking_addr.clone(), + Denom::Cw20(reward_token.clone()), + admin.clone(), + ); + + app.borrow_mut().update_block(|b| b.height = 1000); + + fund_rewards_cw20( + &mut app, + &admin, + reward_token.clone(), + &reward_addr, + 100000000, + ); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(1000)); + assert_eq!(res.reward.period_finish, 101000); + assert_eq!(res.reward.reward_duration, 100000); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 500); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 250); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 250); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 500); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1500); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 750); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 750); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 2000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 1000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 1000); + + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR1), + Uint128::zero() + ); + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR1), + Uint128::new(2000) + ); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); + + app.borrow_mut().update_block(|b| b.height += 10); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); + + unstake_tokens(&mut app, &staking_addr, ADDR2, 50); + unstake_tokens(&mut app, &staking_addr, ADDR3, 50); + + app.borrow_mut().update_block(|b| b.height += 10); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 15000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 3500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 3500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR1), + Uint128::new(17000) + ); + + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR2), + Uint128::new(3500) + ); + + stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR2, 50); + stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 50); + + app.borrow_mut().update_block(|b| b.height += 10); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 2500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 6000); + + app.borrow_mut().update_block(|b| b.height = 101000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 49988000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 24994000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 24997500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR1), + Uint128::new(50005000) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR2), + Uint128::new(24997500) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR3), + Uint128::new(0) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, &reward_addr), + Uint128::new(24997500) + ); + + app.borrow_mut().update_block(|b| b.height = 200000); + + let reward_funding = vec![coin(200000000, denom)]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding, + } + })) + .unwrap(); + + fund_rewards_cw20( + &mut app, + &admin, + reward_token.clone(), + &reward_addr, + 200000000, + ); + + app.borrow_mut().update_block(|b| b.height = 300000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 74997500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR1), + Uint128::new(150005000) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR2), + Uint128::new(74997500) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR3), + Uint128::zero() + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, &reward_addr), + Uint128::new(74997500) + ); + + // Add more rewards + fund_rewards_cw20( + &mut app, + &admin, + reward_token.clone(), + &reward_addr, + 200000000, + ); + + app.borrow_mut().update_block(|b| b.height = 400000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 100000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 50000000); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 124997500); + + claim_rewards(&mut app, reward_addr.clone(), ADDR1); + claim_rewards(&mut app, reward_addr.clone(), ADDR2); + claim_rewards(&mut app, reward_addr.clone(), ADDR3); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR1), + Uint128::new(250005000) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR2), + Uint128::new(124997500) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, ADDR3), + Uint128::new(124997500) + ); + assert_eq!( + get_balance_cw20(&app, &reward_token, &reward_addr), + Uint128::zero() + ); + + app.borrow_mut().update_block(|b| b.height = 500000); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 0); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 0); + + app.borrow_mut().update_block(|b| b.height = 1000000); + unstake_tokens(&mut app, &staking_addr, ADDR3, 1); + stake_tokens(&mut app, &staking_addr, &cw20_addr, ADDR3, 1); +} + +#[test] +fn update_rewards() { + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); + let reward_funding = vec![coin(200000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + // Add funding to Addr1 to make sure it can't update staking contract + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: ADDR1.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + let reward_addr = setup_reward_contract( + &mut app, + staking_addr, + Denom::Native(denom.clone()), + admin.clone(), + ); + + app.borrow_mut().update_block(|b| b.height = 1000); + + let fund_msg = ExecuteMsg::Fund {}; + + // None admin cannot update rewards + let err: ContractError = app + .borrow_mut() + .execute_contract( + Addr::unchecked(ADDR1), + reward_addr.clone(), + &fund_msg, + &reward_funding, + ) + .unwrap_err() + .downcast() + .unwrap(); + + assert_eq!(err, ContractError::Ownable(OwnershipError::NotOwner)); + + let _res = app + .borrow_mut() + .execute_contract( + admin.clone(), + reward_addr.clone(), + &fund_msg, + &reward_funding, + ) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(2000)); + assert_eq!(res.reward.period_finish, 101000); + assert_eq!(res.reward.reward_duration, 100000); + + // Create new period after old period + app.borrow_mut().update_block(|b| b.height = 101000); + + let reward_funding = vec![coin(100000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + let _res = app + .borrow_mut() + .execute_contract( + admin.clone(), + reward_addr.clone(), + &fund_msg, + &reward_funding, + ) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(1000)); + assert_eq!(res.reward.period_finish, 201000); + assert_eq!(res.reward.reward_duration, 100000); + + // Add funds in middle of period returns an error + app.borrow_mut().update_block(|b| b.height = 151000); + + let reward_funding = vec![coin(200000000, denom)]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + let err = app + .borrow_mut() + .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) + .unwrap_err(); + assert_eq!( + ContractError::RewardPeriodNotFinished {}, + err.downcast().unwrap() + ); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(1000)); + assert_eq!(res.reward.period_finish, 201000); + assert_eq!(res.reward.reward_duration, 100000); +} + +#[test] +fn update_reward_duration() { + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); + + let reward_addr = setup_reward_contract( + &mut app, + staking_addr, + Denom::Native(denom.clone()), + admin.clone(), + ); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(0)); + assert_eq!(res.reward.period_finish, 0); + assert_eq!(res.reward.reward_duration, 100000); + + // Zero rewards durations are not allowed. + let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 0 }; + let err: ContractError = app + .borrow_mut() + .execute_contract(admin.clone(), reward_addr.clone(), &msg, &[]) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::ZeroRewardDuration {}); + + let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 10 }; + let _resp = app + .borrow_mut() + .execute_contract(admin.clone(), reward_addr.clone(), &msg, &[]) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(0)); + assert_eq!(res.reward.period_finish, 0); + assert_eq!(res.reward.reward_duration, 10); + + // Non-admin cannot update rewards + let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 100 }; + let err: ContractError = app + .borrow_mut() + .execute_contract(Addr::unchecked("non-admin"), reward_addr.clone(), &msg, &[]) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::Ownable(OwnershipError::NotOwner)); + + let reward_funding = vec![coin(1000, denom)]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + // Add funding to Addr1 to make sure it can't update staking contract + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: ADDR1.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + + app.borrow_mut().update_block(|b| b.height = 1000); + + let fund_msg = ExecuteMsg::Fund {}; + + let _res = app + .borrow_mut() + .execute_contract( + admin.clone(), + reward_addr.clone(), + &fund_msg, + &reward_funding, + ) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(100)); + assert_eq!(res.reward.period_finish, 1010); + assert_eq!(res.reward.reward_duration, 10); + + // Cannot update reward period before it finishes + let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 10 }; + let err: ContractError = app + .borrow_mut() + .execute_contract(admin.clone(), reward_addr.clone(), &msg, &[]) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::RewardPeriodNotFinished {}); + + // Update reward period once rewards are finished + app.borrow_mut().update_block(|b| b.height = 1010); + + let msg = ExecuteMsg::UpdateRewardDuration { new_duration: 100 }; + let _resp = app + .borrow_mut() + .execute_contract(admin, reward_addr.clone(), &msg, &[]) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(100)); + assert_eq!(res.reward.period_finish, 1010); + assert_eq!(res.reward.reward_duration, 100); +} + +#[test] +fn test_update_owner() { + let mut app = mock_app(); + let addr_owner = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); + + let reward_addr = setup_reward_contract( + &mut app, + staking_addr, + Denom::Native(denom), + addr_owner.clone(), + ); + + let owner = get_ownership(&app, &reward_addr).owner; + assert_eq!(owner, Some(addr_owner.clone())); + + // random addr cannot update owner + let msg = ExecuteMsg::UpdateOwnership(Action::TransferOwnership { + new_owner: ADDR1.to_string(), + expiry: None, + }); + let err: ContractError = app + .borrow_mut() + .execute_contract(Addr::unchecked(ADDR1), reward_addr.clone(), &msg, &[]) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::Ownable(OwnershipError::NotOwner)); + + // owner nominates a new onwer. + app.borrow_mut() + .execute_contract(addr_owner.clone(), reward_addr.clone(), &msg, &[]) + .unwrap(); + + let ownership = get_ownership(&app, &reward_addr); + assert_eq!( + ownership, + Ownership:: { + owner: Some(addr_owner), + pending_owner: Some(Addr::unchecked(ADDR1)), + pending_expiry: None, + } + ); + + // new owner accepts the nomination. + app.execute_contract( + Addr::unchecked(ADDR1), + reward_addr.clone(), + &ExecuteMsg::UpdateOwnership(Action::AcceptOwnership), + &[], + ) + .unwrap(); + + let ownership = get_ownership(&app, &reward_addr); + assert_eq!( + ownership, + Ownership:: { + owner: Some(Addr::unchecked(ADDR1)), + pending_owner: None, + pending_expiry: None, + } + ); + + // new owner renounces ownership. + app.execute_contract( + Addr::unchecked(ADDR1), + reward_addr.clone(), + &ExecuteMsg::UpdateOwnership(Action::RenounceOwnership), + &[], + ) + .unwrap(); + + let ownership = get_ownership(&app, &reward_addr); + assert_eq!( + ownership, + Ownership:: { + owner: None, + pending_owner: None, + pending_expiry: None, + } + ); +} + +#[test] +fn test_cannot_fund_with_wrong_coin_native() { + let mut app = mock_app(); + let owner = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); + + let reward_addr = setup_reward_contract( + &mut app, + staking_addr, + Denom::Native(denom.clone()), + owner.clone(), + ); + + app.borrow_mut().update_block(|b| b.height = 1000); + + // No funding + let fund_msg = ExecuteMsg::Fund {}; + + let err: ContractError = app + .borrow_mut() + .execute_contract(owner.clone(), reward_addr.clone(), &fund_msg, &[]) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::InvalidFunds {}); + + // Invalid funding + let invalid_funding = vec![coin(100, "invalid")]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: owner.to_string(), + amount: invalid_funding.clone(), + } + })) + .unwrap(); + + let fund_msg = ExecuteMsg::Fund {}; + + let err: ContractError = app + .borrow_mut() + .execute_contract( + owner.clone(), + reward_addr.clone(), + &fund_msg, + &invalid_funding, + ) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::InvalidFunds {}); + + // Extra funding + let extra_funding = vec![coin(100, denom), coin(100, "extra")]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: owner.to_string(), + amount: extra_funding.clone(), + } + })) + .unwrap(); + + let fund_msg = ExecuteMsg::Fund {}; + + let err: ContractError = app + .borrow_mut() + .execute_contract( + owner.clone(), + reward_addr.clone(), + &fund_msg, + &extra_funding, + ) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::InvalidFunds {}); + + // Cw20 funding fails + let cw20_token = instantiate_cw20( + &mut app, + vec![Cw20Coin { + address: OWNER.to_string(), + amount: Uint128::new(500000000), + }], + ); + let fund_sub_msg = to_json_binary(&ReceiveMsg::Fund {}).unwrap(); + let fund_msg = Cw20ExecuteMsg::Send { + contract: reward_addr.into_string(), + amount: Uint128::new(100), + msg: fund_sub_msg, + }; + let err: ContractError = app + .borrow_mut() + .execute_contract(owner, cw20_token, &fund_msg, &[]) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::InvalidCw20 {}); +} + +#[test] +fn test_cannot_fund_with_wrong_coin_cw20() { + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let _denom = "utest".to_string(); + let (staking_addr, _cw20_addr) = setup_staking_contract(&mut app, initial_balances); + let reward_token = instantiate_cw20( + &mut app, + vec![Cw20Coin { + address: OWNER.to_string(), + amount: Uint128::new(500000000), + }], + ); + let reward_addr = setup_reward_contract( + &mut app, + staking_addr, + Denom::Cw20(Addr::unchecked("dummy_cw20")), + admin.clone(), + ); + + app.borrow_mut().update_block(|b| b.height = 1000); + + // Test with invalid token + let fund_sub_msg = to_json_binary(&ReceiveMsg::Fund {}).unwrap(); + let fund_msg = Cw20ExecuteMsg::Send { + contract: reward_addr.clone().into_string(), + amount: Uint128::new(100), + msg: fund_sub_msg, + }; + let err: ContractError = app + .borrow_mut() + .execute_contract(admin.clone(), reward_token, &fund_msg, &[]) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::InvalidCw20 {}); + + // Test does not work when funded with native + let invalid_funding = vec![coin(100, "invalid")]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: invalid_funding.clone(), + } + })) + .unwrap(); + + let fund_msg = ExecuteMsg::Fund {}; + + let err: ContractError = app + .borrow_mut() + .execute_contract(admin, reward_addr, &fund_msg, &invalid_funding) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::InvalidFunds {}) +} + +#[test] +fn test_rewards_with_zero_staked() { + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + // Instantiate cw20 contract + let cw20_addr = instantiate_cw20(&mut app, initial_balances.clone()); + app.update_block(next_block); + // Instantiate staking contract + let staking_addr = instantiate_staking(&mut app, cw20_addr.clone(), None); + app.update_block(next_block); + let reward_funding = vec![coin(100000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + let reward_addr = setup_reward_contract( + &mut app, + staking_addr.clone(), + Denom::Native(denom), + admin.clone(), + ); + + app.borrow_mut().update_block(|b| b.height = 1000); + + let fund_msg = ExecuteMsg::Fund {}; + + let _res = app + .borrow_mut() + .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(1000)); + assert_eq!(res.reward.period_finish, 101000); + assert_eq!(res.reward.reward_duration, 100000); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 0); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 0); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 0); + + for coin in initial_balances { + stake_tokens( + &mut app, + &staking_addr, + &cw20_addr, + coin.address, + coin.amount.u128(), + ); + } + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 500); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 250); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 250); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 1000); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 500); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 500); +} + +#[test] +fn test_small_rewards() { + // This test was added due to a bug in the contract not properly paying out small reward + // amounts due to floor division + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, _) = setup_staking_contract(&mut app, initial_balances); + let reward_funding = vec![coin(1000000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + let reward_addr = + setup_reward_contract(&mut app, staking_addr, Denom::Native(denom), admin.clone()); + + app.borrow_mut().update_block(|b| b.height = 1000); + + let fund_msg = ExecuteMsg::Fund {}; + + let _res = app + .borrow_mut() + .execute_contract(admin, reward_addr.clone(), &fund_msg, &reward_funding) + .unwrap(); + + let res: InfoResponse = app + .borrow_mut() + .wrap() + .query_wasm_smart(&reward_addr, &QueryMsg::Info {}) + .unwrap(); + + assert_eq!(res.reward.reward_rate, Uint128::new(10)); + assert_eq!(res.reward.period_finish, 101000); + assert_eq!(res.reward.reward_duration, 100000); + + app.borrow_mut().update_block(next_block); + assert_pending_rewards(&mut app, &reward_addr, ADDR1, 5); + assert_pending_rewards(&mut app, &reward_addr, ADDR2, 2); + assert_pending_rewards(&mut app, &reward_addr, ADDR3, 2); +} + +#[test] +fn test_zero_reward_rate_failed() { + // This test is due to a bug when funder provides rewards config that results in less then 1 + // reward per block which rounds down to zer0 + let mut app = mock_app(); + let admin = Addr::unchecked(OWNER); + app.borrow_mut().update_block(|b| b.height = 0); + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, _) = setup_staking_contract(&mut app, initial_balances); + let reward_funding = vec![coin(10000, denom.clone())]; + app.sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: admin.to_string(), + amount: reward_funding.clone(), + } + })) + .unwrap(); + let reward_addr = + setup_reward_contract(&mut app, staking_addr, Denom::Native(denom), admin.clone()); + + app.borrow_mut().update_block(|b| b.height = 1000); + + let fund_msg = ExecuteMsg::Fund {}; + + let _res = app + .borrow_mut() + .execute_contract(admin, reward_addr, &fund_msg, &reward_funding) + .unwrap_err(); +} + +#[test] +fn test_migrate_from_v1() { + let mut app = App::default(); + + let v1_code = app.store_code(cw20_stake_external_rewards_v1_contract()); + let v2_code = app.store_code(cw20_stake_external_rewards_contract()); + + let initial_balances = vec![ + Cw20Coin { + address: ADDR1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: ADDR2.to_string(), + amount: Uint128::new(50), + }, + Cw20Coin { + address: ADDR3.to_string(), + amount: Uint128::new(50), + }, + ]; + let denom = "utest".to_string(); + let (staking_addr, _) = setup_staking_contract(&mut app, initial_balances); + + let rewards_addr = app + .instantiate_contract( + v1_code, + Addr::unchecked(OWNER), + &v1::msg::InstantiateMsg { + owner: Some(OWNER.to_string()), + manager: Some(ADDR1.to_string()), + staking_contract: staking_addr.into_string(), + reward_token: cw20_013::Denom::Native(denom), + reward_duration: 10000, + }, + &[], + "rewards".to_string(), + Some(OWNER.to_string()), + ) + .unwrap(); + + app.execute( + Addr::unchecked(OWNER), + WasmMsg::Migrate { + contract_addr: rewards_addr.to_string(), + new_code_id: v2_code, + msg: to_json_binary(&MigrateMsg::FromV1 {}).unwrap(), + } + .into(), + ) + .unwrap(); + + let ownership = get_ownership(&app, &rewards_addr); + assert_eq!( + ownership, + Ownership:: { + owner: Some(Addr::unchecked(OWNER)), + pending_owner: None, + pending_expiry: None, + } + ); + + let err: ContractError = app + .execute( + Addr::unchecked(OWNER), + WasmMsg::Migrate { + contract_addr: rewards_addr.to_string(), + new_code_id: v2_code, + msg: to_json_binary(&MigrateMsg::FromV1 {}).unwrap(), + } + .into(), + ) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(err, ContractError::AlreadyMigrated {}); +} diff --git a/contracts/staking/cw20-stake-reward-distributor/Cargo.toml b/contracts/staking/cw20-stake-reward-distributor/Cargo.toml index 75972d965..4ce8abc3a 100644 --- a/contracts/staking/cw20-stake-reward-distributor/Cargo.toml +++ b/contracts/staking/cw20-stake-reward-distributor/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "cw20-stake-reward-distributor" edition = "2018" -authors = ["Vernon Johnson , ekez "] +authors = [ + "Vernon Johnson , ekez ", +] description = "Distributes cw20 staking rewards." license = { workspace = true } repository = { workspace = true } @@ -24,11 +26,13 @@ cw-storage-plus = { workspace = true } cw2 = { workspace = true } cw20 = { workspace = true } cw-utils = { workspace = true } -cw20-base = { workspace = true, features = ["library"] } -cw20-stake = { workspace = true, features = ["library"]} +cw20-base = { workspace = true, features = ["library"] } +cw20-stake = { workspace = true, features = ["library"] } thiserror = { workspace = true } cw-ownable = { workspace = true } cw20-stake-reward-distributor-v1 = { workspace = true, features = ["library"] } [dev-dependencies] +cw20-stake-reward-distributor = { workspace = true } cw-multi-test = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/staking/cw20-stake-reward-distributor/src/tests.rs b/contracts/staking/cw20-stake-reward-distributor/src/tests.rs index 7b6bde529..231e4e33a 100644 --- a/contracts/staking/cw20-stake-reward-distributor/src/tests.rs +++ b/contracts/staking/cw20-stake-reward-distributor/src/tests.rs @@ -1,58 +1,24 @@ +use cosmwasm_std::{to_json_binary, Addr, Uint128, WasmMsg}; +use cw20::Cw20Coin; +use cw20_stake_reward_distributor_v1 as v1; +use cw_multi_test::{next_block, App, Executor}; +use cw_ownable::{Action, Expiration, Ownership, OwnershipError}; +use dao_testing::contracts::{ + cw20_base_contract, cw20_stake_contract, cw20_stake_reward_distributor_contract, + v1::cw20_stake_reward_distributor_v1_contract, +}; + use crate::{ msg::{ExecuteMsg, InfoResponse, InstantiateMsg, MigrateMsg, QueryMsg}, state::Config, - ContractError, }; - -use cw20_stake_reward_distributor_v1 as v1; - -use cosmwasm_std::{to_json_binary, Addr, Empty, Uint128, WasmMsg}; -use cw20::Cw20Coin; -use cw_multi_test::{next_block, App, Contract, ContractWrapper, Executor}; -use cw_ownable::{Action, Expiration, Ownership, OwnershipError}; +use cw20_stake_reward_distributor::ContractError; const OWNER: &str = "owner"; const OWNER2: &str = "owner2"; -pub fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn staking_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ); - Box::new(contract) -} - -fn distributor_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - -fn distributor_contract_v1() -> Box> { - let contract = ContractWrapper::new( - v1::contract::execute, - v1::contract::instantiate, - v1::contract::query, - ); - Box::new(contract) -} - fn instantiate_cw20(app: &mut App, initial_balances: Vec) -> Addr { - let cw20_id = app.store_code(cw20_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let msg = cw20_base::msg::InstantiateMsg { name: String::from("Test"), symbol: String::from("TEST"), @@ -67,7 +33,7 @@ fn instantiate_cw20(app: &mut App, initial_balances: Vec) -> Addr { } fn instantiate_staking(app: &mut App, cw20_addr: Addr) -> Addr { - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(cw20_stake_contract()); let msg = cw20_stake::msg::InstantiateMsg { owner: Some(OWNER.to_string()), token_address: cw20_addr.to_string(), @@ -85,7 +51,7 @@ fn instantiate_staking(app: &mut App, cw20_addr: Addr) -> Addr { } fn instantiate_distributor(app: &mut App, msg: InstantiateMsg) -> Addr { - let code_id = app.store_code(distributor_contract()); + let code_id = app.store_code(cw20_stake_reward_distributor_contract()); app.instantiate_contract( code_id, Addr::unchecked(OWNER), @@ -351,7 +317,7 @@ fn test_instantiate_invalid_addrs() { reward_token: "invalid_cw20".to_string(), }; - let code_id = app.store_code(distributor_contract()); + let code_id = app.store_code(cw20_stake_reward_distributor_contract()); let err: ContractError = app .instantiate_contract( code_id, @@ -689,8 +655,8 @@ fn test_migrate_from_v1() { ); let staking_addr = instantiate_staking(&mut app, cw20_addr.clone()); - let v1_code = app.store_code(distributor_contract_v1()); - let v2_code = app.store_code(distributor_contract()); + let v1_code = app.store_code(cw20_stake_reward_distributor_v1_contract()); + let v2_code = app.store_code(cw20_stake_reward_distributor_contract()); let distributor = app .instantiate_contract( v1_code, diff --git a/contracts/staking/cw20-stake/Cargo.toml b/contracts/staking/cw20-stake/Cargo.toml index 4417b372b..de04b0fb2 100644 --- a/contracts/staking/cw20-stake/Cargo.toml +++ b/contracts/staking/cw20-stake/Cargo.toml @@ -35,5 +35,7 @@ cw20-stake-v1 = { workspace = true, features = ["library"] } cw-utils-v1 = { workspace = true } [dev-dependencies] +cw20-stake = { workspace = true } cw-multi-test = { workspace = true } anyhow = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/staking/cw20-stake/src/tests.rs b/contracts/staking/cw20-stake/src/tests.rs index 147bd806f..72a1f1b73 100644 --- a/contracts/staking/cw20-stake/src/tests.rs +++ b/contracts/staking/cw20-stake/src/tests.rs @@ -1,12 +1,13 @@ use anyhow::Result as AnyResult; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; -use cosmwasm_std::{to_json_binary, Addr, Empty, MessageInfo, Uint128, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, MessageInfo, Uint128, WasmMsg}; use cw20::Cw20Coin; use cw_controllers::{Claim, ClaimsResponse}; -use cw_multi_test::{next_block, App, AppResponse, Contract, ContractWrapper, Executor}; +use cw_multi_test::{next_block, App, AppResponse, Executor}; use cw_ownable::{Action, Ownership, OwnershipError}; use cw_utils::Duration; use cw_utils::Expiration::AtHeight; +use dao_testing::contracts::{cw20_base_contract, cw20_stake_contract, v1::cw20_stake_v1_contract}; use dao_voting::duration::UnstakingDurationError; use std::borrow::BorrowMut; @@ -16,7 +17,7 @@ use crate::msg::{ TotalStakedAtHeightResponse, TotalValueResponse, }; use crate::state::{Config, MAX_CLAIMS}; -use crate::ContractError; +use cw20_stake::ContractError; use cw20_stake_v1 as v1; @@ -26,35 +27,6 @@ const ADDR3: &str = "addr0003"; const ADDR4: &str = "addr0004"; const OWNER: &str = "owner"; -fn contract_staking() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - -fn contract_staking_v1() -> Box> { - let contract = ContractWrapper::new( - v1::contract::execute, - v1::contract::instantiate, - v1::contract::query, - ) - .with_migrate(v1::contract::migrate); - Box::new(contract) -} - -fn contract_cw20() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - fn mock_app() -> App { App::default() } @@ -72,7 +44,7 @@ fn get_balance, U: Into>( } fn instantiate_cw20(app: &mut App, initial_balances: Vec) -> Addr { - let cw20_id = app.store_code(contract_cw20()); + let cw20_id = app.store_code(cw20_base_contract()); let msg = cw20_base::msg::InstantiateMsg { name: String::from("Test"), symbol: String::from("TEST"), @@ -87,7 +59,7 @@ fn instantiate_cw20(app: &mut App, initial_balances: Vec) -> Addr { } fn instantiate_staking(app: &mut App, cw20: Addr, unstaking_duration: Option) -> Addr { - let staking_code_id = app.store_code(contract_staking()); + let staking_code_id = app.store_code(cw20_stake_contract()); let msg = crate::msg::InstantiateMsg { owner: Some(OWNER.to_string()), token_address: cw20.to_string(), @@ -1127,8 +1099,8 @@ fn test_migrate_from_v1() { }], ); - let v1_code = app.store_code(contract_staking_v1()); - let v2_code = app.store_code(contract_staking()); + let v1_code = app.store_code(cw20_stake_v1_contract()); + let v2_code = app.store_code(cw20_stake_contract()); let staking = app .instantiate_contract( diff --git a/contracts/test/dao-proposal-hook-counter/Cargo.toml b/contracts/test/dao-proposal-hook-counter/Cargo.toml index 395fb338a..9ac82759a 100644 --- a/contracts/test/dao-proposal-hook-counter/Cargo.toml +++ b/contracts/test/dao-proposal-hook-counter/Cargo.toml @@ -35,3 +35,4 @@ dao-interface = { workspace = true } dao-dao-core = { workspace = true } dao-proposal-single = { workspace = true } cw-multi-test = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/test/dao-proposal-hook-counter/src/tests.rs b/contracts/test/dao-proposal-hook-counter/src/tests.rs index 611c22dad..e28ed1b34 100644 --- a/contracts/test/dao-proposal-hook-counter/src/tests.rs +++ b/contracts/test/dao-proposal-hook-counter/src/tests.rs @@ -1,10 +1,13 @@ -use cosmwasm_std::{to_json_binary, Addr, Empty, Uint128}; +use cosmwasm_std::{to_json_binary, Addr, Uint128}; use cw20::Cw20Coin; use cw_hooks::HooksResponse; -use cw_multi_test::{App, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, Executor}; use dao_interface::state::ProposalModule; use dao_interface::state::{Admin, ModuleInstantiateInfo}; - +use dao_testing::contracts::{ + cw20_base_contract, dao_dao_core_contract, dao_proposal_hook_counter_contract, + dao_proposal_single_contract, dao_voting_cw20_balance_contract, +}; use dao_voting::{ pre_propose::PreProposeInfo, threshold::{PercentageThreshold, Threshold}, @@ -17,54 +20,6 @@ use dao_voting::proposal::SingleChoiceProposeMsg as ProposeMsg; const CREATOR_ADDR: &str = "creator"; -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn single_govmod_contract() -> Box> { - let contract = ContractWrapper::new( - dao_proposal_single::contract::execute, - dao_proposal_single::contract::instantiate, - dao_proposal_single::contract::query, - ) - .with_reply(dao_proposal_single::contract::reply); - Box::new(contract) -} - -fn cw20_balances_voting() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_balance::contract::execute, - dao_voting_cw20_balance::contract::instantiate, - dao_voting_cw20_balance::contract::query, - ) - .with_reply(dao_voting_cw20_balance::contract::reply); - Box::new(contract) -} - -fn cw_gov_contract() -> Box> { - let contract = ContractWrapper::new( - dao_dao_core::contract::execute, - dao_dao_core::contract::instantiate, - dao_dao_core::contract::query, - ) - .with_reply(dao_dao_core::contract::reply); - Box::new(contract) -} - -fn counters_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ); - Box::new(contract) -} - fn instantiate_governance( app: &mut App, code_id: u64, @@ -87,9 +42,9 @@ fn instantiate_with_default_governance( msg: dao_proposal_single::msg::InstantiateMsg, initial_balances: Option>, ) -> Addr { - let cw20_id = app.store_code(cw20_contract()); - let governance_id = app.store_code(cw_gov_contract()); - let votemod_id = app.store_code(cw20_balances_voting()); + let cw20_id = app.store_code(cw20_base_contract()); + let governance_id = app.store_code(dao_dao_core_contract()); + let votemod_id = app.store_code(dao_voting_cw20_balance_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -140,8 +95,8 @@ fn instantiate_with_default_governance( #[test] fn test_counters() { let mut app = App::default(); - let govmod_id = app.store_code(single_govmod_contract()); - let counters_id = app.store_code(counters_contract()); + let govmod_id = app.store_code(dao_proposal_single_contract()); + let counters_id = app.store_code(dao_proposal_hook_counter_contract()); let threshold = Threshold::AbsolutePercentage { percentage: PercentageThreshold::Majority {}, diff --git a/contracts/test/dao-voting-cw20-balance/Cargo.toml b/contracts/test/dao-voting-cw20-balance/Cargo.toml index f126b6840..94d1f0cb0 100644 --- a/contracts/test/dao-voting-cw20-balance/Cargo.toml +++ b/contracts/test/dao-voting-cw20-balance/Cargo.toml @@ -26,7 +26,8 @@ cw-utils = { workspace = true } thiserror = { workspace = true } dao-dao-macros = { workspace = true } dao-interface = { workspace = true } -cw20-base = { workspace = true, features = ["library"] } +cw20-base = { workspace = true, features = ["library"] } [dev-dependencies] cw-multi-test = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/test/dao-voting-cw20-balance/src/tests.rs b/contracts/test/dao-voting-cw20-balance/src/tests.rs index 4560fd5ea..79d1a6cd4 100644 --- a/contracts/test/dao-voting-cw20-balance/src/tests.rs +++ b/contracts/test/dao-voting-cw20-balance/src/tests.rs @@ -1,33 +1,15 @@ -use cosmwasm_std::{Addr, Empty, Uint128}; +use cosmwasm_std::{Addr, Uint128}; use cw2::ContractVersion; use cw20::{Cw20Coin, MinterResponse, TokenInfoResponse}; -use cw_multi_test::{App, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, Executor}; use dao_interface::voting::{InfoResponse, VotingPowerAtHeightResponse}; +use dao_testing::contracts::{cw20_base_contract, dao_voting_cw20_balance_contract}; use crate::msg::{InstantiateMsg, QueryMsg}; const DAO_ADDR: &str = "dao"; const CREATOR_ADDR: &str = "creator"; -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn balance_voting_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply); - Box::new(contract) -} - fn instantiate_voting(app: &mut App, voting_id: u64, msg: InstantiateMsg) -> Addr { app.instantiate_contract( voting_id, @@ -44,8 +26,8 @@ fn instantiate_voting(app: &mut App, voting_id: u64, msg: InstantiateMsg) -> Add #[should_panic(expected = "Initial governance token balances must not be empty")] fn test_instantiate_zero_supply() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(balance_voting_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); instantiate_voting( &mut app, voting_id, @@ -70,8 +52,8 @@ fn test_instantiate_zero_supply() { #[should_panic(expected = "Initial governance token balances must not be empty")] fn test_instantiate_no_balances() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(balance_voting_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); instantiate_voting( &mut app, voting_id, @@ -92,8 +74,8 @@ fn test_instantiate_no_balances() { #[test] fn test_contract_info() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(balance_voting_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); let voting_addr = instantiate_voting( &mut app, @@ -132,8 +114,8 @@ fn test_contract_info() { #[test] fn test_new_cw20() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(balance_voting_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); let voting_addr = instantiate_voting( &mut app, @@ -257,8 +239,8 @@ fn test_new_cw20() { #[test] fn test_existing_cw20() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(balance_voting_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_balance_contract()); let token_addr = app .instantiate_contract( diff --git a/contracts/voting/dao-voting-cw20-staked/Cargo.toml b/contracts/voting/dao-voting-cw20-staked/Cargo.toml index 4eae84a64..8a3857f54 100644 --- a/contracts/voting/dao-voting-cw20-staked/Cargo.toml +++ b/contracts/voting/dao-voting-cw20-staked/Cargo.toml @@ -32,3 +32,4 @@ dao-voting = { workspace = true } [dev-dependencies] cw-multi-test = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/voting/dao-voting-cw20-staked/src/tests.rs b/contracts/voting/dao-voting-cw20-staked/src/tests.rs index 0022f98ed..1ba100fb0 100644 --- a/contracts/voting/dao-voting-cw20-staked/src/tests.rs +++ b/contracts/voting/dao-voting-cw20-staked/src/tests.rs @@ -1,11 +1,14 @@ use cosmwasm_std::{ testing::{mock_dependencies, mock_env}, - to_json_binary, Addr, CosmosMsg, Decimal, Empty, Uint128, WasmMsg, + to_json_binary, Addr, CosmosMsg, Decimal, Uint128, WasmMsg, }; use cw2::ContractVersion; use cw20::{BalanceResponse, Cw20Coin, MinterResponse, TokenInfoResponse}; -use cw_multi_test::{next_block, App, Contract, ContractWrapper, Executor}; +use cw_multi_test::{next_block, App, Executor}; use dao_interface::voting::{InfoResponse, IsActiveResponse, VotingPowerAtHeightResponse}; +use dao_testing::contracts::{ + cw20_base_contract, cw20_stake_contract, dao_voting_cw20_staked_contract, +}; use dao_voting::threshold::{ActiveThreshold, ActiveThresholdResponse}; use crate::{ @@ -16,35 +19,6 @@ use crate::{ const DAO_ADDR: &str = "dao"; const CREATOR_ADDR: &str = "creator"; -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -fn staking_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ); - Box::new(contract) -} - -fn staked_balance_voting_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - fn instantiate_voting(app: &mut App, voting_id: u64, msg: InstantiateMsg) -> Addr { app.instantiate_contract( voting_id, @@ -71,9 +45,9 @@ fn stake_tokens(app: &mut App, staking_addr: Addr, cw20_addr: Addr, sender: &str #[should_panic(expected = "Initial governance token balances must not be empty")] fn test_instantiate_zero_supply() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); instantiate_voting( &mut app, voting_id, @@ -102,9 +76,9 @@ fn test_instantiate_zero_supply() { #[should_panic(expected = "Initial governance token balances must not be empty")] fn test_instantiate_no_balances() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); instantiate_voting( &mut app, voting_id, @@ -130,9 +104,9 @@ fn test_instantiate_no_balances() { #[should_panic(expected = "Active threshold count must be greater than zero")] fn test_instantiate_zero_active_threshold_count() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); instantiate_voting( &mut app, voting_id, @@ -162,9 +136,9 @@ fn test_instantiate_zero_active_threshold_count() { #[test] fn test_contract_info() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = instantiate_voting( &mut app, @@ -213,9 +187,9 @@ fn test_contract_info() { #[test] fn test_new_cw20() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = instantiate_voting( &mut app, @@ -374,9 +348,9 @@ fn test_new_cw20() { #[test] fn test_existing_cw20_new_staking() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_id = app.store_code(cw20_stake_contract()); let token_addr = app .instantiate_contract( @@ -525,9 +499,9 @@ fn test_existing_cw20_new_staking() { #[test] fn test_existing_cw20_existing_staking() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_id = app.store_code(cw20_stake_contract()); let token_addr = app .instantiate_contract( @@ -726,9 +700,9 @@ fn test_existing_cw20_existing_staking() { #[test] fn test_different_heights() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_id = app.store_code(cw20_stake_contract()); let token_addr = app .instantiate_contract( @@ -926,9 +900,9 @@ fn test_different_heights() { #[test] fn test_active_threshold_absolute_count() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = instantiate_voting( &mut app, @@ -986,9 +960,9 @@ fn test_active_threshold_absolute_count() { #[test] fn test_active_threshold_percent() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = instantiate_voting( &mut app, @@ -1046,9 +1020,9 @@ fn test_active_threshold_percent() { #[test] fn test_active_threshold_percent_rounds_up() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = instantiate_voting( &mut app, @@ -1121,9 +1095,9 @@ fn test_active_threshold_percent_rounds_up() { #[test] fn test_active_threshold_none() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = instantiate_voting( &mut app, @@ -1159,9 +1133,9 @@ fn test_active_threshold_none() { #[test] fn test_update_active_threshold() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = instantiate_voting( &mut app, @@ -1227,9 +1201,9 @@ fn test_update_active_threshold() { #[should_panic(expected = "Active threshold percentage must be greater than 0 and less than 1")] fn test_active_threshold_percentage_gt_100() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); instantiate_voting( &mut app, @@ -1261,9 +1235,9 @@ fn test_active_threshold_percentage_gt_100() { #[should_panic(expected = "Active threshold percentage must be greater than 0 and less than 1")] fn test_active_threshold_percentage_lte_0() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); instantiate_voting( &mut app, @@ -1295,9 +1269,9 @@ fn test_active_threshold_percentage_lte_0() { #[should_panic(expected = "Absolute count threshold cannot be greater than the total token supply")] fn test_active_threshold_absolute_count_invalid() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); instantiate_voting( &mut app, @@ -1328,9 +1302,9 @@ fn test_active_threshold_absolute_count_invalid() { #[test] fn test_migrate() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); - let voting_id = app.store_code(staked_balance_voting_contract()); - let staking_contract_id = app.store_code(staking_contract()); + let cw20_id = app.store_code(cw20_base_contract()); + let voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let staking_contract_id = app.store_code(cw20_stake_contract()); let voting_addr = app .instantiate_contract( diff --git a/contracts/voting/dao-voting-cw4/Cargo.toml b/contracts/voting/dao-voting-cw4/Cargo.toml index 55c671560..9120acf99 100644 --- a/contracts/voting/dao-voting-cw4/Cargo.toml +++ b/contracts/voting/dao-voting-cw4/Cargo.toml @@ -29,4 +29,6 @@ cw4 = { workspace = true } cw4-group = { workspace = true } [dev-dependencies] +dao-voting-cw4 = { workspace = true } cw-multi-test = { workspace = true } +dao-testing = { workspace = true } diff --git a/contracts/voting/dao-voting-cw4/src/tests.rs b/contracts/voting/dao-voting-cw4/src/tests.rs index 769c53c4c..9ada195e2 100644 --- a/contracts/voting/dao-voting-cw4/src/tests.rs +++ b/contracts/voting/dao-voting-cw4/src/tests.rs @@ -1,18 +1,19 @@ use cosmwasm_std::{ testing::{mock_dependencies, mock_env}, - to_json_binary, Addr, CosmosMsg, Empty, Uint128, WasmMsg, + to_json_binary, Addr, CosmosMsg, Uint128, WasmMsg, }; use cw2::ContractVersion; -use cw_multi_test::{next_block, App, Contract, ContractWrapper, Executor}; +use cw_multi_test::{next_block, App, Executor}; use dao_interface::voting::{ InfoResponse, TotalPowerAtHeightResponse, VotingPowerAtHeightResponse, }; +use dao_testing::contracts::{cw4_group_contract, dao_voting_cw4_contract}; use crate::{ contract::{migrate, CONTRACT_NAME, CONTRACT_VERSION}, msg::{GroupContract, InstantiateMsg, MigrateMsg, QueryMsg}, - ContractError, }; +use dao_voting_cw4::ContractError; const DAO_ADDR: &str = "dao"; const ADDR1: &str = "addr1"; @@ -20,26 +21,6 @@ const ADDR2: &str = "addr2"; const ADDR3: &str = "addr3"; const ADDR4: &str = "addr4"; -fn cw4_contract() -> Box> { - let contract = ContractWrapper::new( - cw4_group::contract::execute, - cw4_group::contract::instantiate, - cw4_group::contract::query, - ); - Box::new(contract) -} - -fn voting_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - fn instantiate_voting(app: &mut App, voting_id: u64, msg: InstantiateMsg) -> Addr { app.instantiate_contract( voting_id, @@ -53,8 +34,8 @@ fn instantiate_voting(app: &mut App, voting_id: u64, msg: InstantiateMsg) -> Add } fn setup_test_case(app: &mut App) -> Addr { - let cw4_id = app.store_code(cw4_contract()); - let voting_id = app.store_code(voting_contract()); + let cw4_id = app.store_code(cw4_group_contract()); + let voting_id = app.store_code(dao_voting_cw4_contract()); let members = vec![ cw4::Member { @@ -93,8 +74,8 @@ fn test_instantiate() { let _voting_addr = setup_test_case(&mut app); // Instantiate with no members, error - let voting_id = app.store_code(voting_contract()); - let cw4_id = app.store_code(cw4_contract()); + let voting_id = app.store_code(dao_voting_cw4_contract()); + let cw4_id = app.store_code(cw4_group_contract()); let msg = InstantiateMsg { group_contract: GroupContract::New { cw4_group_code_id: cw4_id, @@ -148,8 +129,8 @@ fn test_instantiate() { pub fn test_instantiate_existing_contract() { let mut app = App::default(); - let voting_id = app.store_code(voting_contract()); - let cw4_id = app.store_code(cw4_contract()); + let voting_id = app.store_code(dao_voting_cw4_contract()); + let cw4_id = app.store_code(cw4_group_contract()); // Fail with no members. let cw4_addr = app @@ -573,8 +554,8 @@ fn test_migrate() { ]; // Instantiate with no members, error - let voting_id = app.store_code(voting_contract()); - let cw4_id = app.store_code(cw4_contract()); + let voting_id = app.store_code(dao_voting_cw4_contract()); + let cw4_id = app.store_code(cw4_group_contract()); let msg = InstantiateMsg { group_contract: GroupContract::New { cw4_group_code_id: cw4_id, @@ -631,8 +612,8 @@ fn test_migrate() { fn test_duplicate_member() { let mut app = App::default(); let _voting_addr = setup_test_case(&mut app); - let voting_id = app.store_code(voting_contract()); - let cw4_id = app.store_code(cw4_contract()); + let voting_id = app.store_code(dao_voting_cw4_contract()); + let cw4_id = app.store_code(cw4_group_contract()); // Instantiate with members but have a duplicate // Total weight is actually 69 but ADDR3 appears twice. let msg = InstantiateMsg { diff --git a/contracts/voting/dao-voting-cw721-staked/src/testing/mod.rs b/contracts/voting/dao-voting-cw721-staked/src/testing/mod.rs index c454212c4..aaeeaf8d7 100644 --- a/contracts/voting/dao-voting-cw721-staked/src/testing/mod.rs +++ b/contracts/voting/dao-voting-cw721-staked/src/testing/mod.rs @@ -18,7 +18,7 @@ mod test_tube_env; use cosmwasm_std::Addr; use cw_multi_test::{App, Executor}; use cw_utils::Duration; -use dao_testing::contracts::cw721_staked_voting_contract; +use dao_testing::contracts::dao_voting_cw721_staked_contract; use crate::msg::{InstantiateMsg, NftContract}; @@ -35,7 +35,7 @@ pub(crate) struct CommonTest { pub(crate) fn setup_test(unstaking_duration: Option) -> CommonTest { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let nft = instantiate_cw721_base(&mut app, CREATOR_ADDR, CREATOR_ADDR); let module = app diff --git a/contracts/voting/dao-voting-cw721-staked/src/testing/tests.rs b/contracts/voting/dao-voting-cw721-staked/src/testing/tests.rs index 7126bd904..1ce42119d 100644 --- a/contracts/voting/dao-voting-cw721-staked/src/testing/tests.rs +++ b/contracts/voting/dao-voting-cw721-staked/src/testing/tests.rs @@ -6,7 +6,7 @@ use cw_multi_test::{next_block, App, BankSudo, Executor, SudoMsg}; use cw_utils::Duration; use dao_interface::voting::IsActiveResponse; use dao_testing::contracts::{ - cw721_base_contract, cw721_staked_voting_contract, dao_test_custom_factory, + cw721_base_contract, dao_test_custom_factory_contract, dao_voting_cw721_staked_contract, }; use dao_voting::threshold::{ActiveThreshold, ActiveThresholdResponse}; @@ -34,7 +34,7 @@ use super::{ #[test] fn test_instantiate_with_new_cw721_collection() -> anyhow::Result<()> { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); let module_addr = app @@ -421,7 +421,7 @@ fn test_add_remove_hooks() -> anyhow::Result<()> { #[test] fn test_instantiate_with_invalid_duration_fails() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); let err = app @@ -462,7 +462,7 @@ fn test_instantiate_with_invalid_duration_fails() { fn test_instantiate_zero_active_threshold_count() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); app.instantiate_contract( module_id, @@ -502,7 +502,7 @@ fn test_instantiate_zero_active_threshold_count() { fn test_instantiate_invalid_active_threshold_count_new_nft() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); app.instantiate_contract( module_id, @@ -541,7 +541,7 @@ fn test_instantiate_invalid_active_threshold_count_new_nft() { #[should_panic(expected = "Absolute count threshold cannot be greater than the total token supply")] fn test_instantiate_invalid_active_threshold_count_existing_nft() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_addr = instantiate_cw721_base(&mut app, CREATOR_ADDR, CREATOR_ADDR); app.instantiate_contract( @@ -567,7 +567,7 @@ fn test_instantiate_invalid_active_threshold_count_existing_nft() { fn test_active_threshold_absolute_count() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let voting_addr = app .instantiate_contract( @@ -647,7 +647,7 @@ fn test_active_threshold_absolute_count() { fn test_active_threshold_percent() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let voting_addr = app .instantiate_contract( @@ -708,7 +708,7 @@ fn test_active_threshold_percent() { fn test_active_threshold_percent_rounds_up() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let voting_addr = app .instantiate_contract( @@ -810,7 +810,7 @@ fn test_active_threshold_percent_rounds_up() { fn test_update_active_threshold() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let voting_addr = app .instantiate_contract( @@ -887,7 +887,7 @@ fn test_update_active_threshold() { fn test_active_threshold_percentage_gt_100() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); app.instantiate_contract( module_id, @@ -929,7 +929,7 @@ fn test_active_threshold_percentage_gt_100() { fn test_active_threshold_percentage_lte_0() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); app.instantiate_contract( module_id, @@ -967,7 +967,7 @@ fn test_active_threshold_percentage_lte_0() { #[test] fn test_invalid_instantiate_msg() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); let err = app @@ -1006,7 +1006,7 @@ fn test_invalid_instantiate_msg() { #[test] fn test_invalid_initial_nft_msg() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); let err = app @@ -1045,7 +1045,7 @@ fn test_invalid_initial_nft_msg() { #[test] fn test_invalid_initial_nft_msg_wrong_absolute_count() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); let err = app @@ -1096,7 +1096,7 @@ fn test_invalid_initial_nft_msg_wrong_absolute_count() { fn test_no_initial_nfts_fails() { let mut app = App::default(); let cw721_id = app.store_code(cw721_base_contract()); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let err = app .instantiate_contract( @@ -1133,9 +1133,9 @@ fn test_no_initial_nfts_fails() { #[test] fn test_factory() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); - let factory_id = app.store_code(dao_test_custom_factory()); + let factory_id = app.store_code(dao_test_custom_factory_contract()); // Instantiate factory let factory_addr = app @@ -1186,9 +1186,9 @@ fn test_factory() { #[test] fn test_factory_with_funds_pass_through() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); - let factory_id = app.store_code(dao_test_custom_factory()); + let factory_id = app.store_code(dao_test_custom_factory_contract()); // Mint some tokens to creator app.sudo(SudoMsg::Bank(BankSudo::Mint { @@ -1307,7 +1307,7 @@ fn test_factory_with_funds_pass_through() { #[should_panic(expected = "Factory message must serialize to WasmMsg::Execute")] fn test_unsupported_factory_msg() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let cw721_id = app.store_code(cw721_base_contract()); // Instantiate using factory succeeds @@ -1352,9 +1352,9 @@ fn test_unsupported_factory_msg() { )] fn test_factory_wrong_callback() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let _cw721_id = app.store_code(cw721_base_contract()); - let factory_id = app.store_code(dao_test_custom_factory()); + let factory_id = app.store_code(dao_test_custom_factory_contract()); // Instantiate factory let factory_addr = app @@ -1400,9 +1400,9 @@ fn test_factory_wrong_callback() { #[should_panic(expected = "Invalid reply from sub-message: Missing reply data")] fn test_factory_no_callback() { let mut app = App::default(); - let module_id = app.store_code(cw721_staked_voting_contract()); + let module_id = app.store_code(dao_voting_cw721_staked_contract()); let _cw721_id = app.store_code(cw721_base_contract()); - let factory_id = app.store_code(dao_test_custom_factory()); + let factory_id = app.store_code(dao_test_custom_factory_contract()); // Instantiate factory let factory_addr = app diff --git a/contracts/voting/dao-voting-onft-staked/src/testing/mod.rs b/contracts/voting/dao-voting-onft-staked/src/testing/mod.rs index 487a4dde0..30012f8fa 100644 --- a/contracts/voting/dao-voting-onft-staked/src/testing/mod.rs +++ b/contracts/voting/dao-voting-onft-staked/src/testing/mod.rs @@ -9,7 +9,7 @@ use app::OmniflixApp; use cosmwasm_std::Addr; use cw_multi_test::Executor; use cw_utils::Duration; -use dao_testing::contracts::onft_staked_voting_contract; +use dao_testing::contracts::dao_voting_onft_staked_contract; use dao_voting::threshold::ActiveThreshold; use crate::msg::{InstantiateMsg, OnftCollection}; @@ -33,7 +33,7 @@ pub(crate) fn setup_test( active_threshold: Option, ) -> CommonTest { let mut app = OmniflixApp::new(); - let module_id = app.store_code(onft_staked_voting_contract()); + let module_id = app.store_code(dao_voting_onft_staked_contract()); let nft = create_onft_collection(&mut app, "nft", DAO, DAO); let module = app diff --git a/contracts/voting/dao-voting-token-staked/src/tests/multitest/tests.rs b/contracts/voting/dao-voting-token-staked/src/tests/multitest/tests.rs index 90b4fab28..31133e300 100644 --- a/contracts/voting/dao-voting-token-staked/src/tests/multitest/tests.rs +++ b/contracts/voting/dao-voting-token-staked/src/tests/multitest/tests.rs @@ -5,16 +5,17 @@ use crate::msg::{ }; use crate::state::Config; use cosmwasm_std::testing::{mock_dependencies, mock_env}; -use cosmwasm_std::{coins, Addr, Coin, Decimal, Empty, Uint128}; +use cosmwasm_std::{coins, Addr, Coin, Decimal, Uint128}; use cw_controllers::ClaimsResponse; -use cw_multi_test::{ - next_block, App, AppResponse, BankSudo, Contract, ContractWrapper, Executor, SudoMsg, -}; +use cw_multi_test::{next_block, App, AppResponse, BankSudo, Executor, SudoMsg}; use cw_utils::Duration; use dao_interface::voting::{ DenomResponse, InfoResponse, IsActiveResponse, TotalPowerAtHeightResponse, VotingPowerAtHeightResponse, }; +use dao_testing::contracts::{ + dao_proposal_hook_counter_contract, dao_voting_token_staked_contract, +}; use dao_voting::threshold::{ActiveThreshold, ActiveThresholdResponse}; const DAO_ADDR: &str = "dao"; @@ -24,26 +25,6 @@ const DENOM: &str = "ujuno"; const INVALID_DENOM: &str = "uinvalid"; const ODD_DENOM: &str = "uodd"; -fn hook_counter_contract() -> Box> { - let contract = ContractWrapper::new( - dao_proposal_hook_counter::contract::execute, - dao_proposal_hook_counter::contract::instantiate, - dao_proposal_hook_counter::contract::query, - ); - Box::new(contract) -} - -fn staking_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ) - .with_reply(crate::contract::reply) - .with_migrate(crate::contract::migrate); - Box::new(contract) -} - fn mock_app() -> App { let mut app = App::default(); app.sudo(SudoMsg::Bank(BankSudo::Mint { @@ -205,7 +186,7 @@ fn get_balance(app: &mut App, address: &str, denom: &str) -> Uint128 { fn test_instantiate_existing() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); // Populated fields instantiate_staking( &mut app, @@ -249,7 +230,7 @@ fn test_instantiate_existing() { fn test_instantiate_invalid_unstaking_duration_height() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); // Populated fields instantiate_staking( @@ -272,7 +253,7 @@ fn test_instantiate_invalid_unstaking_duration_height() { fn test_instantiate_invalid_unstaking_duration_time() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); // Populated fields with height instantiate_staking( @@ -295,7 +276,7 @@ fn test_instantiate_invalid_unstaking_duration_time() { fn test_stake_invalid_denom() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -316,7 +297,7 @@ fn test_stake_invalid_denom() { fn test_stake_valid_denom() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -339,7 +320,7 @@ fn test_stake_valid_denom() { fn test_unstake_none_staked() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -360,7 +341,7 @@ fn test_unstake_none_staked() { fn test_unstake_zero_tokens() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -381,7 +362,7 @@ fn test_unstake_zero_tokens() { fn test_unstake_invalid_balance() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -406,7 +387,7 @@ fn test_unstake_invalid_balance() { fn test_unstake() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -443,7 +424,7 @@ fn test_unstake() { fn test_unstake_no_unstaking_duration() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -482,7 +463,7 @@ fn test_unstake_no_unstaking_duration() { fn test_claim_no_claims() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -503,7 +484,7 @@ fn test_claim_no_claims() { fn test_claim_claim_not_reached() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -532,7 +513,7 @@ fn test_claim_claim_not_reached() { fn test_claim() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -585,7 +566,7 @@ fn test_claim() { fn test_update_config_invalid_sender() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -606,7 +587,7 @@ fn test_update_config_invalid_sender() { fn test_update_config_as_owner() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -636,7 +617,7 @@ fn test_update_config_as_owner() { fn test_update_config_invalid_duration() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -657,7 +638,7 @@ fn test_update_config_invalid_duration() { fn test_query_dao() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -679,7 +660,7 @@ fn test_query_dao() { fn test_query_info() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -701,7 +682,7 @@ fn test_query_info() { fn test_query_claims() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -739,7 +720,7 @@ fn test_query_claims() { fn test_query_get_config() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -765,7 +746,7 @@ fn test_query_get_config() { fn test_voting_power_queries() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -873,7 +854,7 @@ fn test_voting_power_queries() { fn test_query_list_stakers() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -960,7 +941,7 @@ fn test_query_list_stakers() { fn test_instantiate_zero_active_threshold_count() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); instantiate_staking( &mut app, staking_id, @@ -980,7 +961,7 @@ fn test_instantiate_zero_active_threshold_count() { fn test_active_threshold_absolute_count() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, @@ -1019,7 +1000,7 @@ fn test_active_threshold_absolute_count() { fn test_active_threshold_percent() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -1057,7 +1038,7 @@ fn test_active_threshold_percent() { fn test_active_threshold_percent_rounds_up() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -1104,7 +1085,7 @@ fn test_active_threshold_percent_rounds_up() { fn test_active_threshold_none() { let mut app = App::default(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -1129,7 +1110,7 @@ fn test_active_threshold_none() { fn test_update_active_threshold() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, staking_id, @@ -1181,7 +1162,7 @@ fn test_update_active_threshold() { fn test_active_threshold_percentage_gt_100() { let mut app = App::default(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); instantiate_staking( &mut app, staking_id, @@ -1204,7 +1185,7 @@ fn test_active_threshold_percentage_gt_100() { fn test_active_threshold_percentage_lte_0() { let mut app = App::default(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); instantiate_staking( &mut app, staking_id, @@ -1225,7 +1206,7 @@ fn test_active_threshold_percentage_lte_0() { fn test_active_threshold_absolute_count_invalid() { let mut app = App::default(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); instantiate_staking( &mut app, staking_id, @@ -1245,7 +1226,7 @@ fn test_active_threshold_absolute_count_invalid() { fn test_add_remove_hooks() { let mut app = App::default(); - let staking_id = app.store_code(staking_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); let addr = instantiate_staking( &mut app, @@ -1307,8 +1288,8 @@ fn test_add_remove_hooks() { fn test_staking_hooks() { let mut app = mock_app(); - let staking_id = app.store_code(staking_contract()); - let hook_id = app.store_code(hook_counter_contract()); + let staking_id = app.store_code(dao_voting_token_staked_contract()); + let hook_id = app.store_code(dao_proposal_hook_counter_contract()); let hook = app .instantiate_contract( diff --git a/packages/cw-denom/Cargo.toml b/packages/cw-denom/Cargo.toml index dfb3b543d..8a0589efc 100644 --- a/packages/cw-denom/Cargo.toml +++ b/packages/cw-denom/Cargo.toml @@ -17,3 +17,4 @@ cw20 = { workspace = true } [dev-dependencies] cw20-base = { workspace = true } cw-multi-test = { workspace = true } +dao-testing = { workspace = true } diff --git a/packages/cw-denom/src/integration_tests.rs b/packages/cw-denom/src/integration_tests.rs index 0cf73c55a..70dba3120 100644 --- a/packages/cw-denom/src/integration_tests.rs +++ b/packages/cw-denom/src/integration_tests.rs @@ -1,23 +1,15 @@ -use cosmwasm_std::{coins, Addr, Empty, Uint128}; +use cosmwasm_std::{coins, Addr, Uint128}; use cw20::Cw20Coin; -use cw_multi_test::{App, BankSudo, Contract, ContractWrapper, Executor}; +use cw_multi_test::{App, BankSudo, Executor}; +use dao_testing::contracts::cw20_base_contract; use crate::CheckedDenom; -fn cw20_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - #[test] fn test_cw20_denom_send() { let mut app = App::default(); - let cw20_id = app.store_code(cw20_contract()); + let cw20_id = app.store_code(cw20_base_contract()); let cw20 = app .instantiate_contract( cw20_id, diff --git a/packages/dao-testing/Cargo.toml b/packages/dao-testing/Cargo.toml index 9b191be86..46429de16 100644 --- a/packages/dao-testing/Cargo.toml +++ b/packages/dao-testing/Cargo.toml @@ -1,6 +1,10 @@ [package] name = "dao-testing" -authors = ["ekez ekez@withoutdoing.com", "Jake Hartnell "] +authors = [ + "ekez ekez@withoutdoing.com", + "Jake Hartnell ", + "noah ", +] description = "Testing helper functions and interfaces for testing DAO modules." edition = { workspace = true } license = { workspace = true } @@ -36,21 +40,31 @@ rand = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +btsg-ft-factory = { workspace = true } cw-admin-factory = { workspace = true } -cw-core-v1 = { workspace = true, features = ["library"] } +cw-fund-distributor = { workspace = true } cw-hooks = { workspace = true } -cw-proposal-single-v1 = { workspace = true } +cw-payroll-factory = { workspace = true } +cw-token-swap = { workspace = true } cw-vesting = { workspace = true } cw20-stake = { workspace = true } +cw20-stake-external-rewards = { workspace = true } +cw20-stake-reward-distributor = { workspace = true } cw721-base = { workspace = true } cw721-roles = { workspace = true } cw-tokenfactory-issuer = { workspace = true } -dao-dao-core = { workspace = true, features = ["library"] } +dao-dao-core = { workspace = true } dao-interface = { workspace = true } +dao-migrator = { workspace = true } +dao-pre-propose-approver = { workspace = true } dao-pre-propose-multiple = { workspace = true } dao-pre-propose-single = { workspace = true } +dao-pre-propose-approval-single = { workspace = true } dao-proposal-condorcet = { workspace = true } dao-proposal-single = { workspace = true } +dao-proposal-multiple = { workspace = true } +dao-proposal-sudo = { workspace = true } +dao-rewards-distributor = { workspace = true } dao-test-custom-factory = { workspace = true } dao-voting = { workspace = true } dao-voting-cw20-balance = { workspace = true } @@ -60,5 +74,25 @@ dao-voting-cw721-staked = { workspace = true } dao-voting-cw721-roles = { workspace = true } dao-voting-onft-staked = { workspace = true } dao-voting-token-staked = { workspace = true } -voting-v1 = { workspace = true } +dao-proposal-hook-counter = { workspace = true } + +# v1 migration +cw-core-v1 = { workspace = true } +cw-proposal-single-v1 = { workspace = true } +cw4-voting-v1 = { workspace = true } +cw20-stake-v1 = { workspace = true } +cw20-stake-external-rewards-v1 = { workspace = true } +cw20-stake-reward-distributor-v1 = { workspace = true } stake-cw20-v03 = { workspace = true } +voting-v1 = { workspace = true } + +# v2.4.1 migration +dao-dao-core-v241 = { workspace = true } +dao-interface-v241 = { workspace = true } +dao-pre-propose-approval-single-v241 = { workspace = true } +dao-pre-propose-single-v241 = { workspace = true } +dao-pre-propose-multiple-v241 = { workspace = true } +dao-proposal-single-v241 = { workspace = true } +dao-proposal-multiple-v241 = { workspace = true } +dao-voting-cw4-v241 = { workspace = true } +dao-voting-v241 = { workspace = true } diff --git a/packages/dao-testing/src/contracts.rs b/packages/dao-testing/src/contracts.rs deleted file mode 100644 index 1739ed124..000000000 --- a/packages/dao-testing/src/contracts.rs +++ /dev/null @@ -1,218 +0,0 @@ -use cosmwasm_std::Empty; - -use cw_multi_test::{Contract, ContractWrapper}; -use dao_pre_propose_multiple as cppm; -use dao_pre_propose_single as cpps; - -pub fn cw20_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -pub fn cw4_group_contract() -> Box> { - let contract = ContractWrapper::new( - cw4_group::contract::execute, - cw4_group::contract::instantiate, - cw4_group::contract::query, - ); - Box::new(contract) -} - -pub fn cw721_base_contract() -> Box> { - let contract = ContractWrapper::new( - cw721_base::entry::execute, - cw721_base::entry::instantiate, - cw721_base::entry::query, - ); - Box::new(contract) -} - -pub fn cw721_roles_contract() -> Box> { - let contract = ContractWrapper::new( - cw721_roles::contract::execute, - cw721_roles::contract::instantiate, - cw721_roles::contract::query, - ); - Box::new(contract) -} - -pub fn cw20_stake_contract() -> Box> { - let contract = ContractWrapper::new( - cw20_stake::contract::execute, - cw20_stake::contract::instantiate, - cw20_stake::contract::query, - ); - Box::new(contract) -} - -pub fn proposal_condorcet_contract() -> Box> { - let contract = ContractWrapper::new( - dao_proposal_condorcet::contract::execute, - dao_proposal_condorcet::contract::instantiate, - dao_proposal_condorcet::contract::query, - ) - .with_reply(dao_proposal_condorcet::contract::reply); - Box::new(contract) -} - -pub fn proposal_single_contract() -> Box> { - let contract = ContractWrapper::new( - dao_proposal_single::contract::execute, - dao_proposal_single::contract::instantiate, - dao_proposal_single::contract::query, - ) - .with_reply(dao_proposal_single::contract::reply) - .with_migrate(dao_proposal_single::contract::migrate); - Box::new(contract) -} - -pub fn pre_propose_single_contract() -> Box> { - let contract = ContractWrapper::new( - cpps::contract::execute, - cpps::contract::instantiate, - cpps::contract::query, - ); - Box::new(contract) -} - -pub fn pre_propose_multiple_contract() -> Box> { - let contract = ContractWrapper::new( - cppm::contract::execute, - cppm::contract::instantiate, - cppm::contract::query, - ); - Box::new(contract) -} - -pub fn cw20_staked_balances_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_staked::contract::execute, - dao_voting_cw20_staked::contract::instantiate, - dao_voting_cw20_staked::contract::query, - ) - .with_reply(dao_voting_cw20_staked::contract::reply); - Box::new(contract) -} - -pub fn cw20_balances_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw20_balance::contract::execute, - dao_voting_cw20_balance::contract::instantiate, - dao_voting_cw20_balance::contract::query, - ) - .with_reply(dao_voting_cw20_balance::contract::reply); - Box::new(contract) -} - -pub fn native_staked_balances_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_token_staked::contract::execute, - dao_voting_token_staked::contract::instantiate, - dao_voting_token_staked::contract::query, - ) - .with_reply(dao_voting_token_staked::contract::reply); - Box::new(contract) -} - -pub fn cw721_staked_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw721_staked::contract::execute, - dao_voting_cw721_staked::contract::instantiate, - dao_voting_cw721_staked::contract::query, - ) - .with_reply(dao_voting_cw721_staked::contract::reply); - Box::new(contract) -} - -pub fn onft_staked_voting_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_onft_staked::contract::execute, - dao_voting_onft_staked::contract::instantiate, - dao_voting_onft_staked::contract::query, - ); - Box::new(contract) -} - -pub fn dao_dao_contract() -> Box> { - let contract = ContractWrapper::new( - dao_dao_core::contract::execute, - dao_dao_core::contract::instantiate, - dao_dao_core::contract::query, - ) - .with_reply(dao_dao_core::contract::reply) - .with_migrate(dao_dao_core::contract::migrate); - Box::new(contract) -} - -pub fn dao_voting_cw4_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw4::contract::execute, - dao_voting_cw4::contract::instantiate, - dao_voting_cw4::contract::query, - ) - .with_reply(dao_voting_cw4::contract::reply); - Box::new(contract) -} - -pub fn dao_voting_cw721_roles_contract() -> Box> { - let contract = ContractWrapper::new( - dao_voting_cw721_roles::contract::execute, - dao_voting_cw721_roles::contract::instantiate, - dao_voting_cw721_roles::contract::query, - ) - .with_reply(dao_voting_cw721_roles::contract::reply); - Box::new(contract) -} - -pub fn v1_proposal_single_contract() -> Box> { - let contract = ContractWrapper::new( - cw_proposal_single_v1::contract::execute, - cw_proposal_single_v1::contract::instantiate, - cw_proposal_single_v1::contract::query, - ) - .with_reply(cw_proposal_single_v1::contract::reply) - .with_migrate(cw_proposal_single_v1::contract::migrate); - Box::new(contract) -} - -pub fn v1_dao_dao_contract() -> Box> { - let contract = ContractWrapper::new( - cw_core_v1::contract::execute, - cw_core_v1::contract::instantiate, - cw_core_v1::contract::query, - ) - .with_reply(cw_core_v1::contract::reply); - Box::new(contract) -} - -pub fn cw_vesting_contract() -> Box> { - let contract = ContractWrapper::new( - cw_vesting::contract::execute, - cw_vesting::contract::instantiate, - cw_vesting::contract::query, - ); - Box::new(contract) -} - -pub fn stake_cw20_v03_contract() -> Box> { - let contract = ContractWrapper::new( - stake_cw20_v03::contract::execute, - stake_cw20_v03::contract::instantiate, - stake_cw20_v03::contract::query, - ); - Box::new(contract) -} - -pub fn dao_test_custom_factory() -> Box> { - let contract = ContractWrapper::new( - dao_test_custom_factory::contract::execute, - dao_test_custom_factory::contract::instantiate, - dao_test_custom_factory::contract::query, - ) - .with_reply(dao_test_custom_factory::contract::reply); - Box::new(contract) -} diff --git a/packages/dao-testing/src/contracts/latest.rs b/packages/dao-testing/src/contracts/latest.rs new file mode 100644 index 000000000..1bbc8aefd --- /dev/null +++ b/packages/dao-testing/src/contracts/latest.rs @@ -0,0 +1,336 @@ +use cosmwasm_std::Empty; +use cw_multi_test::{Contract, ContractWrapper}; + +pub fn cw20_base_contract() -> Box> { + let contract = ContractWrapper::new( + cw20_base::contract::execute, + cw20_base::contract::instantiate, + cw20_base::contract::query, + ) + .with_migrate(cw20_base::contract::migrate); + Box::new(contract) +} + +pub fn cw4_group_contract() -> Box> { + let contract = ContractWrapper::new( + cw4_group::contract::execute, + cw4_group::contract::instantiate, + cw4_group::contract::query, + ); + Box::new(contract) +} + +pub fn cw721_base_contract() -> Box> { + let contract = ContractWrapper::new( + cw721_base::entry::execute, + cw721_base::entry::instantiate, + cw721_base::entry::query, + ) + .with_migrate(cw721_base::entry::migrate); + Box::new(contract) +} + +pub fn cw721_roles_contract() -> Box> { + let contract = ContractWrapper::new( + cw721_roles::contract::execute, + cw721_roles::contract::instantiate, + cw721_roles::contract::query, + ); + Box::new(contract) +} + +pub fn cw20_stake_contract() -> Box> { + let contract = ContractWrapper::new( + cw20_stake::contract::execute, + cw20_stake::contract::instantiate, + cw20_stake::contract::query, + ) + .with_migrate(cw20_stake::contract::migrate); + Box::new(contract) +} + +pub fn dao_proposal_condorcet_contract() -> Box> { + let contract = ContractWrapper::new( + dao_proposal_condorcet::contract::execute, + dao_proposal_condorcet::contract::instantiate, + dao_proposal_condorcet::contract::query, + ) + .with_reply(dao_proposal_condorcet::contract::reply); + Box::new(contract) +} + +pub fn dao_proposal_single_contract() -> Box> { + let contract = ContractWrapper::new( + dao_proposal_single::contract::execute, + dao_proposal_single::contract::instantiate, + dao_proposal_single::contract::query, + ) + .with_reply(dao_proposal_single::contract::reply) + .with_migrate(dao_proposal_single::contract::migrate); + Box::new(contract) +} + +pub fn dao_proposal_multiple_contract() -> Box> { + let contract = ContractWrapper::new( + dao_proposal_multiple::contract::execute, + dao_proposal_multiple::contract::instantiate, + dao_proposal_multiple::contract::query, + ) + .with_reply(dao_proposal_multiple::contract::reply) + .with_migrate(dao_proposal_multiple::contract::migrate); + Box::new(contract) +} + +pub fn dao_proposal_sudo_contract() -> Box> { + let contract = ContractWrapper::new( + dao_proposal_sudo::contract::execute, + dao_proposal_sudo::contract::instantiate, + dao_proposal_sudo::contract::query, + ); + Box::new(contract) +} + +pub fn dao_pre_propose_approver_contract() -> Box> { + let contract = ContractWrapper::new( + dao_pre_propose_approver::contract::execute, + dao_pre_propose_approver::contract::instantiate, + dao_pre_propose_approver::contract::query, + ) + .with_migrate(dao_pre_propose_approver::contract::migrate); + Box::new(contract) +} + +pub fn dao_pre_propose_single_contract() -> Box> { + let contract = ContractWrapper::new( + dao_pre_propose_single::contract::execute, + dao_pre_propose_single::contract::instantiate, + dao_pre_propose_single::contract::query, + ) + .with_migrate(dao_pre_propose_single::contract::migrate); + Box::new(contract) +} + +pub fn dao_pre_propose_multiple_contract() -> Box> { + let contract = ContractWrapper::new( + dao_pre_propose_multiple::contract::execute, + dao_pre_propose_multiple::contract::instantiate, + dao_pre_propose_multiple::contract::query, + ) + .with_migrate(dao_pre_propose_multiple::contract::migrate); + Box::new(contract) +} + +pub fn dao_pre_propose_approval_single_contract() -> Box> { + let contract = ContractWrapper::new( + dao_pre_propose_approval_single::contract::execute, + dao_pre_propose_approval_single::contract::instantiate, + dao_pre_propose_approval_single::contract::query, + ) + .with_migrate(dao_pre_propose_approval_single::contract::migrate); + Box::new(contract) +} + +pub fn dao_voting_cw4_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_cw4::contract::execute, + dao_voting_cw4::contract::instantiate, + dao_voting_cw4::contract::query, + ) + .with_reply(dao_voting_cw4::contract::reply) + .with_migrate(dao_voting_cw4::contract::migrate); + Box::new(contract) +} + +pub fn dao_voting_cw20_staked_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_cw20_staked::contract::execute, + dao_voting_cw20_staked::contract::instantiate, + dao_voting_cw20_staked::contract::query, + ) + .with_reply(dao_voting_cw20_staked::contract::reply) + .with_migrate(dao_voting_cw20_staked::contract::migrate); + Box::new(contract) +} + +pub fn dao_voting_cw20_balance_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_cw20_balance::contract::execute, + dao_voting_cw20_balance::contract::instantiate, + dao_voting_cw20_balance::contract::query, + ) + .with_reply(dao_voting_cw20_balance::contract::reply); + Box::new(contract) +} + +pub fn dao_voting_token_staked_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_token_staked::contract::execute, + dao_voting_token_staked::contract::instantiate, + dao_voting_token_staked::contract::query, + ) + .with_reply(dao_voting_token_staked::contract::reply) + .with_migrate(dao_voting_token_staked::contract::migrate); + Box::new(contract) +} + +pub fn dao_voting_cw721_staked_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_cw721_staked::contract::execute, + dao_voting_cw721_staked::contract::instantiate, + dao_voting_cw721_staked::contract::query, + ) + .with_reply(dao_voting_cw721_staked::contract::reply) + .with_migrate(dao_voting_cw721_staked::contract::migrate); + Box::new(contract) +} + +pub fn dao_voting_cw721_roles_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_cw721_roles::contract::execute, + dao_voting_cw721_roles::contract::instantiate, + dao_voting_cw721_roles::contract::query, + ) + .with_reply(dao_voting_cw721_roles::contract::reply); + Box::new(contract) +} + +pub fn dao_voting_onft_staked_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_onft_staked::contract::execute, + dao_voting_onft_staked::contract::instantiate, + dao_voting_onft_staked::contract::query, + ) + .with_migrate(dao_voting_onft_staked::contract::migrate); + Box::new(contract) +} + +pub fn dao_dao_core_contract() -> Box> { + let contract = ContractWrapper::new( + dao_dao_core::contract::execute, + dao_dao_core::contract::instantiate, + dao_dao_core::contract::query, + ) + .with_reply(dao_dao_core::contract::reply) + .with_migrate(dao_dao_core::contract::migrate); + Box::new(contract) +} + +pub fn dao_migrator_contract() -> Box> { + let contract = ContractWrapper::new( + dao_migrator::contract::execute, + dao_migrator::contract::instantiate, + dao_migrator::contract::query, + ) + .with_reply(dao_migrator::contract::reply); + Box::new(contract) +} + +pub fn cw_vesting_contract() -> Box> { + let contract = ContractWrapper::new( + cw_vesting::contract::execute, + cw_vesting::contract::instantiate, + cw_vesting::contract::query, + ); + Box::new(contract) +} + +pub fn dao_test_custom_factory_contract() -> Box> { + let contract = ContractWrapper::new( + dao_test_custom_factory::contract::execute, + dao_test_custom_factory::contract::instantiate, + dao_test_custom_factory::contract::query, + ) + .with_reply(dao_test_custom_factory::contract::reply); + Box::new(contract) +} + +pub fn cw_fund_distributor_contract() -> Box> { + let contract = ContractWrapper::new( + cw_fund_distributor::contract::execute, + cw_fund_distributor::contract::instantiate, + cw_fund_distributor::contract::query, + ) + .with_migrate(cw_fund_distributor::contract::migrate); + Box::new(contract) +} + +pub fn dao_rewards_distributor_contract() -> Box> { + let contract = ContractWrapper::new( + dao_rewards_distributor::contract::execute, + dao_rewards_distributor::contract::instantiate, + dao_rewards_distributor::contract::query, + ) + .with_migrate(dao_rewards_distributor::contract::migrate); + Box::new(contract) +} + +pub fn btsg_ft_factory_contract() -> Box> { + let contract = ContractWrapper::new( + btsg_ft_factory::contract::execute, + btsg_ft_factory::contract::instantiate, + btsg_ft_factory::contract::query, + ) + .with_reply(btsg_ft_factory::contract::reply) + .with_migrate(btsg_ft_factory::contract::migrate); + Box::new(contract) +} + +pub fn cw_admin_factory_contract() -> Box> { + let contract = ContractWrapper::new( + cw_admin_factory::contract::execute, + cw_admin_factory::contract::instantiate, + cw_admin_factory::contract::query, + ) + .with_reply(cw_admin_factory::contract::reply) + .with_migrate(cw_admin_factory::contract::migrate); + Box::new(contract) +} + +pub fn cw_payroll_factory_contract() -> Box> { + let contract = ContractWrapper::new( + cw_payroll_factory::contract::execute, + cw_payroll_factory::contract::instantiate, + cw_payroll_factory::contract::query, + ) + .with_reply(cw_payroll_factory::contract::reply); + Box::new(contract) +} + +pub fn cw_token_swap_contract() -> Box> { + let contract = ContractWrapper::new( + cw_token_swap::contract::execute, + cw_token_swap::contract::instantiate, + cw_token_swap::contract::query, + ) + .with_migrate(cw_token_swap::contract::migrate); + Box::new(contract) +} + +pub fn cw20_stake_external_rewards_contract() -> Box> { + let contract = ContractWrapper::new( + cw20_stake_external_rewards::contract::execute, + cw20_stake_external_rewards::contract::instantiate, + cw20_stake_external_rewards::contract::query, + ) + .with_migrate(cw20_stake_external_rewards::contract::migrate); + Box::new(contract) +} + +pub fn cw20_stake_reward_distributor_contract() -> Box> { + let contract = ContractWrapper::new( + cw20_stake_reward_distributor::contract::execute, + cw20_stake_reward_distributor::contract::instantiate, + cw20_stake_reward_distributor::contract::query, + ) + .with_migrate(cw20_stake_reward_distributor::contract::migrate); + Box::new(contract) +} + +pub fn dao_proposal_hook_counter_contract() -> Box> { + let contract = ContractWrapper::new( + dao_proposal_hook_counter::contract::execute, + dao_proposal_hook_counter::contract::instantiate, + dao_proposal_hook_counter::contract::query, + ); + Box::new(contract) +} diff --git a/packages/dao-testing/src/contracts/mod.rs b/packages/dao-testing/src/contracts/mod.rs new file mode 100644 index 000000000..51019ef32 --- /dev/null +++ b/packages/dao-testing/src/contracts/mod.rs @@ -0,0 +1,6 @@ +mod latest; + +pub mod v1; +pub mod v241; + +pub use latest::*; diff --git a/packages/dao-testing/src/contracts/v1.rs b/packages/dao-testing/src/contracts/v1.rs new file mode 100644 index 000000000..75751898c --- /dev/null +++ b/packages/dao-testing/src/contracts/v1.rs @@ -0,0 +1,73 @@ +use cosmwasm_std::Empty; +use cw_multi_test::{Contract, ContractWrapper}; + +pub fn cw_proposal_single_v1_contract() -> Box> { + let contract = ContractWrapper::new( + cw_proposal_single_v1::contract::execute, + cw_proposal_single_v1::contract::instantiate, + cw_proposal_single_v1::contract::query, + ) + .with_reply(cw_proposal_single_v1::contract::reply) + .with_migrate(cw_proposal_single_v1::contract::migrate); + Box::new(contract) +} + +pub fn cw_core_v1_contract() -> Box> { + let contract = ContractWrapper::new( + cw_core_v1::contract::execute, + cw_core_v1::contract::instantiate, + cw_core_v1::contract::query, + ) + .with_reply(cw_core_v1::contract::reply) + .with_migrate(cw_core_v1::contract::migrate); + Box::new(contract) +} + +pub fn cw4_voting_v1_contract() -> Box> { + let contract = ContractWrapper::new( + cw4_voting_v1::contract::execute, + cw4_voting_v1::contract::instantiate, + cw4_voting_v1::contract::query, + ) + .with_reply(cw4_voting_v1::contract::reply) + .with_migrate(cw4_voting_v1::contract::migrate); + Box::new(contract) +} + +pub fn cw20_stake_v1_contract() -> Box> { + let contract = ContractWrapper::new( + cw20_stake_v1::contract::execute, + cw20_stake_v1::contract::instantiate, + cw20_stake_v1::contract::query, + ) + .with_migrate(cw20_stake_v1::contract::migrate); + Box::new(contract) +} + +pub fn stake_cw20_v03_contract() -> Box> { + let contract = ContractWrapper::new( + stake_cw20_v03::contract::execute, + stake_cw20_v03::contract::instantiate, + stake_cw20_v03::contract::query, + ); + Box::new(contract) +} + +pub fn cw20_stake_external_rewards_v1_contract() -> Box> { + let contract = ContractWrapper::new( + cw20_stake_external_rewards_v1::contract::execute, + cw20_stake_external_rewards_v1::contract::instantiate, + cw20_stake_external_rewards_v1::contract::query, + ) + .with_migrate(cw20_stake_external_rewards_v1::contract::migrate); + Box::new(contract) +} + +pub fn cw20_stake_reward_distributor_v1_contract() -> Box> { + let contract = ContractWrapper::new( + cw20_stake_reward_distributor_v1::contract::execute, + cw20_stake_reward_distributor_v1::contract::instantiate, + cw20_stake_reward_distributor_v1::contract::query, + ); + Box::new(contract) +} diff --git a/packages/dao-testing/src/contracts/v241.rs b/packages/dao-testing/src/contracts/v241.rs new file mode 100644 index 000000000..51d8b69ac --- /dev/null +++ b/packages/dao-testing/src/contracts/v241.rs @@ -0,0 +1,73 @@ +use cosmwasm_std::Empty; +use cw_multi_test::{Contract, ContractWrapper}; + +pub fn dao_dao_core_v241_contract() -> Box> { + let contract = ContractWrapper::new( + dao_dao_core_v241::contract::execute, + dao_dao_core_v241::contract::instantiate, + dao_dao_core_v241::contract::query, + ) + .with_reply(dao_dao_core_v241::contract::reply) + .with_migrate(dao_dao_core_v241::contract::migrate); + Box::new(contract) +} + +pub fn dao_voting_cw4_v241_contract() -> Box> { + let contract = ContractWrapper::new( + dao_voting_cw4_v241::contract::execute, + dao_voting_cw4_v241::contract::instantiate, + dao_voting_cw4_v241::contract::query, + ) + .with_reply(dao_voting_cw4_v241::contract::reply) + .with_migrate(dao_voting_cw4_v241::contract::migrate); + Box::new(contract) +} + +pub fn dao_proposal_single_v241_contract() -> Box> { + let contract = ContractWrapper::new( + dao_proposal_single_v241::contract::execute, + dao_proposal_single_v241::contract::instantiate, + dao_proposal_single_v241::contract::query, + ) + .with_reply(dao_proposal_single_v241::contract::reply) + .with_migrate(dao_proposal_single_v241::contract::migrate); + Box::new(contract) +} + +pub fn dao_proposal_multiple_v241_contract() -> Box> { + let contract = ContractWrapper::new( + dao_proposal_multiple_v241::contract::execute, + dao_proposal_multiple_v241::contract::instantiate, + dao_proposal_multiple_v241::contract::query, + ) + .with_reply(dao_proposal_multiple_v241::contract::reply) + .with_migrate(dao_proposal_multiple_v241::contract::migrate); + Box::new(contract) +} + +pub fn dao_pre_propose_single_v241_contract() -> Box> { + let contract = ContractWrapper::new( + dao_pre_propose_single_v241::contract::execute, + dao_pre_propose_single_v241::contract::instantiate, + dao_pre_propose_single_v241::contract::query, + ); + Box::new(contract) +} + +pub fn dao_pre_propose_approval_single_v241_contract() -> Box> { + let contract = ContractWrapper::new( + dao_pre_propose_approval_single_v241::contract::execute, + dao_pre_propose_approval_single_v241::contract::instantiate, + dao_pre_propose_approval_single_v241::contract::query, + ); + Box::new(contract) +} + +pub fn dao_pre_propose_multiple_v241_contract() -> Box> { + let contract = ContractWrapper::new( + dao_pre_propose_multiple_v241::contract::execute, + dao_pre_propose_multiple_v241::contract::instantiate, + dao_pre_propose_multiple_v241::contract::query, + ); + Box::new(contract) +} diff --git a/packages/dao-testing/src/helpers.rs b/packages/dao-testing/src/helpers.rs index b629e7ba0..e44c0a787 100644 --- a/packages/dao-testing/src/helpers.rs +++ b/packages/dao-testing/src/helpers.rs @@ -7,9 +7,8 @@ use dao_voting::threshold::ActiveThreshold; use dao_voting_cw4::msg::GroupContract; use crate::contracts::{ - cw20_balances_voting_contract, cw20_base_contract, cw20_stake_contract, - cw20_staked_balances_voting_contract, cw4_group_contract, dao_dao_contract, - dao_voting_cw4_contract, + cw20_base_contract, cw20_stake_contract, cw4_group_contract, dao_dao_core_contract, + dao_voting_cw20_balance_contract, dao_voting_cw20_staked_contract, dao_voting_cw4_contract, }; const CREATOR_ADDR: &str = "creator"; @@ -21,8 +20,8 @@ pub fn instantiate_with_cw20_balances_governance( initial_balances: Option>, ) -> Addr { let cw20_id = app.store_code(cw20_base_contract()); - let core_id = app.store_code(dao_dao_contract()); - let votemod_id = app.store_code(cw20_balances_voting_contract()); + let core_id = app.store_code(dao_dao_core_contract()); + let votemod_id = app.store_code(dao_voting_cw20_balance_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![Cw20Coin { @@ -125,8 +124,8 @@ pub fn instantiate_with_staked_balances_governance( let cw20_id = app.store_code(cw20_base_contract()); let cw20_stake_id = app.store_code(cw20_stake_contract()); - let staked_balances_voting_id = app.store_code(cw20_staked_balances_voting_contract()); - let core_contract_id = app.store_code(dao_dao_contract()); + let staked_balances_voting_id = app.store_code(dao_voting_cw20_staked_contract()); + let core_contract_id = app.store_code(dao_dao_core_contract()); let instantiate_core = dao_interface::msg::InstantiateMsg { dao_uri: None, @@ -233,8 +232,8 @@ pub fn instantiate_with_staking_active_threshold( ) -> Addr { let cw20_id = app.store_code(cw20_base_contract()); let cw20_staking_id = app.store_code(cw20_stake_contract()); - let governance_id = app.store_code(dao_dao_contract()); - let votemod_id = app.store_code(cw20_staked_balances_voting_contract()); + let governance_id = app.store_code(dao_dao_core_contract()); + let votemod_id = app.store_code(dao_voting_cw20_staked_contract()); let initial_balances = initial_balances.unwrap_or_else(|| { vec![ @@ -307,7 +306,7 @@ pub fn instantiate_with_cw4_groups_governance( initial_weights: Option>, ) -> Addr { let cw4_id = app.store_code(cw4_group_contract()); - let core_id = app.store_code(dao_dao_contract()); + let core_id = app.store_code(dao_dao_core_contract()); let votemod_id = app.store_code(dao_voting_cw4_contract()); let initial_weights = initial_weights.unwrap_or_default(); diff --git a/packages/dao-testing/src/lib.rs b/packages/dao-testing/src/lib.rs index eeb38e678..e0985b0fc 100644 --- a/packages/dao-testing/src/lib.rs +++ b/packages/dao-testing/src/lib.rs @@ -1,16 +1,20 @@ #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))] -#[cfg(not(target_arch = "wasm32"))] -pub mod tests; - #[cfg(not(target_arch = "wasm32"))] pub mod helpers; #[cfg(not(target_arch = "wasm32"))] pub mod contracts; +#[cfg(not(target_arch = "wasm32"))] +pub mod tests; #[cfg(not(target_arch = "wasm32"))] pub use tests::*; +#[cfg(not(target_arch = "wasm32"))] +pub mod suite; +#[cfg(not(target_arch = "wasm32"))] +pub use suite::*; + #[cfg(not(target_arch = "wasm32"))] pub mod test_tube; diff --git a/packages/dao-testing/src/suite/base.rs b/packages/dao-testing/src/suite/base.rs new file mode 100644 index 000000000..85ec6d559 --- /dev/null +++ b/packages/dao-testing/src/suite/base.rs @@ -0,0 +1,353 @@ +use cosmwasm_std::{to_json_binary, Addr, Empty, QuerierWrapper, Timestamp}; +use cw20::Cw20Coin; +use cw_multi_test::{App, Executor}; +use cw_utils::Duration; + +use super::*; +use crate::contracts::*; + +#[derive(Clone, Debug)] +pub struct TestDao { + pub core_addr: Addr, + pub voting_module_addr: Addr, + pub proposal_modules: Vec, + pub x: Extra, +} + +pub struct DaoTestingSuiteBase { + pub app: App, + + // Code IDs + // DAO stuff + pub core_id: u64, + pub admin_factory_id: u64, + pub proposal_single_id: u64, + pub proposal_multiple_id: u64, + pub proposal_sudo_id: u64, + pub pre_propose_approval_single_id: u64, + pub pre_propose_single_id: u64, + pub pre_propose_multiple_id: u64, + pub pre_propose_approver_id: u64, + pub voting_cw4_id: u64, + pub voting_cw20_staked_id: u64, + pub voting_cw20_balance_id: u64, + pub voting_cw721_staked_id: u64, + pub voting_token_staked_id: u64, + pub cw20_stake_id: u64, + pub rewards_distributor_id: u64, + // External stuff + pub cw4_group_id: u64, + pub cw20_base_id: u64, + pub cw721_base_id: u64, + + // Addresses + pub admin_factory_addr: Addr, +} + +pub trait DaoTestingSuite { + /// get the testing suite base + fn base(&self) -> &DaoTestingSuiteBase; + + /// get the mutable testing suite base + fn base_mut(&mut self) -> &mut DaoTestingSuiteBase; + + /// get the voting module info to instantiate the DAO with + fn get_voting_module_info(&self) -> dao_interface::state::ModuleInstantiateInfo; + + /// get the extra DAO fields + fn get_dao_extra(&self, _dao: &TestDao) -> Extra; + + /// perform additional setup for the DAO after it is created. empty default + /// implementation makes this optional. + fn dao_setup(&mut self, _dao: &mut TestDao) {} + + /// build the DAO. no need to override this. + fn dao(&mut self) -> TestDao { + let voting_module_info = self.get_voting_module_info(); + + let proposal_module_infos = + vec![dao_interface::state::ModuleInstantiateInfo { + code_id: self.base().proposal_single_id, + msg: to_json_binary(&dao_proposal_single::msg::InstantiateMsg { + threshold: dao_voting::threshold::Threshold::AbsolutePercentage { + percentage: dao_voting::threshold::PercentageThreshold::Majority {}, + }, + max_voting_period: Duration::Height(10), + min_voting_period: None, + only_members_execute: true, + allow_revoting: false, + pre_propose_info: dao_voting::pre_propose::PreProposeInfo::ModuleMayPropose { + info: dao_interface::state::ModuleInstantiateInfo { + code_id: self.base().pre_propose_single_id, + msg: to_json_binary(&dao_pre_propose_single::InstantiateMsg { + deposit_info: None, + submission_policy: + dao_voting::pre_propose::PreProposeSubmissionPolicy::Specific { + dao_members: true, + allowlist: vec![], + denylist: vec![], + }, + extension: Empty {}, + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "single choice pre-propose module".to_string(), + }, + }, + close_proposal_on_execution_failure: true, + veto: None, + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "single choice proposal module".to_string(), + }, + dao_interface::state::ModuleInstantiateInfo { + code_id: self.base().proposal_multiple_id, + msg: to_json_binary(&dao_proposal_multiple::msg::InstantiateMsg { + voting_strategy: dao_voting::multiple_choice::VotingStrategy::SingleChoice { + quorum: dao_voting::threshold::PercentageThreshold::Majority {}, + }, + max_voting_period: Duration::Height(10), + min_voting_period: None, + only_members_execute: true, + allow_revoting: false, + pre_propose_info: dao_voting::pre_propose::PreProposeInfo::ModuleMayPropose { + info: dao_interface::state::ModuleInstantiateInfo { + code_id: self.base().pre_propose_multiple_id, + msg: to_json_binary(&dao_pre_propose_multiple::InstantiateMsg { + deposit_info: None, + submission_policy: + dao_voting::pre_propose::PreProposeSubmissionPolicy::Specific { + dao_members: true, + allowlist: vec![], + denylist: vec![], + }, + extension: Empty {}, + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "multiple choice pre-propose module".to_string(), + }, + }, + close_proposal_on_execution_failure: true, + veto: None, + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "multiple choice proposal module".to_string(), + }]; + + // create the DAO using the base testing suite + let dao = self + .base_mut() + .build(voting_module_info, proposal_module_infos); + + // perform additional queries to get extra fields for DAO struct + let x = self.get_dao_extra(&dao); + + let mut dao = TestDao { + core_addr: dao.core_addr, + voting_module_addr: dao.voting_module_addr, + proposal_modules: dao.proposal_modules, + x, + }; + + // perform additional setup after the DAO is created + self.dao_setup(&mut dao); + + dao + } + + /// get the app querier + fn querier(&self) -> QuerierWrapper<'_> { + self.base().app.wrap() + } +} + +// CONSTRUCTOR +impl DaoTestingSuiteBase { + pub fn base() -> Self { + let mut app = App::default(); + + // start at 0 height and time + app.update_block(|b| { + b.height = 0; + b.time = Timestamp::from_seconds(0); + }); + + let core_id = app.store_code(dao_dao_core_contract()); + let admin_factory_id = app.store_code(cw_admin_factory_contract()); + let proposal_single_id = app.store_code(dao_proposal_single_contract()); + let proposal_multiple_id = app.store_code(dao_proposal_multiple_contract()); + let proposal_sudo_id = app.store_code(dao_proposal_sudo_contract()); + let pre_propose_approval_single_id = + app.store_code(dao_pre_propose_approval_single_contract()); + let pre_propose_single_id = app.store_code(dao_pre_propose_single_contract()); + let pre_propose_multiple_id = app.store_code(dao_pre_propose_multiple_contract()); + let pre_propose_approver_id = app.store_code(dao_pre_propose_approver_contract()); + let voting_cw4_id = app.store_code(dao_voting_cw4_contract()); + let voting_cw20_staked_id = app.store_code(dao_voting_cw20_staked_contract()); + let voting_cw20_balance_id = app.store_code(dao_voting_cw20_balance_contract()); + let voting_cw721_staked_id = app.store_code(dao_voting_cw721_staked_contract()); + let voting_token_staked_id = app.store_code(dao_voting_token_staked_contract()); + let cw20_stake_id = app.store_code(cw20_stake_contract()); + let rewards_distributor_id = app.store_code(dao_rewards_distributor_contract()); + + let cw4_group_id = app.store_code(cw4_group_contract()); + let cw20_base_id = app.store_code(cw20_base_contract()); + let cw721_base_id = app.store_code(cw721_base_contract()); + + let admin_factory_addr = app + .instantiate_contract( + admin_factory_id, + Addr::unchecked(OWNER), + &cw_admin_factory::msg::InstantiateMsg { admin: None }, + &[], + "admin factory", + None, + ) + .unwrap(); + + Self { + app, + + core_id, + admin_factory_id, + proposal_single_id, + proposal_multiple_id, + proposal_sudo_id, + pre_propose_approval_single_id, + pre_propose_single_id, + pre_propose_multiple_id, + pre_propose_approver_id, + voting_cw4_id, + voting_cw20_staked_id, + voting_cw20_balance_id, + voting_cw721_staked_id, + voting_token_staked_id, + cw20_stake_id, + rewards_distributor_id, + cw4_group_id, + cw20_base_id, + cw721_base_id, + + admin_factory_addr, + } + } + + pub fn instantiate_cw20(&mut self, name: &str, initial_balances: Vec) -> Addr { + self.app + .instantiate_contract( + self.cw20_base_id, + Addr::unchecked(OWNER), + &cw20_base::msg::InstantiateMsg { + name: name.to_string(), + symbol: name.to_string(), + decimals: 6, + initial_balances, + mint: None, + marketing: None, + }, + &[], + "cw20", + None, + ) + .unwrap() + } +} + +// DAO CREATION +impl DaoTestingSuiteBase { + pub fn build( + &mut self, + voting_module_instantiate_info: dao_interface::state::ModuleInstantiateInfo, + proposal_modules_instantiate_info: Vec, + ) -> TestDao { + let init = dao_interface::msg::InstantiateMsg { + admin: None, + name: "DAO DAO".to_string(), + description: "A DAO that builds DAOs.".to_string(), + image_url: None, + automatically_add_cw20s: false, + automatically_add_cw721s: false, + voting_module_instantiate_info, + proposal_modules_instantiate_info, + initial_items: None, + dao_uri: None, + }; + + let res = self + .app + .execute_contract( + Addr::unchecked(OWNER), + self.admin_factory_addr.clone(), + &cw_admin_factory::msg::ExecuteMsg::InstantiateContractWithSelfAdmin { + instantiate_msg: to_json_binary(&init).unwrap(), + code_id: self.core_id, + label: "DAO DAO".to_string(), + }, + &[], + ) + .unwrap(); + + // get core address from the instantiate event + let instantiate_event = &res.events[2]; + assert_eq!(instantiate_event.ty, "instantiate"); + let core = Addr::unchecked(instantiate_event.attributes[0].value.clone()); + + // get voting module address + let voting_module: Addr = self + .app + .wrap() + .query_wasm_smart(&core, &dao_interface::msg::QueryMsg::VotingModule {}) + .unwrap(); + + // get proposal modules + let proposal_modules: Vec = self + .app + .wrap() + .query_wasm_smart( + &core, + &dao_interface::msg::QueryMsg::ProposalModules { + start_after: None, + limit: None, + }, + ) + .unwrap(); + + TestDao { + core_addr: core, + voting_module_addr: voting_module, + proposal_modules, + x: Empty::default(), + } + } + + pub fn cw4(&mut self) -> DaoTestingSuiteCw4 { + DaoTestingSuiteCw4::new(self) + } + + pub fn cw20(&mut self) -> DaoTestingSuiteCw20 { + DaoTestingSuiteCw20::new(self) + } + + pub fn cw721(&mut self) -> DaoTestingSuiteCw721 { + DaoTestingSuiteCw721::new(self) + } + + pub fn token(&mut self) -> DaoTestingSuiteToken { + DaoTestingSuiteToken::new(self) + } +} + +// UTILITIES +impl DaoTestingSuiteBase { + /// advance the block height by one + pub fn advance_block(&mut self) { + self.app.update_block(|b| b.height += 1); + } +} diff --git a/packages/dao-testing/src/suite/cw20_suite.rs b/packages/dao-testing/src/suite/cw20_suite.rs new file mode 100644 index 000000000..a26b0b34e --- /dev/null +++ b/packages/dao-testing/src/suite/cw20_suite.rs @@ -0,0 +1,269 @@ +use cosmwasm_std::{to_json_binary, Addr, Uint128}; +use cw20::Cw20Coin; +use cw_utils::Duration; + +use super::*; + +pub struct DaoTestingSuiteCw20<'a> { + pub base: &'a mut DaoTestingSuiteBase, + + pub initial_balances: Vec, + pub initial_dao_balance: Uint128, + pub unstaking_duration: Option, + pub active_threshold: Option, +} + +#[derive(Clone, Debug)] +pub struct Cw20DaoExtra { + pub cw20_addr: Addr, + pub staking_addr: Addr, +} + +pub type Cw20TestDao = TestDao; + +impl<'a> DaoTestingSuiteCw20<'a> { + pub fn new(base: &'a mut DaoTestingSuiteBase) -> Self { + Self { + base, + + initial_balances: vec![ + Cw20Coin { + address: MEMBER1.to_string(), + amount: Uint128::new(100), + }, + Cw20Coin { + address: MEMBER2.to_string(), + amount: Uint128::new(200), + }, + Cw20Coin { + address: MEMBER3.to_string(), + amount: Uint128::new(300), + }, + Cw20Coin { + address: MEMBER4.to_string(), + amount: Uint128::new(300), + }, + Cw20Coin { + address: MEMBER5.to_string(), + amount: Uint128::new(100), + }, + ], + initial_dao_balance: Uint128::new(10000), + unstaking_duration: None, + active_threshold: None, + } + } + + pub fn with_initial_balances(&mut self, initial_balances: Vec) -> &mut Self { + self.initial_balances = initial_balances; + self + } + + pub fn with_initial_dao_balance( + &mut self, + initial_dao_balance: impl Into, + ) -> &mut Self { + self.initial_dao_balance = initial_dao_balance.into(); + self + } + + pub fn with_unstaking_duration(&mut self, unstaking_duration: Option) -> &mut Self { + self.unstaking_duration = unstaking_duration; + self + } + + pub fn with_active_threshold( + &mut self, + active_threshold: Option, + ) -> &mut Self { + self.active_threshold = active_threshold; + self + } + + /// stake tokens + pub fn stake( + &mut self, + dao: &Cw20TestDao, + staker: impl Into, + amount: impl Into, + ) { + self.base + .app + .execute_contract( + Addr::unchecked(staker), + dao.x.cw20_addr.clone(), + &cw20::Cw20ExecuteMsg::Send { + contract: dao.x.staking_addr.to_string(), + amount: amount.into(), + msg: to_json_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(), + }, + &[], + ) + .unwrap(); + } + + /// unstake tokens + pub fn unstake( + &mut self, + dao: &Cw20TestDao, + staker: impl Into, + amount: impl Into, + ) { + self.base + .app + .execute_contract( + Addr::unchecked(staker), + dao.x.staking_addr.clone(), + &cw20_stake::msg::ExecuteMsg::Unstake { + amount: amount.into(), + }, + &[], + ) + .unwrap(); + } + + /// stake all initial balances and progress one block + pub fn stake_all_initial(&mut self, dao: &Cw20TestDao) { + for member in self.initial_balances.clone() { + self.stake(dao, member.address, member.amount); + } + + // staking takes effect at the next block + self.base.advance_block(); + } +} + +impl<'a> DaoTestingSuite for DaoTestingSuiteCw20<'a> { + fn base(&self) -> &DaoTestingSuiteBase { + self.base + } + + fn base_mut(&mut self) -> &mut DaoTestingSuiteBase { + self.base + } + + fn get_voting_module_info(&self) -> dao_interface::state::ModuleInstantiateInfo { + dao_interface::state::ModuleInstantiateInfo { + code_id: self.base.voting_cw20_staked_id, + msg: to_json_binary(&dao_voting_cw20_staked::msg::InstantiateMsg { + token_info: dao_voting_cw20_staked::msg::TokenInfo::New { + code_id: self.base.cw20_base_id, + label: "voting token".to_string(), + name: "Voting Token".to_string(), + symbol: "VOTE".to_string(), + decimals: 6, + initial_balances: self.initial_balances.clone(), + marketing: None, + staking_code_id: self.base.cw20_stake_id, + unstaking_duration: self.unstaking_duration, + initial_dao_balance: Some(self.initial_dao_balance), + }, + active_threshold: self.active_threshold.clone(), + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "voting module".to_string(), + } + } + + fn get_dao_extra(&self, dao: &TestDao) -> Cw20DaoExtra { + let cw20_addr: Addr = self + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw20_staked::msg::QueryMsg::TokenContract {}, + ) + .unwrap(); + let staking_addr: Addr = self + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw20_staked::msg::QueryMsg::StakingContract {}, + ) + .unwrap(); + + Cw20DaoExtra { + cw20_addr, + staking_addr, + } + } + + /// stake all initial balances and progress one block + fn dao_setup(&mut self, dao: &mut Cw20TestDao) { + for member in self.initial_balances.clone() { + self.stake(dao, member.address, member.amount); + } + + // staking takes effect at the next block + self.base.advance_block(); + } +} + +#[cfg(test)] +mod tests { + use cosmwasm_std::Uint128; + + use super::*; + + #[test] + fn dao_testing_suite_cw20() { + let mut suite = DaoTestingSuiteBase::base(); + let mut suite = suite.cw20(); + let dao = suite.dao(); + + let voting_module: Addr = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::VotingModule {}, + ) + .unwrap(); + assert_eq!(voting_module, dao.voting_module_addr); + + let proposal_modules: Vec = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::ProposalModules { + start_after: None, + limit: None, + }, + ) + .unwrap(); + assert_eq!(proposal_modules.len(), 2); + + let cw20_addr: Addr = suite + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw20_staked::msg::QueryMsg::TokenContract {}, + ) + .unwrap(); + assert_eq!(cw20_addr, dao.x.cw20_addr); + + let staking_addr: Addr = suite + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw20_staked::msg::QueryMsg::StakingContract {}, + ) + .unwrap(); + assert_eq!(staking_addr, dao.x.staking_addr); + + let total_weight: dao_interface::voting::TotalPowerAtHeightResponse = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::TotalPowerAtHeight { height: None }, + ) + .unwrap(); + assert_eq!( + total_weight.power, + suite + .initial_balances + .iter() + .fold(Uint128::zero(), |acc, m| acc + m.amount) + ); + } +} diff --git a/packages/dao-testing/src/suite/cw4_suite.rs b/packages/dao-testing/src/suite/cw4_suite.rs new file mode 100644 index 000000000..d3a37c1a7 --- /dev/null +++ b/packages/dao-testing/src/suite/cw4_suite.rs @@ -0,0 +1,148 @@ +use cosmwasm_std::{to_json_binary, Addr}; + +use super::*; + +pub struct DaoTestingSuiteCw4<'a> { + pub base: &'a mut DaoTestingSuiteBase, + + pub members: Vec, +} + +#[derive(Clone, Debug)] +pub struct Cw4DaoExtra { + pub group_addr: Addr, +} + +pub type Cw4TestDao = TestDao; + +impl<'a> DaoTestingSuiteCw4<'a> { + pub fn new(base: &'a mut DaoTestingSuiteBase) -> Self { + Self { + base, + members: vec![ + cw4::Member { + addr: MEMBER1.to_string(), + weight: 1, + }, + cw4::Member { + addr: MEMBER2.to_string(), + weight: 2, + }, + cw4::Member { + addr: MEMBER3.to_string(), + weight: 3, + }, + cw4::Member { + addr: MEMBER4.to_string(), + weight: 3, + }, + cw4::Member { + addr: MEMBER5.to_string(), + weight: 1, + }, + ], + } + } + + pub fn with_members(&mut self, members: Vec) -> &mut Self { + self.members = members; + self + } +} + +impl<'a> DaoTestingSuite for DaoTestingSuiteCw4<'a> { + fn base(&self) -> &DaoTestingSuiteBase { + self.base + } + + fn base_mut(&mut self) -> &mut DaoTestingSuiteBase { + self.base + } + + fn get_voting_module_info(&self) -> dao_interface::state::ModuleInstantiateInfo { + dao_interface::state::ModuleInstantiateInfo { + code_id: self.base.voting_cw4_id, + msg: to_json_binary(&dao_voting_cw4::msg::InstantiateMsg { + group_contract: dao_voting_cw4::msg::GroupContract::New { + cw4_group_code_id: self.base.cw4_group_id, + initial_members: self.members.clone(), + }, + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "voting module".to_string(), + } + } + + fn get_dao_extra(&self, dao: &TestDao) -> Cw4DaoExtra { + let group_addr: Addr = self + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw4::msg::QueryMsg::GroupContract {}, + ) + .unwrap(); + + Cw4DaoExtra { group_addr } + } +} + +#[cfg(test)] +mod tests { + use cosmwasm_std::Uint128; + + use super::*; + + #[test] + fn dao_testing_suite_cw4() { + let mut suite = DaoTestingSuiteBase::base(); + let mut suite = suite.cw4(); + let dao = suite.dao(); + + let voting_module: Addr = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::VotingModule {}, + ) + .unwrap(); + assert_eq!(voting_module, dao.voting_module_addr); + + let proposal_modules: Vec = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::ProposalModules { + start_after: None, + limit: None, + }, + ) + .unwrap(); + assert_eq!(proposal_modules.len(), 2); + + let group_addr: Addr = suite + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw4::msg::QueryMsg::GroupContract {}, + ) + .unwrap(); + assert_eq!(group_addr, dao.x.group_addr); + + let total_weight: dao_interface::voting::TotalPowerAtHeightResponse = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::TotalPowerAtHeight { height: None }, + ) + .unwrap(); + assert_eq!( + total_weight.power, + suite + .members + .iter() + .fold(Uint128::zero(), |acc, m| acc + Uint128::from(m.weight)) + ); + } +} diff --git a/packages/dao-testing/src/suite/cw721_suite.rs b/packages/dao-testing/src/suite/cw721_suite.rs new file mode 100644 index 000000000..001f20c06 --- /dev/null +++ b/packages/dao-testing/src/suite/cw721_suite.rs @@ -0,0 +1,246 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{to_json_binary, Addr, Binary, Empty}; +use cw_utils::Duration; + +use super::*; + +#[cw_serde] +pub struct InitialNft { + pub token_id: String, + pub owner: String, +} + +pub struct DaoTestingSuiteCw721<'a> { + pub base: &'a mut DaoTestingSuiteBase, + + pub initial_nfts: Vec, + pub unstaking_duration: Option, + pub active_threshold: Option, +} + +#[derive(Clone, Debug)] +pub struct Cw721DaoExtra { + pub cw721_addr: Addr, +} + +pub type Cw721TestDao = TestDao; + +impl<'a> DaoTestingSuiteCw721<'a> { + pub fn new(base: &'a mut DaoTestingSuiteBase) -> Self { + Self { + base, + + initial_nfts: vec![ + InitialNft { + token_id: "1".to_string(), + owner: MEMBER1.to_string(), + }, + InitialNft { + token_id: "2".to_string(), + owner: MEMBER2.to_string(), + }, + InitialNft { + token_id: "3".to_string(), + owner: MEMBER3.to_string(), + }, + InitialNft { + token_id: "4".to_string(), + owner: MEMBER4.to_string(), + }, + InitialNft { + token_id: "5".to_string(), + owner: MEMBER5.to_string(), + }, + ], + unstaking_duration: None, + active_threshold: None, + } + } + + pub fn with_initial_nfts(&mut self, initial_nfts: Vec) -> &mut Self { + self.initial_nfts = initial_nfts; + self + } + + pub fn with_unstaking_duration(&mut self, unstaking_duration: Option) -> &mut Self { + self.unstaking_duration = unstaking_duration; + self + } + + pub fn with_active_threshold( + &mut self, + active_threshold: Option, + ) -> &mut Self { + self.active_threshold = active_threshold; + self + } + + /// stake NFT + pub fn stake( + &mut self, + dao: &Cw721TestDao, + staker: impl Into, + token_id: impl Into, + ) { + self.base + .app + .execute_contract( + Addr::unchecked(staker), + dao.x.cw721_addr.clone(), + &cw721_base::msg::ExecuteMsg::::SendNft { + contract: dao.voting_module_addr.to_string(), + token_id: token_id.into(), + msg: Binary::default(), + }, + &[], + ) + .unwrap(); + } + + /// unstake NFT + pub fn unstake( + &mut self, + dao: &Cw721TestDao, + staker: impl Into, + token_id: impl Into, + ) { + self.base + .app + .execute_contract( + Addr::unchecked(staker), + dao.voting_module_addr.clone(), + &dao_voting_cw721_staked::msg::ExecuteMsg::Unstake { + token_ids: vec![token_id.into()], + }, + &[], + ) + .unwrap(); + } +} + +impl<'a> DaoTestingSuite for DaoTestingSuiteCw721<'a> { + fn base(&self) -> &DaoTestingSuiteBase { + self.base + } + + fn base_mut(&mut self) -> &mut DaoTestingSuiteBase { + self.base + } + + fn get_voting_module_info(&self) -> dao_interface::state::ModuleInstantiateInfo { + dao_interface::state::ModuleInstantiateInfo { + code_id: self.base.voting_cw721_staked_id, + msg: to_json_binary(&dao_voting_cw721_staked::msg::InstantiateMsg { + nft_contract: dao_voting_cw721_staked::msg::NftContract::New { + code_id: self.base.cw721_base_id, + label: "voting NFT".to_string(), + msg: to_json_binary(&cw721_base::msg::InstantiateMsg { + name: "Voting NFT".to_string(), + symbol: "VOTE".to_string(), + minter: OWNER.to_string(), + }) + .unwrap(), + initial_nfts: self + .initial_nfts + .iter() + .map(|x| { + to_json_binary(&cw721_base::msg::ExecuteMsg::::Mint { + token_id: x.token_id.clone(), + owner: x.owner.clone(), + token_uri: None, + extension: Empty {}, + }) + .unwrap() + }) + .collect(), + }, + unstaking_duration: self.unstaking_duration, + active_threshold: self.active_threshold.clone(), + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "voting module".to_string(), + } + } + + fn get_dao_extra(&self, dao: &TestDao) -> Cw721DaoExtra { + let dao_voting_cw721_staked::state::Config { nft_address, .. } = self + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw721_staked::msg::QueryMsg::Config {}, + ) + .unwrap(); + + Cw721DaoExtra { + cw721_addr: nft_address, + } + } + + /// stake all initial NFTs and progress one block + fn dao_setup(&mut self, dao: &mut Cw721TestDao) { + for nft in self.initial_nfts.clone() { + self.stake(dao, nft.owner, nft.token_id); + } + + // staking takes effect at the next block + self.base.advance_block(); + } +} + +#[cfg(test)] +mod tests { + use cosmwasm_std::Uint128; + + use super::*; + + #[test] + fn dao_testing_suite_cw721() { + let mut suite = DaoTestingSuiteBase::base(); + let mut suite = suite.cw721(); + let dao = suite.dao(); + + let voting_module: Addr = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::VotingModule {}, + ) + .unwrap(); + assert_eq!(voting_module, dao.voting_module_addr); + + let proposal_modules: Vec = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::ProposalModules { + start_after: None, + limit: None, + }, + ) + .unwrap(); + assert_eq!(proposal_modules.len(), 2); + + let dao_voting_cw721_staked::state::Config { nft_address, .. } = suite + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_cw721_staked::msg::QueryMsg::Config {}, + ) + .unwrap(); + assert_eq!(nft_address, dao.x.cw721_addr); + + let total_weight: dao_interface::voting::TotalPowerAtHeightResponse = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::TotalPowerAtHeight { height: None }, + ) + .unwrap(); + assert_eq!( + total_weight.power, + Uint128::from(suite.initial_nfts.len() as u128) + ); + } +} diff --git a/packages/dao-testing/src/suite/mod.rs b/packages/dao-testing/src/suite/mod.rs new file mode 100644 index 000000000..312380ede --- /dev/null +++ b/packages/dao-testing/src/suite/mod.rs @@ -0,0 +1,23 @@ +mod base; +mod cw20_suite; +mod cw4_suite; +mod cw721_suite; +mod token_suite; + +pub const OWNER: &str = "owner"; + +pub const MEMBER1: &str = "member1"; +pub const MEMBER2: &str = "member2"; +pub const MEMBER3: &str = "member3"; +pub const MEMBER4: &str = "member4"; +pub const MEMBER5: &str = "member5"; + +pub const GOV_DENOM: &str = "ugovtoken"; + +pub use cw_multi_test::Executor; + +pub use base::*; +pub use cw20_suite::*; +pub use cw4_suite::*; +pub use cw721_suite::*; +pub use token_suite::*; diff --git a/packages/dao-testing/src/suite/token_suite.rs b/packages/dao-testing/src/suite/token_suite.rs new file mode 100644 index 000000000..35e686f70 --- /dev/null +++ b/packages/dao-testing/src/suite/token_suite.rs @@ -0,0 +1,228 @@ +use cosmwasm_std::{coins, to_json_binary, Addr, Uint128}; +use cw_multi_test::{BankSudo, SudoMsg}; +use cw_utils::Duration; +use dao_interface::token::InitialBalance; + +use super::*; + +pub struct DaoTestingSuiteToken<'a> { + pub base: &'a mut DaoTestingSuiteBase, + + pub initial_balances: Vec, + pub unstaking_duration: Option, + pub active_threshold: Option, +} + +#[derive(Clone, Debug)] +pub struct TokenDaoExtra { + pub denom: String, +} + +pub type TokenTestDao = TestDao; + +impl<'a> DaoTestingSuiteToken<'a> { + pub fn new(base: &'a mut DaoTestingSuiteBase) -> Self { + Self { + base, + + initial_balances: vec![ + InitialBalance { + address: MEMBER1.to_string(), + amount: Uint128::new(100), + }, + InitialBalance { + address: MEMBER2.to_string(), + amount: Uint128::new(200), + }, + InitialBalance { + address: MEMBER3.to_string(), + amount: Uint128::new(300), + }, + InitialBalance { + address: MEMBER4.to_string(), + amount: Uint128::new(300), + }, + InitialBalance { + address: MEMBER5.to_string(), + amount: Uint128::new(100), + }, + ], + unstaking_duration: None, + active_threshold: None, + } + } + + pub fn with_initial_balances(&mut self, initial_balances: Vec) -> &mut Self { + self.initial_balances = initial_balances; + self + } + + pub fn with_unstaking_duration(&mut self, unstaking_duration: Option) -> &mut Self { + self.unstaking_duration = unstaking_duration; + self + } + + pub fn with_active_threshold( + &mut self, + active_threshold: Option, + ) -> &mut Self { + self.active_threshold = active_threshold; + self + } + + /// mint tokens + pub fn mint( + &mut self, + dao: &TokenTestDao, + recipient: impl Into, + amount: impl Into, + ) { + self.base + .app + .sudo(SudoMsg::Bank({ + BankSudo::Mint { + to_address: recipient.into(), + amount: coins(amount.into(), &dao.x.denom), + } + })) + .unwrap(); + } + + /// stake tokens + pub fn stake( + &mut self, + dao: &TokenTestDao, + staker: impl Into, + amount: impl Into, + ) { + self.base + .app + .execute_contract( + Addr::unchecked(staker), + dao.voting_module_addr.clone(), + &dao_voting_token_staked::msg::ExecuteMsg::Stake {}, + &coins(amount.into(), &dao.x.denom), + ) + .unwrap(); + } + + /// unstake tokens + pub fn unstake( + &mut self, + dao: &TokenTestDao, + staker: impl Into, + amount: impl Into, + ) { + self.base + .app + .execute_contract( + Addr::unchecked(staker), + dao.voting_module_addr.clone(), + &dao_voting_token_staked::msg::ExecuteMsg::Unstake { + amount: amount.into(), + }, + &[], + ) + .unwrap(); + } +} + +impl<'a> DaoTestingSuite for DaoTestingSuiteToken<'a> { + fn base(&self) -> &DaoTestingSuiteBase { + self.base + } + + fn base_mut(&mut self) -> &mut DaoTestingSuiteBase { + self.base + } + + fn get_voting_module_info(&self) -> dao_interface::state::ModuleInstantiateInfo { + dao_interface::state::ModuleInstantiateInfo { + code_id: self.base.voting_token_staked_id, + msg: to_json_binary(&dao_voting_token_staked::msg::InstantiateMsg { + token_info: dao_voting_token_staked::msg::TokenInfo::Existing { + denom: GOV_DENOM.to_string(), + }, + unstaking_duration: self.unstaking_duration, + active_threshold: self.active_threshold.clone(), + }) + .unwrap(), + admin: Some(dao_interface::state::Admin::CoreModule {}), + funds: vec![], + label: "voting module".to_string(), + } + } + + fn get_dao_extra(&self, dao: &TestDao) -> TokenDaoExtra { + let dao_interface::voting::DenomResponse { denom } = self + .querier() + .query_wasm_smart( + &dao.voting_module_addr, + &dao_voting_token_staked::msg::QueryMsg::Denom {}, + ) + .unwrap(); + + TokenDaoExtra { denom } + } + + /// mint and stake all initial balances and progress one block + fn dao_setup(&mut self, dao: &mut TokenTestDao) { + for member in self.initial_balances.clone() { + self.mint(dao, member.address.clone(), member.amount); + self.stake(dao, member.address, member.amount); + } + + // staking takes effect at the next block + self.base.advance_block(); + } +} + +#[cfg(test)] +mod tests { + use cosmwasm_std::Uint128; + + use super::*; + + #[test] + fn dao_testing_suite_token() { + let mut suite = DaoTestingSuiteBase::base(); + let mut suite = suite.token(); + let dao = suite.dao(); + + let voting_module: Addr = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::VotingModule {}, + ) + .unwrap(); + assert_eq!(voting_module, dao.voting_module_addr); + + let proposal_modules: Vec = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::ProposalModules { + start_after: None, + limit: None, + }, + ) + .unwrap(); + assert_eq!(proposal_modules.len(), 2); + + let total_weight: dao_interface::voting::TotalPowerAtHeightResponse = suite + .querier() + .query_wasm_smart( + &dao.core_addr, + &dao_interface::msg::QueryMsg::TotalPowerAtHeight { height: None }, + ) + .unwrap(); + assert_eq!( + total_weight.power, + suite + .initial_balances + .iter() + .fold(Uint128::zero(), |acc, m| acc + m.amount) + ); + } +} diff --git a/scripts/publish.sh b/scripts/publish.sh index 4eb17e1e6..604440d36 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -31,7 +31,7 @@ START_DIR=$(pwd) # Packages cd packages/cw-denom -cargo publish +cargo hack publish --no-dev-deps --allow-dirty cd "$START_DIR" cd packages/cw-hooks