123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- //////////////////////////////////////////////////////////////////////////////
- ///////////////////// Governor.sol base definitions //////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- methods {
- hashProposal(address[],uint256[],bytes[],bytes32) returns uint256 envfree
- state(uint256) returns uint8
- proposalThreshold() returns uint256 envfree
- proposalSnapshot(uint256) returns uint256 envfree // matches proposalVoteStart
- proposalDeadline(uint256) returns uint256 envfree // matches proposalVoteEnd
- proposalProposer(uint256) returns address envfree
- propose(address[], uint256[], bytes[], string) returns uint256
- execute(address[], uint256[], bytes[], bytes32) returns uint256
- cancel(address[], uint256[], bytes[], bytes32) returns uint256
- getVotes(address, uint256) returns uint256 => DISPATCHER(true)
- getVotesWithParams(address, uint256, bytes) returns uint256 => DISPATCHER(true)
- castVote(uint256, uint8) returns uint256
- castVoteWithReason(uint256, uint8, string) returns uint256
- castVoteWithReasonAndParams(uint256, uint8, string, bytes) returns uint256
- // GovernorTimelockController
- queue(address[], uint256[], bytes[], bytes32) returns uint256
- // GovernorCountingSimple
- hasVoted(uint256, address) returns bool envfree
- updateQuorumNumerator(uint256)
- // harness functions
- getAgainstVotes(uint256) returns uint256 envfree
- getAbstainVotes(uint256) returns uint256 envfree
- getForVotes(uint256) returns uint256 envfree
- getExecutor(uint256) returns bool envfree
- isExecuted(uint256) returns bool envfree
- isCanceled(uint256) returns bool envfree
- // full harness functions
- getPastTotalSupply(uint256) returns uint256 => DISPATCHER(true)
- /// getPastVotes(address, uint256) returns uint256 => DISPATCHER(true)
- // internal functions made public in harness:
- quorumReached(uint256) returns bool
- voteSucceeded(uint256) returns bool envfree
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Definitions โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- definition proposalCreated(uint256 pId) returns bool =
- proposalSnapshot(pId) > 0 && proposalDeadline(pId) > 0 && proposalProposer(pId) != 0;
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Helper functions โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- function helperFunctionsWithRevert(uint256 proposalId, method f, env e) {
- address[] targets; uint256[] values; bytes[] calldatas; string reason; bytes32 descriptionHash;
- uint8 support; uint8 v; bytes32 r; bytes32 s; bytes params;
- if (f.selector == propose(address[], uint256[], bytes[], string).selector)
- {
- uint256 result = propose@withrevert(e, targets, values, calldatas, reason);
- require result == proposalId;
- }
- else if (f.selector == execute(address[], uint256[], bytes[], bytes32).selector)
- {
- uint256 result = execute@withrevert(e, targets, values, calldatas, descriptionHash);
- require result == proposalId;
- }
- else if (f.selector == queue(address[], uint256[], bytes[], bytes32).selector)
- {
- uint256 result = queue@withrevert(e, targets, values, calldatas, descriptionHash);
- require result == proposalId;
- }
- else if (f.selector == cancel(address[], uint256[], bytes[], bytes32).selector)
- {
- uint256 result = cancel@withrevert(e, targets, values, calldatas, descriptionHash);
- require result == proposalId;
- }
- else if (f.selector == castVote(uint256, uint8).selector)
- {
- castVote@withrevert(e, proposalId, support);
- }
- else if (f.selector == castVoteWithReason(uint256, uint8, string).selector)
- {
- castVoteWithReason@withrevert(e, proposalId, support, reason);
- }
- else if (f.selector == castVoteWithReasonAndParams(uint256,uint8,string,bytes).selector)
- {
- castVoteWithReasonAndParams@withrevert(e, proposalId, support, reason, params);
- }
- else if (f.selector == castVoteBySig(uint256, uint8,uint8, bytes32, bytes32).selector)
- {
- castVoteBySig@withrevert(e, proposalId, support, v, r, s);
- }
- else if (f.selector == castVoteWithReasonAndParamsBySig(uint256,uint8,string,bytes,uint8,bytes32,bytes32).selector)
- {
- castVoteWithReasonAndParamsBySig@withrevert(e, proposalId, support, reason, params, v, r, s);
- }
- else
- {
- calldataarg args;
- f@withrevert(e, args);
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: Votes start and end are either initialized (non zero) or uninitialized (zero) simultaneously โ
- โ โ
- โ This invariant assumes that the block number cannot be 0 at any stage of the contract cycle โ
- โ This is very safe assumption as usually the 0 block is genesis block which is uploaded with data โ
- โ by the developers and will not be valid to raise proposals (at the current way that block chain is functioning) โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant proposalStateConsistency(uint256 pId)
- (proposalProposer(pId) != 0 <=> proposalSnapshot(pId) != 0) && (proposalProposer(pId) != 0 <=> proposalDeadline(pId) != 0)
- {
- preserved with (env e) {
- require e.block.number > 0;
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: cancel => created โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant canceledImplyCreated(uint pId)
- isCanceled(pId) => proposalCreated(pId)
- {
- preserved with (env e) {
- requireInvariant proposalStateConsistency(pId);
- require e.block.number > 0;
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: executed => created โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant executedImplyCreated(uint pId)
- isExecuted(pId) => proposalCreated(pId)
- {
- preserved with (env e) {
- requireInvariant proposalStateConsistency(pId);
- require e.block.number > 0;
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: Votes start before it ends โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant voteStartBeforeVoteEnd(uint256 pId)
- proposalSnapshot(pId) <= proposalDeadline(pId)
- {
- preserved {
- requireInvariant proposalStateConsistency(pId);
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: A proposal cannot be both executed and canceled simultaneously โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant noBothExecutedAndCanceled(uint256 pId)
- !isExecuted(pId) || !isCanceled(pId)
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: No double proposition โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule noDoublePropose(uint256 pId, env e) {
- require proposalCreated(pId);
- address[] targets; uint256[] values; bytes[] calldatas; string reason;
- uint256 result = propose(e, targets, values, calldatas, reason);
- assert result != pId, "double proposal";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: Once a proposal is created, voteStart, voteEnd and proposer are immutable โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule immutableFieldsAfterProposalCreation(uint256 pId, env e, method f, calldataarg arg) {
- require proposalCreated(pId);
- uint256 voteStart = proposalSnapshot(pId);
- uint256 voteEnd = proposalDeadline(pId);
- address proposer = proposalProposer(pId);
- f(e, arg);
- assert voteStart == proposalSnapshot(pId), "Start date was changed";
- assert voteEnd == proposalDeadline(pId), "End date was changed";
- assert proposer == proposalProposer(pId), "Proposer was changed";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: A user cannot vote twice โ
- โ โ
- โ Checked for castVote only. all 3 castVote functions call _castVote, so the completeness of the verification is โ
- โ counted on the fact that the 3 functions themselves makes no changes, but rather call an internal function to โ
- โ execute. That means that we do not check those 3 functions directly, however for castVote & castVoteWithReason it โ
- โ is quite trivial to understand why this is ok. For castVoteBySig we basically assume that the signature referendum โ
- โ is correct without checking it. We could check each function separately and pass the rule, but that would have โ
- โ uglyfied the code with no concrete benefit, as it is evident that nothing is happening in the first 2 functions โ
- โ (calling a view function), and we do not desire to check the signature verification. โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule noDoubleVoting(uint256 pId, env e, uint8 sup) {
- bool votedCheck = hasVoted(pId, e.msg.sender);
- castVote@withrevert(e, pId, sup);
- assert votedCheck => lastReverted, "double voting occurred";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: A proposal could be executed only if quorum was reached and vote succeeded โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f, calldataarg args) {
- require !isExecuted(pId);
- bool quorumReachedBefore = quorumReached(e, pId);
- bool voteSucceededBefore = voteSucceeded(pId);
- f(e, args);
- assert isExecuted(pId) => (quorumReachedBefore && voteSucceededBefore), "quorum was changed";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: Voting cannot start at a block number prior to proposalโs creation block number โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule noStartBeforeCreation(uint256 pId, env e, method f, calldataarg args){
- require !proposalCreated(pId);
- f(e, args);
- assert proposalCreated(pId) => proposalSnapshot(pId) >= e.block.number, "starts before proposal";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: A proposal cannot be executed before it ends โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule noExecuteBeforeDeadline(uint256 pId, env e, method f, calldataarg args) {
- require !isExecuted(pId);
- f(e, args);
- assert isExecuted(pId) => proposalDeadline(pId) <= e.block.number, "executed before deadline";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: All proposal specific (non-view) functions should revert if proposal is executed โ
- โ โ
- โ In this rule we show that if a function is executed, i.e. execute() was called on the proposal ID, non of the โ
- โ proposal specific functions can make changes again. In executedOnlyAfterExecuteFunc we connected the executed โ
- โ attribute to the execute() function, showing that only execute() can change it, and that it will always change it. โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule allFunctionsRevertIfExecuted(uint256 pId, env e, method f, calldataarg args) filtered {
- f -> !f.isView && !f.isFallback
- && f.selector != updateTimelock(address).selector
- && f.selector != updateQuorumNumerator(uint256).selector
- && f.selector != relay(address,uint256,bytes).selector
- && f.selector != 0xb9a61961 // __acceptAdmin()
- && f.selector != onERC721Received(address,address,uint256,bytes).selector
- && f.selector != onERC1155Received(address,address,uint256,uint256,bytes).selector
- && f.selector != onERC1155BatchReceived(address,address,uint256[],uint256[],bytes).selector
- } {
- require isExecuted(pId);
- requireInvariant noBothExecutedAndCanceled(pId);
- requireInvariant executedImplyCreated(pId);
- helperFunctionsWithRevert(pId, f, e);
- assert lastReverted, "Function was not reverted";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: All proposal specific (non-view) functions should revert if proposal is canceled โ
- โ โ
- โ In this rule we show that if a function is executed, i.e. execute() was called on the proposal ID, non of the โ
- โ proposal specific functions can make changes again. In executedOnlyAfterExecuteFunc we connected the executed โ
- โ attribute to the execute() function, showing that only execute() can change it, and that it will always change it. โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule allFunctionsRevertIfCanceled(uint256 pId, env e, method f, calldataarg args) filtered {
- f -> !f.isView && !f.isFallback
- && f.selector != updateTimelock(address).selector
- && f.selector != updateQuorumNumerator(uint256).selector
- && f.selector != relay(address,uint256,bytes).selector
- && f.selector != 0xb9a61961 // __acceptAdmin()
- && f.selector != onERC721Received(address,address,uint256,bytes).selector
- && f.selector != onERC1155Received(address,address,uint256,uint256,bytes).selector
- && f.selector != onERC1155BatchReceived(address,address,uint256[],uint256[],bytes).selector
- } {
- require isCanceled(pId);
- requireInvariant noBothExecutedAndCanceled(pId);
- requireInvariant canceledImplyCreated(pId);
- helperFunctionsWithRevert(pId, f, e);
- assert lastReverted, "Function was not reverted";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: Proposal can be switched state only by specific functions โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule stateOnlyAfterFunc(uint256 pId, env e, method f) {
- bool createdBefore = proposalCreated(pId);
- bool executedBefore = isExecuted(pId);
- bool canceledBefore = isCanceled(pId);
- helperFunctionsWithRevert(pId, f, e);
- assert (proposalCreated(pId) != createdBefore)
- => (createdBefore == false && f.selector == propose(address[], uint256[], bytes[], string).selector),
- "proposalCreated only changes in the propose method";
- assert (isExecuted(pId) != executedBefore)
- => (executedBefore == false && f.selector == execute(address[], uint256[], bytes[], bytes32).selector),
- "isExecuted only changes in the execute method";
- assert (isCanceled(pId) != canceledBefore)
- => (canceledBefore == false && f.selector == cancel(address[], uint256[], bytes[], bytes32).selector),
- "isCanceled only changes in the cancel method";
- }
|