final govPreventLateQ
This commit is contained in:
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
35
certora/harnesses/InitializableBasicHarness.sol
Normal file
35
certora/harnesses/InitializableBasicHarness.sol
Normal 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;
|
||||
}
|
||||
}
|
||||
18
certora/harnesses/InitializablrComplexHarness.sol
Normal file
18
certora/harnesses/InitializablrComplexHarness.sol
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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" \
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -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);
|
||||
|
||||
3
certora/specs/Initializable.spec
Normal file
3
certora/specs/Initializable.spec
Normal file
@ -0,0 +1,3 @@
|
||||
methods {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user