Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
LABS
Guides

Setting Up On-Chain Voting Processes

A technical guide for developers implementing secure, on-chain voting systems for DAOs and DeFi protocols using standards like Governor and token-weighted voting.
Chainscore © 2026
introduction
IMPLEMENTATION GUIDE

Setting Up On-Chain Voting Processes

A technical walkthrough for developers implementing secure and functional on-chain voting systems using smart contracts.

On-chain voting is a core governance primitive for DAOs and decentralized protocols, enabling transparent, verifiable, and autonomous decision-making. Unlike off-chain signaling, votes are executed directly within smart contracts, with outcomes immutably recorded on the blockchain. This process typically involves creating a proposal, defining a voting period, allowing token holders to cast votes weighted by their stake, and automatically executing the proposal's logic upon successful passage. Popular frameworks like OpenZeppelin Governor and Compound's Governor Bravo provide standardized, audited base contracts that abstract much of this complexity, allowing developers to focus on customizing parameters such as quorum, voting delay, and voting period.

The first step is to define the voting token, which confers voting power. This is often an ERC-20 token or an ERC-721 token (for NFT-based governance). The voting contract must be able to query a user's balance at a specific historical block—typically the start of the voting period—to prevent manipulation via "token renting" or flash loans. This is achieved using the ERC-20Votes or ERC-721Votes extensions, which maintain a history of checkpoints for each account's balance. For example, OpenZeppelin's Governor contract uses the getVotes function to fetch a voter's power at a past block number, ensuring the snapshot is immutable once the proposal is created.

Next, you configure the core governance parameters. These include the votingDelay (blocks between proposal creation and voting start), votingPeriod (duration of the vote in blocks), proposalThreshold (minimum token power to submit a proposal), and quorum (minimum percentage of total voting power required for a proposal to be valid). Setting these requires careful consideration of your community's needs; a short votingPeriod may lead to rushed decisions, while a high quorum can cause governance paralysis. Many implementations express quorum as a function of the total token supply at the time of the proposal, using a quorum numerator over a fixed denominator.

Proposal execution is the final and most critical phase. A successful vote does not automatically change protocol state; it authorizes a set of encoded function calls (targets, values, calldatas) to be executed. This execution is usually permissioned to a TimelockController contract, which queues the proposal for a mandatory delay before execution. This delay provides a safety mechanism, allowing users to exit the system if they disagree with a passed proposal. The execution logic is contained in the governor contract's execute function, which reverts if the proposal hasn't succeeded or if the timelock delay hasn't elapsed.

Here is a minimal example using OpenZeppelin's Governor contracts in Solidity, deploying a governor with a 1-block voting delay, 45818-block voting period (~1 week on Ethereum), and a 4% quorum:

solidity
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/GovernorQuorumFraction.sol";

contract MyGovernor is Governor, GovernorSettings, GovernorVotes, GovernorQuorumFraction {
    constructor(IVotes _token)
        Governor("MyGovernor")
        GovernorSettings(1 /* 1 block */, 45818 /* 1 week */, 0)
        GovernorVotes(_token)
        GovernorQuorumFraction(4) // 4% quorum
    {}
    // ... Override required internal functions
}

This contract skeleton shows how modular extensions compose to build a full governor.

Security considerations are paramount. Always use audited frameworks and implement a timelock for all privileged actions. Be wary of vote manipulation vectors, including the use of flash loans to temporarily inflate voting power, which is mitigated by historical snapshots. Furthermore, consider gas costs for voters; simple yes/no voting is standard, but more complex voting types (like quadratic voting or ranked choice) can be prohibitively expensive on-chain. For complex governance, a common pattern is to conduct sentiment signaling off-chain using tools like Snapshot, followed by a simplified on-chain vote to authorize the execution of pre-agreed-upon transactions, blending efficiency with on-chain finality.

prerequisites
ON-CHAIN VOTING

Prerequisites and Tech Stack

A practical guide to the core technologies and tools required to build secure, transparent on-chain voting systems.

Building an on-chain voting system requires a foundational understanding of smart contract development and the specific blockchain you are targeting. The primary prerequisite is proficiency in a language like Solidity for Ethereum Virtual Machine (EVM) chains (e.g., Ethereum, Polygon, Arbitrum) or Rust for Solana or Cosmos-based chains. You'll need a development environment such as Hardhat, Foundry, or Truffle for EVM, or Anchor for Solana. These frameworks handle compilation, testing, and deployment, which are critical for ensuring the security and correctness of your voting logic before it goes live on a network.

The core tech stack extends beyond the smart contract itself. You must integrate with wallet providers like MetaMask or WalletConnect to authenticate voters and sign transactions. For the frontend, libraries such as ethers.js or web3.js (for EVM) or @solana/web3.js are essential for interacting with your deployed contract. A robust stack also includes indexing and querying tools like The Graph or Subsquid to efficiently fetch proposal data and vote tallies without scanning the entire blockchain, which is vital for user interfaces that display real-time results.

Security is paramount. Your development process must include comprehensive testing with tools like Hardhat's test suite, Foundry's Forge, or Mocha/Chai. Consider formal verification for critical logic. Furthermore, understanding gas optimization is crucial, as voting transactions should be affordable for participants. For governance tokens, adhere to standards like ERC-20 or ERC-1155 for fungible votes or ERC-721 for non-fungible, reputation-based voting. Always plan for upgradeability patterns (e.g., Transparent Proxy, UUPS) to fix bugs or add features, but design with caution to maintain decentralization and voter trust.

Finally, consider the broader ecosystem tools. Use IPFS or Arweave for storing proposal descriptions and related documents off-chain, linking them via on-chain hashes for permanence and censorship resistance. For automated execution of passed proposals, integrate with safe multisig wallets or DAO frameworks like OpenZeppelin Governor. Setting up a local testnet or using a service like Alchemy or Infura for RPC access is necessary for development and testing before deploying to a public testnet and eventually mainnet.

key-concepts-text
CORE GOVERNANCE CONCEPTS

Setting Up On-Chain Voting Processes

On-chain voting is the mechanism by which token holders directly execute governance decisions through smart contracts. This guide details the technical implementation of a basic voting system.

An on-chain voting process typically involves three core smart contract components: a proposal factory for creation, a voting vault for vote casting, and a timelock executor for secure execution. Proposals are stored as immutable data structures containing the target contract address, calldata for the function to execute, and a description hash. The most common voting standard is ERC-5805 (Governor), which provides a modular framework for vote delegation, vote tracking, and quorum logic. For example, OpenZeppelin's Governor contracts implement this standard and are used by protocols like Uniswap and Compound.

The voting lifecycle follows a strict sequence of states: Pending, Active, Succeeded/Defeated, Queued, and Executed. A proposal moves from Pending to Active after a delay, allowing for community review. During the Active period, which often lasts 3-7 days, token holders cast votes weighted by their balance. Votes can be cast directly or via delegation, where a user assigns their voting power to another address. The contract tallies votes using a COUNTING_MODE (e.g., support=for/against/abstain) and checks against a quorum threshold, a minimum percentage of total supply that must participate for the vote to be valid.

Security is paramount. A timelock contract introduces a mandatory delay between a proposal's success and its execution, giving users a final window to exit the system if they disagree with the outcome. Proposal thresholds prevent spam by requiring a minimum token balance to submit a proposal. When writing integration code, you must account for the voting delay and voting period when checking a proposal's state. Always verify the proposal's calldata on a testnet before mainnet execution to ensure it performs the intended action, as executed proposals are irreversible.

COMMON IMPLEMENTATIONS

On-Chain Governance Framework Comparison

A comparison of popular smart contract frameworks for building on-chain governance systems, based on deployment patterns from major DAOs.

Governance FeatureOpenZeppelin GovernorCompound Governor BravoAragon OSx

Core Contract Architecture

Modular, upgradeable

Monolithic, forkable

Plugin-based, upgradeable

Voting Token Standard

ERC-20, ERC-721, ERC-1155

ERC-20 (COMP-style)

ERC-20, Native Gas Token

Proposal Lifecycle Stages

CreatedActiveCanceledDefeatedSucceededQueuedExpiredExecuted
CreatedActiveCanceledDefeatedSucceededQueuedExpiredExecuted
SetupActiveClosedExecutedFailed

Built-in Timelock

Gas-Optimized Voting (Snapshot-style)

Default Proposal Threshold

1 token

65,000 COMP (configurable)

Configurable, often 0.1% supply

Default Quorum

4% of total supply (configurable)

400,000 COMP (configurable)

Configurable, dynamic models

Average Gas Cost for Proposal Creation

$150-300

$200-400

$80-200 (with gasless voting)

implementation-steps
IMPLEMENTATION GUIDE

Setting Up On-Chain Voting Processes

A technical walkthrough for developers to implement secure and functional on-chain voting using smart contracts.

On-chain voting allows token holders to participate directly in a protocol's governance by casting votes recorded immutably on the blockchain. The core mechanism is a smart contract that manages proposal creation, vote casting, tallying, and execution. Unlike off-chain signaling, on-chain votes are binding and can automatically trigger actions like treasury transfers or parameter updates. This guide outlines the key steps to implement a basic but secure voting system using Solidity and OpenZeppelin's governance libraries, focusing on a simple token-weighted model.

The first step is to define the voting token, which determines voting power. This is typically an ERC-20 or ERC-721 token. For a fungible token system, you can use OpenZeppelin's ERC20Votes extension, which provides vote delegation and tracks historical balances to prevent double-voting. Deploy your voting token contract first. Next, you'll need the governance contract itself. A standard approach is to extend OpenZeppelin's Governor contract. Initialize it with parameters like votingDelay (blocks between proposal and voting start), votingPeriod (duration of the vote), and quorum (minimum participation required for a proposal to pass).

Proposal creation is the next phase. Users with sufficient proposal threshold (e.g., a minimum token balance) can call propose on the Governor contract, submitting a list of target addresses, values, and calldata for the actions to execute if the proposal passes. The contract will emit a ProposalCreated event. After the votingDelay, voters can cast their vote using the castVote function, specifying the proposal ID and their support (e.g., For, Against, Abstain). The contract uses the getVotes function from the token contract to determine the voter's power at the proposal's snapshot block.

Once the votingPeriod ends, anyone can call the queue function for successful proposals (those with more For than Against votes and meeting quorum). This moves the proposal to a Timelock queue, a critical security feature that enforces a mandatory delay before execution, giving users time to react to malicious proposals. After the timelock expires, the execute function can be called to run the proposed on-chain actions. Always implement a TimelockController (also provided by OpenZeppelin) as the executor for your Governor contract. This separates the proposal power from immediate execution power.

Testing is crucial. Use a framework like Hardhat or Foundry to simulate the entire governance lifecycle: token delegation, proposal creation, voting across multiple accounts, queuing, and execution. Write tests for edge cases, such as attempting to vote twice, executing a failed proposal, or testing quorum logic. For front-end integration, you'll need to index proposal and vote data. Use The Graph to create a subgraph that indexes events from your Governor and token contracts, making it easy to query active proposals, voter history, and results for display in a dApp interface.

Consider advanced patterns for production systems. These include vote delegation interfaces, gasless voting via meta-transactions using EIP-712 signatures, quadratic voting to reduce whale dominance, and optimistic governance for faster execution on L2s. Security audits are non-negotiable before mainnet deployment. Always refer to the official OpenZeppelin Governor documentation for the latest best practices and contract variants like GovernorCountingSimple or GovernorVotesQuorumFraction.

CONFIGURATION COMPARISON

Voting Parameter Optimization

Key on-chain voting parameters and their impact on security, participation, and governance efficiency.

ParameterConservative (Security-First)Balanced (Default)Aggressive (High Activity)

Voting Delay

7 days

2 days

1 day

Voting Period

14 days

7 days

3 days

Proposal Threshold

1% of supply

0.5% of supply

0.1% of supply

Quorum Requirement

10% of supply

4% of supply

2% of supply

Timelock Delay

7 days

3 days

1 day

Emergency Proposal Support

Vote Snapshot Block Offset

10 blocks

1 block

0 blocks

Proposal Max Operations

10
20
30
ON-CHAIN VOTING

Security Considerations and Audits

On-chain voting introduces unique attack vectors and governance risks. This guide addresses common security pitfalls and developer questions for building robust, auditable voting systems.

On-chain voting systems face several critical security risks that developers must mitigate.

Vote Manipulation: Attackers can exploit flash loans to borrow large amounts of governance tokens, cast votes, and repay the loan within a single transaction, skewing results without holding long-term stake.

Timing Attacks: The "time bomb" or "block stuffing" attack involves miners/validators manipulating block timestamps or transaction ordering to extend or shorten voting periods.

Sybil Attacks: While token-weighted voting reduces this risk, one-token-one-vote systems are highly vulnerable to fake identity creation.

Governance Capture: A single entity accumulating over 50% of voting power can pass malicious proposals. This is a centralization risk, not a code flaw, but the system design must account for it.

Implementation Bugs: Flaws in the vote counting logic, proposal state machine, or privilege escalation in timelock controllers can lead to fund theft or unauthorized execution.

integrating-off-chain-tools
INTEGRATING OFF-CHAIN TOOLS

Setting Up On-Chain Voting Processes

A guide to implementing secure and efficient on-chain voting by integrating off-chain tools for proposal creation, discussion, and verification.

On-chain voting is a core governance mechanism for DAOs and decentralized protocols, allowing token holders to execute binding decisions like treasury allocations or parameter changes. However, conducting the entire process on-chain is inefficient and expensive. A standard workflow integrates off-chain tools for the proposal lifecycle before a final on-chain transaction. This typically involves using a forum like Discourse or Commonwealth for discussion, a snapshot tool for off-chain signaling, and finally an on-chain voting contract (e.g., OpenZeppelin Governor) for execution. This hybrid model reduces gas costs for participants and allows for richer deliberation.

The first step is setting up an off-chain signaling platform. Snapshot is the most widely used tool, enabling gas-free voting on proposals using wallet signatures. Integration involves creating a space for your organization, connecting it to your ERC-20 or ERC-721 token for voting power, and defining voting strategies (e.g., token-weighted, quadratic). Proposals are posted here after community discussion. This off-chain vote does not change blockchain state but provides a crucial signal of community sentiment and helps filter out poorly conceived proposals before they incur on-chain gas fees.

For the on-chain execution layer, you need a smart contract system. The OpenZeppelin Governor contracts provide a modular, audited standard. The core contract manages proposal state (Pending, Active, Defeated, Succeeded, Executed), voting periods, and quorum requirements. You must configure key parameters: votingDelay (blocks between proposal and vote start), votingPeriod (duration of the vote), and proposalThreshold (minimum tokens needed to submit). The Governor contract interacts with a TimelockController to queue and execute successful proposals after a delay, adding a critical security check.

Connecting the off-chain signal to the on-chain proposal requires a relayer or a dedicated proposer address. A common pattern is for a community-elected multisig or a designated proposer role to monitor the Snapshot results. If a proposal passes the off-chain vote with sufficient support, the proposer calls the propose function on the Governor contract, submitting the target contract addresses, calldata, and description. This transaction puts the proposal into the on-chain voting period. Tools like Tally or Sybil can help delegate voting power and provide interfaces for casting on-chain votes.

Security considerations are paramount. The timelock between a vote passing and execution allows users to exit systems if they disagree with the outcome. Always use contract audits for custom voting logic. Beware of vote manipulation via token borrowing (flash loans) during the snapshot block; mitigate this by using time-weighted average balances or vote escrow tokens. Furthermore, ensure your off-chain discussion forum is resistant to sybil attacks, potentially integrating with Proof of Humanity or similar systems for important governance decisions.

ON-CHAIN VOTING

Frequently Asked Questions

Common technical questions and solutions for developers implementing on-chain voting systems, covering smart contract patterns, gas optimization, and security considerations.

Token-weighted voting grants voting power proportional to the number of governance tokens a user holds (1 token = 1 vote). This is simple to implement but can lead to plutocracy.

Quadratic voting (QV) aims to reduce this by making the cost of votes increase quadratically. A user with n tokens can cast sqrt(n) votes. This makes it more expensive for a single entity to dominate. Implementing QV requires:

  • Calculating vote cost using voteCost = (votesDesired ** 2)
  • Managing a credit or token spending mechanism
  • Significant gas overhead for complex math operations

Protocols like Gitcoin Grants use quadratic funding, a related concept, to match community contributions.

conclusion
IMPLEMENTATION REVIEW

Conclusion and Next Steps

This guide has covered the core components of building a secure and functional on-chain voting system. The next steps involve testing, deployment, and exploring advanced governance patterns.

You have now implemented the foundational elements of an on-chain voting process: a GovernanceToken for voting power, a Governor contract to manage proposals, and a TimelockController for secure execution. The key to a robust system is rigorous testing. Use a forked mainnet environment with tools like Foundry or Hardhat to simulate real-world conditions. Test edge cases such as proposal cancellation, quorum changes, and malicious delegate voting. Consider using Tenderly or OpenZeppelin Defender to monitor and automate governance actions post-deployment.

For production deployment, security audits are non-negotiable. Engage with reputable auditing firms and consider a bug bounty program on platforms like Immunefi. Start with a conservative configuration: a high quorum (e.g., 4% of total supply), a long voting delay (e.g., 2 days), and a substantial voting period (e.g., 5 days). These parameters can be adjusted via governance itself as the community matures. Use a multisig wallet or the Timelock as the contract owner during initial setup to mitigate centralization risks.

To evolve your governance system, explore advanced patterns. Implement vote delegation with ERC20Votes and ERC20VotesComp for gas-efficient snapshot voting. Consider gasless voting via meta-transactions with a relayer or integrating with Snapshot for off-chain signaling with on-chain execution. For more complex decision-making, research quadratic voting or conviction voting models. Continuously engage with your community through forums and governance portals like Tally or Boardroom to ensure transparent and participatory governance.

How to Set Up On-Chain Voting for DAOs and DeFi Protocols | ChainScore Guides