VotesExtended.sol 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import {Checkpoints} from "../../utils/structs/Checkpoints.sol";
  4. import {Votes} from "./Votes.sol";
  5. import {SafeCast} from "../../utils/math/SafeCast.sol";
  6. /**
  7. * @dev Extension of {Votes} that adds checkpoints for delegations and balances.
  8. */
  9. abstract contract VotesExtended is Votes {
  10. using SafeCast for uint256;
  11. using Checkpoints for Checkpoints.Trace160;
  12. using Checkpoints for Checkpoints.Trace208;
  13. mapping(address delegatee => Checkpoints.Trace160) private _delegateCheckpoints;
  14. mapping(address account => Checkpoints.Trace208) private _balanceOfCheckpoints;
  15. /**
  16. * @dev Returns the delegate of an `account` at a specific moment in the past. If the `clock()` is
  17. * configured to use block numbers, this will return the value at the end of the corresponding block.
  18. *
  19. * Requirements:
  20. *
  21. * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
  22. */
  23. function getPastDelegate(address account, uint256 timepoint) public view virtual returns (address) {
  24. uint48 currentTimepoint = clock();
  25. if (timepoint >= currentTimepoint) {
  26. revert ERC5805FutureLookup(timepoint, currentTimepoint);
  27. }
  28. return address(_delegateCheckpoints[account].upperLookupRecent(timepoint.toUint48()));
  29. }
  30. /**
  31. * @dev Returns the `balanceOf` of an `account` at a specific moment in the past. If the `clock()` is
  32. * configured to use block numbers, this will return the value at the end of the corresponding block.
  33. *
  34. * Requirements:
  35. *
  36. * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
  37. */
  38. function getPastBalanceOf(address account, uint256 timepoint) public view virtual returns (uint256) {
  39. uint48 currentTimepoint = clock();
  40. if (timepoint >= currentTimepoint) {
  41. revert ERC5805FutureLookup(timepoint, currentTimepoint);
  42. }
  43. return _balanceOfCheckpoints[account].upperLookupRecent(timepoint.toUint48());
  44. }
  45. /// @inheritdoc Votes
  46. function _delegate(address account, address delegatee) internal virtual override {
  47. super._delegate(account, delegatee);
  48. _delegateCheckpoints[account].push(clock(), uint160(delegatee));
  49. }
  50. /// @inheritdoc Votes
  51. function _transferVotingUnits(address from, address to, uint256 amount) internal virtual override {
  52. super._transferVotingUnits(from, to, amount);
  53. if (from != to) {
  54. if (from != address(0)) {
  55. _balanceOfCheckpoints[from].push(clock(), _getVotingUnits(from).toUint208());
  56. }
  57. if (to != address(0)) {
  58. _balanceOfCheckpoints[to].push(clock(), _getVotingUnits(to).toUint208());
  59. }
  60. }
  61. }
  62. }