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

Setting Up On-Chain Voting for Funding Proposals

A technical guide to implementing a secure and gas-efficient on-chain voting system for DAO treasury expenditure proposals, from contract selection to execution.
Chainscore © 2026
introduction
INTRODUCTION

Setting Up On-Chain Voting for Funding Proposals

A practical guide to implementing transparent and decentralized funding decisions using smart contracts.

On-chain voting transforms how decentralized organizations allocate funds, moving governance from opaque forums to transparent, auditable smart contracts. This system allows token holders to directly vote on proposals, with results and fund disbursement executed automatically by code. Unlike traditional governance, on-chain voting provides cryptographic proof of outcomes and eliminates manual intervention, reducing administrative overhead and potential for human error. Platforms like Compound's Governor Bravo and OpenZeppelin Governor have established the standard patterns for these systems.

The core architecture involves three key smart contracts: a voting token (often an ERC-20 or ERC-721), a governor contract that manages proposal lifecycle and tallying, and a timelock contract that queues and executes successful transactions. When a funding proposal is submitted, it specifies a target contract, function call, and amount of native tokens or ERC-20s to transfer. Voters then cast their ballots, with voting power typically determined by their token balance at a specific snapshot block to prevent manipulation.

Implementing a basic system starts with deploying a governance token. Using OpenZeppelin's contracts, you can extend ERC20Votes to track historical balances for snapshotting. The governor contract, built from Governor.sol, is then configured with parameters like votingDelay (blocks before voting starts) and votingPeriod (blocks voting is open). For example, a 1-day voting period on Ethereum is roughly 7200 blocks. The proposal threshold determines the minimum token power needed to submit a proposal.

Security is paramount. Always use a timelock contract between the governor and the treasury. This introduces a mandatory delay between a vote passing and its execution, giving the community a final window to react if a malicious proposal slips through. Furthermore, consider vote delegation (as in ERC-20Votes) to improve participation and quorum requirements to ensure a minimum level of voter turnout is met for a proposal to be valid.

To test your setup, use a framework like Hardhat or Foundry. Simulate a full proposal lifecycle: 1) a proposer submits a transaction to send funds from the treasury, 2) voters cast their votes, 3) the vote is finalized, and 4) after the timelock delay, anyone can execute the successful proposal. Tools like Tally and Boardroom provide user-friendly interfaces for voters, but the immutable logic resides entirely on-chain.

For ongoing maintenance, monitor key metrics like voter participation rates and proposal execution success. Consider integrating with Snapshot for gas-free signaling votes before committing to on-chain execution, or using zodiac modules for more complex multi-chain governance. The goal is a system that is not only functional but also resilient and aligned with the decentralized ethos of the organization it serves.

prerequisites
SETUP

Prerequisites

Before implementing on-chain voting, you must establish the foundational technical and governance infrastructure. This section covers the essential components required to build a secure and functional funding proposal system.

The core of any on-chain voting system is a smart contract that defines the proposal lifecycle and voting logic. You will need a development environment like Hardhat or Foundry to write, test, and deploy these contracts. For Ethereum Virtual Machine (EVM) chains, the OpenZeppelin Contracts library provides battle-tested, modular components for governance, including the Governor contract and its extensions. A standard setup involves contracts for the governance token (e.g., an ERC-20 with voting snapshots), a timelock controller for secure execution, and the main governor contract that orchestrates proposals.

Your governance token must implement a mechanism for vote delegation and snapshotting. This is typically done using the ERC20Votes or ERC20VotesComp extension from OpenZeppelin, which automatically creates snapshots of token balances at the start of each proposal. This prevents users from buying more tokens to sway a live vote. The token contract must also allow users to delegate their voting power to themselves or another address. Ensure your token is deployed and distributed to community members before the governor contract is initialized.

For secure execution of passed proposals, integrate a timelock contract. This acts as a buffer between a proposal's approval and its execution, allowing users time to react if a malicious proposal slips through. The OpenZeppelin TimelockController is the standard choice. The governor contract will be set as a "proposer" on the timelock, and the timelock will be the executor for all actions (like transferring funds from a treasury). This separation of powers is a critical security best practice.

You must decide on key voting parameters that will be hardcoded into your governor contract. These include the voting delay (time between proposal submission and start of voting), voting period (duration of the vote), proposal threshold (minimum token power needed to submit a proposal), and quorum (minimum percentage of total voting power required for a vote to be valid). These parameters directly impact governance responsiveness and security; for example, a 7-day voting period is common for major DAOs like Uniswap.

Finally, you need a front-end interface and indexing layer for users to interact with the system. While the smart contracts handle the logic, users need a way to create proposals, view active votes, cast their votes, and queue/execute successful proposals. You can use a framework like Next.js or Vite with libraries such as wagmi and viem for wallet connection and contract interaction. An indexer like The Graph is highly recommended to efficiently query proposal data and voting history without overloading your RPC provider.

voting-contract-architecture
ON-CHAIN GOVERNANCE

Voting Contract Architecture

A technical guide to building secure, transparent on-chain voting systems for funding proposals using smart contracts.

On-chain voting for funding proposals is a core mechanism in DAOs and decentralized grant programs. It replaces opaque committee decisions with transparent, verifiable logic executed by a smart contract. This architecture typically involves three main components: a proposal registry to submit and store proposals, a voting token (like an ERC-20 or ERC-721) that determines voting power, and a voting engine that tallies votes and executes results. The contract must enforce rules for proposal lifecycle—creation, active voting, tallying, and execution—while preventing common attacks like double-voting or manipulation of the voting period.

The security model is paramount. Contracts should implement checks like ensuring only token holders can vote, using block.timestamp or block numbers to enforce proposal deadlines, and preventing reentrancy during the vote tallying and fund distribution phases. A common pattern is the use of a timelock contract between the voting outcome and execution. This introduces a mandatory delay, allowing token holders to review the automated transaction before funds are moved, which is a critical safety measure for high-value proposals. OpenZeppelin's governance contracts provide audited building blocks for these patterns.

Here is a simplified Solidity snippet showing a proposal struct and core voting function:

solidity
struct Proposal {
    uint256 id;
    address recipient;
    uint256 amount;
    uint256 voteStart;
    uint256 voteEnd;
    uint256 forVotes;
    uint256 againstVotes;
    bool executed;
}
mapping(address => mapping(uint256 => bool)) public hasVoted;
function castVote(uint256 proposalId, bool support) external {
    Proposal storage proposal = proposals[proposalId];
    require(block.number >= proposal.voteStart, "Voting not started");
    require(block.number <= proposal.voteEnd, "Voting ended");
    require(!hasVoted[msg.sender][proposalId], "Already voted");
    require(votingToken.balanceOf(msg.sender) > 0, "No voting power");
    hasVoted[msg.sender][proposalId] = true;
    uint256 voterWeight = votingToken.balanceOf(msg.sender);
    if (support) {
        proposal.forVotes += voterWeight;
    } else {
        proposal.againstVotes += voterWeight;
    }
}

Key design decisions impact voter participation and system integrity. Vote weighting can be linear (1 token = 1 vote) or use quadratic formulas to reduce whale dominance. Vote delegation (as seen in Compound and Uniswap) allows users to delegate their voting power to experts. The choice of voting period (e.g., 3-7 days) must balance responsiveness with sufficient time for deliberation. Furthermore, you must decide if votes are cast on-chain (gas-intensive but fully transparent) or using off-chain signatures with an on-chain verification step (like Snapshot with an execution bridge), which reduces voter cost.

For funding proposals specifically, the execution function must securely transfer assets. This often involves integrating with a treasury contract that holds the DAO's funds. The voting contract, after a successful vote, should call a function on the treasury to stream or transfer funds to the approved recipient. It's critical to validate all parameters in this call—recipient address, amount, and asset type—against the stored proposal data to prevent execution exploits. Always conduct thorough testing and audits, as these contracts manage real value and their compromise can lead to irreversible fund loss.

IMPLEMENTATION OPTIONS

Governance Contract Comparison

Key differences between popular Governor contract implementations for on-chain voting.

Feature / MetricOpenZeppelin GovernorCompound Governor BravoTally Governor v1

Base Contract Type

Governor

GovernorBravoDelegate

Governor

Proposal Threshold

Configurable token amount

Fixed token amount

Configurable token amount

Voting Delay

Configurable (blocks)

Fixed 1 block

Configurable (blocks)

Voting Period

Configurable (blocks)

Fixed ~3 days

Configurable (blocks)

Quorum Required

Configurable (e.g., 4%)

Fixed minimum quorum

Configurable via QuorumVotes contract

Upgrade Mechanism

Gas Optimization (EIP-5805)

Default Proposal ID Format

Hash of proposal data

Sequential integer

Hash of proposal data

Time-lock Integration

GovernorTimelockControl

Timelock.sol

Modular executor system

configuring-voting-parameters
GOVERNANCE

Configuring Voting Parameters

A guide to setting up secure and effective on-chain voting for funding proposals, covering quorum, thresholds, and delegation.

On-chain voting parameters define the rules for how a community approves or rejects funding proposals. These are not just administrative details; they are critical security and incentive mechanisms that protect the treasury and ensure legitimate consensus. Core parameters include the voting delay (time between proposal submission and voting start), voting period (duration votes are accepted), quorum (minimum participation required for validity), and approval thresholds (the percentage of for votes needed to pass). Setting these correctly balances efficiency with security, preventing low-turnout attacks and ensuring proposals reflect the will of an engaged community.

Quorum is arguably the most important defense against governance attacks. A quorum of 4% means at least 4% of the total voting power must participate for the vote to be valid. Without it, a malicious actor with a small token stake could pass proposals in a low-engagement period. The approval threshold is separate; a proposal might need 50% for votes of the votes cast to pass, but only after quorum is met. For critical treasury actions, a supermajority threshold (e.g., 66%) is often used. These values are typically set in the governance contract's constructor or via a prior governance proposal.

Here is a simplified example of setting parameters in a Solidity contract using OpenZeppelin's Governor contracts, a common standard:

solidity
contract MyGovernor is Governor {
    constructor(IVotes _token)
        Governor("MyGovernor")
    {
        // Voting starts 1 block after proposal
        _setVotingDelay(1);
        // Voting lasts 3 days (in blocks)
        _setVotingPeriod(50400);
        // 4% of token supply must vote for quorum
        _setProposalThreshold(4);
        // Proposal needs >50% of cast votes to pass
        _setQuorumNumerator(5000); // Basis points (50%)
    }
}

The _setQuorumNumerator uses basis points (e.g., 5000 = 50%). Always calculate block times for votingPeriod based on your chain's average block time.

Delegation is a key feature that amplifies voter participation without requiring constant wallet interaction. Token holders can delegate their voting power to a trusted community member or themselves. The delegated votes are automatically counted in all active proposals. When configuring parameters, consider if you want to enable vote delegation by signature, which allows users to delegate without a transaction by signing an off-chain message. This improves UX but adds implementation complexity. Platforms like Tally and Boardroom provide interfaces for easy delegation and voting, integrating directly with standard Governor contracts.

After deployment, monitor initial voting cycles closely. Key metrics to track are quorum attainment rate, average voter participation, and proposal passage rate. If quorum is consistently missed, participation incentives or the quorum itself may need adjustment via a new governance proposal. Remember, parameters are not set in stone; they should evolve with the DAO's size and maturity. For high-value treasuries, consider implementing a timelock on executed proposals, adding a mandatory delay between vote passage and fund transfer, giving the community a final safeguard against malicious proposals that somehow pass.

execution-mechanisms
ON-CHAIN GOVERNANCE

Execution and Security Mechanisms

Implementing secure, transparent voting for treasury fund allocation requires understanding key execution patterns and their trade-offs.

05

Security: Timelock & Execution Delays

A TimelockController is non-negotiable for secure treasury management. It enforces a mandatory delay between a proposal's approval and its execution.

  • Purpose: Provides a grace period for users to exit systems or for guardians to veto malicious proposals (if configured).
  • Typical Delay: Ranges from 24 hours for mature DAOs to 7+ days for large treasuries.
  • Implementation: In OpenZeppelin's Governor, the Timelock is the proposer. Votes pass to the Timelock, which queues the action.
24h-7d+
Standard Delay
06

Voting Strategies & Quorum

Define how voting power is calculated and what constitutes a valid proposal pass. This is set in the Governor contract.

  • Voting Tokens: Use GovernorVotes for ERC-20 voting with snapshots, or GovernorVotesQuorumFraction for dynamic quorum.
  • Quorum: A minimum percentage of total voting power must participate for a vote to be valid. 4% is a common starting point.
  • Voting Period: Standard durations are 3-7 days for ample voter participation. Avoid periods under 24 hours.
3-7 days
Typical Voting Period
>4%
Common Quorum
integrating-governance-ui
ON-CHAIN GOVERNANCE

Integrating a Governance UI (Tally, Snapshot)

A guide to implementing on-chain voting for treasury funding proposals using popular governance frontends.

On-chain governance allows token holders to vote directly on protocol changes, including funding proposals, using their wallets. Unlike off-chain signaling, these votes are executed as transactions, making the results binding and enforceable by smart contracts. Popular platforms like Tally and Snapshot provide user-friendly interfaces that abstract away the complexity of interacting with governance contracts. Tally specializes in on-chain governance for DAOs using Compound's Governor model, while Snapshot offers gasless, off-chain voting that can be used to signal intent before an on-chain execution.

To set up on-chain voting, your protocol first needs a governance smart contract. The most common standard is OpenZeppelin's Governor, which provides modular contracts for proposal creation, voting, and execution. A typical setup involves deploying a Governor contract, a TimelockController for secure execution delays, and your governance token (e.g., an ERC-20 with vote delegation). The Governor contract defines key parameters: votingDelay (blocks before voting starts), votingPeriod (duration of the vote), and proposalThreshold (minimum tokens needed to propose).

Once your contracts are deployed, integrating with Tally involves connecting your Governor contract address to the Tally platform. Tally will automatically index proposal events and provide a UI for users to connect their wallets, view active proposals, cast votes, and delegate voting power. For a funding proposal, the calldata in the proposal would typically be a transaction to transfer funds from the DAO's treasury TimelockController to a recipient address. You must ensure the Timelock holds the treasury funds and the Governor has the PROPOSER role on the Timelock.

Snapshot is often used for gasless, off-chain sentiment checks. To use it for an on-chain execution flow, you would create a Snapshot space linked to your token, where users sign messages to vote. A successful Snapshot vote can then be used to create an on-chain proposal in Tally or via a custom script. This two-step process reduces gas costs for voters while maintaining final on-chain execution. The Snapshot strategy must be configured to correctly read voting power from your token's contract or a merkle tree snapshot.

Here is a simplified example of the calldata for an on-chain funding proposal using the Governor contract:

solidity
// Target: Treasury Timelock Contract
address target = treasuryTimelock;
// Value: 10 ETH to send
uint256 value = 10 ether;
// Calldata: call to execute a transfer
bytes memory data = abi.encodeWithSignature(
    "executeTransaction(address,uint256,string,bytes)",
    recipientAddress,
    value,
    "",
    ""
);
// Description
string description = "Funding Proposal #1: Grant to Developer Team";

The proposal is submitted by calling propose(targets, values, calldatas, description) on the Governor contract.

Key considerations for a secure setup include using a timelock for all treasury transactions to allow for a review period, setting appropriate quorum and vote thresholds to prevent attacks, and thoroughly testing proposal execution on a testnet. Always verify that the governance UI correctly reflects the contract state and voting power. Resources include the OpenZeppelin Governor documentation, Tally docs, and Snapshot docs.

deployment-and-testing
DEPLOYMENT AND TESTING STRATEGY

Setting Up On-Chain Voting for Funding Proposals

A technical guide to implementing, testing, and securing a smart contract system for decentralized governance and fund allocation.

On-chain voting for funding proposals is a core primitive of decentralized autonomous organizations (DAOs) and grant programs. A typical system involves a voting token (like an ERC-20 or ERC-721), a proposal factory contract for creating new funding requests, and a voting vault or governor contract that manages the voting logic and treasury payouts. The lifecycle includes proposal submission, an active voting period, vote tallying, and, if successful, execution of the transaction to transfer funds from a shared treasury. Using standards like OpenZeppelin's Governor contracts provides a battle-tested foundation, reducing the need to write complex voting logic from scratch.

A robust deployment strategy begins on a testnet. Deploy your token contract first, followed by the governance contract configured with parameters like votingDelay, votingPeriod, and proposalThreshold. Use a scripted deployment with Hardhat or Foundry for reproducibility. For example, a Foundry script might deploy a MyToken contract, then a MyGovernor contract that accepts the token's address as the voting asset. Always verify your contracts on block explorers like Etherscan immediately after deployment to enable public interaction and verification. Consider using a proxy pattern (e.g., Transparent or UUPS) for your governor contract to allow for future upgrades to the voting logic without losing proposal history.

Comprehensive testing is non-negotiable for financial governance systems. Your test suite should simulate the entire proposal lifecycle: 1) a user creates a proposal, 2) voters cast votes using their token balance, 3) the voting period ends, 4) the proposal state is finalized, and 5) the successful proposal executes a mock treasury transfer. Use fork testing against mainnet state to simulate real token distributions and interactions. Tools like Tenderly or Foundry's cheatcodes (vm.roll) are essential for simulating the passage of time to move proposals through different states. Test edge cases: proposals that fail quorum, votes that create a tie, and malicious attempts to vote twice or execute a failed proposal.

Security considerations must be integrated into the deployment process. Before mainnet, conduct audits and formal verification. Key security checks include ensuring vote weights are calculated correctly from token snapshots (to prevent double-voting), that the execute function can only be called for successful proposals, and that the treasury is controlled exclusively by the governor contract. Use multisig timelocks for the treasury itself, where the governor is the only entity that can propose transactions to it, adding a mandatory delay before funds move. This allows token holders to exit if a malicious proposal passes. Monitoring tools like OpenZeppelin Defender can be set up to track proposal creation and state changes in production.

For gas optimization, batch operations where possible. If your system involves delegating voting power (like in ERC-20Votes), educate users that delegation is a one-time transaction, while voting itself can be gasless via signature-based voting (like EIP-712) using a relayer. The final step is governance activation: after mainnet deployment, the deployer must transfer treasury ownership to the governor contract and often must renounce ownership of the token contract to fully decentralize control. Document all contract addresses, ABIs, and interaction steps for the community to begin submitting and voting on proposals.

ON-CHAIN VOTING

Frequently Asked Questions

Common technical questions and solutions for developers implementing on-chain voting for funding proposals, covering smart contract logic, gas optimization, and security.

Token-weighted voting grants voting power proportional to a user's token holdings (1 token = 1 vote). Quadratic voting (QV) uses a square root function, where voting power = sqrt(tokens committed). This reduces whale dominance. For example, a user with 100 tokens gets 10 votes (sqrt(100)), while a user with 10,000 tokens gets 100 votes, not 10,000. QV is often implemented using the OpenZeppelin Math library for square root calculations. The trade-off is higher gas costs for the sqrt computation versus the simplicity of linear token voting.

conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have successfully configured the core components for an on-chain voting system to manage funding proposals. This guide covered the essential steps from smart contract deployment to frontend integration.

Your deployed system now includes a FundingProposal contract that manages proposal lifecycle states—Draft, Active, Succeeded, and Executed—secured by a GovernanceToken for voting power. The integration of a timelock contract, such as OpenZeppelin's TimelockController, adds a critical security layer by enforcing a mandatory delay between a vote passing and funds being released. This prevents malicious proposals from executing instantly and gives the community time to react. Remember to verify your contracts on block explorers like Etherscan for transparency.

For ongoing management, you should establish clear operational procedures. This includes defining proposal submission requirements, setting appropriate voting periods and quorums based on token distribution, and creating a process for emergency cancellations. Tools like Snapshot can be used for off-chain sentiment signaling before formal on-chain votes. Monitoring tools such as Tenderly or OpenZeppelin Defender are essential for tracking proposal states, voter participation, and contract health. Regular security audits and bug bounty programs are non-negotiable for maintaining trust in the treasury management process.

To extend the system's functionality, consider implementing more advanced features. Quadratic voting can mitigate whale dominance by making vote cost increase quadratically with voting power. You could add delegation mechanisms, allowing token holders to delegate their voting power to experts. Integrating with cross-chain messaging protocols like LayerZero or Axelar would enable multi-chain treasury management. For deeper analysis, use subgraphs with The Graph to index and query proposal and voting data for custom dashboards. The OpenZeppelin Governance documentation is an excellent resource for exploring these advanced patterns.

The next practical step is to test the entire workflow end-to-end in a forked mainnet environment using tools like Foundry or Hardhat. Simulate a full proposal cycle: create a proposal, have multiple addresses vote, reach quorum, wait through the timelock, and finally execute. This tests all edge cases and confirms the frontend UI correctly reflects each state change. Once confident, you can proceed to a live deployment on a testnet, conducting a community trial run before launching on mainnet to govern real treasury assets.

How to Set Up On-Chain Voting for Treasury Proposals | ChainScore Guides