You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
71 lines
2.8 KiB
71 lines
2.8 KiB
4 months ago
|
// SPDX-License-Identifier: MIT
|
||
|
pragma solidity ^0.8.20;
|
||
|
|
||
|
import {Checkpoints} from "../../utils/structs/Checkpoints.sol";
|
||
|
import {Votes} from "./Votes.sol";
|
||
|
import {SafeCast} from "../../utils/math/SafeCast.sol";
|
||
|
|
||
|
/**
|
||
|
* @dev Extension of {Votes} that adds exposes checkpoints for delegations and balances.
|
||
|
*/
|
||
|
abstract contract VotesExtended is Votes {
|
||
|
using SafeCast for uint256;
|
||
|
using Checkpoints for Checkpoints.Trace160;
|
||
|
using Checkpoints for Checkpoints.Trace208;
|
||
|
|
||
|
mapping(address delegatee => Checkpoints.Trace160) private _delegateCheckpoints;
|
||
|
mapping(address account => Checkpoints.Trace208) private _balanceOfCheckpoints;
|
||
|
|
||
|
/**
|
||
|
* @dev Returns the delegate of an `account` at a specific moment in the past. If the `clock()` is
|
||
|
* configured to use block numbers, this will return the value at the end of the corresponding block.
|
||
|
*
|
||
|
* Requirements:
|
||
|
*
|
||
|
* - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
|
||
|
*/
|
||
|
function getPastDelegate(address account, uint256 timepoint) public view virtual returns (address) {
|
||
|
uint48 currentTimepoint = clock();
|
||
|
if (timepoint >= currentTimepoint) {
|
||
|
revert ERC5805FutureLookup(timepoint, currentTimepoint);
|
||
|
}
|
||
|
return address(_delegateCheckpoints[account].upperLookupRecent(timepoint.toUint48()));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Returns the `balanceOf` of an `account` at a specific moment in the past. If the `clock()` is
|
||
|
* configured to use block numbers, this will return the value at the end of the corresponding block.
|
||
|
*
|
||
|
* Requirements:
|
||
|
*
|
||
|
* - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
|
||
|
*/
|
||
|
function getPastBalanceOf(address account, uint256 timepoint) public view virtual returns (uint256) {
|
||
|
uint48 currentTimepoint = clock();
|
||
|
if (timepoint >= currentTimepoint) {
|
||
|
revert ERC5805FutureLookup(timepoint, currentTimepoint);
|
||
|
}
|
||
|
return _balanceOfCheckpoints[account].upperLookupRecent(timepoint.toUint48());
|
||
|
}
|
||
|
|
||
|
/// @inheritdoc Votes
|
||
|
function _delegate(address account, address delegatee) internal virtual override {
|
||
|
super._delegate(account, delegatee);
|
||
|
|
||
|
_delegateCheckpoints[account].push(clock(), uint160(delegatee));
|
||
|
}
|
||
|
|
||
|
/// @inheritdoc Votes
|
||
|
function _transferVotingUnits(address from, address to, uint256 amount) internal virtual override {
|
||
|
super._transferVotingUnits(from, to, amount);
|
||
|
if (from != to) {
|
||
|
if (from != address(0)) {
|
||
|
_balanceOfCheckpoints[from].push(clock(), _getVotingUnits(from).toUint208());
|
||
|
}
|
||
|
if (to != address(0)) {
|
||
|
_balanceOfCheckpoints[to].push(clock(), _getVotingUnits(to).toUint208());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|