Skip to content

Commit

Permalink
Auto Pass Props if User Controls 100% of Voting power DA0-DA0#759
Browse files Browse the repository at this point in the history
  • Loading branch information
nickf12 committed Nov 29, 2023
1 parent 6ca751c commit dc085a3
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 126 deletions.
51 changes: 32 additions & 19 deletions contracts/proposal/dao-proposal-single/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
to_json_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Order, Reply,
to_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Order, Reply,
Response, StdResult, Storage, SubMsg, WasmMsg,
};
use cw2::{get_contract_version, set_contract_version, ContractVersion};
Expand Down Expand Up @@ -183,6 +183,14 @@ pub fn execute_propose(
&dao_interface::msg::QueryMsg::VotingModule {},
)?;

// Get Proposer voting power
let power = get_voting_power(
deps.as_ref(),
proposer.clone(),
&config.dao,
Some(env.block.height),
)?;

// Voting modules are not required to implement this
// query. Lacking an implementation they are active by default.
let active_resp: IsActiveResponse = deps
Expand All @@ -200,6 +208,7 @@ pub fn execute_propose(

let proposal = {
// Limit mutability to this block.
// If proposer has voting power = total_power. AutoPass proposal
let mut proposal = SingleChoiceProposal {
title,
description,
Expand All @@ -210,7 +219,11 @@ pub fn execute_propose(
threshold: config.threshold,
total_power,
msgs,
status: Status::Open,
status: if power == total_power {
Status::Passed
} else {
Status::Open
},
votes: Votes::zero(),
allow_revoting: config.allow_revoting,
};
Expand All @@ -235,7 +248,7 @@ pub fn execute_propose(
//
// `to_vec` is the method used by cosmwasm to convert a struct
// into it's byte representation in storage.
let proposal_size = cosmwasm_std::to_json_vec(&proposal)?.len() as u64;
let proposal_size = cosmwasm_std::to_vec(&proposal)?.len() as u64;
if proposal_size > MAX_PROPOSAL_SIZE {
return Err(ContractError::ProposalTooLarge {
size: proposal_size,
Expand Down Expand Up @@ -295,7 +308,7 @@ pub fn execute_execute(
if !prop.msgs.is_empty() {
let execute_message = WasmMsg::Execute {
contract_addr: config.dao.to_string(),
msg: to_json_binary(&dao_interface::msg::ExecuteMsg::ExecuteProposalHook {
msg: to_binary(&dao_interface::msg::ExecuteMsg::ExecuteProposalHook {
msgs: prop.msgs,
})?,
funds: vec![],
Expand Down Expand Up @@ -326,7 +339,7 @@ pub fn execute_execute(
let hooks = match proposal_creation_policy {
ProposalCreationPolicy::Anyone {} => hooks,
ProposalCreationPolicy::Module { addr } => {
let msg = to_json_binary(&PreProposeHookMsg::ProposalCompletedHook {
let msg = to_binary(&PreProposeHookMsg::ProposalCompletedHook {
proposal_id,
new_status: prop.status,
})?;
Expand Down Expand Up @@ -515,7 +528,7 @@ pub fn execute_close(
let hooks = match proposal_creation_policy {
ProposalCreationPolicy::Anyone {} => hooks,
ProposalCreationPolicy::Module { addr } => {
let msg = to_json_binary(&PreProposeHookMsg::ProposalCompletedHook {
let msg = to_binary(&PreProposeHookMsg::ProposalCompletedHook {
proposal_id,
new_status: prop.status,
})?;
Expand Down Expand Up @@ -730,29 +743,29 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
limit,
} => query_reverse_proposals(deps, env, start_before, limit),
QueryMsg::ProposalCreationPolicy {} => query_creation_policy(deps),
QueryMsg::ProposalHooks {} => to_json_binary(&PROPOSAL_HOOKS.query_hooks(deps)?),
QueryMsg::VoteHooks {} => to_json_binary(&VOTE_HOOKS.query_hooks(deps)?),
QueryMsg::ProposalHooks {} => to_binary(&PROPOSAL_HOOKS.query_hooks(deps)?),
QueryMsg::VoteHooks {} => to_binary(&VOTE_HOOKS.query_hooks(deps)?),
}
}

pub fn query_config(deps: Deps) -> StdResult<Binary> {
let config = CONFIG.load(deps.storage)?;
to_json_binary(&config)
to_binary(&config)
}

pub fn query_dao(deps: Deps) -> StdResult<Binary> {
let config = CONFIG.load(deps.storage)?;
to_json_binary(&config.dao)
to_binary(&config.dao)
}

pub fn query_proposal(deps: Deps, env: Env, id: u64) -> StdResult<Binary> {
let proposal = PROPOSALS.load(deps.storage, id)?;
to_json_binary(&proposal.into_response(&env.block, id))
to_binary(&proposal.into_response(&env.block, id))
}

pub fn query_creation_policy(deps: Deps) -> StdResult<Binary> {
let policy = CREATION_POLICY.load(deps.storage)?;
to_json_binary(&policy)
to_binary(&policy)
}

pub fn query_list_proposals(
Expand All @@ -771,7 +784,7 @@ pub fn query_list_proposals(
.map(|(id, proposal)| proposal.into_response(&env.block, id))
.collect();

to_json_binary(&ProposalListResponse { proposals: props })
to_binary(&ProposalListResponse { proposals: props })
}

pub fn query_reverse_proposals(
Expand All @@ -790,16 +803,16 @@ pub fn query_reverse_proposals(
.map(|(id, proposal)| proposal.into_response(&env.block, id))
.collect();

to_json_binary(&ProposalListResponse { proposals: props })
to_binary(&ProposalListResponse { proposals: props })
}

pub fn query_proposal_count(deps: Deps) -> StdResult<Binary> {
let proposal_count = PROPOSAL_COUNT.load(deps.storage)?;
to_json_binary(&proposal_count)
to_binary(&proposal_count)
}

pub fn query_next_proposal_id(deps: Deps) -> StdResult<Binary> {
to_json_binary(&next_proposal_id(deps.storage)?)
to_binary(&next_proposal_id(deps.storage)?)
}

pub fn query_vote(deps: Deps, proposal_id: u64, voter: String) -> StdResult<Binary> {
Expand All @@ -811,7 +824,7 @@ pub fn query_vote(deps: Deps, proposal_id: u64, voter: String) -> StdResult<Bina
power: ballot.power,
rationale: ballot.rationale,
});
to_json_binary(&VoteResponse { vote })
to_binary(&VoteResponse { vote })
}

pub fn query_list_votes(
Expand Down Expand Up @@ -841,12 +854,12 @@ pub fn query_list_votes(
})
.collect::<StdResult<Vec<_>>>()?;

to_json_binary(&VoteListResponse { votes })
to_binary(&VoteListResponse { votes })
}

pub fn query_info(deps: Deps) -> StdResult<Binary> {
let info = cw2::get_contract_version(deps.storage)?;
to_json_binary(&dao_interface::voting::InfoResponse { info })
to_binary(&dao_interface::voting::InfoResponse { info })
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::testing::{
},
queries::{query_balance_cw20, query_dao_token, query_proposal, query_single_proposal_module},
};
use cosmwasm_std::{to_json_binary, Addr, CosmosMsg, Decimal, Uint128, WasmMsg};
use cosmwasm_std::{to_binary, Addr, CosmosMsg, Decimal, Uint128, WasmMsg};
use cw20::Cw20Coin;
use cw_multi_test::{next_block, App};
use cw_utils::Duration;
Expand All @@ -22,7 +22,7 @@ use dao_voting::{
voting::Vote,
};

use super::CREATOR_ADDR;
use super::{CREATOR_ADDR, MEMBER_ADDR};
use crate::{query::ProposalResponse, ContractError};

struct CommonTest {
Expand Down Expand Up @@ -134,6 +134,13 @@ fn test_execute_proposal_more_than_once() {
proposal_id,
Vote::Yes,
);
vote_on_proposal(
&mut app,
&proposal_module,
MEMBER_ADDR,
proposal_id,
Vote::Yes,
);

app.update_block(next_block);

Expand Down Expand Up @@ -301,7 +308,7 @@ pub fn test_passed_prop_state_remains_after_vote_swing() {
recipient: "threshold".to_string(),
amount: Uint128::new(100_000_000),
};
let binary_msg = to_json_binary(&msg).unwrap();
let binary_msg = to_binary(&msg).unwrap();

mint_cw20s(&mut app, &gov_token, &core_addr, CREATOR_ADDR, 10_000_000);
let proposal_id = make_proposal(
Expand Down
59 changes: 35 additions & 24 deletions contracts/proposal/dao-proposal-single/src/testing/instantiate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cosmwasm_std::{to_json_binary, Addr, Coin, Decimal, Empty, Uint128};
use cosmwasm_std::{to_binary, Addr, Coin, Decimal, Empty, Uint128};
use cw20::Cw20Coin;

use cw_multi_test::{next_block, App, BankSudo, Executor, SudoMsg};
Expand All @@ -21,7 +21,7 @@ use super::{
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,
CREATOR_ADDR, MEMBER_ADDR,
};

pub(crate) fn get_pre_propose_info(
Expand All @@ -34,7 +34,7 @@ pub(crate) fn get_pre_propose_info(
PreProposeInfo::ModuleMayPropose {
info: ModuleInstantiateInfo {
code_id: pre_propose_contract,
msg: to_json_binary(&cppbps::InstantiateMsg {
msg: to_binary(&cppbps::InstantiateMsg {
deposit_info,
open_proposal_submission,
extension: Empty::default(),
Expand Down Expand Up @@ -146,7 +146,7 @@ pub(crate) fn instantiate_with_staked_cw721_governance(
automatically_add_cw721s: false,
voting_module_instantiate_info: ModuleInstantiateInfo {
code_id: cw721_stake_id,
msg: to_json_binary(&dao_voting_cw721_staked::msg::InstantiateMsg {
msg: to_binary(&dao_voting_cw721_staked::msg::InstantiateMsg {
unstaking_duration: None,
nft_contract: dao_voting_cw721_staked::msg::NftContract::Existing {
address: nft_address.to_string(),
Expand All @@ -160,7 +160,7 @@ pub(crate) fn instantiate_with_staked_cw721_governance(
},
proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
code_id: proposal_module_code_id,
msg: to_json_binary(&proposal_module_instantiate).unwrap(),
msg: to_binary(&proposal_module_instantiate).unwrap(),
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO governance module.".to_string(),
Expand Down Expand Up @@ -208,7 +208,7 @@ pub(crate) fn instantiate_with_staked_cw721_governance(
&cw721_base::msg::ExecuteMsg::SendNft::<Option<Empty>, Empty> {
contract: staking_addr.to_string(),
token_id: format!("{address}_{i}"),
msg: to_json_binary("").unwrap(),
msg: to_binary("").unwrap(),
},
&[],
)
Expand Down Expand Up @@ -265,7 +265,7 @@ pub(crate) fn instantiate_with_native_staked_balances_governance(
automatically_add_cw721s: false,
voting_module_instantiate_info: ModuleInstantiateInfo {
code_id: native_stake_id,
msg: to_json_binary(&dao_voting_token_staked::msg::InstantiateMsg {
msg: to_binary(&dao_voting_token_staked::msg::InstantiateMsg {
token_info: dao_voting_token_staked::msg::TokenInfo::Existing {
denom: "ujuno".to_string(),
},
Expand All @@ -279,7 +279,7 @@ pub(crate) fn instantiate_with_native_staked_balances_governance(
},
proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
code_id: proposal_module_code_id,
msg: to_json_binary(&proposal_module_instantiate).unwrap(),
msg: to_binary(&proposal_module_instantiate).unwrap(),
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO governance module.".to_string(),
Expand Down Expand Up @@ -341,10 +341,16 @@ pub(crate) fn instantiate_with_staked_balances_governance(
let proposal_module_code_id = app.store_code(proposal_single_contract());

let initial_balances = initial_balances.unwrap_or_else(|| {
vec![Cw20Coin {
address: CREATOR_ADDR.to_string(),
amount: Uint128::new(100_000_000),
}]
vec![
Cw20Coin {
address: CREATOR_ADDR.to_string(),
amount: Uint128::new(100_000_000),
},
Cw20Coin {
address: MEMBER_ADDR.to_string(),
amount: Uint128::new(100_000_000),
},
]
});

// Collapse balances so that we can test double votes.
Expand Down Expand Up @@ -378,7 +384,7 @@ pub(crate) fn instantiate_with_staked_balances_governance(
automatically_add_cw721s: false,
voting_module_instantiate_info: ModuleInstantiateInfo {
code_id: staked_balances_voting_id,
msg: to_json_binary(&dao_voting_cw20_staked::msg::InstantiateMsg {
msg: to_binary(&dao_voting_cw20_staked::msg::InstantiateMsg {
active_threshold: None,
token_info: dao_voting_cw20_staked::msg::TokenInfo::New {
code_id: cw20_id,
Expand All @@ -400,7 +406,7 @@ pub(crate) fn instantiate_with_staked_balances_governance(
},
proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
code_id: proposal_module_code_id,
msg: to_json_binary(&proposal_module_instantiate).unwrap(),
msg: to_binary(&proposal_module_instantiate).unwrap(),
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO governance module.".to_string(),
Expand Down Expand Up @@ -451,7 +457,7 @@ pub(crate) fn instantiate_with_staked_balances_governance(
&cw20::Cw20ExecuteMsg::Send {
contract: staking_contract.to_string(),
amount,
msg: to_json_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(),
msg: to_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(),
},
&[],
)
Expand Down Expand Up @@ -493,7 +499,7 @@ pub(crate) fn instantiate_with_staking_active_threshold(
automatically_add_cw721s: true,
voting_module_instantiate_info: ModuleInstantiateInfo {
code_id: votemod_id,
msg: to_json_binary(&dao_voting_cw20_staked::msg::InstantiateMsg {
msg: to_binary(&dao_voting_cw20_staked::msg::InstantiateMsg {
token_info: dao_voting_cw20_staked::msg::TokenInfo::New {
code_id: cw20_id,
label: "DAO DAO governance token".to_string(),
Expand All @@ -515,7 +521,7 @@ pub(crate) fn instantiate_with_staking_active_threshold(
},
proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
code_id: proposal_module_code_id,
msg: to_json_binary(&proposal_module_instantiate).unwrap(),
msg: to_binary(&proposal_module_instantiate).unwrap(),
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO governance module".to_string(),
Expand Down Expand Up @@ -543,12 +549,17 @@ pub(crate) fn instantiate_with_cw4_groups_governance(
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 initial_weights = initial_weights.unwrap_or_else(|| {
vec![Cw20Coin {
address: CREATOR_ADDR.to_string(),
amount: Uint128::new(1),
}]
vec![
Cw20Coin {
address: CREATOR_ADDR.to_string(),
amount: Uint128::new(1),
},
Cw20Coin {
address: MEMBER_ADDR.to_string(),
amount: Uint128::new(1),
},
]
});

// Remove duplicates so that we can test duplicate voting.
Expand Down Expand Up @@ -581,7 +592,7 @@ pub(crate) fn instantiate_with_cw4_groups_governance(
automatically_add_cw721s: true,
voting_module_instantiate_info: ModuleInstantiateInfo {
code_id: votemod_id,
msg: to_json_binary(&dao_voting_cw4::msg::InstantiateMsg {
msg: to_binary(&dao_voting_cw4::msg::InstantiateMsg {
group_contract: GroupContract::New {
cw4_group_code_id: cw4_id,
initial_members: initial_weights,
Expand All @@ -594,7 +605,7 @@ pub(crate) fn instantiate_with_cw4_groups_governance(
},
proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
code_id: proposal_module_code_id,
msg: to_json_binary(&proposal_module_instantiate).unwrap(),
msg: to_binary(&proposal_module_instantiate).unwrap(),
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO governance module".to_string(),
Expand Down
1 change: 1 addition & 0 deletions contracts/proposal/dao-proposal-single/src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ mod queries;
mod tests;

pub(crate) const CREATOR_ADDR: &str = "creator";
pub(crate) const MEMBER_ADDR: &str = "dao_member";
Loading

0 comments on commit dc085a3

Please sign in to comment.