final govPreventLateQ

This commit is contained in:
teryanarmen
2022-05-28 11:01:25 -07:00
parent ca0d3363b8
commit b2cdcc38d4
8 changed files with 199 additions and 97 deletions

View File

@ -1,6 +1,12 @@
diff -ruN .gitignore .gitignore
--- .gitignore 1969-12-31 16:00:00.000000000 -0800
+++ .gitignore 2022-05-27 01:31:23.000000000 -0700
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff -ruN access/AccessControl.sol access/AccessControl.sol
--- access/AccessControl.sol 2022-05-25 15:36:58.849363940 -0400
+++ access/AccessControl.sol 2022-05-25 16:07:31.897814961 -0400
--- access/AccessControl.sol 2022-05-25 09:38:35.000000000 -0700
+++ access/AccessControl.sol 2022-05-27 01:31:23.000000000 -0700
@@ -93,7 +93,7 @@
*
* _Available since v4.6._
@ -10,29 +16,9 @@ diff -ruN access/AccessControl.sol access/AccessControl.sol
_checkRole(role, _msgSender());
}
diff -ruN .gitignore .gitignore
--- .gitignore 1969-12-31 19:00:00.000000000 -0500
+++ .gitignore 2022-05-25 16:07:31.901816357 -0400
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff -ruN governance/extensions/GovernorPreventLateQuorum.sol governance/extensions/GovernorPreventLateQuorum.sol
--- governance/extensions/GovernorPreventLateQuorum.sol 2022-05-25 15:36:58.849363940 -0400
+++ governance/extensions/GovernorPreventLateQuorum.sol 2022-05-25 16:07:31.901816357 -0400
@@ -21,8 +21,8 @@
using SafeCast for uint256;
using Timers for Timers.BlockNumber;
- uint64 private _voteExtension;
- mapping(uint256 => Timers.BlockNumber) private _extendedDeadlines;
+ uint64 internal _voteExtension;
+ mapping(uint256 => Timers.BlockNumber) internal _extendedDeadlines;
/// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period.
event ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline);
diff -ruN governance/Governor.sol governance/Governor.sol
--- governance/Governor.sol 2022-05-25 15:36:58.849363940 -0400
+++ governance/Governor.sol 2022-05-25 16:07:31.901816357 -0400
--- governance/Governor.sol 2022-05-25 09:38:35.000000000 -0700
+++ governance/Governor.sol 2022-05-27 01:31:23.000000000 -0700
@@ -44,7 +44,7 @@
string private _name;
@ -43,8 +29,8 @@ diff -ruN governance/Governor.sol governance/Governor.sol
// This queue keeps track of the governor operating on itself. Calls to functions protected by the
// {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute},
diff -ruN governance/TimelockController.sol governance/TimelockController.sol
--- governance/TimelockController.sol 2022-05-25 15:36:58.849363940 -0400
+++ governance/TimelockController.sol 2022-05-25 16:07:31.901816357 -0400
--- governance/TimelockController.sol 2022-05-25 09:38:35.000000000 -0700
+++ governance/TimelockController.sol 2022-05-27 01:31:23.000000000 -0700
@@ -28,10 +28,10 @@
bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
@ -58,9 +44,35 @@ diff -ruN governance/TimelockController.sol governance/TimelockController.sol
/**
* @dev Emitted when a call is scheduled as part of operation `id`.
diff -ruN governance/extensions/GovernorCountingSimple.sol governance/extensions/GovernorCountingSimple.sol
--- governance/extensions/GovernorCountingSimple.sol 2022-05-25 09:38:35.000000000 -0700
+++ governance/extensions/GovernorCountingSimple.sol 2022-05-27 03:15:40.000000000 -0700
@@ -27,7 +27,7 @@
mapping(address => bool) hasVoted;
}
- mapping(uint256 => ProposalVote) private _proposalVotes;
+ mapping(uint256 => ProposalVote) internal _proposalVotes;
/**
* @dev See {IGovernor-COUNTING_MODE}.
diff -ruN governance/extensions/GovernorPreventLateQuorum.sol governance/extensions/GovernorPreventLateQuorum.sol
--- governance/extensions/GovernorPreventLateQuorum.sol 2022-05-25 09:38:35.000000000 -0700
+++ governance/extensions/GovernorPreventLateQuorum.sol 2022-05-27 01:31:23.000000000 -0700
@@ -21,8 +21,8 @@
using SafeCast for uint256;
using Timers for Timers.BlockNumber;
- uint64 private _voteExtension;
- mapping(uint256 => Timers.BlockNumber) private _extendedDeadlines;
+ uint64 internal _voteExtension;
+ mapping(uint256 => Timers.BlockNumber) internal _extendedDeadlines;
/// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period.
event ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline);
diff -ruN governance/utils/Votes.sol governance/utils/Votes.sol
--- governance/utils/Votes.sol 2022-05-25 15:36:58.849363940 -0400
+++ governance/utils/Votes.sol 2022-05-25 16:07:31.901816357 -0400
--- governance/utils/Votes.sol 2022-05-25 09:38:35.000000000 -0700
+++ governance/utils/Votes.sol 2022-05-27 01:31:23.000000000 -0700
@@ -35,7 +35,25 @@
bytes32 private constant _DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
@ -134,8 +146,8 @@ diff -ruN governance/utils/Votes.sol governance/utils/Votes.sol
+ function _getVotingUnits(address) public virtual returns (uint256); // HARNESS: internal -> public
}
diff -ruN token/ERC1155/ERC1155.sol token/ERC1155/ERC1155.sol
--- token/ERC1155/ERC1155.sol 2022-05-25 15:36:58.853363841 -0400
+++ token/ERC1155/ERC1155.sol 2022-05-25 16:07:31.901816357 -0400
--- token/ERC1155/ERC1155.sol 2022-05-25 09:38:35.000000000 -0700
+++ token/ERC1155/ERC1155.sol 2022-05-27 01:31:23.000000000 -0700
@@ -268,7 +268,7 @@
uint256 id,
uint256 amount,
@ -191,8 +203,8 @@ diff -ruN token/ERC1155/ERC1155.sol token/ERC1155/ERC1155.sol
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
diff -ruN token/ERC20/ERC20.sol token/ERC20/ERC20.sol
--- token/ERC20/ERC20.sol 2022-05-25 15:36:58.853363841 -0400
+++ token/ERC20/ERC20.sol 2022-05-25 16:19:02.895813907 -0400
--- token/ERC20/ERC20.sol 2022-05-25 09:38:35.000000000 -0700
+++ token/ERC20/ERC20.sol 2022-05-27 01:31:23.000000000 -0700
@@ -277,7 +277,7 @@
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
@ -203,8 +215,8 @@ diff -ruN token/ERC20/ERC20.sol token/ERC20/ERC20.sol
_beforeTokenTransfer(account, address(0), amount);
diff -ruN token/ERC20/extensions/ERC20FlashMint.sol token/ERC20/extensions/ERC20FlashMint.sol
--- token/ERC20/extensions/ERC20FlashMint.sol 2022-05-25 15:36:58.853363841 -0400
+++ token/ERC20/extensions/ERC20FlashMint.sol 2022-05-25 16:07:31.901816357 -0400
--- token/ERC20/extensions/ERC20FlashMint.sol 2022-05-25 09:38:35.000000000 -0700
+++ token/ERC20/extensions/ERC20FlashMint.sol 2022-05-27 01:31:23.000000000 -0700
@@ -40,9 +40,11 @@
require(token == address(this), "ERC20FlashMint: wrong token");
// silence warning about unused variable without the addition of bytecode.
@ -219,8 +231,8 @@ diff -ruN token/ERC20/extensions/ERC20FlashMint.sol token/ERC20/extensions/ERC20
* @dev Returns the receiver address of the flash fee. By default this
* implementation returns the address(0) which means the fee amount will be burnt.
diff -ruN token/ERC20/extensions/ERC20Votes.sol token/ERC20/extensions/ERC20Votes.sol
--- token/ERC20/extensions/ERC20Votes.sol 2022-03-02 13:56:14.831535075 -0500
+++ token/ERC20/extensions/ERC20Votes.sol 2022-05-25 16:14:01.137717224 -0400
--- token/ERC20/extensions/ERC20Votes.sol 2022-05-06 13:43:21.000000000 -0700
+++ token/ERC20/extensions/ERC20Votes.sol 2022-05-27 01:31:23.000000000 -0700
@@ -33,8 +33,8 @@
bytes32 private constant _DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
@ -242,8 +254,8 @@ diff -ruN token/ERC20/extensions/ERC20Votes.sol token/ERC20/extensions/ERC20Vote
_writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
diff -ruN token/ERC20/extensions/ERC20Wrapper.sol token/ERC20/extensions/ERC20Wrapper.sol
--- token/ERC20/extensions/ERC20Wrapper.sol 2022-05-25 15:36:58.853363841 -0400
+++ token/ERC20/extensions/ERC20Wrapper.sol 2022-05-25 16:07:31.909819153 -0400
--- token/ERC20/extensions/ERC20Wrapper.sol 2022-05-25 09:38:35.000000000 -0700
+++ token/ERC20/extensions/ERC20Wrapper.sol 2022-05-27 01:31:23.000000000 -0700
@@ -55,7 +55,7 @@
* @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake. Internal
* function that can be exposed with access control if desired.
@ -254,8 +266,8 @@ diff -ruN token/ERC20/extensions/ERC20Wrapper.sol token/ERC20/extensions/ERC20Wr
_mint(account, value);
return value;
diff -ruN token/ERC721/extensions/draft-ERC721Votes.sol token/ERC721/extensions/draft-ERC721Votes.sol
--- token/ERC721/extensions/draft-ERC721Votes.sol 2022-05-25 15:36:58.853363841 -0400
+++ token/ERC721/extensions/draft-ERC721Votes.sol 2022-05-25 16:07:31.909819153 -0400
--- token/ERC721/extensions/draft-ERC721Votes.sol 2022-05-25 09:38:35.000000000 -0700
+++ token/ERC721/extensions/draft-ERC721Votes.sol 2022-05-27 01:31:23.000000000 -0700
@@ -34,7 +34,7 @@
/**
* @dev Returns the balance of `account`.
@ -266,8 +278,8 @@ diff -ruN token/ERC721/extensions/draft-ERC721Votes.sol token/ERC721/extensions/
}
}
diff -ruN utils/Address.sol utils/Address.sol
--- utils/Address.sol 2022-05-25 15:36:58.853363841 -0400
+++ utils/Address.sol 2022-05-25 16:07:31.909819153 -0400
--- utils/Address.sol 2022-05-25 09:38:35.000000000 -0700
+++ utils/Address.sol 2022-05-27 01:31:23.000000000 -0700
@@ -131,6 +131,7 @@
uint256 value,
string memory errorMessage

View File

@ -31,19 +31,34 @@ contract GovernorPreventLateQuorumHarness is Governor, GovernorCountingSimple, G
return _voteExtension;
}
function getExtendedDeadlineIsUnset(uint256 id) public view returns(bool) {
return _extendedDeadlines[id].isUnset();
function getExtendedDeadlineIsUnset(uint256 proposalId) public view returns(bool) {
return _extendedDeadlines[proposalId].isUnset();
}
function getExtendedDeadlineIsStarted(uint256 id) public view returns(bool) {
return _extendedDeadlines[id].isStarted();
function getExtendedDeadlineIsStarted(uint256 proposalId) public view returns(bool) {
return _extendedDeadlines[proposalId].isStarted();
}
function getExtendedDeadline(uint256 id) public view returns(uint64) {
return _extendedDeadlines[id].getDeadline();
function getExtendedDeadline(uint256 proposalId) public view returns(uint64) {
return _extendedDeadlines[proposalId].getDeadline();
}
// Harness from GovernorCountingSimple //
function getAgainstVotes(uint256 proposalId) public view returns(uint256) {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return proposalvote.againstVotes;
}
function getAbstainVotes(uint256 proposalId) public view returns(uint256) {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return proposalvote.abstainVotes;
}
function getForVotes(uint256 proposalId) public view returns(uint256) {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return proposalvote.forVotes;
}
function quorumReached(uint256 proposalId) public view returns(bool) {
return _quorumReached(proposalId);

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "../munged/proxy/utils/Initializable4.6.sol";
contract InitializableBasicHarness is Initializable {
uint256 public unchangeable;
modifier version1() {
require(_initialized == 1);
_;
}
modifier version2() {
require(_initialized == 2);
_;
}
function initialize(uint256 val) public initializer {
unchangeable = val;
}
function reinitialize(uint256 val) public reinitializer(2) {
unchangeable = val;
}
function returnsV1() public view version1 returns(uint256) {
return unchangeable/2;
}
function returnsV2() public view version2 returns(uint256) {
return unchangeable/3;
}
}

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "../munged/proxy/utils/Initializable4.6.sol";
contract InitializableBasicHarness is Initializable {
uint256 public unchangeable;
function initialize(uint256 _val) public initializer {
unchangeable = _val;
}
function reinitialize(uint256 _val) public reinitializer(2) {
unchangeable = _val;
}
}

View File

@ -1,12 +1,13 @@
certoraRun \
certora/harnesses/ERC721VotesHarness.sol certora/munged/governance/TimelockController.sol certora/harnesses/GovernorPreventLateQuorumHarness.sol \
--verify GovernorPreventLateQuorumHarness:certora/specs/GovernorPreventLateQuorum.spec \
--solc solc8.13 \
--solc solc \
--optimistic_loop \
--disable_auto_cache_key_gen \
--staging \
--settings -optimisticFallback=true \
--send_only \
--loop_iter 1 \
--rule $1 \
--msg "$1" \

View File

@ -38,7 +38,9 @@ methods {
// proposal was created - relation proved in noStartBeforeCreation
definition proposalCreated(uint256 pId) returns bool = proposalSnapshot(pId) > 0;
definition proposalCreated(uint256 pId) returns bool =
proposalSnapshot(pId) > 0
&& proposalDeadline(pId) > 0;
//////////////////////////////////////////////////////////////////////////////

View File

@ -12,6 +12,9 @@ methods {
getExtendedDeadlineIsUnset(uint256) returns bool envfree
getExtendedDeadlineIsStarted(uint256) returns bool envfree
getExtendedDeadline(uint256) returns uint64 envfree
getAgainstVotes(uint256) returns uint256 envfree
getAbstainVotes(uint256) returns uint256 envfree
getForVotes(uint256) returns uint256 envfree
// more robust check than f.selector == _castVote(...).selector
latestCastVoteCall() returns uint256 envfree
@ -22,6 +25,8 @@ methods {
hashOperationBatch(address[], uint256[], bytes[], bytes32, bytes32) => DISPATCHER(true)
executeBatch(address[], uint256[], bytes[], bytes32, bytes32) => CONSTANT
scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256) => CONSTANT
// checkpoint length ERC721
numCheckpoints(address) returns uint32
}
@ -54,27 +59,55 @@ function helperFunctionsWithRevertOnlyCastVote(uint256 proposalId, method f, env
// proposal deadline can be extended (but isn't)
definition deadlineExtendable(env e, uint256 pId) returns bool =
getExtendedDeadlineIsUnset(pId)
getExtendedDeadlineIsUnset(pId) // deadline == 0
&& !quorumReached(e, pId);
// proposal deadline has been extended
definition deadlineExtended(env e, uint256 pId) returns bool =
getExtendedDeadlineIsStarted(pId)
getExtendedDeadlineIsStarted(pId) // deadline > 0
&& quorumReached(e, pId);
definition proposalNotCreated(env e, uint256 pId) returns bool =
proposalSnapshot(pId) == 0
&& proposalDeadline(pId) == 0
&& getExtendedDeadlineIsUnset(pId)
&& getAgainstVotes(pId) == 0
&& getAbstainVotes(pId) == 0
&& getForVotes(pId) == 0
&& !quorumReached(e, pId);
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Invariants /////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/*
* I1: A propsal must be in state deadlineExtendable or deadlineExtended.
* --INVARIANT PASSING // fails for updateQuorumNumerator
* --ADVANCED SANITY PASSING // can't sanity test failing rules, not sure how it works for invariants
* I1: If a proposal has reached quorum then the proposal snapshot (start block.number) must be non-zero
* INVARIANT NOT PASSING // fails for updateQuorumNumerator and in the initial state when voting token total supply is 0 (causes quoromReached to return true)
* ADVANCED SANITY NOT RAN
*/
invariant quorumReachedEffect(env e, uint256 pId)
quorumReached(e, pId) => proposalCreated(pId) // bug: 0 supply 0 votes => quorumReached
// filtered { f -> f.selector != updateQuorumNumerator(uint256).selector } // * fails for this function
/*
* I2: A non-existant proposal must meet the definition of one.
* INVARIANT NOT PASSING // fails for updateQuorumNumerator and in the initial state when voting token total supply is 0 (causes quoromReached to return true)
* ADVANCED SANITY NOT RAN
*/
invariant proposalInOneState(env e, uint256 pId)
deadlineExtendable(e, pId) || deadlineExtended(e, pId)
{ preserved { require proposalCreated(pId); } }
invariant proposalNotCreatedEffects(env e, uint256 pId)
!proposalCreated(pId) => proposalNotCreated(e, pId)
// filtered { f -> f.selector != updateQuorumNumerator(uint256).selector } // * fails for this function
/*
* I3: A created propsal must be in state deadlineExtendable or deadlineExtended.
* INVARIANT NOT PASSING // fails for updateQuorumNumerator and in the initial state when voting token total supply is 0 (causes quoromReached to return true)
* ADVANCED SANITY NOT RAN
*/
invariant proposalInOneState(env e, uint256 pId)
proposalNotCreated(e, pId) || deadlineExtendable(e, pId) || deadlineExtended(e, pId)
// filtered { f -> f.selector != updateQuorumNumerator(uint256).selector } // * fails for this function
{ preserved { requireInvariant proposalNotCreatedEffects(e, pId); }}
//////////////////////////////////////////////////////////////////////////////
@ -92,7 +125,7 @@ invariant proposalInOneState(env e, uint256 pId)
rule deadlineChangeEffects(method f) filtered {f -> !f.isView} {
env e; calldataarg args; uint256 pId;
require (proposalCreated(pId));
requireInvariant quorumReachedEffect(e, pId);
uint256 deadlineBefore = proposalDeadline(pId);
f(e, args);
@ -110,12 +143,12 @@ rule deadlineChangeEffects(method f) filtered {f -> !f.isView} {
rule deadlineCantBeUnextended(method f)
filtered {
f -> !f.isView
&& f.selector != updateQuorumNumerator(uint256).selector // * fails for this function
// && f.selector != updateQuorumNumerator(uint256).selector // * fails for this function
} {
env e; calldataarg args; uint256 pId;
require(deadlineExtended(e, pId));
require(proposalCreated(pId));
requireInvariant quorumReachedEffect(e, pId);
f(e, args);
@ -125,14 +158,14 @@ rule deadlineCantBeUnextended(method f)
/*
* R3: A proposal's deadline can't change in deadlineExtended state.
* RULE PASSING*
* RULE PASSING
* ADVANCED SANITY PASSING
*/
rule canExtendDeadlineOnce(method f) filtered {f -> !f.isView} {
env e; calldataarg args; uint256 pId;
require(deadlineExtended(e, pId));
require(proposalCreated(pId));
requireInvariant quorumReachedEffect(e, pId);
uint256 deadlineBefore = proposalDeadline(pId);
f(e, args);
@ -145,7 +178,7 @@ rule canExtendDeadlineOnce(method f) filtered {f -> !f.isView} {
//////////////////////////// second set of rules ////////////////////////////
// HIGH LEVEL RULE R6: deadline can only extended if quorum reached w/ <= timeOfExtension left to vote
// I1, R4 and R5 are assumed in R6 so we prove them first
// I3, R4 and R5 are assumed in R6 so we prove them first
/*
* R4: A change in hasVoted must be correlated with an increasing of the vote supports, i.e. casting a vote increases the total number of votes.
@ -163,7 +196,7 @@ rule hasVotedCorrelationNonzero(uint256 pId, method f, env e) filtered {f -> !f.
bool hasVotedBefore = hasVoted(e, pId, acc);
helperFunctionsWithRevertOnlyCastVote(pId, f, e);
helperFunctionsWithRevertOnlyCastVote(pId, f, e); // should be f(e, args)
uint256 againstAfter = votesAgainst();
uint256 forAfter = votesFor();
@ -175,11 +208,11 @@ rule hasVotedCorrelationNonzero(uint256 pId, method f, env e) filtered {f -> !f.
assert
(!hasVotedBefore && hasVotedAfter) =>
(againstBefore <= againstAfter && forBefore <= forAfter && abstainBefore <= abstainAfter),
"no correlation: some category decreased"; // currently vacous but keeping for CI tests
"after a vote is cast, the number of votes for each category must not decrease"; // currently vacous but keeping for CI tests
assert
(!hasVotedBefore && hasVotedAfter) =>
(againstBefore < againstAfter || forBefore < forAfter || abstainBefore < abstainAfter),
"no correlation: no category increased";
"after a vote is cast, the number of votes of at least one category must increase";
}
@ -200,7 +233,7 @@ rule againstVotesDontCount(method f) filtered {f -> !f.isView} {
bool quorumAfter = quorumReached(e, pId);
uint256 againstAfter = votesAgainst();
assert (againstBefore < againstAfter) => quorumBefore == quorumAfter, "quorum reached with against vote";
assert (againstBefore < againstAfter) => quorumBefore == quorumAfter, "quorum must not be reached with an against vote";
}
/*
@ -211,9 +244,9 @@ rule againstVotesDontCount(method f) filtered {f -> !f.isView} {
rule deadlineExtenededIfQuorumReached(method f) filtered {f -> !f.isView} {
env e; calldataarg args; uint256 pId;
// need invariant that proves that a propsal must be in state deadlineExtendable or deadlineExtended
require(deadlineExtended(e, pId) || deadlineExtendable(e, pId));
require(proposalCreated(pId));
requireInvariant proposalInOneState(e, pId);
requireInvariant quorumReachedEffect(e, pId);
requireInvariant proposalNotCreatedEffects(e, pId);
bool wasDeadlineExtendable = deadlineExtendable(e, pId);
uint64 extension = lateQuorumVoteExtension();
@ -221,8 +254,8 @@ rule deadlineExtenededIfQuorumReached(method f) filtered {f -> !f.isView} {
f(e, args);
uint256 deadlineAfter = proposalDeadline(pId);
assert(deadlineAfter > deadlineBefore => wasDeadlineExtendable, "deadline was not extendable");
assert(deadlineAfter > deadlineBefore => deadlineBefore - e.block.number <= extension, "deadline extension should not be used");
assert deadlineAfter > deadlineBefore => wasDeadlineExtendable, "deadline must have been extendable for the deadline to be extended";
assert deadlineAfter > deadlineBefore => deadlineBefore - e.block.number <= extension, "deadline extension should not be used";
}
/*
@ -232,7 +265,8 @@ rule deadlineExtenededIfQuorumReached(method f) filtered {f -> !f.isView} {
*/
rule extendedDeadlineValueSetIfQuorumReached(method f) filtered {f -> !f.isView} {
env e; calldataarg args; uint256 pId;
require(deadlineExtended(e, pId) || deadlineExtendable(e, pId));
requireInvariant proposalInOneState(e, pId);
bool extendedBefore = deadlineExtended(e, pId);
f(e, args);
@ -247,33 +281,15 @@ rule extendedDeadlineValueSetIfQuorumReached(method f) filtered {f -> !f.isView}
}
/*
* R8: If the deadline for a proposal has not been reached, users can still vote.
* --RULE PASSING
* --ADVANCED SANITY PASSING
*/
rule canVote(method f) filtered {f -> !f.isView} {
env e; calldataarg args; uint256 pId;
address acc = e.msg.sender;
uint256 deadline = proposalDeadline(pId);
bool votedBefore = hasVoted(e, pId, acc);
require(proposalCreated(pId));
require(deadline >= e.block.number);
// last error?
helperFunctionsWithRevertOnlyCastVote(pId, f, e);
bool votedAfter = hasVoted(e, pId, acc);
assert !votedBefore && votedAfter => deadline >= e.block.number;
}
/*
* R9: Deadline can never be reduced.
* R8: Deadline can never be reduced.
* RULE PASSING
* ADVANCED SANITY PASSING
*/
rule deadlineNeverReduced(method f) filtered {f -> !f.isView} {
env e; calldataarg args; uint256 pId;
require(proposalCreated(pId));
requireInvariant quorumReachedEffect(e, pId);
requireInvariant proposalNotCreatedEffects(e, pId);
uint256 deadlineBefore = proposalDeadline(pId);
f(e, args);

View File

@ -0,0 +1,3 @@
methods {
}