|
@@ -33,53 +33,38 @@ methods {
|
|
|
// Helper Functions //
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
-function setup(env e1, env e2) {
|
|
|
- require getQuorumNumeratorLength() + 1 < max_uint;
|
|
|
- require e2.block.number >= e1.block.number;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-//// #### Definitions //
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-/// The proposal with proposal id `pId` has a deadline which is extendable.
|
|
|
-definition deadlineExtendable(env e, uint256 pId) returns bool =
|
|
|
- getExtendedDeadline(pId) == 0 && !quorumReached(e, pId);
|
|
|
-
|
|
|
-/// The proposal with proposal id `pId` has a deadline which has been extended.
|
|
|
-definition deadlineExtended(env e, uint256 pId) returns bool =
|
|
|
- getExtendedDeadline(pId) > 0 && quorumReached(e, pId);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
|
|
|
|
|
|
+function sanity() {
|
|
|
+ require getQuorumNumeratorLength() + 1 < max_uint;
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+definition deadlineExtendable(env e, uint256 pId) returns bool = getExtendedDeadline(pId) == 0;
|
|
|
+definition deadlineExtended(env e, uint256 pId) returns bool = getExtendedDeadline(pId) > 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-invariant deadlineExtendableConsistency(env e, uint256 pId)
|
|
|
- !quorumReached(e, pId) => getExtendedDeadline(pId) == 0
|
|
|
+invariant deadlineConsistency(env e, uint256 pId)
|
|
|
+ (!quorumReached(e, pId) => deadlineExtendable(pId))
|
|
|
+ &&
|
|
|
+ (deadlineExtended(pId) => quorumReached(e, pId))
|
|
|
|
|
|
-invariant deadlineExtendedConsistency(env e, uint256 pId)
|
|
|
- getExtendedDeadline(pId) > 0 => quorumReached(e, pId)
|
|
|
|
|
|
-invariant proposalNotCreatedState(uint256 pId)
|
|
|
- !proposalCreated(pId) => (getAgainstVotes(pId) == 0 && getAbstainVotes(pId) == 0 && getForVotes(pId) == 0)
|
|
|
+invariant proposalStateConsistencyExtended(uint256 pId)
|
|
|
+ !proposalCreated(pId) => (getAgainstVotes(pId) == 0 && getAbstainVotes(pId) == 0 && getForVotes(pId) == 0)
|
|
|
+ && (proposalProposer(pId) == 0 <=> proposalSnapshot(pId) == 0)
|
|
|
+ && (proposalProposer(pId) == 0 <=> proposalDeadline(pId) == 0)
|
|
|
+ {
|
|
|
+ preserved with (env e) {
|
|
|
+ require e.block.number > 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
@@ -88,9 +73,30 @@ invariant proposalNotCreatedState(uint256 pId)
|
|
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * If a proposal has reached quorum then the proposal snapshot (start `block.number`) must be non-zero
|
|
|
+ */
|
|
|
+invariant quorumReachedEffect(env e, uint256 pId)
|
|
|
+ (quorumReached(e, pId) && getPastTotalSupply(proposalSnapshot(pId)) > 0) => proposalCreated(pId)
|
|
|
|
|
|
+/**
|
|
|
+ * The quorum numerator is always less than or equal to the quorum denominator.
|
|
|
+ */
|
|
|
+invariant quorumRatioLessThanOne(env e, uint256 blockNumber)
|
|
|
+ quorumNumerator(e, blockNumber) <= quorumDenominator()
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * If a proposal's deadline has been extended, then the proposal must have been created and reached quorum.
|
|
|
+ */
|
|
|
+invariant cantExtendWhenQuorumUnreached(env e, uint256 pId)
|
|
|
+ getExtendedDeadline(pId) > 0 => (quorumReached(e, pId) && proposalCreated(pId))
|
|
|
+ //{
|
|
|
+ // preserved with (env e1) {
|
|
|
+ // require e1.block.number > proposalSnapshot(pId);
|
|
|
+ // setup(e1, e);
|
|
|
+ // }
|
|
|
+ //}
|
|
|
|
|
|
|
|
|
|
|
@@ -110,6 +116,9 @@ rule quorumReachedCantChange(uint256 pId, env e, method f) filtered { f ->
|
|
|
&& f.selector != relay(address,uint256,bytes).selector
|
|
|
&& !castVoteSubset(f)
|
|
|
} {
|
|
|
+ sanity(); // not overflowing checkpoint struct
|
|
|
+ require proposalSnapshot(pId) < e.block.number; // vote has started
|
|
|
+
|
|
|
bool quorumReachedBefore = quorumReached(e, pId);
|
|
|
|
|
|
uint256 newQuorumNumerator;
|
|
@@ -193,7 +202,7 @@ rule deadlineChangeEffects(uint256 pId, env e, method f, calldataarg args) filte
|
|
|
&& f.selector != relay(address,uint256,bytes).selector
|
|
|
&& !castVoteSubset(f)
|
|
|
} {
|
|
|
- requireInvariant proposalStateConsistency(pId);
|
|
|
+ requireInvariant proposalStateConsistencyExtended(pId);
|
|
|
|
|
|
uint256 deadlineBefore = proposalDeadline(pId);
|
|
|
bool deadlineExtendedBefore = deadlineExtended(e, pId);
|
|
@@ -257,6 +266,15 @@ rule deadlineChangeEffects(uint256 pId, env e, method f, calldataarg args) filte
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+function setup(env e1, env e2) {
|
|
|
+ require getQuorumNumeratorLength() + 1 < max_uint;
|
|
|
+ require e2.block.number >= e1.block.number;
|
|
|
+}
|
|
|
|
|
|
/// The proposal with proposal id `pId` has not been created.
|
|
|
definition proposalNotCreated(env e, uint256 pId) returns bool =
|
|
@@ -276,30 +294,6 @@ definition castVoteSubset(method f) returns bool =
|
|
|
f.selector == castVoteWithReasonAndParams(uint256,uint8,string,bytes).selector ||
|
|
|
f.selector == castVoteWithReasonAndParamsBySig(uint256,uint8,string,bytes,uint8,bytes32,bytes32).selector;
|
|
|
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-//// ### Properties //
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-// Invariants //
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
* A created proposal must be in state `deadlineExtendable` or `deadlineExtended`.
|
|
|
* @dev We assume the total supply of the voting token is non-zero
|
|
@@ -312,57 +306,3 @@ invariant proposalInOneState(env e1, uint256 pId)
|
|
|
setup(e1, e2);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-/**
|
|
|
- * The quorum numerator is always less than or equal to the quorum denominator.
|
|
|
- */
|
|
|
-invariant quorumNumerLTEDenom(env e1, uint256 blockNumber)
|
|
|
- quorumNumerator(e1, blockNumber) <= quorumDenominator()
|
|
|
- {
|
|
|
- preserved with (env e2) {
|
|
|
- setup(e1, e2);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * The deprecated quorum numerator variable `_quorumNumerator` is always 0 in a contract that is not upgraded.
|
|
|
- */
|
|
|
-invariant deprecatedQuorumStateIsUninitialized()
|
|
|
- getDeprecatedQuorumNumerator() == 0
|
|
|
-
|
|
|
-/**
|
|
|
- * If a proposal's deadline has been extended, then the proposal must have been created and reached quorum.
|
|
|
- */
|
|
|
-invariant cantExtendWhenQuorumUnreached(env e2, uint256 pId)
|
|
|
- getExtendedDeadline(pId) > 0 => (quorumReached(e2, pId) && proposalCreated(pId))
|
|
|
- filtered { f -> !f.isFallback && !f.isView && !castVoteSubset(f) && f.selector != relay(address,uint256,bytes).selector }
|
|
|
- {
|
|
|
- preserved with (env e1) {
|
|
|
- require e1.block.number > proposalSnapshot(pId);
|
|
|
- setup(e1, e2);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * The snapshot arrat keeping tracking of quorum numerators must never be uninitialized.
|
|
|
- */
|
|
|
-invariant quorumLengthGt0(env e)
|
|
|
- getQuorumNumeratorLength() > 0
|
|
|
- filtered { f -> !f.isFallback && !f.isView && !castVoteSubset(f) && f.selector != relay(address,uint256,bytes).selector }
|
|
|
- {
|
|
|
- preserved {
|
|
|
- setup(e,e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * If a proposal has reached quorum then the proposal snapshot (start `block.number`) must be non-zero
|
|
|
- */
|
|
|
-invariant quorumReachedEffect(env e, uint256 pId)
|
|
|
- quorumReached(e, pId) => proposalCreated(pId)
|
|
|
-// filtered { f -> !f.isFallback && !f.isView && !castVoteSubset(f) && f.selector != relay(address,uint256,bytes).selector }
|
|
|
-// {
|
|
|
-// preserved with (env e2) {
|
|
|
-// setup(e1, e2);
|
|
|
-// }
|
|
|
-// }
|