Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions src/CrispVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ contract CrispVoting is PluginUUPSUpgradeable, ProposalUpgradeable, ICrispVoting
// snapshot the previous block so voting power is read from a finalized block
snapshotBlock: block.number - 1,
minVotingPower: votingSettings.minProposerVotingPower,
minParticipation: votingSettings.minParticipation
minParticipation: votingSettings.minParticipation,
creditMode: ICRISP.CreditMode(creditMode)
});
proposal.allowFailureMap = _allowFailureMap;
proposal.targetConfig = getTargetConfig();
Expand All @@ -211,6 +212,11 @@ contract CrispVoting is PluginUUPSUpgradeable, ProposalUpgradeable, ICrispVoting

Proposal storage proposal = proposals[_proposalId];

// signaling-only proposals (polls) cannot be executed
if (_isSignalingOnly(proposal.parameters)) {
revert ProposalNotExecutable(_proposalId);
}

// the voting window must have closed before a proposal can be executed
if (block.timestamp < proposal.parameters.endDate) {
revert ProposalExecutionForbidden(_proposalId);
Expand Down Expand Up @@ -437,6 +443,11 @@ contract CrispVoting is PluginUUPSUpgradeable, ProposalUpgradeable, ICrispVoting
return false;
}

// signaling-only proposals (polls) are never executable
if (_isSignalingOnly(proposal.parameters)) {
return false;
}

// Sum all votes for quorum check
uint256 totalVotes = 0;
for (uint256 i = 0; i < counts.length;) {
Expand All @@ -458,12 +469,17 @@ contract CrispVoting is PluginUUPSUpgradeable, ProposalUpgradeable, ICrispVoting
}

// For 2-3 options: yes (index 0) must strictly beat no (index 1)
if (proposal.parameters.numOptions <= 3) {
return counts[0] > counts[1];
}
return counts[0] > counts[1];
}

// For 4+ options: quorum is sufficient
return true;
/// @notice Whether a proposal is signaling-only (a poll) and therefore cannot be executed.
/// @dev Only binary-style votes are executable: at most 3 options (yes/no/abstain) and CUSTOM
/// credits (so the token-supply quorum denominator is meaningful). Proposals with more than 3
/// options, or CONSTANT credits, are polls whose tally is informational only.
/// @param _parameters The stored parameters of the proposal.
/// @return Returns `true` if the proposal is signaling-only, otherwise false.
function _isSignalingOnly(ProposalParameters memory _parameters) internal pure returns (bool) {
return _parameters.numOptions > 3 || _parameters.creditMode == ICRISP.CreditMode.CONSTANT;
}

/// @notice Checks if proposal exists or not.
Expand Down
8 changes: 8 additions & 0 deletions src/ICrispVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {Action} from "@aragon/osx-commons-contracts/src/executors/IExecutor.sol"
import {IPlugin} from "@aragon/osx-commons-contracts/src/plugin/IPlugin.sol";
import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol";
import {IEnclave} from "./IEnclave.sol";
import {ICRISP} from "./ICRISP.sol";

/// @notice Interface for the Crisp Voting plugin
interface ICrispVoting {
Expand All @@ -26,6 +27,11 @@ interface ICrispVoting {
/// @notice Thrown when the number of options is less than 2.
/// @param numOptions The number of options provided.
error InvalidOptionCount(uint256 numOptions);
/// @notice Thrown when attempting to execute a signaling-only proposal. A proposal is
/// signaling-only (poll) if it has more than 3 options or uses CONSTANT credits, and therefore
/// has no binding execution semantics.
/// @param proposalId The ID of the proposal.
error ProposalNotExecutable(uint256 proposalId);
/// @notice Thrown when a proposal date is outside the allowed bounds.
/// @param limit The bound limit (earliest allowed start or end date).
/// @param actual The provided date.
Expand Down Expand Up @@ -67,13 +73,15 @@ interface ICrispVoting {
/// @param snapshotBlock The number of the block prior to the proposal creation.
/// @param minVotingPower The minimum voting power needed.
/// @param minParticipation The minimum participation needed.
/// @param creditMode The credit mode for the vote. CONSTANT proposals are signaling-only.
struct ProposalParameters {
uint256 numOptions;
uint64 startDate;
uint64 endDate;
uint256 snapshotBlock;
uint256 minVotingPower;
uint256 minParticipation;
ICRISP.CreditMode creditMode;
}

/// @notice The parameters for initializing the plugin
Expand Down
Loading