GovernorFunctions.spec 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. require clockSanity(e);
  12. uint256 otherId;
  13. uint8 stateBefore = state(e, pId);
  14. uint8 otherStateBefore = state(e, otherId);
  15. uint256 otherVoteStart = proposalSnapshot(otherId);
  16. uint256 otherVoteEnd = proposalDeadline(otherId);
  17. address otherProposer = proposalProposer(otherId);
  18. address[] targets; uint256[] values; bytes[] calldatas; string descr;
  19. require validString(descr);
  20. require pId == propose@withrevert(e, targets, values, calldatas, descr);
  21. bool success = !lastReverted;
  22. // liveness & double proposal
  23. assert success <=> (
  24. stateBefore == UNSET() &&
  25. validProposal(targets, values, calldatas)
  26. );
  27. // effect
  28. assert success => (
  29. state(e, pId) == PENDING() &&
  30. proposalProposer(pId) == e.msg.sender &&
  31. proposalSnapshot(pId) == clock(e) + votingDelay() &&
  32. proposalDeadline(pId) == clock(e) + votingDelay() + votingPeriod()
  33. );
  34. // no side-effect
  35. assert state(e, otherId) != otherStateBefore => otherId == pId;
  36. assert proposalSnapshot(otherId) == otherVoteStart;
  37. assert proposalDeadline(otherId) == otherVoteEnd;
  38. assert proposalProposer(otherId) == otherProposer;
  39. }
  40. /*
  41. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  42. โ”‚ Rule: votes effect and liveness. Includes "A user cannot vote twice" โ”‚
  43. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  44. */
  45. rule castVote(uint256 pId, env e, method f)
  46. filtered { f -> voting(f) }
  47. {
  48. require nonpayable(e);
  49. require clockSanity(e);
  50. uint8 support;
  51. address voter;
  52. address otherVoter;
  53. uint256 otherId;
  54. uint8 stateBefore = state(e, pId);
  55. bool hasVotedBefore = hasVoted(pId, voter);
  56. bool otherVotedBefore = hasVoted(otherId, otherVoter);
  57. uint256 againstVotesBefore = getAgainstVotes(pId);
  58. uint256 forVotesBefore = getForVotes(pId);
  59. uint256 abstainVotesBefore = getAbstainVotes(pId);
  60. uint256 otherAgainstVotesBefore = getAgainstVotes(otherId);
  61. uint256 otherForVotesBefore = getForVotes(otherId);
  62. uint256 otherAbstainVotesBefore = getAbstainVotes(otherId);
  63. // voting weight overflow check
  64. uint256 voterWeight = token_getPastVotes(voter, proposalSnapshot(pId));
  65. require againstVotesBefore + voterWeight <= max_uint256;
  66. require forVotesBefore + voterWeight <= max_uint256;
  67. require abstainVotesBefore + voterWeight <= max_uint256;
  68. uint256 weight = helperVoteWithRevert(e, f, pId, voter, support);
  69. bool success = !lastReverted;
  70. assert success <=> (
  71. stateBefore == ACTIVE() &&
  72. !hasVotedBefore &&
  73. (support == 0 || support == 1 || support == 2)
  74. );
  75. assert success => (
  76. state(e, pId) == ACTIVE() &&
  77. voterWeight == weight &&
  78. getAgainstVotes(pId) == againstVotesBefore + (support == 0 ? weight : 0) &&
  79. getForVotes(pId) == forVotesBefore + (support == 1 ? weight : 0) &&
  80. getAbstainVotes(pId) == abstainVotesBefore + (support == 2 ? weight : 0) &&
  81. hasVoted(pId, voter)
  82. );
  83. // no side-effect
  84. assert hasVoted(otherId, otherVoter) != otherVotedBefore => (otherId == pId && otherVoter == voter);
  85. assert getAgainstVotes(otherId) != otherAgainstVotesBefore => (otherId == pId);
  86. assert getForVotes(otherId) != otherForVotesBefore => (otherId == pId);
  87. assert getAbstainVotes(otherId) != otherAbstainVotesBefore => (otherId == pId);
  88. }
  89. /*
  90. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  91. โ”‚ Rule: queue effect and liveness. โ”‚
  92. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  93. */
  94. rule queue(uint256 pId, env e) {
  95. require nonpayable(e);
  96. require clockSanity(e);
  97. uint256 otherId;
  98. uint8 stateBefore = state(e, pId);
  99. uint8 otherStateBefore = state(e, otherId);
  100. bool queuedBefore = isQueued(pId);
  101. bool otherQueuedBefore = isQueued(otherId);
  102. address[] targets; uint256[] values; bytes[] calldatas; bytes32 descrHash;
  103. require pId == queue@withrevert(e, targets, values, calldatas, descrHash);
  104. bool success = !lastReverted;
  105. // liveness
  106. assert success <=> stateBefore == SUCCEEDED();
  107. // effect
  108. assert success => (
  109. state(e, pId) == QUEUED() &&
  110. !queuedBefore &&
  111. isQueued(pId)
  112. );
  113. // no side-effect
  114. assert state(e, otherId) != otherStateBefore => otherId == pId;
  115. assert isQueued(otherId) != otherQueuedBefore => otherId == pId;
  116. }
  117. /*
  118. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  119. โ”‚ Rule: execute effect and liveness. โ”‚
  120. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  121. */
  122. rule execute(uint256 pId, env e) {
  123. require nonpayable(e);
  124. require clockSanity(e);
  125. uint256 otherId;
  126. uint8 stateBefore = state(e, pId);
  127. uint8 otherStateBefore = state(e, otherId);
  128. address[] targets; uint256[] values; bytes[] calldatas; bytes32 descrHash;
  129. require pId == execute@withrevert(e, targets, values, calldatas, descrHash);
  130. bool success = !lastReverted;
  131. // liveness: can't check full equivalence because of execution call reverts
  132. assert success => (stateBefore == SUCCEEDED() || stateBefore == QUEUED());
  133. // effect
  134. assert success => (
  135. state(e, pId) == EXECUTED()
  136. );
  137. // no side-effect
  138. assert state(e, otherId) != otherStateBefore => otherId == pId;
  139. }
  140. /*
  141. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  142. โ”‚ Rule: cancel (public) effect and liveness. โ”‚
  143. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  144. */
  145. rule cancel(uint256 pId, env e) {
  146. require nonpayable(e);
  147. require clockSanity(e);
  148. uint256 otherId;
  149. uint8 stateBefore = state(e, pId);
  150. uint8 otherStateBefore = state(e, otherId);
  151. bool otherQueuedBefore = isQueued(otherId);
  152. address[] targets; uint256[] values; bytes[] calldatas; bytes32 descrHash;
  153. require pId == cancel@withrevert(e, targets, values, calldatas, descrHash);
  154. bool success = !lastReverted;
  155. // liveness
  156. assert success <=> (
  157. stateBefore == PENDING() &&
  158. e.msg.sender == proposalProposer(pId)
  159. );
  160. // effect
  161. assert success => (
  162. state(e, pId) == CANCELED() &&
  163. !isQueued(pId) // cancel resets timelockId
  164. );
  165. // no side-effect
  166. assert state(e, otherId) != otherStateBefore => otherId == pId;
  167. assert isQueued(otherId) != otherQueuedBefore => otherId == pId;
  168. }