Pausable.spec 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import "helpers/helpers.spec";
  2. methods {
  3. function paused() external returns (bool) envfree;
  4. function pause() external;
  5. function unpause() external;
  6. function onlyWhenPaused() external;
  7. function onlyWhenNotPaused() external;
  8. }
  9. /*
  10. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  11. │ Function correctness: _pause pauses the contract │
  12. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  13. */
  14. rule pause(env e) {
  15. require nonpayable(e);
  16. bool pausedBefore = paused();
  17. pause@withrevert(e);
  18. bool success = !lastReverted;
  19. bool pausedAfter = paused();
  20. // liveness
  21. assert success <=> !pausedBefore, "works if and only if the contract was not paused before";
  22. // effect
  23. assert success => pausedAfter, "contract must be paused after a successful call";
  24. }
  25. /*
  26. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  27. │ Function correctness: _unpause unpauses the contract │
  28. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  29. */
  30. rule unpause(env e) {
  31. require nonpayable(e);
  32. bool pausedBefore = paused();
  33. unpause@withrevert(e);
  34. bool success = !lastReverted;
  35. bool pausedAfter = paused();
  36. // liveness
  37. assert success <=> pausedBefore, "works if and only if the contract was paused before";
  38. // effect
  39. assert success => !pausedAfter, "contract must be unpaused after a successful call";
  40. }
  41. /*
  42. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  43. │ Function correctness: whenPaused modifier can only be called if the contract is paused │
  44. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  45. */
  46. rule whenPaused(env e) {
  47. require nonpayable(e);
  48. onlyWhenPaused@withrevert(e);
  49. assert !lastReverted <=> paused(), "works if and only if the contract is paused";
  50. }
  51. /*
  52. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  53. │ Function correctness: whenNotPaused modifier can only be called if the contract is not paused │
  54. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  55. */
  56. rule whenNotPaused(env e) {
  57. require nonpayable(e);
  58. onlyWhenNotPaused@withrevert(e);
  59. assert !lastReverted <=> !paused(), "works if and only if the contract is not paused";
  60. }
  61. /*
  62. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  63. │ Rules: only _pause and _unpause can change paused status │
  64. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  65. */
  66. rule noPauseChange(env e) {
  67. method f;
  68. calldataarg args;
  69. bool pausedBefore = paused();
  70. f(e, args);
  71. bool pausedAfter = paused();
  72. assert pausedBefore != pausedAfter => (
  73. (!pausedAfter && f.selector == sig:unpause().selector) ||
  74. (pausedAfter && f.selector == sig:pause().selector)
  75. ), "contract's paused status can only be changed by _pause() or _unpause()";
  76. }