diff --git a/contracts/delegation/dao-vote-delegation/src/testing/mod.rs b/contracts/delegation/dao-vote-delegation/src/testing/mod.rs index 591459a01..836069a0a 100644 --- a/contracts/delegation/dao-vote-delegation/src/testing/mod.rs +++ b/contracts/delegation/dao-vote-delegation/src/testing/mod.rs @@ -1,4 +1,2 @@ pub mod suite; pub mod tests; - -pub use suite::*; diff --git a/contracts/delegation/dao-vote-delegation/src/testing/suite.rs b/contracts/delegation/dao-vote-delegation/src/testing/suite/base.rs similarity index 79% rename from contracts/delegation/dao-vote-delegation/src/testing/suite.rs rename to contracts/delegation/dao-vote-delegation/src/testing/suite/base.rs index 0a3b5728f..de897ba14 100644 --- a/contracts/delegation/dao-vote-delegation/src/testing/suite.rs +++ b/contracts/delegation/dao-vote-delegation/src/testing/suite/base.rs @@ -2,25 +2,23 @@ use std::ops::{Deref, DerefMut}; use cosmwasm_std::{Addr, Decimal, Uint128}; use dao_interface::helpers::{OptionalUpdate, Update}; -use dao_testing::{Cw4TestDao, DaoTestingSuite, DaoTestingSuiteBase}; +use dao_testing::DaoTestingSuiteBase; use crate::ContractError; -use super::tests::dao_vote_delegation_contract; +use super::super::tests::dao_vote_delegation_contract; -pub struct DaoVoteDelegationTestingSuite { +pub struct DaoVoteDelegationTestingSuiteBase { /// base testing suite that we're extending pub base: DaoTestingSuiteBase, // initial config - vp_cap_percent: Option, - delegation_validity_blocks: Option, - max_delegations: Option, + pub vp_cap_percent: Option, + pub delegation_validity_blocks: Option, + pub max_delegations: Option, - /// cw4-group voting DAO - pub dao: Cw4TestDao, - /// members of the DAO - pub members: Vec, + /// DAO core address + pub dao_core_addr: Addr, /// delegation code ID pub delegation_code_id: u64, @@ -29,7 +27,7 @@ pub struct DaoVoteDelegationTestingSuite { } // allow direct access to base testing suite methods -impl Deref for DaoVoteDelegationTestingSuite { +impl Deref for DaoVoteDelegationTestingSuiteBase { type Target = DaoTestingSuiteBase; fn deref(&self) -> &Self::Target { @@ -38,21 +36,18 @@ impl Deref for DaoVoteDelegationTestingSuite { } // allow direct access to base testing suite methods -impl DerefMut for DaoVoteDelegationTestingSuite { +impl DerefMut for DaoVoteDelegationTestingSuiteBase { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.base } } // CONSTRUCTOR -impl DaoVoteDelegationTestingSuite { +impl DaoVoteDelegationTestingSuiteBase { pub fn new() -> Self { let mut base = DaoTestingSuiteBase::base(); let mut suite = base.cw4(); - let members = suite.members.clone(); - let dao = suite.dao(); - let delegation_code_id = suite.store(dao_vote_delegation_contract); Self { @@ -62,84 +57,16 @@ impl DaoVoteDelegationTestingSuite { delegation_validity_blocks: None, max_delegations: None, - dao, - members, + dao_core_addr: Addr::unchecked(""), delegation_code_id, delegation_addr: Addr::unchecked(""), } } - - pub fn with_vp_cap_percent(mut self, vp_cap_percent: Decimal) -> Self { - self.vp_cap_percent = Some(vp_cap_percent); - self - } - - pub fn with_delegation_validity_blocks(mut self, delegation_validity_blocks: u64) -> Self { - self.delegation_validity_blocks = Some(delegation_validity_blocks); - self - } - - pub fn with_max_delegations(mut self, max_delegations: u64) -> Self { - self.max_delegations = Some(max_delegations); - self - } - - pub fn build(mut self) -> Self { - let code_id = self.delegation_code_id; - let core_addr = self.dao.core_addr.clone(); - let group_addr = self.dao.x.group_addr.to_string(); - let vp_cap_percent = self.vp_cap_percent; - let delegation_validity_blocks = self.delegation_validity_blocks; - let max_delegations = self.max_delegations; - - self.delegation_addr = self.instantiate( - code_id, - &core_addr, - &crate::msg::InstantiateMsg { - dao: None, - vp_hook_callers: Some(vec![group_addr]), - no_sync_proposal_modules: None, - vp_cap_percent, - delegation_validity_blocks, - max_delegations, - }, - &[], - "delegation", - Some(core_addr.to_string()), - ); - - self.setup_delegation_module(); - - self - } } // EXECUTIONS -impl DaoVoteDelegationTestingSuite { - /// set up delegation module by adding necessary hooks and adding it to the - /// proposal modules - pub fn setup_delegation_module(&mut self) { - let dao = self.dao.clone(); - let delegation_addr = self.delegation_addr.to_string(); - - // add voting power changed hook to cw4-group - self.execute_smart_ok( - &dao.core_addr, - &dao.x.group_addr, - &cw4::Cw4ExecuteMsg::AddHook { - addr: delegation_addr.clone(), - }, - &[], - ); - - // add vote hook to all proposal modules - self.add_vote_hook(&dao, &delegation_addr); - - // set the delegation module for all proposal modules - self.set_delegation_module(&dao, &delegation_addr); - } - +impl DaoVoteDelegationTestingSuiteBase { /// register a user as a delegate pub fn register(&mut self, delegate: impl Into) { let delegation_addr = self.delegation_addr.clone(); @@ -219,7 +146,7 @@ impl DaoVoteDelegationTestingSuite { add: Option>, remove: Option>, ) { - let core_addr = self.dao.core_addr.clone(); + let core_addr = self.dao_core_addr.clone(); let delegation_addr = self.delegation_addr.clone(); self.execute_smart_ok( core_addr, @@ -231,7 +158,7 @@ impl DaoVoteDelegationTestingSuite { /// sync proposal modules pub fn sync_proposal_modules(&mut self, start_after: Option, limit: Option) { - let core_addr = self.dao.core_addr.clone(); + let core_addr = self.dao_core_addr.clone(); let delegation_addr = self.delegation_addr.clone(); self.execute_smart_ok( core_addr, @@ -243,7 +170,7 @@ impl DaoVoteDelegationTestingSuite { /// update VP cap percent pub fn update_vp_cap_percent(&mut self, vp_cap_percent: Option) { - let core_addr = self.dao.core_addr.clone(); + let core_addr = self.dao_core_addr.clone(); let delegation_addr = self.delegation_addr.clone(); self.execute_smart_ok( core_addr, @@ -261,7 +188,7 @@ impl DaoVoteDelegationTestingSuite { /// update delegation validity blocks pub fn update_delegation_validity_blocks(&mut self, delegation_validity_blocks: Option) { - let core_addr = self.dao.core_addr.clone(); + let core_addr = self.dao_core_addr.clone(); let delegation_addr = self.delegation_addr.clone(); self.execute_smart_ok( core_addr, @@ -279,7 +206,7 @@ impl DaoVoteDelegationTestingSuite { /// update max delegations pub fn update_max_delegations(&mut self, max_delegations: u64) { - let core_addr = self.dao.core_addr.clone(); + let core_addr = self.dao_core_addr.clone(); let delegation_addr = self.delegation_addr.clone(); self.execute_smart_ok( core_addr, @@ -295,7 +222,7 @@ impl DaoVoteDelegationTestingSuite { } /// QUERIES -impl DaoVoteDelegationTestingSuite { +impl DaoVoteDelegationTestingSuiteBase { /// get whether a delegate is registered pub fn registered(&self, delegate: impl Into, height: Option) -> bool { self.querier() @@ -400,7 +327,7 @@ impl DaoVoteDelegationTestingSuite { } /// ASSERTIONS -impl DaoVoteDelegationTestingSuite { +impl DaoVoteDelegationTestingSuiteBase { /// assert that there are N delegations pub fn assert_delegations_count(&self, delegator: impl Into, count: u32) { let delegations = self.delegations(delegator, None, None, None); diff --git a/contracts/delegation/dao-vote-delegation/src/testing/suite/cw4.rs b/contracts/delegation/dao-vote-delegation/src/testing/suite/cw4.rs new file mode 100644 index 000000000..544be9aaf --- /dev/null +++ b/contracts/delegation/dao-vote-delegation/src/testing/suite/cw4.rs @@ -0,0 +1,114 @@ +use std::ops::{Deref, DerefMut}; + +use cosmwasm_std::Decimal; +use dao_testing::{Cw4TestDao, DaoTestingSuite}; + +use super::base::DaoVoteDelegationTestingSuiteBase; + +pub struct Cw4DaoVoteDelegationTestingSuite { + /// base testing suite that we're extending + pub base: DaoVoteDelegationTestingSuiteBase, + + /// cw4-group voting DAO + pub dao: Cw4TestDao, + /// members of the DAO + pub members: Vec, +} + +// allow direct access to base testing suite methods +impl Deref for Cw4DaoVoteDelegationTestingSuite { + type Target = DaoVoteDelegationTestingSuiteBase; + + fn deref(&self) -> &Self::Target { + &self.base + } +} + +// allow direct access to base testing suite methods +impl DerefMut for Cw4DaoVoteDelegationTestingSuite { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.base + } +} + +// CONSTRUCTOR +impl Cw4DaoVoteDelegationTestingSuite { + pub fn new() -> Self { + let mut base = DaoVoteDelegationTestingSuiteBase::new(); + let mut suite = base.cw4(); + + let members = suite.members.clone(); + let dao = suite.dao(); + + base.dao_core_addr = dao.core_addr.clone(); + + Self { base, dao, members } + } + + pub fn with_vp_cap_percent(mut self, vp_cap_percent: Decimal) -> Self { + self.vp_cap_percent = Some(vp_cap_percent); + self + } + + pub fn with_delegation_validity_blocks(mut self, delegation_validity_blocks: u64) -> Self { + self.delegation_validity_blocks = Some(delegation_validity_blocks); + self + } + + pub fn with_max_delegations(mut self, max_delegations: u64) -> Self { + self.max_delegations = Some(max_delegations); + self + } + + pub fn build(mut self) -> Self { + let code_id = self.delegation_code_id; + let core_addr = self.dao.core_addr.clone(); + let group_addr = self.dao.x.group_addr.to_string(); + let vp_cap_percent = self.vp_cap_percent; + let delegation_validity_blocks = self.delegation_validity_blocks; + let max_delegations = self.max_delegations; + + self.delegation_addr = self.instantiate( + code_id, + &core_addr, + &crate::msg::InstantiateMsg { + dao: None, + vp_hook_callers: Some(vec![group_addr]), + no_sync_proposal_modules: None, + vp_cap_percent, + delegation_validity_blocks, + max_delegations, + }, + &[], + "delegation", + Some(core_addr.to_string()), + ); + + self.setup_delegation_module(); + + self + } + + /// set up delegation module by adding necessary hooks and adding it to the + /// proposal modules + pub fn setup_delegation_module(&mut self) { + let dao = self.dao.clone(); + let delegation_addr = self.delegation_addr.to_string(); + + // add voting power changed hook to cw4-group + self.execute_smart_ok( + &dao.core_addr, + &dao.x.group_addr, + &cw4::Cw4ExecuteMsg::AddHook { + addr: delegation_addr.clone(), + }, + &[], + ); + + // add vote hook to all proposal modules + self.add_vote_hook(&dao, &delegation_addr); + + // set the delegation module for all proposal modules + self.set_delegation_module(&dao, &delegation_addr); + } +} diff --git a/contracts/delegation/dao-vote-delegation/src/testing/suite/mod.rs b/contracts/delegation/dao-vote-delegation/src/testing/suite/mod.rs new file mode 100644 index 000000000..10ddffdea --- /dev/null +++ b/contracts/delegation/dao-vote-delegation/src/testing/suite/mod.rs @@ -0,0 +1,3 @@ +pub mod base; +pub mod cw4; +pub mod token; diff --git a/contracts/delegation/dao-vote-delegation/src/testing/suite/token.rs b/contracts/delegation/dao-vote-delegation/src/testing/suite/token.rs new file mode 100644 index 000000000..dddcbfd1d --- /dev/null +++ b/contracts/delegation/dao-vote-delegation/src/testing/suite/token.rs @@ -0,0 +1,115 @@ +use std::ops::{Deref, DerefMut}; + +use cosmwasm_std::Decimal; +use dao_interface::token::InitialBalance; +use dao_testing::{DaoTestingSuite, TokenTestDao}; + +use super::base::DaoVoteDelegationTestingSuiteBase; + +pub struct TokenDaoVoteDelegationTestingSuite { + /// base testing suite that we're extending + pub base: DaoVoteDelegationTestingSuiteBase, + + /// token-based voting DAO + pub dao: TokenTestDao, + /// members of the DAO + pub members: Vec, +} + +// allow direct access to base testing suite methods +impl Deref for TokenDaoVoteDelegationTestingSuite { + type Target = DaoVoteDelegationTestingSuiteBase; + + fn deref(&self) -> &Self::Target { + &self.base + } +} + +// allow direct access to base testing suite methods +impl DerefMut for TokenDaoVoteDelegationTestingSuite { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.base + } +} + +// CONSTRUCTOR +impl TokenDaoVoteDelegationTestingSuite { + pub fn new() -> Self { + let mut base = DaoVoteDelegationTestingSuiteBase::new(); + let mut suite = base.token(); + + let members = suite.initial_balances.clone(); + let dao = suite.dao(); + + base.dao_core_addr = dao.core_addr.clone(); + + Self { base, dao, members } + } + + pub fn with_vp_cap_percent(mut self, vp_cap_percent: Decimal) -> Self { + self.vp_cap_percent = Some(vp_cap_percent); + self + } + + pub fn with_delegation_validity_blocks(mut self, delegation_validity_blocks: u64) -> Self { + self.delegation_validity_blocks = Some(delegation_validity_blocks); + self + } + + pub fn with_max_delegations(mut self, max_delegations: u64) -> Self { + self.max_delegations = Some(max_delegations); + self + } + + pub fn build(mut self) -> Self { + let code_id = self.delegation_code_id; + let core_addr = self.dao.core_addr.clone(); + let voting_module_addr = self.dao.voting_module_addr.clone(); + let vp_cap_percent = self.vp_cap_percent; + let delegation_validity_blocks = self.delegation_validity_blocks; + let max_delegations = self.max_delegations; + + self.delegation_addr = self.instantiate( + code_id, + &core_addr, + &crate::msg::InstantiateMsg { + dao: None, + vp_hook_callers: Some(vec![voting_module_addr.to_string()]), + no_sync_proposal_modules: None, + vp_cap_percent, + delegation_validity_blocks, + max_delegations, + }, + &[], + "delegation", + Some(core_addr.to_string()), + ); + + self.setup_delegation_module(); + + self + } + + /// set up delegation module by adding necessary hooks and adding it to the + /// proposal modules + pub fn setup_delegation_module(&mut self) { + let dao = self.dao.clone(); + let delegation_addr = self.delegation_addr.to_string(); + + // add voting power changed hook to voting module + self.execute_smart_ok( + &dao.core_addr, + &dao.voting_module_addr, + &dao_voting_token_staked::msg::ExecuteMsg::AddHook { + addr: delegation_addr.clone(), + }, + &[], + ); + + // add vote hook to all proposal modules + self.add_vote_hook(&dao, &delegation_addr); + + // set the delegation module for all proposal modules + self.set_delegation_module(&dao, &delegation_addr); + } +} diff --git a/contracts/delegation/dao-vote-delegation/src/testing/tests.rs b/contracts/delegation/dao-vote-delegation/src/testing/tests.rs index 37543d0ca..ebe77016f 100644 --- a/contracts/delegation/dao-vote-delegation/src/testing/tests.rs +++ b/contracts/delegation/dao-vote-delegation/src/testing/tests.rs @@ -11,7 +11,9 @@ use crate::{ ContractError, }; -use super::*; +use super::suite::{ + cw4::Cw4DaoVoteDelegationTestingSuite, token::TokenDaoVoteDelegationTestingSuite, +}; pub fn dao_vote_delegation_contract() -> Box> { let contract = ContractWrapper::new( @@ -25,7 +27,7 @@ pub fn dao_vote_delegation_contract() -> Box> { #[test] fn test_simple() { - let mut suite = DaoVoteDelegationTestingSuite::new() + let mut suite = Cw4DaoVoteDelegationTestingSuite::new() .with_vp_cap_percent(Decimal::percent(50)) .with_delegation_validity_blocks(10) .build(); @@ -220,7 +222,7 @@ fn test_simple() { #[test] fn test_vp_cap_update() { - let mut suite = DaoVoteDelegationTestingSuite::new() + let mut suite = Cw4DaoVoteDelegationTestingSuite::new() .with_vp_cap_percent(Decimal::percent(50)) .with_delegation_validity_blocks(10) .build(); @@ -377,7 +379,7 @@ fn test_vp_cap_update() { #[test] fn test_expiration_update() { - let mut suite = DaoVoteDelegationTestingSuite::new() + let mut suite = Cw4DaoVoteDelegationTestingSuite::new() .with_delegation_validity_blocks(10) .build(); @@ -452,7 +454,7 @@ fn test_expiration_update() { #[test] fn test_max_delegations() { - let mut suite = DaoVoteDelegationTestingSuite::new() + let mut suite = Cw4DaoVoteDelegationTestingSuite::new() .with_max_delegations(2) .build(); @@ -518,7 +520,7 @@ fn test_max_delegations() { #[test] fn test_update_hook_callers() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); let dao = suite.dao.clone(); // ensure setup correctly @@ -575,7 +577,7 @@ fn test_update_hook_callers() { #[test] fn test_vote_with_override() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); let dao = suite.dao.clone(); // register ADDR0 and ADDR3 as delegates @@ -695,7 +697,7 @@ fn test_vote_with_override() { #[test] fn test_overrideable_vote_doesnt_end_proposal_early() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); let dao = suite.dao.clone(); // register ADDR0 and ADDR1 as delegates @@ -795,7 +797,7 @@ fn test_overrideable_vote_doesnt_end_proposal_early() { #[test] fn test_allow_register_after_unregister_same_block() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.unregister(ADDR0); @@ -808,7 +810,7 @@ fn test_allow_register_after_unregister_same_block() { #[test] fn test_allow_register_after_unregister_next_block() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.advance_block(); @@ -824,7 +826,7 @@ fn test_allow_register_after_unregister_next_block() { #[test] #[should_panic(expected = "invalid delegation validity blocks: provided 1, minimum 2")] fn test_validate_delegation_validity_blocks() { - DaoVoteDelegationTestingSuite::new() + Cw4DaoVoteDelegationTestingSuite::new() .with_delegation_validity_blocks(1) .build(); } @@ -832,7 +834,7 @@ fn test_validate_delegation_validity_blocks() { #[test] #[should_panic(expected = "invalid delegation validity blocks: provided 1, minimum 2")] fn test_validate_delegation_validity_blocks_update() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.update_delegation_validity_blocks(Some(1)); } @@ -840,7 +842,7 @@ fn test_validate_delegation_validity_blocks_update() { #[test] fn test_max_delegations_config() { // instantiate with nothing, should set default - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.assert_max_delegations(DEFAULT_MAX_DELEGATIONS); @@ -849,7 +851,7 @@ fn test_max_delegations_config() { suite.assert_max_delegations(75); // instantiate with a value set - let suite = DaoVoteDelegationTestingSuite::new() + let suite = Cw4DaoVoteDelegationTestingSuite::new() .with_max_delegations(100) .build(); @@ -859,7 +861,7 @@ fn test_max_delegations_config() { #[test] #[should_panic(expected = "delegate already registered")] fn test_no_double_register() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.register(ADDR0); @@ -868,7 +870,7 @@ fn test_no_double_register() { #[test] #[should_panic(expected = "no voting power")] fn test_no_vp_register() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register("non_member"); } @@ -876,7 +878,7 @@ fn test_no_vp_register() { #[test] #[should_panic(expected = "cannot register as a delegate with existing delegations")] fn test_cannot_register_with_delegations_same_block() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.delegate(ADDR1, ADDR0, Decimal::percent(100)); @@ -886,7 +888,7 @@ fn test_cannot_register_with_delegations_same_block() { #[test] #[should_panic(expected = "cannot register as a delegate with existing delegations")] fn test_cannot_register_with_delegations_next_block() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.delegate(ADDR1, ADDR0, Decimal::percent(100)); @@ -897,7 +899,7 @@ fn test_cannot_register_with_delegations_next_block() { #[test] #[should_panic(expected = "delegate not registered")] fn test_cannot_unregister_unregistered() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.unregister(ADDR0); } @@ -905,7 +907,7 @@ fn test_cannot_unregister_unregistered() { #[test] #[should_panic(expected = "invalid voting power percent")] fn test_cannot_delegate_zero_percent() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.delegate(ADDR1, ADDR0, Decimal::zero()); @@ -914,7 +916,7 @@ fn test_cannot_delegate_zero_percent() { #[test] #[should_panic(expected = "invalid voting power percent")] fn test_cannot_delegate_more_than_100_percent() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.delegate(ADDR1, ADDR0, Decimal::percent(101)); @@ -923,7 +925,7 @@ fn test_cannot_delegate_more_than_100_percent() { #[test] #[should_panic(expected = "delegates cannot delegate to others")] fn test_delegates_cannot_delegate() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.register(ADDR1); @@ -933,7 +935,7 @@ fn test_delegates_cannot_delegate() { #[test] #[should_panic(expected = "delegate not registered")] fn test_cannot_delegate_unregistered() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.delegate(ADDR0, ADDR1, Decimal::percent(100)); } @@ -941,7 +943,7 @@ fn test_cannot_delegate_unregistered() { #[test] #[should_panic(expected = "no voting power")] fn test_cannot_delegate_no_vp() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.delegate("not_member", ADDR0, Decimal::percent(100)); @@ -950,7 +952,7 @@ fn test_cannot_delegate_no_vp() { #[test] #[should_panic(expected = "cannot delegate more than 100% (current: 50%, attempt: 101%)")] fn test_cannot_delegate_more_than_100() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.register(ADDR1); @@ -961,14 +963,14 @@ fn test_cannot_delegate_more_than_100() { #[test] #[should_panic(expected = "delegation does not exist")] fn test_cannot_undelegate_nonexistent() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.undelegate(ADDR0, ADDR1); } #[test] fn test_delegate_undelegate_same_block() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.delegate(ADDR1, ADDR0, Decimal::percent(100)); @@ -978,7 +980,7 @@ fn test_delegate_undelegate_same_block() { #[test] #[should_panic(expected = "delegation does not exist")] fn test_cannot_undelegate_twice() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); suite.register(ADDR0); suite.delegate(ADDR1, ADDR0, Decimal::percent(100)); @@ -989,7 +991,7 @@ fn test_cannot_undelegate_twice() { #[test] #[should_panic(expected = "unauthorized")] fn test_unauthorized_update_voting_power_hook_callers() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); let delegation_addr = suite.delegation_addr.clone(); suite.execute_smart_ok( @@ -1006,7 +1008,7 @@ fn test_unauthorized_update_voting_power_hook_callers() { #[test] #[should_panic(expected = "unauthorized")] fn test_unauthorized_config_update() { - let mut suite = DaoVoteDelegationTestingSuite::new().build(); + let mut suite = Cw4DaoVoteDelegationTestingSuite::new().build(); let delegation_addr = suite.delegation_addr.clone(); suite.execute_smart_ok( @@ -1068,3 +1070,187 @@ fn test_migrate() { assert_eq!(version.contract, CONTRACT_NAME); assert_eq!(version.version, CONTRACT_VERSION); } + +#[test] +fn test_vp_cap_update_token_dao() { + let mut suite = TokenDaoVoteDelegationTestingSuite::new() + .with_vp_cap_percent(Decimal::percent(50)) + .with_delegation_validity_blocks(10) + .with_max_delegations(100) + .build(); + let dao = suite.dao.clone(); + + // register ADDR0 as a delegate + suite.register(ADDR0); + + // delegate 100% of every other member's voting power to ADDR0 + for member in suite.members.clone() { + if member.address != ADDR0 { + suite.delegate(member.address, ADDR0, Decimal::percent(100)); + } + } + + // delegations take effect on the next block + suite.advance_block(); + + let total_vp_except_addr0 = suite + .members + .iter() + .map(|m| { + if m.address == ADDR0 { + 0 + } else { + m.amount.into() + } + }) + .sum::(); + suite.assert_delegate_total_delegated_vp(ADDR0, total_vp_except_addr0); + + // propose a proposal + let (proposal_module, id1, p1) = + suite.propose_single_choice(&dao, ADDR0, "test proposal", vec![]); + + // ensure delegation is correctly applied to proposal and that VP cap is + // applied correctly. effective should be 50% of total voting power, and + // total should be everything that's delegated to ADDR0 + suite.assert_effective_udvp( + ADDR0, + &proposal_module, + id1, + p1.start_height, + // VP cap is set to 50% of total voting power + suite + .members + .iter() + .map(|m| m.amount) + .sum::() + .mul_floor(Decimal::percent(50)), + ); + suite.assert_total_udvp( + ADDR0, + &proposal_module, + id1, + p1.start_height, + total_vp_except_addr0, + ); + + // change VP cap to 30% of total + suite.update_vp_cap_percent(Some(Decimal::percent(30))); + // updates take effect on the next block + suite.advance_block(); + + // propose another proposal + let (_, id2, p2) = suite.propose_single_choice(&dao, ADDR0, "test proposal", vec![]); + + // ensure delegation is correctly applied to proposal and that VP cap is + // applied correctly. effective should be 30% of total voting power, and + // total should still be everything that's delegated to ADDR0 + suite.assert_effective_udvp( + ADDR0, + &proposal_module, + id2, + p2.start_height, + // VP cap is set to 30% of total voting power + suite + .members + .iter() + .map(|m| m.amount) + .sum::() + .mul_floor(Decimal::percent(30)), + ); + suite.assert_total_udvp( + ADDR0, + &proposal_module, + id2, + p2.start_height, + total_vp_except_addr0, + ); + + // old proposal should still use old VP cap + suite.assert_effective_udvp( + ADDR0, + &proposal_module, + id1, + p1.start_height, + // VP cap is set to 50% of total voting power + suite + .members + .iter() + .map(|m| m.amount) + .sum::() + .mul_floor(Decimal::percent(50)), + ); + suite.assert_total_udvp( + ADDR0, + &proposal_module, + id1, + p1.start_height, + total_vp_except_addr0, + ); + + // remove VP cap + suite.update_vp_cap_percent(None); + // updates take effect on the next block + suite.advance_block(); + + // propose another proposal + let (_, id3, p3) = suite.propose_single_choice(&dao, ADDR0, "test proposal", vec![]); + + // effective should now be equal to total since there is no cap + suite.assert_effective_udvp( + ADDR0, + &proposal_module, + id3, + p3.start_height, + total_vp_except_addr0, + ); + suite.assert_total_udvp( + ADDR0, + &proposal_module, + id3, + p3.start_height, + total_vp_except_addr0, + ); + + // old proposals should still use old VP caps + suite.assert_effective_udvp( + ADDR0, + &proposal_module, + id2, + p2.start_height, + // VP cap is set to 30% of total voting power + suite + .members + .iter() + .map(|m| m.amount) + .sum::() + .mul_floor(Decimal::percent(30)), + ); + suite.assert_total_udvp( + ADDR0, + &proposal_module, + id2, + p2.start_height, + total_vp_except_addr0, + ); + suite.assert_effective_udvp( + ADDR0, + &proposal_module, + id1, + p1.start_height, + // VP cap is set to 50% of total voting power + suite + .members + .iter() + .map(|m| m.amount) + .sum::() + .mul_floor(Decimal::percent(50)), + ); + suite.assert_total_udvp( + ADDR0, + &proposal_module, + id1, + p1.start_height, + total_vp_except_addr0, + ); +}