123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- import "methods/IGovernor.spec"
- import "Governor.helpers.spec"
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Definitions โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- definition proposalCreated(uint256 pId) returns bool =
- proposalSnapshot(pId) > 0 && proposalDeadline(pId) > 0 && proposalProposer(pId) != 0;
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ 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 clock(e) > 0;
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: cancel => created โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant canceledImplyCreated(uint pId)
- isCanceled(pId) => proposalCreated(pId)
- {
- preserved with (env e) {
- requireInvariant proposalStateConsistency(pId);
- require clock(e) > 0;
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: executed => created โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant executedImplyCreated(uint pId)
- isExecuted(pId) => proposalCreated(pId)
- {
- preserved with (env e) {
- requireInvariant proposalStateConsistency(pId);
- require clock(e) > 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(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) >= clock(e), "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) <= clock(e), "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";
- }
|