ERC20Votes.spec 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import "helpers.spec"
  2. import "methods/IERC20.spec"
  3. import "methods/IERC5805.spec"
  4. import "methods/IERC6372.spec"
  5. import "ERC20.spec"
  6. methods {
  7. numCheckpoints(address) returns (uint32) envfree
  8. ckptFromBlock(address, uint32) returns (uint32) envfree
  9. ckptVotes(address, uint32) returns (uint224) envfree
  10. maxSupply() returns (uint224) envfree
  11. }
  12. use invariant totalSupplyIsSumOfBalances
  13. /*
  14. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  15. โ”‚ Helpers โ”‚
  16. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  17. */
  18. definition max_uint224() returns uint224 = 0xffffffffffffffffffffffffffff;
  19. definition lastCheckpoint(address a) returns uint32 = to_uint32(numCheckpoints(a) - 1);
  20. /*
  21. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  22. โ”‚ Ghost & hooks โ”‚
  23. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  24. */
  25. /*
  26. ghost totalVotes() returns uint224 {
  27. init_state axiom totalVotes() == 0;
  28. }
  29. ghost mapping(address => uint256) userVotes {
  30. init_state axiom forall address a. userVotes[a] == 0;
  31. }
  32. ghost mapping(address => uint32) userLast {
  33. init_state axiom forall address a. userLast[a] == 0;
  34. }
  35. ghost mapping(address => uint32) userClock {
  36. init_state axiom forall address a. userClock[a] == 0;
  37. }
  38. hook Sstore currentContract._checkpoints[KEY address account][INDEX uint32 index].votes uint224 newVotes (uint224 oldVotes) STORAGE {
  39. havoc totalVotes assuming totalVotes@new() == totalVotes@old() + newVotes - userVotes[account];
  40. userVotes[account] = newVotes;
  41. userLast[account] = index;
  42. }
  43. hook Sstore currentContract._checkpoints[KEY address account][INDEX uint32 index].fromBlock uint32 newTimepoint (uint32 oldTimepoint) STORAGE {
  44. userClock[account] = newTimepoint;
  45. }
  46. */
  47. /*
  48. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  49. โ”‚ Invariant: clock โ”‚
  50. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  51. */
  52. invariant clockMode(env e)
  53. clock(e) == e.block.number || clock(e) == e.block.timestamp
  54. invariant userClockInThePast(env e, address a)
  55. numCheckpoints(a) > 0 => ckptFromBlock(lastCheckpoint(a)) <= clock(e)
  56. {
  57. preserved with (env e2) {
  58. require clock(e2) <= clock(e);
  59. }
  60. }
  61. /*
  62. invariant hooksAreCorrect(env e, address a)
  63. numCheckpoints(a) > 0 => (
  64. userLast(a) == ckptFromBlock(lastCheckpoint(a)) &&
  65. userVotes(a) == ckptVotes(lastCheckpoint(a))
  66. )
  67. */
  68. /*
  69. invariant userVotesAndClockConsistency(address a)
  70. numCheckpoints(a) > 0 => (
  71. userLast(a) == numCheckpoints(a) - 1 &&
  72. userLast(a) <= max_uint32 &&
  73. userVotes(a) == ckptVotes(a, lastUserIndex(a)) &&
  74. userVotes(a) <= max_uint224() &&
  75. userClock(a) == ckptFromBlock(a, lastUserIndex(a)) &&
  76. userClock(a) <= max_uint224()
  77. )
  78. */
  79. /*
  80. invariant noDuplicate(address a)
  81. !lastUserDuplicate(a)
  82. // passes
  83. invariant userVotesOverflow()
  84. forall address a. lastUserVotes(a) <= max_uint256
  85. invariant userVotes(env e)
  86. forall address a. userCkptNumber(a) > 0 => lastUserVotes(a) == getVotes(e, a)
  87. {
  88. preserved {
  89. requireInvariant totalSupplyIsSumOfBalances;
  90. }
  91. }
  92. invariant userVotesLessTotalVotes()
  93. forall address a. userCkptNumber(a) > 0 => lastUserVotes(a) <= totalVotes()
  94. {
  95. preserved {
  96. requireInvariant totalSupplyIsSumOfBalances;
  97. }
  98. }
  99. // passes
  100. invariant totalVotesLessTotalSupply()
  101. totalVotes() <= totalSupply()
  102. {
  103. preserved {
  104. requireInvariant totalSupplyIsSumOfBalances;
  105. }
  106. }
  107. */