Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
use EIP5805
  • Loading branch information
Amxx authored and JulissaDantes committed Nov 10, 2022
commit 40f414b51bb5838b019714e28619dca716552129
6 changes: 3 additions & 3 deletions contracts/governance/extensions/GovernorVotes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
pragma solidity ^0.8.0;

import "../Governor.sol";
import "../utils/IVotes.sol";
import "../utils/IEIP5805.sol";

/**
* @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token.
*
* _Available since v4.3._
*/
abstract contract GovernorVotes is Governor {
IVotes public immutable token;
IEIP5805 public immutable token;

constructor(IVotes tokenAddress) {
constructor(IEIP5805 tokenAddress) {
token = tokenAddress;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (governance/utils/Votes.sol)
pragma solidity ^0.8.0;

<<<<<<< HEAD:contracts/governance/utils/Votes.sol
import "./IVotes.sol";
import "../../utils/cryptography/draft-EIP712.sol";
import "../../utils/cryptography/ECDSA.sol";
=======
>>>>>>> 040f8132 (use EIP5805):contracts/governance/utils/EIP5805.sol
import "../../utils/Context.sol";
import "../../utils/Nonces.sol";
import "../../utils/Counters.sol";
import "../../utils/Checkpoints.sol";
import "../../utils/cryptography/EIP712.sol";
import "./IEIP5805.sol";

/**
* @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be
* @dev Core implementation of EIP-5805
*
* This is a base abstract contract that tracks voting units, which are a measure of voting power that can be
* transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of
* "representative" that will pool delegated voting units from different accounts and can then use it to vote in
* decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to
Expand All @@ -19,25 +25,32 @@ import "../../utils/Checkpoints.sol";
* This contract is often combined with a token contract such that voting units correspond to token units. For an
* example, see {ERC721Votes}.
*
* The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed
* at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the
* cost of this history tracking optional.
* The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as
* distributed at a particular timestamp to protect against flash loans and double voting. The opt-in delegate system
* makes the cost of this history tracking optional.
*
* When using this module the derived contract must implement {_getVotingUnits} (for example, make it return
* {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the
* previous example, it would be included in {ERC721-_beforeTokenTransfer}).
*
* _Available since v4.5._
*/
abstract contract Votes is IVotes, Context, EIP712, Nonces {
using Checkpoints for Checkpoints.History;
abstract contract EIP5805 is IEIP5805, Context, EIP712 {
using Checkpoints for Checkpoints.Trace224;
using Counters for Counters.Counter;

bytes32 private constant _DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

mapping(address => address) private _delegation;
mapping(address => Checkpoints.History) private _delegateCheckpoints;
Checkpoints.History private _totalCheckpoints;
mapping(address => Checkpoints.Trace224) private _delegateCheckpoints;
Checkpoints.Trace224 private _totalCheckpoints;
mapping(address => Counters.Counter) private _nonces;

/**
* @dev Return the current timestamp, this can be overriden to use `block.timestamp` or any other mechanism
*/
function clock() public view virtual override returns (uint256) {
return block.number;
}

/**
* @dev Returns the current amount of votes that `account` has.
Expand All @@ -47,29 +60,43 @@ abstract contract Votes is IVotes, Context, EIP712, Nonces {
}

/**
* @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
* @dev Returns the amount of votes that `account` had at the end of a past timepoint (`timepoint`).
*
* Requirements:
*
* - `blockNumber` must have been already mined
* - `timepoint` must have been already mined
*/
<<<<<<< HEAD:contracts/governance/utils/Votes.sol
function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
return _delegateCheckpoints[account].getAtProbablyRecentBlock(blockNumber);
=======
function getPastVotes(address account, uint256 timepoint) public view virtual override returns (uint256) {
require(timepoint < clock(), "Checkpoints: invalid past lookup");
// TODO: optimisitc lookup
return _delegateCheckpoints[account].upperLookup(SafeCast.toUint32(timepoint));
>>>>>>> 040f8132 (use EIP5805):contracts/governance/utils/EIP5805.sol
}

/**
* @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
* @dev Returns the total supply of votes available at the end of a past timepoint (`timepoint`).
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*
* Requirements:
*
* - `blockNumber` must have been already mined
* - `timepoint` must have been already mined
*/
<<<<<<< HEAD:contracts/governance/utils/Votes.sol
function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
return _totalCheckpoints.getAtBlock(blockNumber);
=======
function getPastTotalSupply(uint256 timepoint) public view virtual override returns (uint256) {
require(timepoint < clock(), "Checkpoints: invalid past lookup");
// TODO: optimisitc lookup
return _totalCheckpoints.upperLookup(SafeCast.toUint32(timepoint));
>>>>>>> 040f8132 (use EIP5805):contracts/governance/utils/EIP5805.sol
}

/**
Expand Down Expand Up @@ -139,10 +166,10 @@ abstract contract Votes is IVotes, Context, EIP712, Nonces {
uint256 amount
) internal virtual {
if (from == address(0)) {
_totalCheckpoints.push(_add, amount);
_totalCheckpoints.push(SafeCast.toUint32(clock()), _add, amount);
}
if (to == address(0)) {
_totalCheckpoints.push(_subtract, amount);
_totalCheckpoints.push(SafeCast.toUint32(clock()), _subtract, amount);
}
_moveDelegateVotes(delegates(from), delegates(to), amount);
}
Expand All @@ -157,22 +184,40 @@ abstract contract Votes is IVotes, Context, EIP712, Nonces {
) private {
if (from != to && amount > 0) {
if (from != address(0)) {
(uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount);
(uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(SafeCast.toUint32(clock()), _subtract, amount);
emit DelegateVotesChanged(from, oldValue, newValue);
}
if (to != address(0)) {
(uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount);
(uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(SafeCast.toUint32(clock()), _add, amount);
emit DelegateVotesChanged(to, oldValue, newValue);
}
}
}

function _add(uint256 a, uint256 b) private pure returns (uint256) {
return a + b;
function _add(uint224 a, uint256 b) private pure returns (uint224) {
return SafeCast.toUint224(a + b);
}

function _subtract(uint224 a, uint256 b) private pure returns (uint224) {
return SafeCast.toUint224(a - b);
}

function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
return a - b;
/**
* @dev Consumes a nonce.
*
* Returns the current value and increments nonce.
*/
function _useNonce(address owner) internal virtual returns (uint256 current) {
Counters.Counter storage nonce = _nonces[owner];
current = nonce.current();
nonce.increment();
}

/**
* @dev Returns an address nonce.
*/
function nonces(address owner) public view virtual returns (uint256) {
return _nonces[owner].current();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.0;

/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*
* _Available since v4.5._
* @dev EIP-5805 interface: common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*/
interface IVotes {
interface IEIP5805 {
/**
* @dev Emitted when an account changes their delegate.
*/
Expand All @@ -18,6 +15,11 @@ interface IVotes {
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);

/**
* @dev Return the current timestamp, this can be overriden to use `block.timestamp` or any other mechanism
*/
function clock() external view returns (uint256);

/**
* @dev Returns the current amount of votes that `account` has.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

pragma solidity ^0.8.0;

import "../governance/utils/Votes.sol";
import "../governance/utils/EIP5805.sol";

contract VotesMock is Votes {
contract EIP5805Mock is EIP5805 {
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _owners;

Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/GovernorMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contract GovernorMock is
{
constructor(
string memory name_,
IVotes token_,
IEIP5805 token_,
uint256 votingDelay_,
uint256 votingPeriod_,
uint256 quorumNumerator_
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/GovernorPreventLateQuorumMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ contract GovernorPreventLateQuorumMock is

constructor(
string memory name_,
IVotes token_,
IEIP5805 token_,
uint256 votingDelay_,
uint256 votingPeriod_,
uint256 quorum_,
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/GovernorTimelockCompoundMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contract GovernorTimelockCompoundMock is
{
constructor(
string memory name_,
IVotes token_,
IEIP5805 token_,
uint256 votingDelay_,
uint256 votingPeriod_,
ICompoundTimelock timelock_,
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/GovernorTimelockControlMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contract GovernorTimelockControlMock is
{
constructor(
string memory name_,
IVotes token_,
IEIP5805 token_,
uint256 votingDelay_,
uint256 votingPeriod_,
TimelockController timelock_,
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/GovernorVoteMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "../governance/extensions/GovernorCountingSimple.sol";
import "../governance/extensions/GovernorVotes.sol";

contract GovernorVoteMocks is GovernorVotes, GovernorCountingSimple {
constructor(string memory name_, IVotes token_) Governor(name_) GovernorVotes(token_) {}
constructor(string memory name_, IEIP5805 token_) Governor(name_) GovernorVotes(token_) {}

function quorum(uint256) public pure override returns (uint256) {
return 0;
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/GovernorWithParamsMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "../governance/extensions/GovernorVotes.sol";
contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple {
event CountParams(uint256 uintParam, string strParam);

constructor(string memory name_, IVotes token_) Governor(name_) GovernorVotes(token_) {}
constructor(string memory name_, IEIP5805 token_) Governor(name_) GovernorVotes(token_) {}

function quorum(uint256) public pure override returns (uint256) {
return 0;
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/wizard/MyGovernor1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract MyGovernor1 is
GovernorVotesQuorumFraction,
GovernorCountingSimple
{
constructor(IVotes _token, TimelockController _timelock)
constructor(IEIP5805 _token, TimelockController _timelock)
Governor("MyGovernor")
GovernorVotes(_token)
GovernorVotesQuorumFraction(4)
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/wizard/MyGovernor2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ contract MyGovernor2 is
GovernorVotesQuorumFraction,
GovernorCountingSimple
{
constructor(IVotes _token, TimelockController _timelock)
constructor(IEIP5805 _token, TimelockController _timelock)
Governor("MyGovernor")
GovernorVotes(_token)
GovernorVotesQuorumFraction(4)
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/wizard/MyGovernor3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract MyGovernor is
GovernorVotes,
GovernorVotesQuorumFraction
{
constructor(IVotes _token, TimelockController _timelock)
constructor(IEIP5805 _token, TimelockController _timelock)
Governor("MyGovernor")
GovernorVotes(_token)
GovernorVotesQuorumFraction(4)
Expand Down
4 changes: 2 additions & 2 deletions contracts/token/ERC721/extensions/ERC721Votes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pragma solidity ^0.8.0;

import "../ERC721.sol";
import "../../../governance/utils/Votes.sol";
import "../../../governance/utils/EIP5805.sol";

/**
* @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts
Expand All @@ -15,7 +15,7 @@ import "../../../governance/utils/Votes.sol";
*
* _Available since v4.5._
*/
abstract contract ERC721Votes is ERC721, Votes {
abstract contract ERC721Votes is ERC721, EIP5805 {
/**
* @dev See {ERC721-_afterTokenTransfer}. Adjusts votes when tokens are transferred.
*
Expand Down
30 changes: 30 additions & 0 deletions contracts/utils/Checkpoints.sol
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,21 @@ library Checkpoints {
return _insert(self._checkpoints, key, value);
}

/**
* @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will
* be set to `op(latest, delta)`.
*
* Returns previous value and new value.
*/
function push(
Trace224 storage self,
uint32 key,
function(uint224, uint256) view returns (uint224) op,
uint256 delta
) internal returns (uint256, uint256) {
return push(self, key, op(latest(self), delta));
}

/**
* @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
*/
Expand Down Expand Up @@ -399,6 +414,21 @@ library Checkpoints {
return _insert(self._checkpoints, key, value);
}

/**
* @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will
* be set to `op(latest, delta)`.
*
* Returns previous value and new value.
*/
function push(
Trace160 storage self,
uint96 key,
function(uint160, uint256) view returns (uint160) op,
uint256 delta
) internal returns (uint256, uint256) {
return push(self, key, op(latest(self), delta));
}

/**
* @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
*/
Expand Down
Loading