ERC20Votes.sol 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC20Votes.sol)
  3. pragma solidity ^0.8.0;
  4. import "./ERC20Permit.sol";
  5. import "../../../interfaces/IERC5805.sol";
  6. import "../../../utils/math/Math.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 ERC20Permit, IERC5805 {
  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) private _delegates;
  32. mapping(address => Checkpoint[]) private _checkpoints;
  33. Checkpoint[] private _totalSupplyCheckpoints;
  34. /**
  35. * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
  36. */
  37. function clock() public view virtual override returns (uint48) {
  38. return SafeCast.toUint48(block.number);
  39. }
  40. /**
  41. * @dev Description of the clock
  42. */
  43. // solhint-disable-next-line func-name-mixedcase
  44. function CLOCK_MODE() public view virtual override returns (string memory) {
  45. // Check that the clock was not modified
  46. require(clock() == block.number);
  47. return "mode=blocknumber&from=default";
  48. }
  49. /**
  50. * @dev Get the `pos`-th checkpoint for `account`.
  51. */
  52. function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
  53. return _checkpoints[account][pos];
  54. }
  55. /**
  56. * @dev Get number of checkpoints for `account`.
  57. */
  58. function numCheckpoints(address account) public view virtual returns (uint32) {
  59. return SafeCast.toUint32(_checkpoints[account].length);
  60. }
  61. /**
  62. * @dev Get the address `account` is currently delegating to.
  63. */
  64. function delegates(address account) public view virtual override returns (address) {
  65. return _delegates[account];
  66. }
  67. /**
  68. * @dev Gets the current votes balance for `account`
  69. */
  70. function getVotes(address account) public view virtual override returns (uint256) {
  71. uint256 pos = _checkpoints[account].length;
  72. unchecked {
  73. return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
  74. }
  75. }
  76. /**
  77. * @dev Retrieve the number of votes for `account` at the end of `timepoint`.
  78. *
  79. * Requirements:
  80. *
  81. * - `timepoint` must be in the past
  82. */
  83. function getPastVotes(address account, uint256 timepoint) public view virtual override returns (uint256) {
  84. require(timepoint < clock(), "ERC20Votes: future lookup");
  85. return _checkpointsLookup(_checkpoints[account], timepoint);
  86. }
  87. /**
  88. * @dev Retrieve the `totalSupply` at the end of `timepoint`. Note, this value is the sum of all balances.
  89. * It is NOT the sum of all the delegated votes!
  90. *
  91. * Requirements:
  92. *
  93. * - `timepoint` must be in the past
  94. */
  95. function getPastTotalSupply(uint256 timepoint) public view virtual override returns (uint256) {
  96. require(timepoint < clock(), "ERC20Votes: future lookup");
  97. return _checkpointsLookup(_totalSupplyCheckpoints, timepoint);
  98. }
  99. /**
  100. * @dev Lookup a value in a list of (sorted) checkpoints.
  101. */
  102. function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 timepoint) private view returns (uint256) {
  103. // We run a binary search to look for the earliest checkpoint taken after `timepoint`.
  104. //
  105. // Initially we check if the block is recent to narrow the search range.
  106. // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
  107. // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
  108. // - If the middle checkpoint is after `timepoint`, we look in [low, mid)
  109. // - If the middle checkpoint is before or equal to `timepoint`, we look in [mid+1, high)
  110. // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
  111. // out of bounds (in which case we're looking too far in the past and the result is 0).
  112. // Note that if the latest checkpoint available is exactly for `timepoint`, we end up with an index that is
  113. // past the end of the array, so we technically don't find a checkpoint after `timepoint`, but it works out
  114. // the same.
  115. uint256 length = ckpts.length;
  116. uint256 low = 0;
  117. uint256 high = length;
  118. if (length > 5) {
  119. uint256 mid = length - Math.sqrt(length);
  120. if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) {
  121. high = mid;
  122. } else {
  123. low = mid + 1;
  124. }
  125. }
  126. while (low < high) {
  127. uint256 mid = Math.average(low, high);
  128. if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) {
  129. high = mid;
  130. } else {
  131. low = mid + 1;
  132. }
  133. }
  134. unchecked {
  135. return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
  136. }
  137. }
  138. /**
  139. * @dev Delegate votes from the sender to `delegatee`.
  140. */
  141. function delegate(address delegatee) public virtual override {
  142. _delegate(_msgSender(), delegatee);
  143. }
  144. /**
  145. * @dev Delegates votes from signer to `delegatee`
  146. */
  147. function delegateBySig(
  148. address delegatee,
  149. uint256 nonce,
  150. uint256 expiry,
  151. uint8 v,
  152. bytes32 r,
  153. bytes32 s
  154. ) public virtual override {
  155. require(block.timestamp <= expiry, "ERC20Votes: signature expired");
  156. address signer = ECDSA.recover(
  157. _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
  158. v,
  159. r,
  160. s
  161. );
  162. require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
  163. _delegate(signer, delegatee);
  164. }
  165. /**
  166. * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
  167. */
  168. function _maxSupply() internal view virtual returns (uint224) {
  169. return type(uint224).max;
  170. }
  171. /**
  172. * @dev Snapshots the totalSupply after it has been increased.
  173. */
  174. function _mint(address account, uint256 amount) internal virtual override {
  175. super._mint(account, amount);
  176. require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
  177. _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
  178. }
  179. /**
  180. * @dev Snapshots the totalSupply after it has been decreased.
  181. */
  182. function _burn(address account, uint256 amount) internal virtual override {
  183. super._burn(account, amount);
  184. _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
  185. }
  186. /**
  187. * @dev Move voting power when tokens are transferred.
  188. *
  189. * Emits a {IVotes-DelegateVotesChanged} event.
  190. */
  191. function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual override {
  192. super._afterTokenTransfer(from, to, amount);
  193. _moveVotingPower(delegates(from), delegates(to), amount);
  194. }
  195. /**
  196. * @dev Change delegation for `delegator` to `delegatee`.
  197. *
  198. * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
  199. */
  200. function _delegate(address delegator, address delegatee) internal virtual {
  201. address currentDelegate = delegates(delegator);
  202. uint256 delegatorBalance = balanceOf(delegator);
  203. _delegates[delegator] = delegatee;
  204. emit DelegateChanged(delegator, currentDelegate, delegatee);
  205. _moveVotingPower(currentDelegate, delegatee, delegatorBalance);
  206. }
  207. function _moveVotingPower(address src, address dst, uint256 amount) private {
  208. if (src != dst && amount > 0) {
  209. if (src != address(0)) {
  210. (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
  211. emit DelegateVotesChanged(src, oldWeight, newWeight);
  212. }
  213. if (dst != address(0)) {
  214. (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
  215. emit DelegateVotesChanged(dst, oldWeight, newWeight);
  216. }
  217. }
  218. }
  219. function _writeCheckpoint(
  220. Checkpoint[] storage ckpts,
  221. function(uint256, uint256) view returns (uint256) op,
  222. uint256 delta
  223. ) private returns (uint256 oldWeight, uint256 newWeight) {
  224. uint256 pos = ckpts.length;
  225. unchecked {
  226. Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
  227. oldWeight = oldCkpt.votes;
  228. newWeight = op(oldWeight, delta);
  229. if (pos > 0 && oldCkpt.fromBlock == clock()) {
  230. _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
  231. } else {
  232. ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), votes: SafeCast.toUint224(newWeight)}));
  233. }
  234. }
  235. }
  236. function _add(uint256 a, uint256 b) private pure returns (uint256) {
  237. return a + b;
  238. }
  239. function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
  240. return a - b;
  241. }
  242. /**
  243. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  244. */
  245. function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
  246. assembly {
  247. mstore(0, ckpts.slot)
  248. result.slot := add(keccak256(0, 0x20), pos)
  249. }
  250. }
  251. }