Release v5.2 audit fixes (#5330)

Signed-off-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Sam Bugs <101145325+0xsambugs@users.noreply.github.com>
Co-authored-by: Ernesto García <ernestognw@gmail.com>
Co-authored-by: Arr00 <13561405+arr00@users.noreply.github.com>
Co-authored-by: wizard <112275929+famouswizard@users.noreply.github.com>
Co-authored-by: leopardracer <136604165+leopardracer@users.noreply.github.com>
Co-authored-by: cairo <cairoeth@protonmail.com>
This commit is contained in:
Hadrien Croubois
2024-12-04 17:37:13 +01:00
committed by GitHub
parent 98d28f9261
commit e5e9ff72f0
26 changed files with 489 additions and 151 deletions

View File

@ -6,15 +6,36 @@ import {Votes} from "./Votes.sol";
import {SafeCast} from "../../utils/math/SafeCast.sol";
/**
* @dev Extension of {Votes} that adds exposes checkpoints for delegations and balances.
* @dev Extension of {Votes} that adds checkpoints for delegations and balances.
*
* WARNING: While this contract extends {Votes}, valid uses of {Votes} may not be compatible with
* {VotesExtended} without additional considerations. This implementation of {_transferVotingUnits} must
* run AFTER the voting weight movement is registered, such that it is reflected on {_getVotingUnits}.
*
* Said differently, {VotesExtended} MUST be integrated in a way that calls {_transferVotingUnits} AFTER the
* asset transfer is registered and balances are updated:
*
* ```solidity
* contract VotingToken is Token, VotesExtended {
* function transfer(address from, address to, uint256 tokenId) public override {
* super.transfer(from, to, tokenId); // <- Perform the transfer first ...
* _transferVotingUnits(from, to, 1); // <- ... then call _transferVotingUnits.
* }
*
* function _getVotingUnits(address account) internal view override returns (uint256) {
* return balanceOf(account);
* }
* }
* ```
*
* {ERC20Votes} and {ERC721Votes} follow this pattern and are thus safe to use with {VotesExtended}.
*/
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;
mapping(address delegator => Checkpoints.Trace160) private _userDelegationCheckpoints;
mapping(address account => Checkpoints.Trace208) private _userVotingUnitsCheckpoints;
/**
* @dev Returns the delegate of an `account` at a specific moment in the past. If the `clock()` is
@ -25,11 +46,7 @@ abstract contract VotesExtended is Votes {
* - `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()));
return address(_userDelegationCheckpoints[account].upperLookupRecent(_validateTimepoint(timepoint)));
}
/**
@ -41,18 +58,14 @@ abstract contract VotesExtended is Votes {
* - `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());
return _userVotingUnitsCheckpoints[account].upperLookupRecent(_validateTimepoint(timepoint));
}
/// @inheritdoc Votes
function _delegate(address account, address delegatee) internal virtual override {
super._delegate(account, delegatee);
_delegateCheckpoints[account].push(clock(), uint160(delegatee));
_userDelegationCheckpoints[account].push(clock(), uint160(delegatee));
}
/// @inheritdoc Votes
@ -60,10 +73,10 @@ abstract contract VotesExtended is Votes {
super._transferVotingUnits(from, to, amount);
if (from != to) {
if (from != address(0)) {
_balanceOfCheckpoints[from].push(clock(), _getVotingUnits(from).toUint208());
_userVotingUnitsCheckpoints[from].push(clock(), SafeCast.toUint208(_getVotingUnits(from)));
}
if (to != address(0)) {
_balanceOfCheckpoints[to].push(clock(), _getVotingUnits(to).toUint208());
_userVotingUnitsCheckpoints[to].push(clock(), SafeCast.toUint208(_getVotingUnits(to)));
}
}
}