parent
1b27c13096
commit
2c08f85744
@ -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…
Reference in new issue