ERC20Votes.sol 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Votes.sol)
  3. pragma solidity ^0.8.0;
  4. import "./draft-ERC20Permit.sol";
  5. import "../../../utils/math/Math.sol";
  6. import "../../../governance/utils/IVotes.sol";
  7. import "../../../utils/math/SafeCast.sol";
  8. import "../../../utils/cryptography/ECDSA.sol";
  9. /**
  10. * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
  11. * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
  12. *
  13. * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.
  14. *
  15. * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
  16. * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
  17. * power can be queried through the public accessors {getVotes} and {getPastVotes}.
  18. *
  19. * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
  20. * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
  21. *
  22. * _Available since v4.2._
  23. */
  24. abstract contract ERC20Votes is IVotes, ERC20Permit {
  25. struct Checkpoint {
  26. uint32 fromBlock;
  27. uint224 votes;
  28. }
  29. bytes32 private constant _DELEGATION_TYPEHASH =
  30. keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
  31. mapping(address => address) public _delegates;
  32. mapping(address => Checkpoint[]) public _checkpoints;
  33. Checkpoint[] private _totalSupplyCheckpoints;
  34. /**
  35. * @dev Get the `pos`-th checkpoint for `account`.
  36. */
  37. function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
  38. return _checkpoints[account][pos];
  39. }
  40. /**
  41. * @dev Get number of checkpoints for `account`.
  42. */
  43. function numCheckpoints(address account) public view virtual returns (uint32) {
  44. return SafeCast.toUint32(_checkpoints[account].length);
  45. }
  46. /**
  47. * @dev Get the address `account` is currently delegating to.
  48. */
  49. function delegates(address account) public view virtual override returns (address) {
  50. return _delegates[account];
  51. }
  52. /**
  53. * @dev Gets the current votes balance for `account`
  54. */
  55. function getVotes(address account) public view virtual override returns (uint256) {
  56. uint256 pos = _checkpoints[account].length;
  57. return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
  58. }
  59. /**
  60. * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
  61. *
  62. * Requirements:
  63. *
  64. * - `blockNumber` must have been already mined
  65. */
  66. function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
  67. require(blockNumber < block.number, "ERC20Votes: block not yet mined");
  68. return _checkpointsLookup(_checkpoints[account], blockNumber);
  69. }
  70. /**
  71. * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
  72. * It is but NOT the sum of all the delegated votes!
  73. *
  74. * Requirements:
  75. *
  76. * - `blockNumber` must have been already mined
  77. */
  78. function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
  79. require(blockNumber < block.number, "ERC20Votes: block not yet mined");
  80. return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
  81. }
  82. /**
  83. * @dev Lookup a value in a list of (sorted) checkpoints.
  84. */
  85. function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
  86. // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
  87. //
  88. // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
  89. // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
  90. // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
  91. // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
  92. // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
  93. // out of bounds (in which case we're looking too far in the past and the result is 0).
  94. // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
  95. // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
  96. // the same.
  97. uint256 high = ckpts.length;
  98. uint256 low = 0;
  99. while (low < high) {
  100. uint256 mid = Math.average(low, high);
  101. if (ckpts[mid].fromBlock > blockNumber) {
  102. high = mid;
  103. } else {
  104. low = mid + 1;
  105. }
  106. }
  107. return high == 0 ? 0 : ckpts[high - 1].votes;
  108. }
  109. /**
  110. * @dev Delegate votes from the sender to `delegatee`.
  111. */
  112. function delegate(address delegatee) public virtual override {
  113. _delegate(_msgSender(), delegatee);
  114. }
  115. /**
  116. * @dev Delegates votes from signer to `delegatee`
  117. */
  118. function delegateBySig(
  119. address delegatee,
  120. uint256 nonce,
  121. uint256 expiry,
  122. uint8 v,
  123. bytes32 r,
  124. bytes32 s
  125. ) public virtual override {
  126. require(block.timestamp <= expiry, "ERC20Votes: signature expired");
  127. address signer = ECDSA.recover(
  128. _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
  129. v,
  130. r,
  131. s
  132. );
  133. require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
  134. _delegate(signer, delegatee);
  135. }
  136. /**
  137. * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
  138. */
  139. function _maxSupply() public view virtual returns (uint224) { //harnessed to public
  140. return type(uint224).max;
  141. }
  142. /**
  143. * @dev Snapshots the totalSupply after it has been increased.
  144. */
  145. function _mint(address account, uint256 amount) internal virtual override {
  146. super._mint(account, amount);
  147. require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
  148. _writeCheckpointAdd(_totalSupplyCheckpoints, amount); // HARNESS: new version without pointer
  149. }
  150. /**
  151. * @dev Snapshots the totalSupply after it has been decreased.
  152. */
  153. function _burn(address account, uint256 amount) public virtual override returns (bool){ // HARNESS: internal -> public (to comply with the ERC20 harness)
  154. super._burn(account, amount);
  155. _writeCheckpointSub(_totalSupplyCheckpoints, amount); // HARNESS: new version without pointer
  156. return true;
  157. }
  158. /**
  159. * @dev Move voting power when tokens are transferred.
  160. *
  161. * Emits a {DelegateVotesChanged} event.
  162. */
  163. function _afterTokenTransfer(
  164. address from,
  165. address to,
  166. uint256 amount
  167. ) internal virtual override {
  168. super._afterTokenTransfer(from, to, amount);
  169. _moveVotingPower(delegates(from), delegates(to), amount);
  170. }
  171. /**
  172. * @dev Change delegation for `delegator` to `delegatee`.
  173. *
  174. * Emits events {DelegateChanged} and {DelegateVotesChanged}.
  175. */
  176. function _delegate(address delegator, address delegatee) public virtual { // HARNESSED TO MAKE PUBLIC
  177. address currentDelegate = delegates(delegator);
  178. uint256 delegatorBalance = balanceOf(delegator);
  179. _delegates[delegator] = delegatee;
  180. emit DelegateChanged(delegator, currentDelegate, delegatee);
  181. _moveVotingPower(currentDelegate, delegatee, delegatorBalance);
  182. }
  183. function _moveVotingPower(
  184. address src,
  185. address dst,
  186. uint256 amount
  187. ) private {
  188. if (src != dst && amount > 0) {
  189. if (src != address(0)) {
  190. (uint256 oldWeight, uint256 newWeight) = _writeCheckpointSub(_checkpoints[src], amount); // HARNESS: new version without pointer
  191. emit DelegateVotesChanged(src, oldWeight, newWeight);
  192. }
  193. if (dst != address(0)) {
  194. (uint256 oldWeight, uint256 newWeight) = _writeCheckpointAdd(_checkpoints[dst], amount); // HARNESS: new version without pointer
  195. emit DelegateVotesChanged(dst, oldWeight, newWeight);
  196. }
  197. }
  198. }
  199. // HARNESS: split _writeCheckpoint() to two functions as a workaround for function pointers that cannot be managed by the tool
  200. function _writeCheckpointAdd(
  201. Checkpoint[] storage ckpts,
  202. uint256 delta
  203. ) private returns (uint256 oldWeight, uint256 newWeight) {
  204. uint256 pos = ckpts.length;
  205. oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
  206. newWeight = _add(oldWeight, delta);
  207. if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {
  208. ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);
  209. } else {
  210. ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
  211. }
  212. }
  213. function _writeCheckpointSub(
  214. Checkpoint[] storage ckpts,
  215. uint256 delta
  216. ) private returns (uint256 oldWeight, uint256 newWeight) {
  217. uint256 pos = ckpts.length;
  218. oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
  219. newWeight = _subtract(oldWeight, delta);
  220. if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {
  221. ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);
  222. } else {
  223. ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
  224. }
  225. }
  226. // backup of original function
  227. //
  228. // function _writeCheckpoint(
  229. // Checkpoint[] storage ckpts,
  230. // function(uint256, uint256) view returns (uint256) op,
  231. // uint256 delta
  232. // ) private returns (uint256 oldWeight, uint256 newWeight) {
  233. // uint256 pos = ckpts.length;
  234. // oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
  235. // newWeight = op(oldWeight, delta);
  236. //
  237. // if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {
  238. // ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);
  239. // } else {
  240. // ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
  241. // }
  242. // }
  243. function _add(uint256 a, uint256 b) private pure returns (uint256) {
  244. return a + b;
  245. }
  246. function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
  247. return a - b;
  248. }
  249. }