Token-based governance is a mechanism where voting power is proportional to a user's token holdings, enabling decentralized decision-making for protocol upgrades, treasury management, and parameter changes. This framework is foundational for DAOs (Decentralized Autonomous Organizations) and is implemented by protocols like Uniswap, Compound, and Aave. The core components typically include a governance token, a timelock controller for executing passed proposals, and a governor contract that manages proposal lifecycle and voting logic. Setting this up requires careful consideration of key parameters like voting delay, voting period, proposal threshold, and quorum requirements to balance security with participation.
Setting Up a Token-Based Governance Framework
Setting Up a Token-Based Governance Framework
A technical walkthrough for deploying and configuring a token-based governance system using popular smart contract frameworks.
The most efficient way to implement governance is by using audited, battle-tested frameworks. OpenZeppelin Contracts provides a modular library of secure Governor contracts. A basic setup involves deploying three contracts: your ERC-20 Votes token, a Governor contract (e.g., GovernorBravo-style or GovernorCountingSimple), and a TimelockController. The token must implement the IVotes interface to allow for snapshot-based voting, which prevents double-spending of voting power. The governor contract is configured with the token address as the voting token and the timelock as the executor. Critical initialization parameters include setting a votingDelay (blocks before voting starts), a votingPeriod (blocks voting is open), and a proposalThreshold (minimum tokens needed to submit a proposal).
Here is a simplified example of deploying a governance system using Hardhat and OpenZeppelin:
javascriptconst { ethers } = require("hardhat"); async function deployGovernance() { // 1. Deploy the governance token const Token = await ethers.getContractFactory("MyVotesToken"); const token = await Token.deploy(); // 2. Deploy the Timelock Controller const Timelock = await ethers.getContractFactory("TimelockController"); const timelock = await Timelock.deploy(3600, [], []); // 1 hour min delay // 3. Deploy the Governor const Governor = await ethers.getContractFactory("GovernorContract"); const governor = await Governor.deploy( token.address, timelock.address, 1, // voting delay (1 block) 45818, // voting period (~1 week) 1000000000000000000n // proposal threshold (1 token) ); // 4. Setup roles: Grant the governor the 'PROPOSER_ROLE' on the timelock const PROPOSER_ROLE = await timelock.PROPOSER_ROLE(); await timelock.grantRole(PROPOSER_ROLE, governor.address); }
After deployment, token holders can delegate their voting power and create proposals to execute arbitrary calls through the timelock.
Post-deployment, you must establish clear governance processes. This includes creating a forum (like Discourse or Commonwealth) for discussion, a snapshot page for off-chain signaling, and documentation for proposal standards. Security is paramount: the timelock delay allows the community to react to malicious proposals, and a multisig or guardian role is often retained initially to pause the system in an emergency. It's also crucial to decide on vote aggregation methods—options include simple majority, weighted voting, or quadratic voting to mitigate whale dominance. Regularly audit proposal calldata and consider implementing a veto or cancel function guarded by a trusted entity in the early stages of the protocol.
Real-world examples provide valuable templates. Compound's Governor Bravo introduced a formal proposal lifecycle with states like Pending, Active, Canceled, Defeated, Succeeded, Queued, and Expired. Uniswap uses a delegated voting model where users can delegate to representatives, separating token ownership from active governance participation. When setting quorum, analyze historical voter turnout; setting it too high can lead to governance paralysis, while setting it too low risks attacks. Tools like Tally and Boardroom offer user-friendly interfaces for interacting with deployed governor contracts, tracking proposals, and delegating votes, which are essential for broad community participation.
The final step is testing the governance lifecycle end-to-end in a forked mainnet environment or a testnet. Simulate proposal creation, voting, queuing via the timelock, and execution. Monitor gas costs for critical functions, as they can be prohibitively high. Remember that on-chain governance is immutable and carries significant risk; all logic, including upgrade paths for the governor itself, must be carefully considered at deployment. For further learning, review the OpenZeppelin Governor documentation and the source code for live implementations like Compound Governor Bravo.
Prerequisites
Before implementing a token-based governance system, you need to establish the foundational technical and conceptual components. This guide covers the essential prerequisites.
A token-based governance framework requires a governance token as its core voting mechanism. This is typically an ERC-20 token on Ethereum or a similar standard on other EVM-compatible chains like Arbitrum or Polygon. The token's distribution model—whether through a fair launch, airdrop, or vested allocation—directly impacts decentralization and voter turnout. You must decide if the token will have additional utility (e.g., staking, fee discounts) or be purely for governance, as this affects economic incentives and attack vectors.
You will need a smart contract to manage proposal creation, voting, and execution. Most projects build upon or fork established governance platforms like OpenZeppelin Governor, Compound's Governor Bravo, or Aave's governance v2. These provide battle-tested contracts for core functions: a TimelockController for secure, delayed execution; a voting token interface; and logic for proposal lifecycle states (Pending, Active, Defeated, Succeeded, Executed). Understanding these contracts' upgradeability patterns and security assumptions is critical.
For on-chain execution, integrate a Timelock contract. This adds a mandatory delay between a proposal's approval and its execution, giving token holders a final window to exit the system if they disagree with a passed proposal. The Timelock becomes the owner of the protocol's core contracts, ensuring only queued transactions from the governance module can execute. Set the delay period (e.g., 24-72 hours) based on your security-composability trade-off.
Define your voting parameters upfront, as they are hard to change later. Key parameters include: votingDelay (blocks between proposal submission and voting start), votingPeriod (duration of the voting window), proposalThreshold (minimum token balance to submit a proposal), and quorum (minimum percentage of circulating supply required for a vote to be valid). These settings dictate governance agility and resistance to takeover.
Establish an off-chain infrastructure for community discussion and signaling before proposals reach the chain. Tools like Snapshot for gasless voting, Discourse forums, and Commonwealth are standard. This layer is crucial for gauging sentiment, refining proposals, and achieving rough consensus, which prevents network spam from frivolous on-chain proposals and reduces voter fatigue.
Finally, prepare a testing and deployment strategy. Use a local fork of a mainnet (with Hardhat or Foundry) to simulate governance actions end-to-end. Deploy first to a testnet like Goerli or Sepolia, and consider using a bridged token or mintable test token to simulate real voting. Document the governance process clearly for your community, including step-by-step guides for creating and voting on proposals using wallets like MetaMask.
Setting Up a Token-Based Governance Framework
A practical guide to the essential smart contracts and parameters required to launch a decentralized, token-based governance system on Ethereum and EVM-compatible chains.
A token-based governance framework is built on three core smart contracts: the governance token, the governor contract, and the timelock controller. The governance token, typically an ERC-20 or ERC-20Votes variant, represents voting power and is distributed to the community. The governor contract, such as OpenZeppelin's Governor, is the primary engine; it defines the rules for proposal creation, voting, and execution. The timelock controller acts as a secure, programmable multisig that queues and executes successful proposals after a mandatory delay, providing a critical security checkpoint for treasury or parameter changes.
The governor contract is configured through several key parameters that define the governance process. Voting delay is the number of blocks between proposal submission and the start of voting. Voting period sets how long voting remains open, typically 3-7 days in block time. Proposal threshold is the minimum token balance required to submit a proposal. Quorum defines the minimum number of votes (often a percentage of total token supply) required for a proposal to pass. These parameters must be carefully calibrated to balance security, efficiency, and participation.
Here is a basic example of deploying a Governor contract using OpenZeppelin's modular system, combining the OZ Governor, a token with vote tracking (ERC20Votes), and a TimelockController. This setup uses a majority voting strategy with a 4-day voting period and a 1-day timelock delay.
solidity// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/governance/Governor.sol"; import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol"; import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; contract MyGovernor is Governor, GovernorSettings, GovernorVotes, GovernorTimelockControl { constructor(IVotes _token, TimelockController _timelock) Governor("MyGovernor") GovernorSettings(1 /* 1 block voting delay */, 28800 /* ~4 day voting period */, 0 /* proposal threshold */) GovernorVotes(_token) GovernorTimelockControl(_timelock) {} // Override required functions... }
After deployment, the governance lifecycle begins. A user with sufficient tokens submits a proposal, which is a calldata bundle targeting specific contracts with encoded function calls. After the voting delay, token holders cast votes weighted by their balance. Proposals pass if they meet quorum and achieve a majority for votes. Successful proposals are then queued in the timelock. After the delay expires, anyone can execute the proposal, triggering the predefined on-chain actions. This entire flow is transparent and immutable, with events emitted at each stage for off-chain tracking.
Key security considerations include setting a meaningful proposal threshold to prevent spam, a sufficient timelock delay (e.g., 2-7 days) to allow community reaction to malicious proposals, and a quorum that ensures meaningful participation. For treasury management, it's critical that the timelock holds the assets, not the governor contract itself. Always use audited, standard libraries like OpenZeppelin Governor and conduct thorough testing on a testnet with a full governance cycle before mainnet deployment. Real-world examples include Uniswap, which uses a similar OZ-based GovernorAlpha/GovernorBravo system, and Compound's Governor Bravo.
Essential Resources and Tools
Key tools, protocols, and design components for implementing a token-based governance framework in production. Each resource focuses on a concrete step, from onchain voting logic to proposal lifecycle management and voter participation.
Token Distribution and Voting Power Design
A token-based governance framework is only as robust as its token distribution model. Poor initial allocation can lead to governance capture or inactive voting.
Key design decisions:
- Initial supply allocation between team, investors, treasury, and community
- Use of vesting contracts to delay voting power concentration
- Delegation mechanics to improve voter turnout
- Quorum and proposal thresholds aligned with circulating supply
Common pitfalls:
- Setting quorum too high, resulting in stalled governance
- Allowing instant voting power for unlocked team tokens
- Ignoring delegation UX, leading to <10% voter participation
Best practice is to simulate governance scenarios using real supply schedules and expected participation rates before deployment. Many mature DAOs iterate these parameters over multiple governance upgrades.
On-Chain vs. Off-Chain Voting Mechanisms
Key technical and operational differences between on-chain and off-chain governance models for DAOs.
| Feature | On-Chain Voting | Off-Chain Voting (Snapshot) |
|---|---|---|
Vote Execution | Transactions executed automatically by smart contracts. | Votes are signals; execution requires a separate, trusted transaction. |
Finality & Immutability | ||
Gas Costs | Voters pay gas for each proposal and vote. | Gasless for voters; costs borne by proposal creator or relayer. |
Voting Speed | Block time dependent (e.g., ~12s Ethereum, ~2s Polygon). | Instant; limited only by frontend and indexing speed. |
Voter Sybil Resistance | Based on token holdings or delegated stake at block height. | Relies on token snapshot at a specific block; vulnerable to token borrowing. |
Typical Use Case | Direct treasury control, parameter changes. | Community sentiment, signaling, high-frequency polls. |
Integration Complexity | High; requires custom or forked governance contracts. | Low; uses existing Snapshot space with strategy plugins. |
Security Model | Inherits blockchain security; vulnerable to contract bugs. | Depends on the security of the Snapshot platform and IPFS. |
Step 1: Designing the Governance Token
The governance token is the core instrument of your DAO, defining membership, voting power, and economic alignment. This step covers the critical design decisions for its distribution, utility, and technical implementation.
A governance token is more than a voting credential; it is a coordination mechanism that aligns incentives and delegates decision-making authority. Its design directly impacts the DAO's security, decentralization, and long-term viability. Key initial decisions include the token's total supply, its initial distribution (e.g., via a fair launch, pre-mine, or airdrop), and its underlying standard—most commonly an ERC-20 token on Ethereum or an equivalent on other EVM-compatible chains like Arbitrum or Optimism. The choice of blockchain affects gas costs, voter accessibility, and the ecosystem of supporting tools.
Token utility extends beyond governance votes. Consider embedding fee-sharing mechanisms, where protocol revenue is distributed to token holders, or staking models that require locking tokens to participate in governance, which can reduce supply volatility and encourage long-term commitment. The voting power calculation must also be defined: will it be one-token-one-vote, or will it incorporate time-locked boosts as seen in models like veTokenomics (e.g., Curve Finance)? This decision influences whether power is concentrated among whales or distributed to committed, long-term holders.
The technical implementation involves writing and deploying the smart contract. A basic governance token contract using OpenZeppelin's libraries provides standard functionality with security best practices baked in. For example, a minimal ERC-20 with snapshot capabilities (using ERC20Snapshot) allows for voting on historical token balances, preventing manipulation by buying tokens just before a vote. Here's a simplified contract outline:
solidityimport "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol"; contract GovernanceToken is ERC20Snapshot { constructor(uint256 initialSupply) ERC20("DAO Token", "DAO") { _mint(msg.sender, initialSupply); _snapshot(); // Take an initial snapshot } }
Initial distribution is a pivotal and often contentious phase. A common model allocates tokens to: - core contributors for early work, - treasury for future grants and incentives, - community members via an airdrop or liquidity mining program, and - investors if applicable. Transparency about these allocations is critical for trust. Tools like Token Distributor contracts or platforms like Sablier for streaming distributions can automate and enforce vesting schedules, ensuring contributors are aligned with the DAO's multi-year trajectory rather than short-term token price.
Finally, consider the token's legal and regulatory landscape. While a pure governance token with no expectation of profit might have different implications, any attached financial rights (like revenue share) increases regulatory scrutiny. Consulting with legal experts familiar with jurisdictions like Switzerland or the Cayman Islands, which have clearer frameworks for decentralized entities, is advisable. The design choices made here form the immutable foundation of your DAO's political and economic system, making thorough planning essential before proceeding to the next step: deploying the governance framework.
Step 2: Building the Proposal Contract
This step implements the core smart contract that allows token holders to create and vote on governance proposals. We'll build a `TokenVoting` contract that integrates with your ERC-20 token.
The TokenVoting contract is the central hub for your DAO's governance. It manages the proposal lifecycle—from creation and voting to execution. We'll inherit from OpenZeppelin's Governor contracts, which provide a secure, audited foundation. Key parameters you must define include the votingDelay (time between proposal creation and voting start) and votingPeriod (duration votes are accepted). A common setup is a 1-block delay and a 3-day voting period, configured as 1 and 45818 blocks (assuming ~13.2 second block time).
The most critical function is createProposal, which allows a user to submit an on-chain action. This function takes parameters like the target contract address, the amount of ETH to send, the calldata for the function call, and a description. The contract uses the propose function from OpenZeppelin Governor, which automatically snapshots voting power at the proposal creation block. This prevents users from buying tokens just to vote on a live proposal. Only addresses holding more than a proposalThreshold (e.g., 1% of total supply) can create proposals.
Voting logic is implemented in the _countVote function. We will configure it to use the GovernorVotesQuorumFraction module, which bases quorum on a percentage of the total token supply. For example, setting a 4% quorum means at least 4% of all tokens must participate for a vote to be valid. Votes are weighted by token balance, following the one-token-one-vote principle. Voters can typically choose: For, Against, or Abstain. The voting power is calculated from the token snapshot taken when the proposal was created.
After the voting period ends, anyone can call the execute function to carry out the proposal's actions if it succeeded. Execution requires the proposal to meet two conditions: it must have reached quorum, and more votes must be For than Against. The contract will then make the encoded function call to the target address. It's crucial that all state-changing logic for the DAO (like treasury transfers or parameter updates) is only accessible through this governance contract, ensuring community control.
Here is a minimal constructor example for the TokenVoting contract:
solidityconstructor(IVotes _token) Governor("MyDAOGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) // 4% quorum { // Set voting parameters (in blocks) votingDelay = 1; votingPeriod = 45818; // ~3 days proposalThreshold = 1000e18; // 1000 tokens }
This setup initializes the governor with your token, a 4% quorum, and specific timing rules.
Finally, you must ensure your ERC-20 token implements the IVotes interface (OpenZeppelin's ERC20Votes). This extension provides the snapshot functionality for vote delegation and historical balance lookups. Once deployed, the TokenVoting contract address becomes the DAO's primary executive, and ownership of other core contracts (like the Treasury) should be transferred to it. The next step will involve building a frontend interface to interact with these proposals.
Step 3: Implementing Voting Logic
This section details the implementation of the core voting and proposal execution logic within a Solidity smart contract, covering proposal lifecycle, vote casting, and state transitions.
The heart of any governance system is its voting logic, which determines how proposals are created, voted on, and executed. In a token-based framework, this is typically implemented in a smart contract that manages the proposal lifecycle. A standard implementation involves defining a Proposal struct containing fields like id, proposer, targets, values, calldatas, startBlock, endBlock, forVotes, againstVotes, abstainVotes, and executed. The contract state transitions a proposal through stages: Pending, Active, Succeeded/Defeated, Queued, and Executed. Key functions include propose() to create a new proposal, castVote() for token holders to vote, and execute() to carry out the proposal's actions if it passes.
Vote casting must account for the voter's token balance, often using a snapshot mechanism to prevent manipulation. A common pattern is to record votes based on the number of tokens held at a specific block number (e.g., the proposal creation block). The castVote function signature might look like: function castVote(uint256 proposalId, uint8 support) external. The support parameter is an integer where 1 = For, 0 = Against, and 2 = Abstain. The contract logic adds the voter's token weight to the respective tally, ensuring each address can only vote once per proposal. It's critical to implement checks for reentrancy and ensure the voter has not delegated their voting power elsewhere.
Determining if a proposal passes involves evaluating the vote totals against predefined thresholds after the voting period ends. A standard quorum requirement might be that a minimum percentage of the total token supply must participate. The victory condition is then typically a simple majority of forVotes over againstVotes (abstentions often do not affect the outcome). The contract's state() function returns the current status by performing these calculations. For execution, successful proposals often have a timelock delay, implemented via a separate TimelockController contract (like OpenZeppelin's), which queues and executes transactions after a mandatory waiting period. This delay is a critical security feature, allowing users to react to malicious proposals.
Here is a simplified code snippet illustrating the core voting logic structure using Solidity and OpenZeppelin's governance contracts as a foundation:
solidityimport "@openzeppelin/contracts/governance/Governor.sol"; import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol"; contract MyGovernor is Governor, GovernorSettings { constructor(IVotes _token) Governor("MyGovernor") GovernorSettings(7200 /* 1 day */, 50400 /* 1 week */, 0) {} function quorum(uint256 blockNumber) public pure override returns (uint256) { return 1000e18; // Example: 1000 token quorum } function votingDelay() public view override returns (uint256) { /*...*/ } function votingPeriod() public view override returns (uint256) { /*...*/ } function proposalThreshold() public view override returns (uint256) { /*...*/ } }
This contract inherits from OpenZeppelin's battle-tested Governor base, which handles much of the complex lifecycle management, allowing developers to focus on configuring parameters like votingDelay, votingPeriod, and quorum.
When implementing custom logic, consider edge cases such as: - Vote delegation: How does the contract handle tokens that have been delegated for voting? - Gas optimization: Can you use uint256 packing for proposal state to reduce storage costs? - Upgradeability: Is the governance contract upgradeable, and if so, how are upgrades themselves governed? - Cross-chain governance: For protocols deployed on multiple chains, will you use a hub-and-spoke model or individual DAOs per chain? Testing is paramount; use a framework like Foundry or Hardhat to simulate proposal creation, voting across multiple addresses, and execution with mocked target contracts to ensure the system behaves as intended under all conditions.
Step 4: Adding Execution and Timelock
This step moves governance proposals from voting to action by implementing the execution logic and a security delay mechanism.
After a proposal passes a vote, it must be executed on-chain to enact its changes. The execution function is the core logic that translates a proposal's intent into a concrete blockchain transaction. Typically, this involves calling a function on a target contract with specific calldata. For a token-based governor, the execution logic validates that the proposal is in the correct state (e.g., Succeeded), checks that the msg.sender has the right to execute (often the governor contract itself), and then uses a low-level call to the target address. A critical security pattern here is to store the proposal's target, value, and calldata in a struct when the proposal is created, ensuring execution is deterministic and cannot be altered post-vote.
A timelock is a security module that introduces a mandatory delay between a proposal's approval and its execution. This delay is a defense mechanism, providing a "cooling-off" period during which token holders can react to a malicious or faulty proposal. If a harmful proposal passes, holders have time to exit the protocol or prepare a defensive action before the changes take effect. In practice, the timelock contract sits between the governor and the protocol's core contracts. The governor does not execute directly on the target; instead, it schedules an operation on the timelock, which executes it after the delay elapses. Popular implementations include OpenZeppelin's TimelockController and Compound's Timelock.
Integrating a timelock modifies the governance flow. The governor contract must be configured as a proposer for the timelock, and the timelock contract must be set as the executor for the governor. When a proposal passes, the governor's execute function calls timelock.scheduleBatch() (for multiple actions) or timelock.schedule(), passing the target, value, and calldata. After the delay (e.g., 48 hours), anyone can call timelock.execute() to carry out the operation. This separation of powers ensures no single entity, not even the governor contract, can immediately execute arbitrary code, significantly raising the security bar for the entire protocol.
Here is a simplified code snippet showing a governor's execution function that interacts with a timelock. This example assumes the use of OpenZeppelin's Governor and TimelockController contracts.
solidityfunction execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public payable override { // Require the proposal is in a state that allows execution require(state(proposalId) == ProposalState.Succeeded, "Governor: proposal not successful"); // Schedule the operation on the timelock timelock.scheduleBatch( targets, values, calldatas, 0, // predecessor (for dependency management) salt, // unique identifier for the operation MIN_DELAY // the enforced timelock delay ); // Mark the proposal as executed in the governor's state _proposals[proposalId].executed = true; }
After this function is called, the actual execution must wait for the MIN_DELAY to pass before anyone can call the corresponding timelock.execute function.
When designing your timelock, key parameters must be carefully chosen. The delay period is the most critical: too short (e.g., 1 hour) offers little protection, while too long (e.g., 30 days) can hamper protocol agility. For major DeFi protocols, delays commonly range from 2 to 7 days. The grace period is also important; this is the window of time after the delay during which the operation can be executed before it expires. OpenZeppelin's default is 14 days. Furthermore, consider role-based access: the timelock should have an admin role (often a multi-sig for emergency purposes) that can cancel pending operations or adjust roles, but this power should be used extremely sparingly to maintain trust in the decentralized process.
Completing this step finalizes the core lifecycle of an on-chain proposal: Propose → Vote → Queue (in timelock) → Execute. The addition of a timelock transforms your governance framework from a simple voting mechanism into a robust, time-tested system that protects against rushed or malicious upgrades. The next steps typically involve front-end integration, creating proposal creation interfaces, and setting up off-chain infrastructure like a Snapshot page for gas-free signaling or a Tally dashboard for proposal tracking and delegation management.
Critical Governance Parameters and Defaults
Key on-chain parameters that define the behavior of a token-based governance system, with common default values from protocols like Compound, Uniswap, and Aave.
| Parameter | Purpose | Typical Default | Range / Considerations |
|---|---|---|---|
Voting Delay | Time between proposal submission and voting start | 1 day | 0-7 days. Longer delays allow for voter education. |
Voting Period | Duration of the active voting window | 3 days | 1-14 days. Balances urgency with participation. |
Proposal Threshold | Minimum token balance required to submit a proposal | 0.25% of supply | 0.1%-1%. Higher thresholds reduce spam. |
Quorum | Minimum percentage of total supply that must vote for a proposal to be valid | 4% | 1%-20%. Critical for legitimacy; often adjusts dynamically. |
Timelock Delay | Delay between a proposal passing and execution | 2 days | 0-14 days. Provides a safety window for review. |
Vote Differential | Margin by which "For" votes must exceed "Against" | Simple majority (>50%) | Can be set higher (e.g., 67%) for major changes. |
Emergency Proposal Period | Shorter voting period for urgent actions | Typically 24-48 hours if enabled. Requires higher quorum. | |
Delegation | Ability for token holders to delegate voting power | Fundamental for representative governance. |
Common Pitfalls and FAQ
Addressing frequent technical hurdles and conceptual questions developers face when implementing on-chain governance with tokens.
This is often caused by a mismatch between the token's totalSupply() and the actual circulating, transferable supply used for voting. Common culprits include:
- Tokens in non-participating contracts: Tokens held in DEX liquidity pools, vesting contracts, or multi-sig wallets that don't delegate voting power.
- Misconfigured snapshot block: If your governance system uses a snapshot (like OpenZeppelin's
GovernorVotes), ensure the snapshot block number is set before voting starts, not after. Votes are calculated from token balances at that historical block. - Lack of delegation: With ERC20Votes-based systems, holders must actively delegate voting power to themselves or another address. An undelegated balance has zero voting weight.
Fix: Audit token holdings. Use getVotes(account) from the token contract to check an address's voting power, not balanceOf(account).
Conclusion and Next Steps
You have now explored the core components of a token-based governance framework. This section outlines the final steps to launch your system and resources for further development.
Before launching your governance framework, conduct a final audit of your smart contracts. This includes a security review by a reputable firm and a thorough test of all governance functions on a testnet. Key actions to verify are: - Vote delegation and snapshot mechanics - Proposal creation, voting, and execution flows - Quorum and vote threshold calculations - Timelock and execution delay enforcement. Use tools like Tenderly or Hardhat to simulate complex multi-step proposals and edge cases.
A successful governance launch requires clear documentation and community onboarding. Create a governance portal that explains the proposal process, voting power calculation, and key contracts like the Governor and Token. Publish tutorials for common actions: creating a proposal, delegating votes, and understanding the treasury. Establish communication channels on forums like Discord or Commonwealth to foster discussion. Transparent documentation reduces friction and increases participation.
Governance is not static. After launch, monitor key metrics: voter turnout, proposal frequency, and delegation patterns. Consider implementing governance upgrades, such as moving from a simple majority to quadratic voting or adding a security council for emergency actions. Explore advanced modules like OpenZeppelin's Governor Contracts, which offer pre-audited functionality for vote delegation, timelocks, and gas optimization. The goal is to create a living system that evolves with your protocol's needs and community input.