start work on governor

pull/2997/head
Shelly Grossman 3 years ago
parent 1b27c13096
commit 2c08f85744
  1. 29
      certora/harnesses/GovernorCountingSimpleHarness.sol
  2. 58
      certora/harnesses/GovernorHarness.sol
  3. 58
      certora/harnesses/GovernorProposalThresholdHarness.sol
  4. 58
      certora/harnesses/GovernorTimelockCompoundHarness.sol
  5. 52
      certora/harnesses/GovernorVotesHarness.sol
  6. 46
      certora/harnesses/GovernorVotesQuorumFractionHarness.sol
  7. 2
      certora/scripts/Governor.sh
  8. 2
      certora/scripts/GovernorCountingSimple.sh
  9. 2
      certora/scripts/GovernorProposalThreshold.sh
  10. 2
      certora/scripts/GovernorTimelockCompound.sh
  11. 2
      certora/scripts/GovernorVotes.sh
  12. 2
      certora/scripts/GovernorVotesQuorumFractionHarness.sh
  13. 7
      certora/scripts/check.sh
  14. 79
      certora/specs/GovernorBase.spec
  15. 31
      certora/specs/Privileged.spec

@ -0,0 +1,29 @@
import "../../contracts/governance/extensions/GovernorCountingSimple.sol";
contract GovernorCountingSimpleHarness is GovernorCountingSimple {
mapping(uint256 => uint256) _quorum;
function quorum(uint256 blockNumber) public view override virtual returns (uint256) {
return _quorum[blockNumber];
}
mapping (address => mapping (uint256 => uint256)) _getVotes;
function getVotes(address account, uint256 blockNumber) public view override virtual returns (uint256) {
return _getVotes[account][blockNumber];
}
uint256 _votingDelay;
function votingDelay() public view override virtual returns (uint256) {
return _votingDelay;
}
uint256 _votingPeriod;
function votingPeriod() public view override virtual returns (uint256) {
return _votingPeriod;
}
constructor(string memory name) Governor(name) {}
}

@ -0,0 +1,58 @@
import "../../contracts/governance/Governor.sol";
contract GovernorHarness is Governor {
mapping(uint256 => uint256) _quorum;
function quorum(uint256 blockNumber) public view override virtual returns (uint256) {
return _quorum[blockNumber];
}
mapping (address => mapping (uint256 => uint256)) _getVotes;
function getVotes(address account, uint256 blockNumber) public view override virtual returns (uint256) {
return _getVotes[account][blockNumber];
}
mapping (uint256 => bool) __quoromReached;
function _quorumReached(uint256 proposalId) internal view override virtual returns (bool) {
return __quoromReached[proposalId];
}
mapping (uint256 => bool) __voteSucceeded;
function _voteSucceeded(uint256 proposalId) internal view override virtual returns (bool) {
return __voteSucceeded[proposalId];
}
//string _COUNTING_MODE;
function COUNTING_MODE() public pure override virtual returns (string memory) {
return "dummy";
}
mapping(uint256 => mapping(address => bool)) _hasVoted;
function hasVoted(uint256 proposalId, address account) public view override virtual returns (bool) {
return _hasVoted[proposalId][account];
}
uint256 _votingDelay;
function votingDelay() public view override virtual returns (uint256) {
return _votingDelay;
}
uint256 _votingPeriod;
function votingPeriod() public view override virtual returns (uint256) {
return _votingPeriod;
}
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal override virtual {
// havoc something
}
constructor(string memory name) Governor(name) {}
}

@ -0,0 +1,58 @@
import "../../contracts/governance/extensions/GovernorProposalThreshold.sol";
contract GovernorProposalThresholdHarness is GovernorProposalThreshold {
mapping(uint256 => uint256) _quorum;
function quorum(uint256 blockNumber) public view override virtual returns (uint256) {
return _quorum[blockNumber];
}
mapping (address => mapping (uint256 => uint256)) _getVotes;
function getVotes(address account, uint256 blockNumber) public view override virtual returns (uint256) {
return _getVotes[account][blockNumber];
}
mapping (uint256 => bool) __quoromReached;
function _quorumReached(uint256 proposalId) internal view override virtual returns (bool) {
return __quoromReached[proposalId];
}
mapping (uint256 => bool) __voteSucceeded;
function _voteSucceeded(uint256 proposalId) internal view override virtual returns (bool) {
return __voteSucceeded[proposalId];
}
//string _COUNTING_MODE;
function COUNTING_MODE() public pure override virtual returns (string memory) {
return "dummy";
}
mapping(uint256 => mapping(address => bool)) _hasVoted;
function hasVoted(uint256 proposalId, address account) public view override virtual returns (bool) {
return _hasVoted[proposalId][account];
}
uint256 _votingDelay;
function votingDelay() public view override virtual returns (uint256) {
return _votingDelay;
}
uint256 _votingPeriod;
function votingPeriod() public view override virtual returns (uint256) {
return _votingPeriod;
}
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal override virtual {
// havoc something
}
constructor(string memory name) Governor(name) {}
}

@ -0,0 +1,58 @@
import "../../contracts/governance/extensions/GovernorTimelockCompound.sol";
contract GovernorTimelockCompoundHarness is GovernorTimelockCompound {
mapping(uint256 => uint256) _quorum;
function quorum(uint256 blockNumber) public view override virtual returns (uint256) {
return _quorum[blockNumber];
}
mapping (address => mapping (uint256 => uint256)) _getVotes;
function getVotes(address account, uint256 blockNumber) public view override virtual returns (uint256) {
return _getVotes[account][blockNumber];
}
mapping (uint256 => bool) __quoromReached;
function _quorumReached(uint256 proposalId) internal view override virtual returns (bool) {
return __quoromReached[proposalId];
}
mapping (uint256 => bool) __voteSucceeded;
function _voteSucceeded(uint256 proposalId) internal view override virtual returns (bool) {
return __voteSucceeded[proposalId];
}
//string _COUNTING_MODE;
function COUNTING_MODE() public pure override virtual returns (string memory) {
return "dummy";
}
mapping(uint256 => mapping(address => bool)) _hasVoted;
function hasVoted(uint256 proposalId, address account) public view override virtual returns (bool) {
return _hasVoted[proposalId][account];
}
uint256 _votingDelay;
function votingDelay() public view override virtual returns (uint256) {
return _votingDelay;
}
uint256 _votingPeriod;
function votingPeriod() public view override virtual returns (uint256) {
return _votingPeriod;
}
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal override virtual {
// havoc something
}
constructor(string memory name, ICompoundTimelock timelock) Governor(name) GovernorTimelockCompound(timelock) {}
}

@ -0,0 +1,52 @@
import "../../contracts/governance/extensions/GovernorVotes.sol";
contract GovernorVotesHarness is GovernorVotes {
mapping(uint256 => uint256) _quorum;
function quorum(uint256 blockNumber) public view override virtual returns (uint256) {
return _quorum[blockNumber];
}
mapping (uint256 => bool) __quoromReached;
function _quorumReached(uint256 proposalId) internal view override virtual returns (bool) {
return __quoromReached[proposalId];
}
mapping (uint256 => bool) __voteSucceeded;
function _voteSucceeded(uint256 proposalId) internal view override virtual returns (bool) {
return __voteSucceeded[proposalId];
}
//string _COUNTING_MODE;
function COUNTING_MODE() public pure override virtual returns (string memory) {
return "dummy";
}
mapping(uint256 => mapping(address => bool)) _hasVoted;
function hasVoted(uint256 proposalId, address account) public view override virtual returns (bool) {
return _hasVoted[proposalId][account];
}
uint256 _votingDelay;
function votingDelay() public view override virtual returns (uint256) {
return _votingDelay;
}
uint256 _votingPeriod;
function votingPeriod() public view override virtual returns (uint256) {
return _votingPeriod;
}
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal override virtual {
// havoc something
}
constructor(string memory name) Governor(name) {}
}

@ -0,0 +1,46 @@
import "../../contracts/governance/extensions/GovernorVotesQuorumFractionGovernor.sol";
contract GovernorVotesQuorumFractionHarness is GovernorVotesQuorumFraction {
mapping (uint256 => bool) __quoromReached;
function _quorumReached(uint256 proposalId) internal view override virtual returns (bool) {
return __quoromReached[proposalId];
}
mapping (uint256 => bool) __voteSucceeded;
function _voteSucceeded(uint256 proposalId) internal view override virtual returns (bool) {
return __voteSucceeded[proposalId];
}
//string _COUNTING_MODE;
function COUNTING_MODE() public pure override virtual returns (string memory) {
return "dummy";
}
mapping(uint256 => mapping(address => bool)) _hasVoted;
function hasVoted(uint256 proposalId, address account) public view override virtual returns (bool) {
return _hasVoted[proposalId][account];
}
uint256 _votingDelay;
function votingDelay() public view override virtual returns (uint256) {
return _votingDelay;
}
uint256 _votingPeriod;
function votingPeriod() public view override virtual returns (uint256) {
return _votingPeriod;
}
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal override virtual {
// havoc something
}
constructor(string memory name) Governor(name) {}
}

@ -0,0 +1,2 @@
certoraRun certora/harnesses/GovernorHarness.sol \
--verify GovernorHarness:certora/specs/Privileged.spec

@ -0,0 +1,2 @@
certoraRun certora/harnesses/GovernorCountingSimpleHarness.sol \
--verify GovernorCountingSimpleHarness:certora/specs/Privileged.spec

@ -0,0 +1,2 @@
certoraRun certora/harnesses/GovernorProposalThresholdHarness.sol \
--verify GovernorProposalThresholdHarness:certora/specs/Privileged.spec

@ -0,0 +1,2 @@
certoraRun certora/harnesses/GovernorTimelockCompoundHarness.sol \
--verify GovernorTimelockCompoundHarness:certora/specs/Privileged.spec

@ -0,0 +1,2 @@
certoraRun certora/harnesses/GovernorVotesHarness.sol \
--verify GovernorVotesHarness:certora/specs/Privileged.spec

@ -0,0 +1,2 @@
certoraRun certora/harnesses/GovernorVotesQuorumFractionHarness.sol \
--verify GovernorVotesQuorumFractionHarness:certora/specs/Privileged.spec

@ -0,0 +1,7 @@
echo "Usage: Contract Spec"
echo "e.g. GovernorVotes Privileged"
Contract=$1
Spec=$2
shift 2
certoraRun certora/harnesses/${Contract}Harness.sol \
--verify ${Contract}Harness:certora/specs/${Spec}.spec "$@"

@ -0,0 +1,79 @@
// Governor.sol base definitions
methods {
proposalSnapshot(uint256) returns uint256 envfree // matches proposalVoteStart
}
ghost proposalVoteStart(uint256) returns uint64 {
init_state axiom forall uint256 pId. proposalVoteStart(pId) == 0;
}
ghost proposalVoteEnd(uint256) returns uint64 {
init_state axiom forall uint256 pId. proposalVoteEnd(pId) == 0;
}
ghost proposalExecuted(uint256) returns bool {
init_state axiom forall uint256 pId. !proposalExecuted(pId);
}
ghost proposalCanceled(uint256) returns bool {
init_state axiom forall uint256 pId. !proposalCanceled(pId);
}
hook Sstore _proposals[KEY uint256 pId].(offset 0) uint64 newValue STORAGE {
havoc proposalVoteStart assuming (
proposalVoteStart@new(pId) == newValue
&& (forall uint256 pId2. pId != pId2 => proposalVoteStart@new(pId2) == proposalVoteStart@old(pId2))
);
}
hook Sload uint64 value _proposals[KEY uint256 pId].(offset 0) STORAGE {
require proposalVoteStart(pId) == value;
}
hook Sstore _proposals[KEY uint256 pId].(offset 32).(offset 0) uint64 newValue STORAGE {
havoc proposalVoteEnd assuming (
proposalVoteEnd@new(pId) == newValue
&& (forall uint256 pId2. pId != pId2 => proposalVoteEnd@new(pId2) == proposalVoteEnd@old(pId2))
);
}
hook Sload uint64 value _proposals[KEY uint256 pId].(offset 32).(offset 0) STORAGE {
require proposalVoteEnd(pId) == value;
}
rule sanityCheckVoteStart(method f, uint256 pId) {
uint64 preGhost = proposalVoteStart(pId);
uint256 pre = proposalSnapshot(pId);
env e;
calldataarg arg;
f(e, arg);
uint64 postGhost = proposalVoteStart(pId);
uint256 post = proposalSnapshot(pId);
assert preGhost == postGhost <=> pre == post, "ghost changes are correlated with getter changes";
assert pre == preGhost => post == postGhost, "if correlated at the beginning should be correlated at the end";
}
rule sanityCheckVoteEnd(method f, uint256 pId) {
uint64 preGhost = proposalVoteEnd(pId);
uint256 pre = proposalSnapshot(pId);
env e;
calldataarg arg;
f(e, arg);
uint64 postGhost = proposalVoteEnd(pId);
uint256 post = proposalSnapshot(pId);
assert preGhost == postGhost <=> pre == post, "ghost changes are correlated with getter changes";
assert pre == preGhost => post == postGhost, "if correlated at the beginning should be correlated at the end";
}
/**
* A proposal cannot end unless it started.
*/
invariant voteStartBeforeVoteEnd(uint256 pId) proposalVoteStart(pId) < proposalVoteEnd(pId)
/**
* A proposal cannot be both executed and canceled.
*/
invariant noBothExecutedAndCanceled(uint256 pId) !proposalExecuted(pId) || !proposalCanceled(pId)

@ -0,0 +1,31 @@
definition knownAsNonPrivileged(method f) returns bool = false
/* ( f.selector == isWhitelistedOtoken(address).selector ||
f.selector == isWhitelistedProduct(address,address,address,bool).selector ||
f.selector == owner().selector ||
f.selector == isWhitelistedCallee(address).selector ||
f.selector == whitelistOtoken(address).selector ||
f.selector == addressBook().selector ||
f.selector == isWhitelistedCollateral(address).selector )*/;
rule privilegedOperation(method f, address privileged)
description "$f can be called by more than one user without reverting"
{
env e1;
calldataarg arg;
require !knownAsNonPrivileged(f);
require e1.msg.sender == privileged;
storage initialStorage = lastStorage;
invoke f(e1, arg); // privileged succeeds executing candidate privileged operation.
bool firstSucceeded = !lastReverted;
env e2;
calldataarg arg2;
require e2.msg.sender != privileged;
invoke f(e2, arg2) at initialStorage; // unprivileged
bool secondSucceeded = !lastReverted;
assert !(firstSucceeded && secondSucceeded), "${f.selector} can be called by both ${e1.msg.sender} and ${e2.msg.sender}, so it is not privileged";
}
Loading…
Cancel
Save