diff --git a/certora/diff/governance_Governor.sol.patch b/certora/diff/governance_Governor.sol.patch index aa667d8d2..1e9d63215 100644 --- a/certora/diff/governance_Governor.sol.patch +++ b/certora/diff/governance_Governor.sol.patch @@ -1,5 +1,5 @@ --- governance/Governor.sol 2023-03-07 10:48:47.730155491 +0100 -+++ governance/Governor.sol 2023-03-13 15:30:49.107167674 +0100 ++++ governance/Governor.sol 2023-03-14 22:09:12.664754077 +0100 @@ -216,6 +216,21 @@ return _proposals[proposalId].proposer; } @@ -15,7 +15,7 @@ + } + + // FV -+ function _governanceCallLength() public view returns (uint256) { ++ function _governanceCallLength() internal view returns (uint256) { + return _governanceCall.length(); + } + diff --git a/certora/diff/governance_extensions_GovernorTimelockControl.sol.patch b/certora/diff/governance_extensions_GovernorTimelockControl.sol.patch index 5d5cf28f6..57e213f34 100644 --- a/certora/diff/governance_extensions_GovernorTimelockControl.sol.patch +++ b/certora/diff/governance_extensions_GovernorTimelockControl.sol.patch @@ -1,5 +1,5 @@ ---- governance/extensions/GovernorTimelockControl.sol 2023-03-07 10:48:47.733488857 +0100 -+++ governance/extensions/GovernorTimelockControl.sol 2023-03-13 16:18:10.255122179 +0100 +--- governance/extensions/GovernorTimelockControl.sol 2023-03-14 15:48:49.307543354 +0100 ++++ governance/extensions/GovernorTimelockControl.sol 2023-03-14 22:09:12.661420438 +0100 @@ -84,6 +84,11 @@ return eta == 1 ? 0 : eta; // _DONE_TIMESTAMP (1) should be replaced with a 0 value } diff --git a/certora/diff/token_ERC721_ERC721.sol.patch b/certora/diff/token_ERC721_ERC721.sol.patch index 312fc4ff6..1623beae9 100644 --- a/certora/diff/token_ERC721_ERC721.sol.patch +++ b/certora/diff/token_ERC721_ERC721.sol.patch @@ -1,5 +1,5 @@ --- token/ERC721/ERC721.sol 2023-03-07 10:48:47.736822221 +0100 -+++ token/ERC721/ERC721.sol 2023-03-09 19:50:20.555856358 +0100 ++++ token/ERC721/ERC721.sol 2023-03-14 22:09:12.654753162 +0100 @@ -199,6 +199,11 @@ return _owners[tokenId]; } diff --git a/certora/specs/GovernorBaseRules.spec b/certora/specs/GovernorBaseRules.spec index 405a1085c..ebf5e9cf4 100644 --- a/certora/specs/GovernorBaseRules.spec +++ b/certora/specs/GovernorBaseRules.spec @@ -26,14 +26,16 @@ rule noDoublePropose(uint256 pId, env e) { │ Rule: Once a proposal is created, voteStart, voteEnd and proposer are immutable │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule immutableFieldsAfterProposalCreation(uint256 pId, env e, method f, calldataarg arg) { +rule immutableFieldsAfterProposalCreation(uint256 pId, env e, method f, calldataarg args) + filtered { f -> !skip(f) } +{ require proposalCreated(pId); uint256 voteStart = proposalSnapshot(pId); uint256 voteEnd = proposalDeadline(pId); address proposer = proposalProposer(pId); - f(e, arg); + f(e, args); assert voteStart == proposalSnapshot(pId), "Start date was changed"; assert voteEnd == proposalDeadline(pId), "End date was changed"; @@ -66,7 +68,9 @@ rule noDoubleVoting(uint256 pId, env e, uint8 sup) { │ Rule: A proposal could be executed only if quorum was reached and vote succeeded │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f, calldataarg args) { +rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f, calldataarg args) + filtered { f -> !skip(f) } +{ require !isExecuted(pId); bool quorumReachedBefore = quorumReached(pId); @@ -82,7 +86,9 @@ rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f, │ Rule: Voting cannot start at a block number prior to proposal’s creation block number │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule noStartBeforeCreation(uint256 pId, env e, method f, calldataarg args){ +rule noStartBeforeCreation(uint256 pId, env e, method f, calldataarg args) + filtered { f -> !skip(f) } +{ require !proposalCreated(pId); f(e, args); assert proposalCreated(pId) => proposalSnapshot(pId) >= clock(e), "starts before proposal"; @@ -93,7 +99,9 @@ rule noStartBeforeCreation(uint256 pId, env e, method f, calldataarg args){ │ Rule: A proposal cannot be executed before it ends │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule noExecuteBeforeDeadline(uint256 pId, env e, method f, calldataarg args) { +rule noExecuteBeforeDeadline(uint256 pId, env e, method f, calldataarg args) + filtered { f -> !skip(f) } +{ require !isExecuted(pId); f(e, args); assert isExecuted(pId) => proposalDeadline(pId) <= clock(e), "executed before deadline"; diff --git a/certora/specs/GovernorChanges.spec b/certora/specs/GovernorChanges.spec index c521f7995..a1d9922e3 100644 --- a/certora/specs/GovernorChanges.spec +++ b/certora/specs/GovernorChanges.spec @@ -1,28 +1,35 @@ import "helpers.spec" import "methods/IGovernor.spec" import "Governor.helpers.spec" +import "GovernorInvariants.spec" + +use invariant proposalStateConsistency /* ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Rule: Proposal can be switched state only by specific functions │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule changes(uint256 pId, env e) { - require nonpayable(e); +rule changes(uint256 pId, env e, method f, calldataarg args) + filtered { f -> !skip(f) } +{ require clockSanity(e); + requireInvariant proposalStateConsistency(pId); address user; + bool existBefore = proposalCreated(pId); bool isExecutedBefore = isExecuted(pId); bool isCanceledBefore = isCanceled(pId); bool isQueuedBefore = isQueued(pId); bool hasVotedBefore = hasVoted(pId, user); - method f; calldataarg args; f(e, args); + f(e, args); - assert isExecuted(pId) != isExecutedBefore => (!isExecutedBefore && f.selector == execute(address[],uint256[],bytes[],bytes32).selector); - assert isCanceled(pId) != isCanceledBefore => (!isCanceledBefore && f.selector == cancel(address[],uint256[],bytes[],bytes32).selector); - assert hasVoted(pId, user) != hasVotedBefore => (!hasVotedBefore && votingAll(f)); + assert proposalCreated(pId) != existBefore => (!existBefore && f.selector == propose(address[],uint256[],bytes[],string).selector); + assert isExecuted(pId) != isExecutedBefore => (!isExecutedBefore && f.selector == execute(address[],uint256[],bytes[],bytes32).selector); + assert isCanceled(pId) != isCanceledBefore => (!isCanceledBefore && f.selector == cancel(address[],uint256[],bytes[],bytes32).selector); + assert hasVoted(pId, user) != hasVotedBefore => (!hasVotedBefore && votingAll(f)); // queue is cleared on cancel assert isQueued(pId) != isQueuedBefore => (