GovernorFunctions.spec 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import "helpers.spec"
  2. import "methods/IGovernor.spec"
  3. import "Governor.helpers.spec"
  4. /*
  5. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  6. โ”‚ Rule: propose effect and liveness. Includes "no double proposition" โ”‚
  7. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  8. */
  9. rule propose(uint256 pId, env e) {
  10. require nonpayable(e);
  11. uint256 otherId;
  12. uint8 stateBefore = state(e, pId);
  13. uint8 otherStateBefore = state(e, otherId);
  14. uint256 otherVoteStart = proposalSnapshot(otherId);
  15. uint256 otherVoteEnd = proposalDeadline(otherId);
  16. address otherProposer = proposalProposer(otherId);
  17. address[] targets; uint256[] values; bytes[] calldatas; string reason;
  18. require pId == propose@withrevert(e, targets, values, calldatas, reason);
  19. bool success = !lastReverted;
  20. // liveness & double proposal
  21. assert success <=> stateBefore == UNSET();
  22. // effect
  23. assert success => (
  24. state(e, pId) == PENDING() &&
  25. proposalProposer(pId) == e.msg.sender &&
  26. proposalSnapshot(pId) == clock(e) + votingDelay() &&
  27. proposalDeadline(pId) == clock(e) + votingDelay() + votingPeriod()
  28. );
  29. // no side-effect
  30. assert state(e, otherId) != otherStateBefore => otherId == pId;
  31. assert proposalSnapshot(otherId) == otherVoteStart;
  32. assert proposalDeadline(otherId) == otherVoteEnd;
  33. assert proposalProposer(otherId) == otherProposer;
  34. }
  35. /*
  36. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  37. โ”‚ Rule: votes effect and liveness. Includes "A user cannot vote twice" โ”‚
  38. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  39. */
  40. rule castVote(uint256 pId, env e, method f)
  41. filtered { f -> voting(f) }
  42. {
  43. require nonpayable(e);
  44. uint8 support;
  45. address voter;
  46. address otherVoter;
  47. uint256 otherId;
  48. uint8 stateBefore = state(e, pId);
  49. bool hasVotedBefore = hasVoted(pId, voter);
  50. bool otherVotedBefore = hasVoted(otherId, otherVoter);
  51. uint256 againstVotesBefore = getAgainstVotes(pId);
  52. uint256 forVotesBefore = getForVotes(pId);
  53. uint256 abstainVotesBefore = getAbstainVotes(pId);
  54. uint256 otherAgainstVotesBefore = getAgainstVotes(otherId);
  55. uint256 otherForVotesBefore = getForVotes(otherId);
  56. uint256 otherAbstainVotesBefore = getAbstainVotes(otherId);
  57. // voting weight overflow check
  58. uint256 voterWeight = token_getPastVotes(voter, proposalSnapshot(pId));
  59. require againstVotesBefore + voterWeight <= max_uint256;
  60. require forVotesBefore + voterWeight <= max_uint256;
  61. require abstainVotesBefore + voterWeight <= max_uint256;
  62. uint256 weight = helperVoteWithRevert(e, f, pId, voter, support);
  63. bool success = !lastReverted;
  64. assert success <=> (
  65. stateBefore == ACTIVE() &&
  66. !hasVotedBefore &&
  67. (support == 0 || support == 1 || support == 2)
  68. );
  69. assert success => (
  70. state(e, pId) == ACTIVE() &&
  71. voterWeight == weight &&
  72. getAgainstVotes(pId) == againstVotesBefore + (support == 0 ? weight : 0) &&
  73. getForVotes(pId) == forVotesBefore + (support == 1 ? weight : 0) &&
  74. getAbstainVotes(pId) == abstainVotesBefore + (support == 2 ? weight : 0) &&
  75. hasVoted(pId, voter)
  76. );
  77. // no side-effect
  78. assert hasVoted(otherId, otherVoter) != otherVotedBefore => (otherId == pId && otherVoter == voter);
  79. assert getAgainstVotes(otherId) != otherAgainstVotesBefore => (otherId == pId);
  80. assert getForVotes(otherId) != otherForVotesBefore => (otherId == pId);
  81. assert getAbstainVotes(otherId) != otherAbstainVotesBefore => (otherId == pId);
  82. }
  83. rule queue(uint256 pId, env e) {
  84. require nonpayable(e);
  85. uint256 otherId;
  86. uint8 stateBefore = state(e, pId);
  87. uint8 otherStateBefore = state(e, otherId);
  88. address[] targets; uint256[] values; bytes[] calldatas; string reason;
  89. require pId == queue@withrevert(e, targets, values, calldatas, reason);
  90. bool success = !lastReverted;
  91. // liveness
  92. assert success <=> stateBefore == SUCCEEDED();
  93. // effect
  94. assert success => (
  95. state(e, pId) == QUEUED()
  96. );
  97. // no side-effect
  98. assert state(e, otherId) != otherStateBefore => otherId == pId;
  99. }
  100. rule execute(uint256 pId, env e) {
  101. require nonpayable(e);
  102. uint256 otherId;
  103. uint8 stateBefore = state(e, pId);
  104. uint8 otherStateBefore = state(e, otherId);
  105. address[] targets; uint256[] values; bytes[] calldatas; string reason;
  106. require pId == execute@withrevert(e, targets, values, calldatas, reason);
  107. bool success = !lastReverted;
  108. // liveness: can't check full equivalence because of execution call reverts
  109. assert success => (stateBefore == SUCCEEDED() || stateBefore == QUEUED());
  110. // effect
  111. assert success => (
  112. state(e, pId) == EXECUTED()
  113. );
  114. // no side-effect
  115. assert state(e, otherId) != otherStateBefore => otherId == pId;
  116. }
  117. rule cancel(uint256 pId, env e) {
  118. require nonpayable(e);
  119. uint256 otherId;
  120. uint8 stateBefore = state(e, pId);
  121. uint8 otherStateBefore = state(e, otherId);
  122. address[] targets; uint256[] values; bytes[] calldatas; string reason;
  123. require pId == cancel@withrevert(e, targets, values, calldatas, reason);
  124. bool success = !lastReverted;
  125. // liveness
  126. assert success <=> (
  127. stateBefore == PENDING() &&
  128. e.msg.sender == proposalProposer(pId)
  129. );
  130. // effect
  131. assert success => (
  132. state(e, pId) == CANCELED()
  133. );
  134. // no side-effect
  135. assert state(e, otherId) != otherStateBefore => otherId == pId;
  136. }