Skip to content
Contract · Governance

Governor DAO

On-chain governance backed by ERC20Votes token with timelock-guarded execution.

All templates
DAO
Audited base
~3.8M gas
Ethereum
Post-deploy checklist
  1. Confirm votes token is ERC20Votes and holders have self-delegated
  2. Deploy Timelock first; pass its address here
  3. Set votingDelay / votingPeriod / quorum for your chain’s block times
  4. Grant Timelock PROPOSER to this Governor; revoke leftover admin keys
  5. Transfer treasury / Ownable roles to the Timelock, not an EOA
  6. 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(); }
}