Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/CompoundGovernor.sol": {
"content": "// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.26;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IGovernor} from "contracts/extensions/IGovernor.sol";
import {GovernorUpgradeable} from "contracts/extensions/GovernorUpgradeable.sol";
import {GovernorSequentialProposalIdUpgradeable} from "contracts/extensions/GovernorSequentialProposalIdUpgradeable.sol";
import {GovernorVotesCompUpgradeable} from "contracts/extensions/GovernorVotesCompUpgradeable.sol";
import {GovernorSettableFixedQuorumUpgradeable} from "contracts/extensions/GovernorSettableFixedQuorumUpgradeable.sol";
import {GovernorCountingFractionalUpgradeable} from "contracts/extensions/GovernorCountingFractionalUpgradeable.sol";
import {GovernorTimelockCompoundUpgradeable} from "contracts/extensions/GovernorTimelockCompoundUpgradeable.sol";
import {ICompoundTimelock} from "@openzeppelin/contracts/vendor/compound/ICompoundTimelock.sol";
import {GovernorSettingsUpgradeable} from "contracts/extensions/GovernorSettingsUpgradeable.sol";
import {GovernorPreventLateQuorumUpgradeable} from "contracts/extensions/GovernorPreventLateQuorumUpgradeable.sol";
import {IComp} from "contracts/interfaces/IComp.sol";
import {GovernorAlphaInterface} from "contracts/GovernorBravoInterfaces.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
/// @title CompoundGovernor
/// @author WOOF! Software
/// @notice A governance contract for the Compound DAO.
/// @custom:security-contact dmitriy@woof.software
contract CompoundGovernor is
Initializable,
GovernorVotesCompUpgradeable,
GovernorTimelockCompoundUpgradeable,
GovernorSettingsUpgradeable,
GovernorCountingFractionalUpgradeable,
GovernorPreventLateQuorumUpgradeable,
GovernorSettableFixedQuorumUpgradeable,
GovernorSequentialProposalIdUpgradeable
{
/// @dev To use the `EnumerableSet` library for managing a set of addresses.
using EnumerableSet for EnumerableSet.AddressSet;
/**
* @notice Emitted when the expiration of a whitelisted account is set or updated.
* @param setter The address of the account that set the expiration.
* @param account The address of the account being whitelisted.
* @param expiration The timestamp until which the account is whitelisted.
*/
event WhitelistAccountExpirationSet(address setter, address account, uint256 expiration);
/// @notice Emitted when the whitelistGuardian is set or changed.
/// @param oldGuardian The address of the previous whitelistGuardian.
/// @param newGuardian The address of the new whitelistGuardian.
event WhitelistGuardianSet(address oldGuardian, address newGuardian);
/// @notice Emitted when the proposal guardian is set or updated.
/// @param oldProposalGuardian The address of the previous proposal guardian.
/// @param oldProposalGuardianExpiry The expiration timestamp of the previous proposal guardian's role.
/// @param newProposalGuardian The address of the new proposal guardian.
/// @param newProposalGuardianExpiry The expiration timestamp of the new proposal guardian's role.
event ProposalGuardianSet(
address oldProposalGuardian,
uint96 oldProposalGuardianExpiry,
address newProposalGuardian,
uint96 newProposalGuardianExpiry
);
/// @notice Emitted when a new proposer is added to the allowed proposers list.
/// @param proposer The address of the proposer that was added.
event ProposerAdded(address indexed proposer);
/// @notice Emitted when a proposer is removed from the allowed proposers list.
/// @param proposer The address of the proposer that was removed.
event ProposerRemoved(address indexed proposer);
/// @notice Error thrown when an unauthorized address attempts to perform a restricted action.
/// @param reason A brief description of why the caller is unauthorized.
/// @param caller The address that attempted the unauthorized action.
error Unauthorized(bytes32 reason, address caller);
/// @notice Error thrown when a proposer attempts to create a new proposal while they have an active proposal.
/// @param proposer The address of the proposer.
/// @param proposalId The ID of the active proposal.
/// @param state The state of the active proposal.
error ProposerActiveProposal(address proposer, uint256 proposalId, ProposalState state);
/// @notice Error thrown when a zero address is used.
error ZeroAddress();
/// @notice Error thrown when a zero address is used at a specific index.
/// @param index The index where the zero address was used.
error ZeroAddressAtIndex(uint256 index);
/// @notice Error thrown when a caller is not an allowed proposer.
error OnlyAllowedProposers();
/// @notice Error thrown when an account is already set.
/// @param account The address of the account that is already set.
error AlreadySet(address account);
/// @notice Error thrown when an account is the proposal guardian.
/// @param account The address of the account that is the proposal guardian.
error IsProposalGuardian(address account);
/// @notice Error thrown when an account's lifetime exceeds the maximum lifetime.
/// @param account The address of the account that exceeds the maximum lifetime.
error ExceedsMaxLifetime(address account);
/// @notice Error thrown when an account is not in the allowed proposers list.
/// @param account The address of the account that is not in the allowed proposers list.
error NotInAllowedProposers(address account);
/// @notice Error thrown when amount of allowed proposers is below the minimum proposers.
error BelowMinimumProposers();
/// @notice Error thrown during batchWhitelist when the first address is not the proposal guardian.
/// @param account The address of the account that is not the proposal guardian.
error FirstMustBeProposalGuardian(address account);
/// @notice Error thrown during batchWhitelist when an account is duplicated.
/// @param account The address of the account that is already set.
error DuplicateAddress(address account);
/// @notice Error thrown when the minimum number of proposers is reached.
/// @dev This error is thrown when the proposal guardian tries to add an allowed proposer when the minimum number of
/// proposers is reached.
error MinProposersReached();
/// @notice Error thrown when a proposal is invalid because the proposal guardian has expired and only
/// setProposalGuardian proposals are allowed.
error InvalidProposalWhenGuardianExpired();
/// @notice Error thrown when the caller is not the proxy admin.
error OnlyProxyAdmin();
/// @notice Error thrown when the caller is not the proposer or the proposal guardian.
error OnlyProposerOrProposalGuardian();
/// @notice The address and expiration of the proposal guardian.
struct ProposalGuardian {
// Address of the `ProposalGuardian`
address account;
// Timestamp at which the guardian loses the ability to cancel proposals
uint96 expiration;
}
GovernorAlphaInterface private constant compoundGovernorBravo =
GovernorAlphaInterface(0xc0Da02939E1441F497fd74F78cE7Decb17B66529);
/// @notice Address which manages whitelisted proposals and whitelist accounts.
/// @dev This address has the ability to set account whitelist expirations and can be changed through the governance
/// process.
address public whitelistGuardian;
/// @notice Account which has the ability to cancel proposals. This privilege expires at the given expiration
/// timestamp.
ProposalGuardian public proposalGuardian;
/// @notice Stores the expiration of account whitelist status as a timestamp.
mapping(address account => uint256 timestamp) public whitelistAccountExpirations;
/// @notice Stores the latest proposal ID for each proposer.
mapping(address proposer => uint256 latestProposalId) public latestProposalIds;
/*//////////////////////////////////////////////////////////////
NEW STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice The address of the proxy admin.
/// @dev This is the address of the proxy admin that will be used to upgrade the proxy and call batchWhitelist.
address public constant PROXY_ADMIN = 0x725ED7F44F0888aeC1b7630AB1ACdced91E0591A;
/// @notice Minimum number of proposers that must remain in the allowed proposers list.
uint8 public constant MIN_PROPOSERS = 5;
/// @notice Maximum lifetime for a temporary proposer.
uint32 public constant MAX_TEMPORARY_PROPOSER_LIFETIME = 365 days;
/// @notice Function selector for setProposalGuardian(ProposalGuardian).
bytes4 public constant SET_PROPOSAL_GUARDIAN_SELECTOR = 0xb80d105a;
/// @notice A set of addresses that are allowed to make proposals.
/// @dev Using EnumerableSet for managing the allow list.
EnumerableSet.AddressSet private allowedProposers;
/// @notice Disables the initialize function.
constructor() {
_disableInitializers();
}
/// @notice Initialize Governor.
/// @param _initialVotingDelay The initial voting delay.
/// @param _initialVotingPeriod The initial voting period.
/// @param _initialProposalThreshold The initial proposal threshold.
/// @param _compAddress The address of the Comp token.
/// @param _quorumVotes The quorum votes.
/// @param _timelockAddress The address of the Timelock.
/// @param _initialVoteExtension The initial vote extension.
/// @param _whitelistGuardian The address of the whitelist guardian.
/// @param _proposalGuardian The proposal guardian.
function initialize(
uint48 _initialVotingDelay,
uint32 _initialVotingPeriod,
uint256 _initialProposalThreshold,
IComp _compAddress,
uint256 _quorumVotes,
ICompoundTimelock _timelockAddress,
uint48 _initialVoteExtension,
address _whitelistGuardian,
ProposalGuardian calldata _proposalGuardian
) public initializer {
__Governor_init("Compound Governor");
__GovernorSettings_init(_initialVotingDelay, _initialVotingPeriod, _initialProposalThreshold);
__GovernorVotesComp_init(_compAddress);
__GovernorTimelockCompound_init(_timelockAddress);
__GovernorPreventLateQuorum_init(_initialVoteExtension);
__GovernorSettableFixedQuorum_init(_quorumVotes);
__GovernorSequentialProposalId_init();
__GovernorCountingFractional_init();
_setWhitelistGuardian(_whitelistGuardian);
_setProposalGuardian(_proposalGuardian);
}
/**
* @notice Batch initializes the allowed proposers list during upgrade.
* @dev This function can only be called once during the upgrade process.
* @param _initProposers Array of addresses to add to the allowed proposers list.
*/
function batchWhitelist(address[] calldata _initProposers) external reinitializer(2) {
if (_msgSender() != PROXY_ADMIN) {
revert OnlyProxyAdmin();
}
if (_initProposers.length < MIN_PROPOSERS) {
revert BelowMinimumProposers();
}
// First address must be proposalGuardian
if (_initProposers[0] != proposalGuardian.account) {
revert FirstMustBeProposalGuardian(_initProposers[0]);
}
// Check for zero addresses and duplicates
address proposer;
for (uint256 i; i < _initProposers.length; ++i) {
proposer = _initProposers[i];
if (proposer == address(0)) {
revert ZeroAddressAtIndex(i);
}
if (!allowedProposers.add(proposer)) {
revert DuplicateAddress(proposer);
}
emit ProposerAdded(proposer);
}
}
/// @notice Sets the next proposal ID. Designed to be callable once by the executor (timelock) on upgrade from
/// Compound GovernorBravo.
function setNextProposalId() external {
if (_executor() != _msgSender()) {
revert GovernorOnlyExecutor(_msgSender());
}
// In GovernorBravo, proposal IDs start at 1, so its proposalCount() function is the most recent
// proposal ID created. This function sets the first proposal ID for the CompoundGovernor to 1 beyond that,
// so the first proposal ID of compoundGovernor is one more that the last proposal ID of GovernorBravo.
_setNextProposalId(compoundGovernorBravo.proposalCount() + 1);
}
/// @inheritdoc GovernorSequentialProposalIdUpgradeable
/// @dev Since GovernorBravo indexed from 1, we decrement the proposal count by 1.
function proposalCount() public view override returns (uint256) {
return super.proposalCount() - 1;
}
/// @notice A modified `hashProposal` that supports sequential proposal IDs.
function hashProposal(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
bytes32 _descriptionHash
) public virtual override(GovernorUpgradeable, GovernorSequentialProposalIdUpgradeable) returns (uint256) {
return GovernorSequentialProposalIdUpgradeable.hashProposal(_targets, _values, _calldatas, _descriptionHash);
}
/// @notice Creates a new proposal. Skips proposal threshold check for whitelisted accounts.
/// @param _targets An array of addresses that will be called if the proposal is executed.
/// @param _values An array of ETH values to be sent to each address when the proposal is executed.
/// @param _calldatas An array of calldata to be sent to each address when the proposal is executed.
/// @param _description A human-readable description of the proposal.
/// @return uint256 The ID of the newly created proposal.
function propose(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
string memory _description
) public override(GovernorUpgradeable) returns (uint256) {
address _proposer = _msgSender();
// check description restriction
if (!_isValidDescriptionForProposer(_proposer, _description)) {
revert GovernorRestrictedProposer(_proposer);
}
// Check if proposer is in allowed proposers list or has temporary whitelist
if (!isAllowedProposer(_proposer) && !isWhitelisted(_proposer)) {
revert GovernorNotWhitelisted(_proposer);
}
// If proposal guardian has expired, only allow setProposalGuardian proposals
if (isProposalGuardianExpired()) {
if (!_isValidProposalWhenGuardianExpired(_targets, _calldatas)) {
revert InvalidProposalWhenGuardianExpired();
}
}
return _propose(_targets, _values, _calldatas, _description, _proposer);
}
/// @notice Internal function used to create a new proposal.
/// @dev This is an override that supports sequential proposal IDs. Called by the public `propose` function.
/// @param _targets An array of addresses that will be called if the proposal is executed.
/// @param _values An array of ETH values to be sent to each address when the proposal is executed.
/// @param _calldatas An array of calldata to be sent to each address when the proposal is executed.
/// @param _description A human-readable description of the proposal.
/// @param _proposer The address of the account creating the proposal.
/// @return uint256 The ID of the newly created proposal.
function _propose(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
string memory _description,
address _proposer
) internal override(GovernorUpgradeable, GovernorSequentialProposalIdUpgradeable) returns (uint256) {
uint256 _latestProposalId = latestProposalIds[_proposer];
if (_latestProposalId != 0) {
ProposalState _lastProposalState = state(_latestProposalId);
if (_lastProposalState == ProposalState.Active || _lastProposalState == ProposalState.Pending) {
revert ProposerActiveProposal(_proposer, _latestProposalId, _lastProposalState);
}
}
uint256 _proposalId =
GovernorSequentialProposalIdUpgradeable._propose(_targets, _values, _calldatas, _description, _proposer);
latestProposalIds[_proposer] = _proposalId;
return _proposalId;
}
/**
* @notice Cancels an active proposal.
* @dev This function can be called by the proposer or proposal guardian.
* @param _targets An array of addresses that will be called if the proposal is executed.
* @param _values An array of ETH values to be sent to each address when the proposal is executed.
* @param _calldatas An array of calldata to be sent to each address when the proposal is executed.
* @param _descriptionHash The hash of the proposal's description string.
* @return uint256 The ID of the canceled proposal.
*/
function cancel(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
bytes32 _descriptionHash
) public override returns (uint256) {
uint256 _proposalId = hashProposal(_targets, _values, _calldatas, _descriptionHash);
address _proposer = proposalProposer(_proposalId);
// Only proposer and proposal guardian can cancel.
if (
_msgSender() != _proposer
&& (_msgSender() != proposalGuardian.account || block.timestamp > proposalGuardian.expiration)
) {
revert OnlyProposerOrProposalGuardian();
}
return _cancel(_targets, _values, _calldatas, _descriptionHash);
}
/**
* @notice Cancels a proposal given its ID.
* @dev This function can be called by the proposer or proposal guardian.
* It retrieves proposal details and calls the main cancel function with those details.
* @param _proposalId The ID of the proposal to cancel.
*/
function cancel(uint256 _proposalId) public override {
(address[] memory _targets, uint256[] memory _values, bytes[] memory _calldatas, bytes32 _descriptionHash) =
proposalDetails(_proposalId);
cancel(_targets, _values, _calldatas, _descriptionHash);
}
/**
* @notice Sets or updates the whitelist expiration for a specific account.
* A whitelisted account can create proposals without needing to be an allowed proposer.
* A whitelisted account's proposals cannot be canceled by anyone except the `whitelistGuardian`.
* A whitelisted account and `proposalGuardian` can still cancel its proposals.
* @dev Only an allowed proposer can call this function to whitelist other accounts.
* @param _account The address of the account to be whitelisted.
* @param _expiration The timestamp until which the account will be whitelisted.
*/
function setWhitelistAccountExpiration(address _account, uint256 _expiration) external {
address _sender = _msgSender();
// Check that msg.sender is in allowedProposers
if (!allowedProposers.contains(_sender)) {
revert OnlyAllowedProposers();
}
// Check that _account is not zero address
if (_account == address(0)) {
revert ZeroAddress();
}
// Check that _account is not equal to proposalGuardian
if (_account == proposalGuardian.account) {
revert IsProposalGuardian(_account);
}
// Check that _account is not in allowedProposers
if (allowedProposers.contains(_account)) {
revert AlreadySet(_account);
}
// If expiration is not less than now, check the lifetime constraint
if (_expiration > block.timestamp && _expiration - block.timestamp > MAX_TEMPORARY_PROPOSER_LIFETIME) {
revert ExceedsMaxLifetime(_account);
}
whitelistAccountExpirations[_account] = _expiration;
emit WhitelistAccountExpirationSet(_sender, _account, _expiration);
}
/**
* @notice Adds a new address to the allowed proposers list.
* @dev Only the executor (timelock) or proposal guardian (when below minimum proposers) can call this function.
* @param _newProposer The address to add to the allowed proposers list.
*/
function addProposer(address _newProposer) external {
address _sender = _msgSender();
address _proposalGuardian = proposalGuardian.account;
/**
* Note Proposers can always be added by proposals
* Note Proposal guardian can add proposers when below minimum proposers even if he is expired
* This was done to prevent a case after upgrade where whitelist proposers expired and non of allowed
* proposers were whitelisted
* Note Proposal guardian can only add proposers when below minimum
*/
if (_sender != _executor()) {
if (_sender != proposalGuardian.account) {
revert GovernorOnlyExecutor(_sender);
}
if (allowedProposers.length() >= MIN_PROPOSERS) {
revert MinProposersReached();
}
}
if (_newProposer == address(0)) {
revert ZeroAddress();
}
if (_newProposer == _proposalGuardian) {
revert IsProposalGuardian(_newProposer);
}
if (isAllowedProposer(_newProposer)) {
revert AlreadySet(_newProposer);
}
allowedProposers.add(_newProposer);
emit ProposerAdded(_newProposer);
}
/**
* @notice Removes an address from the allowed proposers list.
* @dev Only the executor (timelock) can call this function.
* @param _proposer The address to remove from the allowed proposers list.
*/
function removeProposer(address _proposer) external {
if (_executor() != _msgSender()) {
revert GovernorOnlyExecutor(_msgSender());
}
if (_proposer == address(0)) {
revert ZeroAddress();
}
if (_proposer == proposalGuardian.account) {
revert IsProposalGuardian(_proposer);
}
if (!isAllowedProposer(_proposer)) {
revert NotInAllowedProposers(_proposer);
}
if (allowedProposers.length() <= MIN_PROPOSERS) {
revert BelowMinimumProposers();
}
allowedProposers.remove(_proposer);
emit ProposerRemoved(_proposer);
}
/// @notice Checks if an account is currently whitelisted.
/// @param _account The address of the account to check.
/// @return bool Returns true if the account is whitelisted (expiration is in the future), false otherwise.
function isWhitelisted(address _account) public view returns (bool) {
return (whitelistAccountExpirations[_account] > block.timestamp);
}
/// @notice Returns the list of allowed proposers.
/// @return address[] An array of addresses that are allowed to make proposals.
function getAllowedProposers() public view returns (address[] memory) {
return allowedProposers.values();
}
/// @notice Checks if an address is in the allowed proposers list.
/// @param _account The address to check.
/// @return bool True if the address is an allowed proposer.
function isAllowedProposer(address _account) public view returns (bool) {
return allowedProposers.contains(_account);
}
/// @notice Checks if the proposal guardian has expired.
/// @return bool True if the proposal guardian has expired, false otherwise.
function isProposalGuardianExpired() public view returns (bool) {
return block.timestamp > proposalGuardian.expiration;
}
/// @notice Validates that a proposal contains exactly one setProposalGuardian call.
/// @param _targets An array of addresses that will be called if the proposal is executed.
/// @param _calldatas An array of calldata to be sent to each address when the proposal is executed.
/// @return bool True if the proposal contains exactly one setProposalGuardian call, false otherwise.
function _isValidProposalWhenGuardianExpired(address[] memory _targets, bytes[] memory _calldatas)
internal
view
returns (bool)
{
// Must have exactly one call when guardian has expired
if (_targets.length != 1 || _calldatas.length != 1) {
return false;
}
// Check that the single call is to this contract and uses setProposalGuardian selector
if (_targets[0] != address(this)) {
return false;
}
// Check that the calldata is the setProposalGuardian selector
bytes4 selector = bytes4(_calldatas[0]);
if (selector != SET_PROPOSAL_GUARDIAN_SELECTOR) {
return false;
}
return true;
}
/// @notice Sets a new `whitelistGuardian`.
/// @notice a `whitelistGuardian` can whitelist accounts and can cancel whitelisted accounts' proposals when they
/// fall.
/// below `proposalThreshold.
/// @dev Only the executor (timelock) can call this function.
/// @param _newWhitelistGuardian The address of the new `whitelistGuardian`.
function setWhitelistGuardian(address _newWhitelistGuardian) external {
_checkGovernance();
_setWhitelistGuardian(_newWhitelistGuardian);
}
/// @notice Sets a new proposal guardian.
/// @dev This function can only be called by the executor (timelock).
/// @param _newProposalGuardian The new proposal guardian to be set, including their address and expiration.
function setProposalGuardian(ProposalGuardian memory _newProposalGuardian) external {
_checkGovernance();
_setProposalGuardian(_newProposalGuardian);
}
/// @notice Admin function for setting the whitelistGuardian. WhitelistGuardian can cancel proposals from
/// whitelisted addresses.
/// @param _newWhitelistGuardian Account to set whitelistGuardian to (0x0 to remove whitelistGuardian).
function _setWhitelistGuardian(address _newWhitelistGuardian) internal {
emit WhitelistGuardianSet(whitelistGuardian, _newWhitelistGuardian);
whitelistGuardian = _newWhitelistGuardian;
}
/**
* @notice Internal function to set a new proposal guardian.
* @dev Updates the proposal guardian and emits a {ProposalGuardianSet} event.
* If the new proposal guardian is different from the current one, the current proposal guardian
* is removed from the allowed proposers and the new proposal guardian is added.
* @param _newProposalGuardian The new proposal guardian to be set, including their address and expiration.
*/
function _setProposalGuardian(ProposalGuardian memory _newProposalGuardian) internal {
address currentProposalGuardian = proposalGuardian.account;
address newProposalGuardian = _newProposalGuardian.account;
emit ProposalGuardianSet(
currentProposalGuardian, proposalGuardian.expiration, newProposalGuardian, _newProposalGuardian.expiration
);
/// Note If batchWhitelist was not called during upgrade, we check that the current proposal guardian is in the
/// allowed proposers
if (currentProposalGuardian != newProposalGuardian) {
allowedProposers.remove(currentProposalGuardian);
allowedProposers.add(newProposalGuardian);
}
proposalGuardian = _newProposalGuardian;
}
/// @inheritdoc GovernorTimelockCompoundUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function _cancel(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
bytes32 _descriptionHash
) internal override(GovernorUpgradeable, GovernorTimelockCompoundUpgradeable) returns (uint256) {
return GovernorTimelockCompoundUpgradeable._cancel(_targets, _values, _calldatas, _descriptionHash);
}
/// @inheritdoc GovernorPreventLateQuorumUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function _castVote(
uint256 _proposalId,
address _account,
uint8 _support,
string memory _reason,
bytes memory _params
) internal override(GovernorUpgradeable, GovernorPreventLateQuorumUpgradeable) returns (uint256) {
return GovernorPreventLateQuorumUpgradeable._castVote(_proposalId, _account, _support, _reason, _params);
}
/// @inheritdoc GovernorTimelockCompoundUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function _executeOperations(
uint256 _proposalId,
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
bytes32 _descriptionHash
) internal override(GovernorUpgradeable, GovernorTimelockCompoundUpgradeable) {
return GovernorTimelockCompoundUpgradeable._executeOperations(
_proposalId, _targets, _values, _calldatas, _descriptionHash
);
}
/// @inheritdoc GovernorTimelockCompoundUpgradeable
function _executor()
internal
view
override(GovernorUpgradeable, GovernorTimelockCompoundUpgradeable)
returns (address)
{
return GovernorTimelockCompoundUpgradeable._executor();
}
/// @inheritdoc GovernorTimelockCompoundUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function _queueOperations(
uint256 _proposalId,
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
bytes32 _descriptionHash
) internal override(GovernorUpgradeable, GovernorTimelockCompoundUpgradeable) returns (uint48) {
return GovernorTimelockCompoundUpgradeable._queueOperations(
_proposalId, _targets, _values, _calldatas, _descriptionHash
);
}
/// @inheritdoc GovernorPreventLateQuorumUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function proposalDeadline(uint256 _proposalId)
public
view
override(GovernorPreventLateQuorumUpgradeable, GovernorUpgradeable)
returns (uint256)
{
return GovernorPreventLateQuorumUpgradeable.proposalDeadline(_proposalId);
}
/// @inheritdoc GovernorTimelockCompoundUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function proposalNeedsQueuing(uint256 _proposalId)
public
view
override(GovernorTimelockCompoundUpgradeable, GovernorUpgradeable)
returns (bool)
{
return GovernorTimelockCompoundUpgradeable.proposalNeedsQueuing(_proposalId);
}
/// @inheritdoc GovernorSettingsUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function proposalThreshold()
public
view
override(GovernorSettingsUpgradeable, GovernorUpgradeable)
returns (uint256)
{
return GovernorSettingsUpgradeable.proposalThreshold();
}
/// @inheritdoc GovernorTimelockCompoundUpgradeable
/// @dev We override this function to resolve ambiguity between inherited contracts.
function state(uint256 _proposalId)
public
view
override(GovernorUpgradeable, GovernorTimelockCompoundUpgradeable)
returns (ProposalState)
{
return GovernorTimelockCompoundUpgradeable.state(_proposalId);
}
/// @inheritdoc GovernorCountingFractionalUpgradeable
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE()
public
pure
override(IGovernor, GovernorCountingFractionalUpgradeable)
returns (string memory)
{
return "support=bravo,fractional&quorum=for¶ms=fractional";
}
/// @notice Internal function that returns true if the amount of 'for' votes already cast meets the quorum limit,
/// false otherwise.
/// @dev We override this function to implement quorum functionality that only includes votes in favor.
function _quorumReached(uint256 proposalId)
internal
view
override(GovernorUpgradeable, GovernorCountingFractionalUpgradeable)
returns (bool)
{
(, uint256 _forVotes,) = GovernorCountingFractionalUpgradeable.proposalVotes(proposalId);
return quorum(proposalSnapshot(proposalId)) <= _forVotes;
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
"
},
"contracts/extensions/IGovernor.sol": {
"content": "// SPDX-License-Identifier: MIT
// Sourced from contract below, with change to hashProposal (removed pure) for sequential proposal ID support.
// OpenZeppelin Contracts (last updated v5.1.0) (governance/IGovernor.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {IERC6372} from "@openzeppelin/contracts/interfaces/IERC6372.sol";
/**
* @dev Interface of the {Governor} core.
*
* NOTE: Event parameters lack the `indexed` keyword for compatibility with GovernorBravo events.
* Making event parameters `indexed` affects how events are decoded, potentially breaking existing indexers.
*/
interface IGovernor is IERC165, IERC6372 {
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed
}
/**
* @dev Empty proposal or a mismatch between the parameters length for a proposal call.
*/
error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values);
/**
* @dev The vote was already cast.
*/
error GovernorAlreadyCastVote(address voter);
/**
* @dev Token deposits are disabled in this contract.
*/
error GovernorDisabledDeposit();
/**
* @dev The `account` is not a proposer.
*/
error GovernorOnlyProposer(address account);
/**
* @dev The `account` is not the governance executor.
*/
error GovernorOnlyExecutor(address account);
/**
* @dev The `proposalId` doesn't exist.
*/
error GovernorNonexistentProposal(uint256 proposalId);
/**
* @dev The current state of a proposal is not the required for performing an operation.
* The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position
* counting from right to left.
*
* NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist).
* This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated).
*
* See {Governor-_encodeStateBitmap}.
*/
error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates);
/**
* @dev The voting period set is not a valid period.
*/
error GovernorInvalidVotingPeriod(uint256 votingPeriod);
/**
* @dev The `proposer` does not have the required votes to create a proposal.
*/
error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold);
/**
* @dev The `proposer` is not allowed to create a proposal.
*/
error GovernorRestrictedProposer(address proposer);
/**
* @dev The vote type used is not valid for the corresponding counting module.
*/
error GovernorInvalidVoteType();
/**
* @dev The provided params buffer is not supported by the counting module.
*/
error GovernorInvalidVoteParams();
/**
* @dev Queue operation is not implemented for this governor. Execute should be called directly.
*/
error GovernorQueueNotImplemented();
/**
* @dev The proposal hasn't been queued yet.
*/
error GovernorNotQueuedProposal(uint256 proposalId);
/**
* @dev The proposal has already been queued.
*/
error GovernorAlreadyQueuedProposal(uint256 proposalId);
/**
* @dev The provided signature is not valid for the expected `voter`.
* If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}.
*/
error GovernorInvalidSignature(address voter);
/**
* @dev The `account` is not whitelisted or not whitelisted permanently to propose.
*/
error GovernorNotWhitelisted(address account);
/**
* @dev Emitted when a proposal is created.
*/
event ProposalCreated(
uint256 proposalId,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 voteStart,
uint256 voteEnd,
string description
);
/**
* @dev Emitted when a proposal is queued.
*/
event ProposalQueued(uint256 proposalId, uint256 etaSeconds);
/**
* @dev Emitted when a proposal is executed.
*/
event ProposalExecuted(uint256 proposalId);
/**
* @dev Emitted when a proposal is canceled.
*/
event ProposalCanceled(uint256 proposalId);
/**
* @dev Emitted when a vote is cast without params.
*
* Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
*/
event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason);
/**
* @dev Emitted when a vote is cast with params.
*
* Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
* `params` are additional encoded parameters. Their interpretation also depends on the voting module used.
*/
event VoteCastWithParams(
address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason, bytes params
);
/**
* @notice module:core
* @dev Name of the governor instance (used in building the EIP-712 domain separator).
*/
function name() external view returns (string memory);
/**
* @notice module:core
* @dev Version of the governor instance (used in building the EIP-712 domain separator). Default: "1"
*/
function version() external view returns (string memory);
/**
* @notice module:voting
* @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to
* be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence
* of
* key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
*
* There are 2 standard keys: `support` and `quorum`.
*
* - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`.
* - `quorum=bravo` means that only For votes are counted towards quorum.
* - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
*
* If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique
* name that describes the behavior. For example:
*
* - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain.
* - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote.
*
* NOTE: The string can be decoded by the standard
* https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`]
* JavaScript class.
*/
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE() external view returns (string memory);
/**
* @notice module:core
* @dev Hashing function used to (re)build the proposal id from the proposal details..
*/
function hashProposal(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external returns (uint256);
/**
* @notice module:core
* @dev Current state of a proposal, following Compound's convention
*/
function state(uint256 proposalId) external view returns (ProposalState);
/**
* @notice module:core
* @dev The number of votes required in order for a voter to become a proposer.
*/
function proposalThreshold() external view returns (uint256);
/**
* @notice module:core
* @dev Timepoint used to retrieve user's votes and quorum. If using block number (as per Compound's Comp), the
* snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the
* following block.
*/
function proposalSnapshot(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is
* possible to cast a vote during this block.
*/
function proposalDeadline(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev The account that created a proposal.
*/
function proposalProposer(uint256 proposalId) external view returns (address);
/**
* @notice module:core
* @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and
* {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be
* different. In most cases this will be a timestamp.
*/
function proposalEta(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev Whether a proposal needs to be queued before execution.
*/
function proposalNeedsQueuing(uint256 proposalId) external view returns (bool);
/**
* @notice module:user-config
* @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends
* on the clock (see ERC-6372) this contract uses.
*
* This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a
* proposal starts.
*
* NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type.
* Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}.
*/
function votingDelay() external view returns (uint256);
/**
* @notice module:user-config
* @dev Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock
* (see ERC-6372) this contract uses.
*
* NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting
* duration compared to the voting delay.
*
* NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect
* proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this
* interface returns a uint256, the value it returns should fit in a uint32.
*/
function votingPeriod() external view returns (uint256);
/**
* @notice module:user-config
* @dev Minimum number of cast voted required for a proposal to be successful.
*
* NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the
* quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}).
*/
function quorum(uint256 timepoint) external view returns (uint256);
/**
* @notice module:reputation
* @dev Voting power of an `account` at a specific `timepoint`.
*
* Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or
* multiple), {ERC20Votes} tokens.
*/
function getVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @notice module:reputation
* @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters.
*/
function getVotesWithParams(address account, uint256 timepoint, bytes memory params)
external
view
returns (uint256);
/**
* @notice module:voting
* @dev Returns whether `account` has cast a vote on `proposalId`.
*/
function hasVoted(uint256 proposalId, address account) external view returns (bool);
/**
* @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a
* duration specified by {IGovernor-votingPeriod}.
*
* Emits a {ProposalCreated} event.
*
* NOTE: The state of the Governor and `targets` may change between the proposal creation and its execution.
* This may be the result of third party actions on the targeted contracts, or other governor proposals.
* For example, the balance of this contract could be updated or its access control permissions may be modified,
* possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough
* value to cover a proposal with multiple transfers).
*/
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) external returns (uint256 proposalId);
/**
* @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing
* is not necessary, this function may revert.
* Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached.
*
* Emits a {ProposalQueued} event.
*/
function queue(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
external
returns (uint256 proposalId);
/**
* @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the
* deadline to be reached. Depending on the governor it might also be required that the proposal was queued and
* that some delay passed.
*
* Emits a {ProposalExecuted} event.
*
* NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock.
*/
function execute(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external payable returns (uint256 proposalId);
/**
* @dev Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e.
* before the vote starts.
*
* Emits a {ProposalCanceled} event.
*/
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external returns (uint256 proposalId);
/**
* @dev Cast a vote
*
* Emits a {VoteCast} event.
*/
function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);
/**
* @dev Cast a vote with a reason
*
* Emits a {VoteCast} event.
*/
function castVoteWithReason(uint256 proposalId, uint8 support, string calldata reason)
external
returns (uint256 balance);
/**
* @dev Cast a vote with a reason and additional encoded parameters
*
* Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
*/
function castVoteWithReasonAndParams(uint256 proposalId, uint8 support, string calldata reason, bytes memory params)
external
returns (uint256 balance);
/**
* @dev Cast a vote using the voter's signature, including ERC-1271 signature support.
*
* Emits a {VoteCast} event.
*/
function castVoteBySig(uint256 proposalId, uint8 support, address voter, bytes memory signature)
external
returns (uint256 balance);
/**
* @dev Cast a vote with a reason and additional encoded parameters using the voter's signature,
* including ERC-1271 signature support.
*
* Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
*/
function castVoteWithReasonAndParamsBySig(
uint256 proposalId,
uint8 support,
address voter,
string calldata reason,
bytes memory params,
bytes memory signature
) external returns (uint256 balance);
}
"
},
"contracts/extensions/GovernorUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// Sourced from contract below, with change to hashProposal (removed pure) for sequential proposal ID support.
// OpenZeppelin Contracts (last updated v5.1.0) (governance/extensions/GovernorUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {DoubleEndedQueue} from "@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import {NoncesUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/NoncesUpgradeable.sol";
import {IGovernor} from "contracts/extensions/IGovernor.sol";
import {IERC6372} from "@openzeppelin/contracts/interfaces/IERC6372.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @dev Core of the governance system, designed to be extended through various modules.
*
* This contract is abstract and requires several functions to be implemented in various modules:
*
* - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote}
* - A voting module must implement {_getVotes}
* - Additionally, {votingPeriod} must also be implemented
*/
abstract contract GovernorUpgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, EIP712Upgradeable, NoncesUpgradeable, IGovernor, IERC721Receiver, IERC1155Receiver {
using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;
bytes32 public constant BALLOT_TYPEHASH =
keccak256("Ballot(uint256 proposalId,uint8 support,address voter,uint256 nonce)");
bytes32 public constant EXTENDED_BALLOT_TYPEHASH =
keccak256(
"ExtendedBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason,bytes params)"
);
struct ProposalCore {
address proposer;
uint48 voteStart;
uint32 voteDuration;
bool executed;
bool canceled;
uint48 etaSeconds;
}
bytes32 private constant ALL_PROPOSAL_STATES_BITMAP = bytes32((2 ** (uint8(type(ProposalState).max) + 1)) - 1);
/// @custom:storage-location erc7201:openzeppelin.storage.Governor
struct GovernorStorage {
string _name;
mapping(uint256 proposalId => ProposalCore) _proposals;
// This queue keeps track of the governor operating on itself. Calls to functions protected by the {onlyGovernance}
// modifier needs to be whitelisted in this queue. Whitelisting is set in {execute}, consumed by the
// {onlyGovernance} modifier and eventually reset after {_executeOperations} completes. This ensures that the
// execution of {onlyGovernance} protected calls can only be achieved through successful proposals.
DoubleEndedQueue.Bytes32Deque _governanceCall;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Governor")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant GovernorStorageLocation = 0x7c712897014dbe49c045ef1299aa2d5f9e67e48eea4403efa21f1e0f3ac0cb00;
function _getGovernorStorage() private pure returns (GovernorStorage storage $) {
assembly {
$.slot := GovernorStorageLocation
}
}
/**
* @dev Restricts a function so it can only be executed through governance proposals. For example, governance
* parameter setters in {GovernorSettings} are protected using this modifier.
*
* The governance executing address may be different from the Governor's own address, for example it could be a
* timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these
* functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus,
* for example, additional timelock proposers are not able to change governance parameters without going through the
* governance protocol (since v4.6).
*/
modifier onlyGovernance() {
_checkGovernance();
_;
}
/**
* @dev Sets the value for {name} and {version}
*/
function __Governor_init(string memory name_) internal onlyInitializing {
__EIP712_init_unchained(name_, version());
__Governor_init_unchained(name_);
}
function __Governor_init_unchained(string memory name_) internal onlyInitializing {
GovernorStorage storage $ = _getGovernorStorage();
$._name = name_;
}
/**
* @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract)
*/
receive() external payable virtual {
if (_executor() != address(this)) {
rever
Submitted on: 2025-10-21 14:09:02
Comments
Log in to comment.
No comments yet.