GovernorInvariants.spec 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import "helpers.spec"
  2. import "methods/IGovernor.spec"
  3. import "Governor.helpers.spec"
  4. /*
  5. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  6. │ Invariant: clock is consistent between the goernor and the token │
  7. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  8. */
  9. rule clockMode(env e) {
  10. assert clock(e) == e.block.number || clock(e) == e.block.timestamp;
  11. assert clock(e) == token_clock(e);
  12. }
  13. /*
  14. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  15. │ Invariant: Proposal is UNSET iff the proposer, the snapshot and the deadline are unset. │
  16. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  17. */
  18. invariant createdConsistency(env e, uint256 pId)
  19. safeState(e, pId) == UNSET() <=> proposalProposer(pId) == 0 &&
  20. safeState(e, pId) == UNSET() <=> proposalSnapshot(pId) == 0 &&
  21. safeState(e, pId) == UNSET() <=> proposalDeadline(pId) == 0 &&
  22. safeState(e, pId) == UNSET() => !isExecuted(pId) &&
  23. safeState(e, pId) == UNSET() => !isCanceled(pId)
  24. {
  25. preserved {
  26. require clock(e) > 0;
  27. }
  28. }
  29. invariant createdConsistencyWeak(uint256 pId)
  30. proposalProposer(pId) == 0 <=> proposalSnapshot(pId) == 0 &&
  31. proposalProposer(pId) == 0 <=> proposalDeadline(pId) == 0
  32. {
  33. preserved with (env e) {
  34. require clock(e) > 0;
  35. }
  36. }
  37. /*
  38. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  39. │ Invariant: Votes start before it ends │
  40. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  41. */
  42. invariant voteStartBeforeVoteEnd(uint256 pId)
  43. proposalSnapshot(pId) <= proposalDeadline(pId)
  44. {
  45. preserved {
  46. requireInvariant createdConsistencyWeak(pId);
  47. }
  48. }
  49. /*
  50. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  51. │ Invariant: A proposal cannot be both executed and canceled simultaneously │
  52. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  53. */
  54. invariant noBothExecutedAndCanceled(uint256 pId)
  55. !isExecuted(pId) || !isCanceled(pId)
  56. /*
  57. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  58. │ Rule: Once a proposal is created, voteStart, voteEnd and proposer are immutable │
  59. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  60. */
  61. rule immutableFieldsAfterProposalCreation(uint256 pId, env e, method f, calldataarg arg)
  62. filtered { f -> !skip(f) }
  63. {
  64. require state(e, pId) != UNSET();
  65. uint256 voteStart = proposalSnapshot(pId);
  66. uint256 voteEnd = proposalDeadline(pId);
  67. address proposer = proposalProposer(pId);
  68. f(e, arg);
  69. assert voteStart == proposalSnapshot(pId), "Start date was changed";
  70. assert voteEnd == proposalDeadline(pId), "End date was changed";
  71. assert proposer == proposalProposer(pId), "Proposer was changed";
  72. }