Skip to main content

MajorityVotingBase

Description

The abstract implementation of majority voting plugins.

Parameterization

We define two parameters support=NyesNyes+Nno[0,1]\texttt{support} = \frac{N_\text{yes}}{N_\text{yes} + N_\text{no}} \in [0,1] and participation=Nyes+Nno+NabstainNtotal[0,1],\texttt{participation} = \frac{N_\text{yes} + N_\text{no} + N_\text{abstain}}{N_\text{total}} \in [0,1], where NyesN_\text{yes}, NnoN_\text{no}, and NabstainN_\text{abstain} are the yes, no, and abstain votes that have been cast and NtotalN_\text{total} is the total voting power available at proposal creation time.

Limit Values: Support Threshold & Minimum Participation

Two limit values are associated with these parameters and decide if a proposal execution should be possible: supportThreshold[0,1]\texttt{supportThreshold} \in [0,1] and minParticipation[0,1]\texttt{minParticipation} \in [0,1].

For threshold values, >> comparison is used. This does not include the threshold value. E.g., for supportThreshold=50%\texttt{supportThreshold} = 50\%, the criterion is fulfilled if there is at least one more yes than no votes (Nyes=Nno+1N_\text{yes} = N_\text{no} + 1). For minimum values, \ge{} comparison is used. This does include the minimum participation value. E.g., for minParticipation=40%\texttt{minParticipation} = 40\% and Ntotal=10N_\text{total} = 10, the criterion is fulfilled if 4 out of 10 votes were casted.

Majority voting implies that the support threshold is set with supportThreshold50%.\texttt{supportThreshold} \ge 50\% . However, this is not enforced by the contract code and developers can make unsafe parameters and only the frontend will warn about bad parameter settings.

Execution Criteria

After the vote is closed, two criteria decide if the proposal passes.

The Support Criterion

For a proposal to pass, the required ratio of yes and no votes must be met: (1supportThreshold)Nyes>supportThresholdNno.(1- \texttt{supportThreshold}) \cdot N_\text{yes} > \texttt{supportThreshold} \cdot N_\text{no}. Note, that the inequality yields the simple majority voting condition for supportThreshold=12\texttt{supportThreshold}=\frac{1}{2}.

The Participation Criterion

For a proposal to pass, the minimum voting power must have been cast: Nyes+Nno+NabstainminVotingPower,N_\text{yes} + N_\text{no} + N_\text{abstain} \ge \texttt{minVotingPower}, where minVotingPower=minParticipationNtotal\texttt{minVotingPower} = \texttt{minParticipation} \cdot N_\text{total}.

Vote Replacement Execution

The contract allows votes to be replaced. Voters can vote multiple times and only the latest voteOption is tallied.

Early Execution

This contract allows a proposal to be executed early, iff the vote outcome cannot change anymore by more people voting. Accordingly, vote replacement and early execution are /// mutually exclusive options. The outcome cannot change anymore iff the support threshold is met even if all remaining votes are no votes. We call this number the worst-case number of no votes and define it as

Nno, worst-case=Nno, worst-case+remainingVotesN_\text{no, worst-case} = N_\text{no, worst-case} + \texttt{remainingVotes}

where

remainingVotes=Ntotal(Nyes+Nno+Nabstain)turnout.\texttt{remainingVotes} = N_\text{total}-\underbrace{(N_\text{yes}+N_\text{no}+N_\text{abstain})}_{\text{turnout}}.

We can use this quantity to calculate the worst-case support that would be obtained if all remaining votes are casted with no:

worstCaseSupport=NyesNyes+(Nno, worst-case)=NyesNyes+(Nno+remainingVotes)=NyesNyes+Nno+Ntotal(Nyes+Nno+Nabstain)=NyesNtotalNabstain\begin{align*} \texttt{worstCaseSupport} &= \frac{N_\text{yes}}{N_\text{yes} + (N_\text{no, worst-case})} \\[3mm] &= \frac{N_\text{yes}}{N_\text{yes} + (N_\text{no} + \texttt{remainingVotes})} \\[3mm] &= \frac{N_\text{yes}}{N_\text{yes} + N_\text{no} + N_\text{total} - (N_\text{yes} + N_\text{no} + N_\text{abstain})} \\[3mm] &= \frac{N_\text{yes}}{N_\text{total} - N_\text{abstain}} \end{align*}

In analogy, we can modify the support criterion from above to allow for early execution:

(1supportThreshold)Nyes>supportThresholdNno, worst-case>supportThreshold(Nno+remainingVotes)>supportThreshold(Nno+Ntotal(Nyes+Nno+Nabstain))>supportThreshold(NtotalNyesNabstain)\begin{align*} (1 - \texttt{supportThreshold}) \cdot N_\text{yes} &> \texttt{supportThreshold} \cdot N_\text{no, worst-case} \\[3mm] &> \texttt{supportThreshold} \cdot (N_\text{no} + \texttt{remainingVotes}) \\[3mm] &> \texttt{supportThreshold} \cdot (N_\text{no} + N_\text{total}-(N_\text{yes}+N_\text{no}+N_\text{abstain})) \\[3mm] &> \texttt{supportThreshold} \cdot (N_\text{total} - N_\text{yes} - N_\text{abstain}) \end{align*}

Accordingly, early execution is possible when the vote is open, the modified support criterion, and the particicpation criterion are met.

This contract implements the IMajorityVoting interface.

Implementation

enum VotingMode

enum VotingMode {
Standard,
EarlyExecution,
VoteReplacement
}

public struct VotingSettings

struct VotingSettings {
enum MajorityVotingBase.VotingMode votingMode;
uint32 supportThreshold;
uint32 minParticipation;
uint64 minDuration;
uint256 minProposerVotingPower;
}

public struct Proposal

struct Proposal {
bool executed;
struct MajorityVotingBase.ProposalParameters parameters;
struct MajorityVotingBase.Tally tally;
mapping(address => enum IMajorityVoting.VoteOption) voters;
struct IDAO.Action[] actions;
uint256 allowFailureMap;
}

public struct ProposalParameters

struct ProposalParameters {
enum MajorityVotingBase.VotingMode votingMode;
uint32 supportThreshold;
uint64 startDate;
uint64 endDate;
uint64 snapshotBlock;
uint256 minVotingPower;
}

public struct Tally

struct Tally {
uint256 abstain;
uint256 yes;
uint256 no;
}

internal variable MAJORITY_VOTING_BASE_INTERFACE_ID

The ERC-165 interface ID of the contract.

bytes4 MAJORITY_VOTING_BASE_INTERFACE_ID

public variable UPDATE_VOTING_SETTINGS_PERMISSION_ID

The ID of the permission required to call the updateVotingSettings function.

bytes32 UPDATE_VOTING_SETTINGS_PERMISSION_ID

internal variable proposals

A mapping between proposal IDs and proposal information.

mapping(uint256 => struct MajorityVotingBase.Proposal) proposals

error DateOutOfBounds

Thrown if a date is out of bounds.

error DateOutOfBounds(uint64 limit, uint64 actual)
InputTypeDescription
limituint64The limit value.
actualuint64The actual value.

error MinDurationOutOfBounds

Thrown if the minimal duration value is out of bounds (less than one hour or greater than 1 year).

error MinDurationOutOfBounds(uint64 limit, uint64 actual)
InputTypeDescription
limituint64The limit value.
actualuint64The actual value.

error ProposalCreationForbidden

Thrown when a sender is not allowed to create a proposal.

error ProposalCreationForbidden(address sender)
InputTypeDescription
senderaddressThe sender address.

error VoteCastForbidden

Thrown if an account is not allowed to cast a vote. This can be because the vote

  • has not started,
  • has ended,
  • was executed, or
  • the account doesn't have voting powers.
error VoteCastForbidden(uint256 proposalId, address account, enum IMajorityVoting.VoteOption voteOption)
InputTypeDescription
proposalIduint256The ID of the proposal.
accountaddressThe address of the _account.
voteOptionenum IMajorityVoting.VoteOptionThe chosen vote option.

error ProposalExecutionForbidden

Thrown if the proposal execution is forbidden.

error ProposalExecutionForbidden(uint256 proposalId)
InputTypeDescription
proposalIduint256The ID of the proposal.

event VotingSettingsUpdated

Emitted when the voting settings are updated.

event VotingSettingsUpdated(enum MajorityVotingBase.VotingMode votingMode, uint32 supportThreshold, uint32 minParticipation, uint64 minDuration, uint256 minProposerVotingPower)
InputTypeDescription
votingModeenum MajorityVotingBase.VotingModeA parameter to select the vote mode.
supportThresholduint32The support threshold value.
minParticipationuint32The minimum participation value.
minDurationuint64The minimum duration of the proposal vote in seconds.
minProposerVotingPoweruint256The minimum voting power required to create a proposal.

internal function __MajorityVotingBase_init

Initializes the component to be used by inheriting contracts.

function __MajorityVotingBase_init(contract IDAO _dao, struct MajorityVotingBase.VotingSettings _votingSettings) internal
InputTypeDescription
_daocontract IDAOThe IDAO interface of the associated DAO.
_votingSettingsstruct MajorityVotingBase.VotingSettingsThe voting settings.

This method is required to support ERC-1822.

public function supportsInterface

Checks if this or the parent contract supports an interface by its ID.

function supportsInterface(bytes4 _interfaceId) public view virtual returns (bool)
InputTypeDescription
_interfaceIdbytes4The ID of the interface.
Output
0boolReturns true if the interface is supported.

public function vote

Votes for a vote option and, optionally, executes the proposal.

function vote(uint256 _proposalId, enum IMajorityVoting.VoteOption _voteOption, bool _tryEarlyExecution) public virtual
InputTypeDescription
_proposalIduint256The ID of the proposal.
_voteOptionenum IMajorityVoting.VoteOptionThe chosen vote option.
_tryEarlyExecutionboolIf true, early execution is tried after the vote cast. The call does not revert if early execution is not possible.

_voteOption, 1 -> abstain, 2 -> yes, 3 -> no

public function execute

Executes a proposal.

function execute(uint256 _proposalId) public virtual
InputTypeDescription
_proposalIduint256The ID of the proposal to be executed.

public function getVoteOption

Returns whether the account has voted for the proposal. Note, that this does not check if the account has voting power.

function getVoteOption(uint256 _proposalId, address _voter) public view virtual returns (enum IMajorityVoting.VoteOption)
InputTypeDescription
_proposalIduint256The ID of the proposal.
_voteraddress
Output
0enum IMajorityVoting.VoteOptionThe vote option cast by a voter for a certain proposal.

public function canVote

Checks if an account can participate on a proposal vote. This can be because the vote

  • has not started,
  • has ended,
  • was executed, or
  • the voter doesn't have voting powers.
function canVote(uint256 _proposalId, address _voter, enum IMajorityVoting.VoteOption _voteOption) public view virtual returns (bool)
InputTypeDescription
_proposalIduint256The proposal Id.
_voteraddress
_voteOptionenum IMajorityVoting.VoteOptionWhether the voter abstains, supports or opposes the proposal.
Output
0boolReturns true if the account is allowed to vote.

The function assumes the queried proposal exists.

public function canExecute

Checks if a proposal can be executed.

function canExecute(uint256 _proposalId) public view virtual returns (bool)
InputTypeDescription
_proposalIduint256The ID of the proposal to be checked.
Output
0boolTrue if the proposal can be executed, false otherwise.

public function isSupportThresholdReached

Checks if the support value defined as support=NyesNyes+Nno\texttt{support} = \frac{N_\text{yes}}{N_\text{yes}+N_\text{no}} for a proposal vote is greater than the support threshold.

function isSupportThresholdReached(uint256 _proposalId) public view virtual returns (bool)
InputTypeDescription
_proposalIduint256The ID of the proposal.
Output
0boolReturns true if the support is greater than the support threshold and false otherwise.

public function isSupportThresholdReachedEarly

Checks if the worst-case support value defined as worstCaseSupport=NyesNtotalNabstain\texttt{worstCaseSupport} = \frac{N_\text{yes}}{ N_\text{total}-N_\text{abstain}} for a proposal vote is greater than the support threshold.

function isSupportThresholdReachedEarly(uint256 _proposalId) public view virtual returns (bool)
InputTypeDescription
_proposalIduint256The ID of the proposal.
Output
0boolReturns true if the worst-case support is greater than the support threshold and false otherwise.

public function isMinParticipationReached

Checks if the participation value defined as participation=Nyes+Nno+NabstainNtotal\texttt{participation} = \frac{N_\text{yes}+N_\text{no}+N_\text{abstain}}{N_\text{total}} for a proposal vote is greater or equal than the minimum participation value.

function isMinParticipationReached(uint256 _proposalId) public view virtual returns (bool)
InputTypeDescription
_proposalIduint256The ID of the proposal.
Output
0boolReturns true if the participation is greater than the minimum participation and false otherwise.

public function supportThreshold

Returns the support threshold parameter stored in the voting settings.

function supportThreshold() public view virtual returns (uint32)
OutputTypeDescription
0uint32The support threshold parameter.

public function minParticipation

Returns the minimum participation parameter stored in the voting settings.

function minParticipation() public view virtual returns (uint32)
OutputTypeDescription
0uint32The minimum participation parameter.

public function minDuration

Returns the minimum duration parameter stored in the voting settings.

function minDuration() public view virtual returns (uint64)
OutputTypeDescription
0uint64The minimum duration parameter.

public function minProposerVotingPower

Returns the minimum voting power required to create a proposal stored in the voting settings.

function minProposerVotingPower() public view virtual returns (uint256)
OutputTypeDescription
0uint256The minimum voting power required to create a proposal.

public function votingMode

Returns the vote mode stored in the voting settings.

function votingMode() public view virtual returns (enum MajorityVotingBase.VotingMode)
OutputTypeDescription
0enum MajorityVotingBase.VotingModeThe vote mode parameter.

public function totalVotingPower

Returns the total voting power checkpointed for a specific block number.

function totalVotingPower(uint256 _blockNumber) public view virtual returns (uint256)
InputTypeDescription
_blockNumberuint256The block number.
Output
0uint256The total voting power.

public function getProposal

Returns all information for a proposal vote by its ID.

function getProposal(uint256 _proposalId) public view virtual returns (bool open, bool executed, struct MajorityVotingBase.ProposalParameters parameters, struct MajorityVotingBase.Tally tally, struct IDAO.Action[] actions, uint256 allowFailureMap)
InputTypeDescription
_proposalIduint256The ID of the proposal.
Output
openboolWhether the proposal is open or not.
executedboolWhether the proposal is executed or not.
parametersstruct MajorityVotingBase.ProposalParametersThe parameters of the proposal vote.
tallystruct MajorityVotingBase.TallyThe current tally of the proposal vote.
actionsstruct IDAO.Action[]The actions to be executed in the associated DAO after the proposal has passed.
allowFailureMapuint256The bit map representations of which actions are allowed to revert so tx still succeeds.

external function updateVotingSettings

Updates the voting settings.

function updateVotingSettings(struct MajorityVotingBase.VotingSettings _votingSettings) external virtual
InputTypeDescription
_votingSettingsstruct MajorityVotingBase.VotingSettingsThe new voting settings.

external function createProposal

Creates a new majority voting proposal.

function createProposal(bytes _metadata, struct IDAO.Action[] _actions, uint256 _allowFailureMap, uint64 _startDate, uint64 _endDate, enum IMajorityVoting.VoteOption _voteOption, bool _tryEarlyExecution) external virtual returns (uint256 proposalId)
InputTypeDescription
_metadatabytesThe metadata of the proposal.
_actionsstruct IDAO.Action[]The actions that will be executed after the proposal passes.
_allowFailureMapuint256Allows proposal to succeed even if an action reverts. Uses bitmap representation. If the bit at index x is 1, the tx succeeds even if the action at x failed. Passing 0 will be treated as atomic execution.
_startDateuint64The start date of the proposal vote. If 0, the current timestamp is used and the vote starts immediately.
_endDateuint64The end date of the proposal vote. If 0, _startDate + minDuration is used.
_voteOptionenum IMajorityVoting.VoteOptionThe chosen vote option to be casted on proposal creation.
_tryEarlyExecutionboolIf true, early execution is tried after the vote cast. The call does not revert if early execution is not possible.
Output
proposalIduint256The ID of the proposal.

internal function _vote

Internal function to cast a vote. It assumes the queried vote exists.

function _vote(uint256 _proposalId, enum IMajorityVoting.VoteOption _voteOption, address _voter, bool _tryEarlyExecution) internal virtual
InputTypeDescription
_proposalIduint256The ID of the proposal.
_voteOptionenum IMajorityVoting.VoteOptionThe chosen vote option to be casted on the proposal vote.
_voteraddress
_tryEarlyExecutionboolIf true, early execution is tried after the vote cast. The call does not revert if early execution is not possible.

internal function _execute

Internal function to execute a vote. It assumes the queried proposal exists.

function _execute(uint256 _proposalId) internal virtual
InputTypeDescription
_proposalIduint256The ID of the proposal.

internal function _canVote

Internal function to check if a voter can vote. It assumes the queried proposal exists.

function _canVote(uint256 _proposalId, address _voter, enum IMajorityVoting.VoteOption _voteOption) internal view virtual returns (bool)
InputTypeDescription
_proposalIduint256The ID of the proposal.
_voteraddressThe address of the voter to check.
_voteOptionenum IMajorityVoting.VoteOptionWhether the voter abstains, supports or opposes the proposal.
Output
0boolReturns true if the given voter can vote on a certain proposal and false otherwise.

internal function _canExecute

Internal function to check if a proposal can be executed. It assumes the queried proposal exists.

function _canExecute(uint256 _proposalId) internal view virtual returns (bool)
InputTypeDescription
_proposalIduint256The ID of the proposal.
Output
0boolTrue if the proposal can be executed, false otherwise.

Threshold and minimal values are compared with > and >= comparators, respectively.

internal function _isProposalOpen

Internal function to check if a proposal vote is still open.

function _isProposalOpen(struct MajorityVotingBase.Proposal proposal_) internal view virtual returns (bool)
InputTypeDescription
proposal_struct MajorityVotingBase.ProposalThe proposal struct.
Output
0boolTrue if the proposal vote is open, false otherwise.

internal function _updateVotingSettings

Internal function to update the plugin-wide proposal vote settings.

function _updateVotingSettings(struct MajorityVotingBase.VotingSettings _votingSettings) internal virtual
InputTypeDescription
_votingSettingsstruct MajorityVotingBase.VotingSettingsThe voting settings to be validated and updated.

internal function _validateProposalDates

Validates and returns the proposal vote dates.

function _validateProposalDates(uint64 _start, uint64 _end) internal view virtual returns (uint64 startDate, uint64 endDate)
InputTypeDescription
_startuint64The start date of the proposal vote. If 0, the current timestamp is used and the vote starts immediately.
_enduint64The end date of the proposal vote. If 0, _start + minDuration is used.
Output
startDateuint64The validated start date of the proposal vote.
endDateuint64The validated end date of the proposal vote.
© 2024