ERC20VotesLegacyMock.sol 9.2 KB

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