Contract · Governance
Governor DAO
On-chain governance backed by ERC20Votes token with timelock-guarded execution.
DAO
Audited base
~3.8M gas
Ethereum
Post-deploy checklist
- Confirm votes token is ERC20Votes and holders have self-delegated
- Deploy Timelock first; pass its address here
- Set votingDelay / votingPeriod / quorum for your chain’s block times
- Grant Timelock PROPOSER to this Governor; revoke leftover admin keys
- Transfer treasury / Ownable roles to the Timelock, not an EOA
- Run a dry-run proposal on a testnet
Configure & deploy
Must implement IVotes (ERC20Votes). Plain ERC20 balances do not count until users delegate.
TimelockController that will execute passed proposals. Deploy it first.
~1 day on ~12s blocks. Gives voters time to rearrange votes after proposal creation.
~1 week on ~12s blocks. Longer periods favor deliberation over haste.
Percent of total supply that must vote for a proposal to succeed (GovernorVotesQuorumFraction).
Use cases
- Protocol parameter changes
- Treasury spending proposals
- On-chain elections
AppGovernor.solsolidity
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0 (Wizard / Contracts MCP patterns)
// Compiled with Solidity ^0.8.24 — Ethereum Toolset browser solc
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
import "@openzeppelin/contracts/governance/utils/IVotes.sol";
import "@openzeppelin/contracts/governance/TimelockController.sol";
contract AppGovernor is
Governor,
GovernorSettings,
GovernorCountingSimple,
GovernorVotes,
GovernorVotesQuorumFraction,
GovernorTimelockControl
{
constructor(IVotes _token, TimelockController _timelock)
Governor("AppGovernor")
GovernorSettings(7200, 50400, 0)
GovernorVotes(_token)
GovernorVotesQuorumFraction(4)
GovernorTimelockControl(_timelock)
{}
// Solidity requires resolving multiple inheritance for these:
function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) { return super.votingDelay(); }
function votingPeriod() public view override(Governor, GovernorSettings) returns (uint256) { return super.votingPeriod(); }
function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { return super.quorum(blockNumber); }
function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { return super.proposalThreshold(); }
function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { return super.state(proposalId); }
function proposalNeedsQueuing(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (bool) { return super.proposalNeedsQueuing(proposalId); }
function _queueOperations(uint256 pid, address[] memory ts, uint256[] memory vs, bytes[] memory cs, bytes32 d) internal override(Governor, GovernorTimelockControl) returns (uint48) { return super._queueOperations(pid, ts, vs, cs, d); }
function _executeOperations(uint256 pid, address[] memory ts, uint256[] memory vs, bytes[] memory cs, bytes32 d) internal override(Governor, GovernorTimelockControl) { super._executeOperations(pid, ts, vs, cs, d); }
function _cancel(address[] memory ts, uint256[] memory vs, bytes[] memory cs, bytes32 d) internal override(Governor, GovernorTimelockControl) returns (uint256) { return super._cancel(ts, vs, cs, d); }
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { return super._executor(); }
}
