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

Launching a Token with Embedded Voting Rights and Eligibility Checks

A developer tutorial for implementing a compliant security token with on-chain governance, vote delegation, and automated eligibility verification based on holding period and investor type.
Chainscore © 2026
introduction
TOKEN DESIGN

Introduction

This guide explains how to launch an ERC-20 token with embedded on-chain governance and automated eligibility verification.

Standard fungible tokens like the basic ERC-20 are powerful for representing value, but they lack mechanisms for community governance and access control. A token with embedded voting rights and eligibility checks integrates these features directly into the token's smart contract logic. This creates a self-contained system where token ownership is intrinsically linked to governance power and where certain actions—like transferring tokens or participating in votes—can be gated by real-time, on-chain checks. This design is foundational for creating DAO membership tokens, compliant securities, or gated community assets.

The core innovation lies in moving governance and compliance logic from off-chain processes into the token contract itself. Instead of relying on separate voting contracts or manual whitelists, the token's transfer, mint, or vote functions can execute custom checks. For example, a transfer could be blocked unless the recipient passes a Sybil resistance check via a registry like Ethereum Attestation Service (EAS) or holds a Soulbound Token (SBT) credential. This creates a programmable and transparent layer of rules that execute autonomously, reducing administrative overhead and central points of failure.

Implementing this requires extending the standard ERC-20 contract. Key technical components include: an internal voting mechanism (often using snapshot patterns to prevent double-voting), integration with oracles or verifiable credential registries for off-chain data, and modifier functions that enforce eligibility. A common pattern is to override the _beforeTokenTransfer hook in OpenZeppelin's ERC-20 to insert custom logic. This guide will walk through building such a contract using Solidity 0.8.20+, integrating with the EAS SDK for attestation checks, and deploying it on a testnet.

Practical use cases are diverse. A venture DAO could issue tokens only to accredited investors verified via a KYC attestation. A protocol governance token could restrict proposal creation to wallets that have staked a minimum amount for a specific duration. A community rewards token might be non-transferable until a user completes certain on-chain actions. By baking these rules into the token, projects ensure enforceable and transparent membership criteria, aligning token utility directly with organizational goals.

Following this introduction, we will provide a step-by-step tutorial to build and deploy a GovernanceToken contract. The tutorial will cover: setting up the development environment with Foundry, writing the core contract with OpenZeppelin libraries, integrating an eligibility module, writing tests, and finally, deploying and verifying the contract on the Sepolia testnet. The final code will be available in a dedicated GitHub repository for reference.

prerequisites
TOKEN LAUNCH FOUNDATION

Prerequisites

Before deploying a token with integrated governance, ensure your development environment and foundational knowledge are in place.

Launching a token with embedded voting rights requires a solid technical foundation. You must have a working knowledge of Ethereum Virtual Machine (EVM)-compatible blockchains like Ethereum, Arbitrum, or Polygon, as this is where most governance-enabled tokens are deployed. Proficiency in Solidity for writing the smart contracts is non-negotiable. You'll also need a development environment set up with Hardhat or Foundry, Node.js, and a package manager like npm or yarn. Familiarity with ERC-20 token standards is the baseline; you will be extending this standard to add governance logic.

Beyond the core tooling, you need to understand the key concepts you'll be implementing. Token-based voting means each token represents one vote, requiring mechanisms to snapshot balances and prevent double-spending during proposal periods. Eligibility checks involve verifying a holder's status before allowing them to vote or create proposals, which can be based on minimum token balance, whitelisted addresses, or NFT ownership. You should also be comfortable with OpenZeppelin contracts, as we will use their audited ERC20Votes and Votes libraries for secure vote tracking and delegation.

For testing and deployment, you'll require a wallet with testnet ETH (e.g., from a Sepolia or Goerli faucet) and knowledge of using Alchemy or Infura as RPC providers. Understanding how to verify contracts on block explorers like Etherscan is also crucial for transparency. Finally, consider the user experience: how will token holders interact with the governance system? Planning for a front-end interface using a library like wagmi or ethers.js is a later step, but acknowledging it now informs your contract design choices for ease of integration.

key-concepts
TOKEN LAUNCH

Key Concepts

Core technical concepts for launching a token with integrated governance and access control.

01

Token Standards for Governance

Choosing the right token standard is foundational. ERC-20 is the base for fungible tokens, but you need to layer on governance. ERC-5805 (Votes) and ERC-6372 (Clock) are modern standards for checkpointed voting power and timekeeping. For snapshot-based voting without gas, consider ERC-20Votes. ERC-721 (NFTs) can represent non-transferable membership rights for eligibility checks. The standard dictates how voting power is tracked, delegated, and queried on-chain.

02

On-Chain Eligibility Verification

Embedding rules directly into the token contract controls who can vote or claim. This is done via a verifier function (e.g., canVote(address voter)). Common checks include:

  • Token Balance: Minimum holding of governance tokens.
  • NFT Membership: Holding a specific ERC-721 token for gated access.
  • Snapshot Merkle Proofs: Off-chain allowlists verified with a Merkle root stored on-chain.
  • Time-Based Lock: Requiring tokens to be staked or locked for a duration (using ERC-6372 for time). This prevents sybil attacks and ensures committed participants.
03

Voting Power & Delegation Mechanics

Voting power is not always 1 token = 1 vote. Systems use checkpoints to record historical balances, preventing manipulation by transferring tokens mid-vote. ERC-5805 standardizes this. Key mechanics:

  • Self-Delegation: A user's balance counts as their own voting power.
  • Delegate Voting: Users can delegate their voting power to another address, separating ownership from governance influence.
  • Compound-Like Delegation: Delegates can further delegate, creating representative trees.
  • Power Decay: Voting power can decay over time to incentivize ongoing participation. The delegation state is a critical on-chain variable.
04

Proposal Lifecycle & Execution

A governance proposal moves through distinct phases managed by smart contracts.

  1. Creation: A transaction submits proposal calldata (e.g., target, value, data).
  2. Voting Delay: A waiting period (blocks) before voting starts.
  3. Voting Period: A fixed window (e.g., 3 days) where token holders cast votes.
  4. Quorum & Threshold: Proposal passes only if a minimum voting power (quorum) participates and a majority meets the threshold (e.g., >50% for).
  5. Timelock & Execution: Passed proposals are queued in a TimelockController (like OpenZeppelin's) for a delay before execution, providing a safety review period.
05

Gas Optimization for Voters

On-chain voting gas costs can deter participation. Strategies to reduce costs include:

  • Checkpointing: Only write state during transfers/delegation, not on every vote. ERC-20Votes uses this.
  • Signature-Based Voting (EIP-712): Allow voters to sign off-chain messages; a relayer submits votes in batches.
  • Voting Strategies: Use lightweight contracts that compute voting power from a snapshot block hash, avoiding complex state reads.
  • Gasless Relayers: Integrate with services like Gelato or OpenZeppelin Defender to sponsor transaction gas for users. Optimizing these patterns is crucial for accessibility.
06

Security & Attack Vectors

Governance contracts are high-value targets. Critical considerations:

  • Timestamp Manipulation: Use block numbers instead of timestamps for proposal timing where possible.
  • Flash Loan Attacks: An attacker borrows tokens to meet a quorum, votes, and repays. Mitigate with vote snapshots (checkpoints) or requiring tokens be held before the proposal starts.
  • Governance Capture: A single entity amassing >50% of tokens. Consider a multi-sig guardian or veto power in early stages.
  • Function Selector Clashes: Ensure proposal execution calldata cannot accidentally call dangerous functions in the Timelock or token contract itself. Audits are mandatory.
contract-architecture
CONTRACT ARCHITECTURE AND BASE STANDARDS

Launching a Token with Embedded Voting Rights and Eligibility Checks

Designing a governance token requires integrating voting logic and eligibility rules directly into the token's smart contract. This guide covers the architectural patterns and key standards for building a secure, functional token with on-chain governance.

The foundation for a governance token is the ERC-20 standard, which defines the core token interface for balances and transfers. To add governance, you extend this base with voting logic. The ERC-5805 (Votes) and ERC-6372 (Clock) standards provide a modern, gas-efficient framework for on-chain voting and timekeeping. Instead of creating separate contracts, these standards allow you to embed vote tracking directly into the token, making each token a native voting unit. This integrated approach simplifies delegation, reduces transaction overhead, and ensures vote weight is always synchronized with token balance.

Eligibility checks are critical for enforcing governance rules. Common checks include: a minimum token balance or lock-up period to vote, snapshotting mechanisms to prevent last-minute token buying ("airdrop sniping"), and whitelists for specific proposal types. These rules are enforced in the contract's _beforeTokenTransfer hook or within custom voting functions. For example, you can use OpenZeppelin's Votes library, which automatically adjusts delegate voting power on token transfers and provides a getPastVotes function for historical balance checks, a common requirement for snapshot-based voting.

A typical contract architecture inherits from ERC20, ERC20Permit (for gasless approvals), Votes, and NonblockingLzApp if deploying on an L2 or alt-L1 for cross-chain governance. The voting contract itself, often following ERC-6372, manages proposal lifecycle and execution. Key functions include propose, castVote, and execute. Security best practices mandate using timelocks for executed proposals, implementing governor-specific roles (e.g., PROPOSER_ROLE), and ensuring all state changes for votes and eligibility are immutable after a proposal is finalized to prevent manipulation.

When deploying, you must initialize the contract with correct parameters: the voting delay, voting period, proposal threshold, and quorum required. For gas optimization on L2s, consider using EIP-712 typed structured data hashing for off-chain signature validation of votes. Testing is paramount; simulate governance attacks like flash loan attacks to manipulate voting power, and ensure delegation logic works correctly across complex transfer scenarios. Always audit the final contract, as embedded governance significantly increases the attack surface compared to a standard token.

eligibility-verification
TOKEN LAUNCH GUIDE

Implementing Eligibility Verification Logic

This guide explains how to build on-chain verification for token-gated voting, covering Merkle proofs, snapshot strategies, and smart contract integration.

Eligibility verification determines who can vote with a governance token. Common criteria include holding a minimum token balance, being on a whitelist, or possessing a specific NFT. The logic must be trustless and gas-efficient, executed directly within the voting smart contract. Off-chain verification is insufficient as it introduces centralization; the contract must autonomously validate a user's right to participate. This is a core component of token-curated registries and decentralized autonomous organizations (DAOs).

A Merkle proof is the most common on-chain verification method. An off-chain service generates a Merkle tree from a list of eligible addresses (e.g., token holders at a specific block). The root hash is stored in the contract. To prove eligibility, a user submits a transaction with a Merkle proof—a path of hashes from their leaf to the root. The contract verifies the proof against the stored root. This is gas-efficient for voters and allows list updates by changing only the root. OpenZeppelin's MerkleProof library provides standard verification functions.

For dynamic eligibility like minimum token balances, use a snapshot strategy. Record token balances at a historic block number using block.number. The voting contract can then verify a user's past balance via a state proof (like Merkle Patricia proofs from archive nodes) or by reading from a snapshot contract that recorded balances. For example, a contract can store a mapping snapshots[blockNumber][address] populated by an initial transaction. The verify function would then check snapshots[eligibleBlock][msg.sender] >= requiredBalance.

Here is a basic smart contract example using a Merkle tree for a whitelist:

solidity
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract VotingWithWhitelist {
    bytes32 public merkleRoot;
    mapping(address => bool) public hasVoted;

    constructor(bytes32 _merkleRoot) {
        merkleRoot = _merkleRoot;
    }

    function vote(uint256 proposalId, bytes32[] calldata merkleProof) external {
        require(!hasVoted[msg.sender], "Already voted");
        bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
        require(MerkleProof.verify(merkleProof, merkleRoot, leaf), "Not eligible");
        hasVoted[msg.sender] = true;
        // ... record vote logic
    }
}

The vote function reverts if the provided proof is invalid, ensuring only listed addresses can participate.

Consider gas optimization and user experience. Merkle proofs shift gas costs to the prover (the voter), which can be high for large trees. For better UX, consider using EIP-712 signed messages where an off-chain authority signs eligibility, and the contract verifies the signature. However, this reintroduces an off-chain dependency. For pure on-chain verification of ERC-20 balances, use a checkpointed token standard like ERC-20Votes or ERC-5805, which natively support historical balance lookups, eliminating the need for custom snapshot logic.

Always audit your verification logic. Common vulnerabilities include: replay attacks (mitigated by tracking hasVoted), incorrect Merkle tree construction, and front-running snapshot blocks. Use established libraries like OpenZeppelin and test thoroughly with edge cases. For production, consider integrating with snapshot tools like Snapshot.org for off-chain voting or Governor standards (OpenZeppelin Governor) for on-chain execution. The goal is a system that is permissionless for verified users yet resistant to sybil and replay attacks.

voting-delegation-snapshot
TOKEN GOVERNANCE

Adding Voting, Delegation, and Snapshot Mechanisms

This guide explains how to embed on-chain voting, delegation, and snapshot-based eligibility into your token, enabling decentralized governance from day one.

A governance token is more than a transferable asset; it's a credential that grants voting power over a protocol's future. To implement this, you must define a core set of functions: checking a user's voting weight, allowing them to delegate that weight to another address, and recording a snapshot of token holdings at a specific block. The simplest approach extends the ERC-20 standard with the OpenZeppelin ERC20Votes contract, which automatically maintains a history of account balances for lookups. This history is essential for creating a fair, immutable snapshot, preventing users from borrowing tokens to manipulate a vote after the snapshot is taken.

The delegation mechanism is central to liquid democracy. Instead of voting directly, a token holder can delegate their voting power to a trusted representative. In your contract, this is managed by a mapping, such as delegates(address delegatee), which tracks who an address has delegated to. When a user calls delegate(address delegatee), their historical voting power is moved from their own address to the delegatee's. The ERC20Votes contract handles the complex math of tracking these power transfers across time, providing a getVotes(address account) function that returns the correct voting weight for any past block number.

Before a proposal goes live, you must take a snapshot to determine voter eligibility. This is done by recording a specific block number. In a vote, you check a user's balance not at the current block, but at the recorded snapshot block using getPastVotes(account, snapshotBlock). This ensures the vote reflects the community's stake at the proposal's inception. For example, a createProposal function would store the snapshotBlock as block.number - 1. All subsequent vote checks for that proposal would query balances at that historical block, locking in the eligible voting power.

For on-chain execution, voting logic must be added. A proposal struct typically tracks the snapshot block, vote counts for/against/abstain, and an execution state. The core castVote function should: 1) Verify the proposal is active, 2) Use getPastVotes(voter, proposal.snapshotBlock) to get the voter's weight, 3) Ensure they haven't already voted, and 4) Add their weight to the chosen tally. After the voting period ends, a separate function can execute the proposal's actions if quorum and majority thresholds are met, often via a timelock contract for security.

Off-chain voting platforms like Snapshot offer a gasless alternative. Here, your token's on-chain snapshot capability is still required. The Snapshot protocol reads the getPastVotes data from your contract at the specified block to determine voting power. You must verify your contract's address and the correct ABI on Snapshot's space settings. This hybrid model allows for complex, multi-choice voting without gas costs, while the definitive token ledger and snapshot logic remain securely on-chain, providing a verifiable trust anchor for the off-platform vote.

proposal-creation-execution
TOKEN LAUNCH

Creating and Executing Governance Proposals

A technical guide to designing and deploying a governance token with on-chain voting rights and automated eligibility verification.

Launching a governance token requires embedding voting logic directly into the token's smart contract. Unlike standard ERC-20 tokens, governance tokens integrate functions for proposal creation, voting, and quorum calculation. The most common standard is ERC-20Votes, an extension that tracks historical balances for secure, snapshot-based voting. This prevents users from acquiring tokens after a proposal snapshot to manipulate the vote. The contract must also define key parameters: the votingDelay (time between proposal submission and voting start), votingPeriod (duration votes are accepted), and proposalThreshold (minimum token balance required to submit a proposal).

Eligibility checks are critical for secure governance. A basic check verifies a voter's token balance at a specific block number, typically the block where the proposal was created. More advanced systems implement multisig timelocks for treasury actions or require votes to be delegated from a staking contract. For example, a contract might check getPriorVotes(account, blockNumber) >= 1 to ensure the voter held at least one token at the snapshot. You can also gate proposal creation behind a governance module or DAO-specific rules, such as requiring the proposer to be a verified member of an on-chain registry.

Here is a simplified example of a governance proposal lifecycle using OpenZeppelin's Governor contracts, the industry standard for secure on-chain governance. First, a user calls propose() with a list of target addresses, values, and calldata for the actions to execute. The contract snapshots token balances and initiates the voting delay.

solidity
function propose(
    address[] memory targets,
    uint256[] memory values,
    bytes[] memory calldatas,
    string memory description
) public returns (uint256 proposalId);

After the delay, token holders call castVote(proposalId, support) where support is 0 (against), 1 (for), or 2 (abstain). The contract validates the vote using the historical balance snapshot.

Once the voting period ends, anyone can call queue(proposalId) to move a successful proposal to a timelock executor, like OpenZeppelin's TimelockController. This adds a mandatory delay before execution, allowing token holders to react to malicious proposals. Finally, after the timelock expires, execute(proposalId) runs the encoded transactions on the target contracts. This multi-step process with built-in delays is a security best practice, preventing rushed governance attacks. Always audit the target contract's logic separately, as the governor will execute any calldata provided.

For production deployments, consider gas optimization and voter participation. Gasless voting via signature delegation (EIP-712) allows users to sign votes off-chain, which a relayer submits on-chain, drastically reducing voter cost. Platforms like Snapshot offer off-chain voting with on-chain execution, ideal for frequent, low-stakes polls. However, for treasury control or protocol upgrades, on-chain voting remains the gold standard for its tamper-proof guarantees. Test all governance flows extensively on a testnet, simulating proposal creation, voting, queuing, and execution with tools like Hardhat or Foundry.

Key takeaways for a secure launch: 1) Use audited standards like OpenZeppelin Governor, 2) Implement a timelock for all executable proposals, 3) Enable gasless voting signatures to boost participation, and 4) Clearly document proposal thresholds and voting periods for your community. The contract code and configuration become the immutable constitution of your DAO, so its design requires careful consideration of security, inclusivity, and efficiency.

ERC STANDARD COMPARISON

Token Standards for Governance and Compliance

Comparison of key Ethereum token standards for implementing on-chain voting and compliance logic.

Feature / CapabilityERC-20 (Base)ERC-1155 (Multi-Token)ERC-1400 (Security Token)

Native Voting Support

Transfer Restrictions

Granular Permissioning

Multi-Token Governance

On-Chain Compliance Checks

Gas Efficiency for Batch Ops

Implementation Complexity

Low

Medium

High

Primary Use Case

Utility / Currency

NFTs / Gaming Assets

Regulated Securities

testing-auditing
SECURING SMART CONTRACTS

Testing and Security Auditing

A robust security and testing strategy is non-negotiable for a token with complex governance logic. This section outlines the essential steps to verify your contract's correctness and resilience before mainnet deployment.

Begin with comprehensive unit testing using a framework like Hardhat or Foundry. For a token with voting rights, you must test all state transitions: minting tokens, checking eligibility, casting votes, and tallying results. Write tests for both happy paths and edge cases, such as a user whose eligibility expires mid-vote or attempting to vote with zero balance. Foundry's forge test is particularly powerful for this, allowing you to write tests in Solidity and perform fuzz testing to automatically generate random inputs that might break your logic.

After unit tests, conduct integration testing to ensure your token contract interacts correctly with external systems. This includes testing the integration with your eligibility oracle or Snapshot strategy. Use a forked mainnet environment (e.g., Hardhat's hardhat_reset with an Alchemy RPC) to simulate real-world conditions. Deploy your contracts to a testnet like Sepolia or Goerli and execute end-to-end governance proposals. Monitor events and state changes to confirm that vote weights are calculated correctly based on the embedded token logic and that only eligible addresses can participate.

Formal verification and static analysis are critical for mathematical correctness. Use tools like Slither or MythX to perform automated security analysis. These tools can detect common vulnerabilities such as reentrancy, integer overflows, and improper access control in your vote and updateEligibility functions. For mission-critical logic, consider using formal verification with the Certora Prover, which mathematically proves that your contract's rules (e.g., "only eligible token holders can vote") hold under all possible conditions, providing the highest level of assurance.

Finally, engage a professional smart contract auditing firm. Reputable auditors like Trail of Bits, OpenZeppelin, or ConsenSys Diligence will perform a manual, line-by-line review. Provide them with a detailed technical specification outlining the voting mechanics, eligibility criteria, and privilege roles. A thorough audit typically takes 2-4 weeks and results in a report categorizing issues by severity (Critical, High, Medium). All findings must be addressed before launch. Budget at least $15,000-$50,000 for this service; it is the most effective investment to protect user funds and your project's reputation.

TOKEN LAUNCH

Frequently Asked Questions

Common technical questions and solutions for developers implementing on-chain voting and eligibility for token launches.

Two primary patterns are used to embed voting rights. The first is a modular approach using separate, composable contracts. This involves a base ERC-20 token and a separate governance contract (like OpenZeppelin's Governor) that reads token balances via an interface. The second is a monolithic approach where voting logic is built directly into the token contract, often by inheriting from standards like ERC-5805 (Votes) and ERC-6372 (Clock). The modular pattern offers upgradeability and separation of concerns, while the monolithic pattern can reduce gas costs and contract calls. Most modern implementations, like those used by Compound and Uniswap, favor the modular Governor pattern for its flexibility.

conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have now built a token with integrated governance and eligibility verification. This guide covered the core concepts and a basic implementation path.

This tutorial demonstrated how to embed voting rights and eligibility checks directly into an ERC-20 token's logic. By overriding the _beforeTokenTransfer hook in a custom contract, you can enforce that only eligible, verified holders can receive tokens, thereby creating a closed governance ecosystem. This approach is more secure and transparent than using separate, off-chain whitelists, as the rules are immutable and enforced on-chain. The example used a simple mapping for eligibility, but this can be extended to integrate with on-chain identity protocols like ERC-725 or Verifiable Credentials for more complex KYC/AML checks.

For production deployment, several critical enhancements are necessary. First, implement a robust administrative function to manage the eligibility list, potentially using a multi-signature wallet or a separate governance contract for updates. Second, consider gas optimization; storing eligibility on-chain can be expensive. Using merkle proofs for verification, as seen in token airdrops, can significantly reduce costs. Third, integrate a snapshot mechanism for voting. Tools like OpenZeppelin's Governor or Snapshot allow token holders to vote on proposals without moving tokens, which is essential for a functional governance system.

To test your implementation thoroughly, write comprehensive unit tests using Hardhat or Foundry. Key test scenarios should include: transferring tokens to an eligible address (success), transferring to an ineligible address (revert), and updating eligibility mid-transfer. You can reference the complete OpenZeppelin ERC-20 documentation for best practices on extending token behavior. Always conduct an audit from a reputable firm before deploying a token with custom transfer restrictions to a mainnet, as errors in the transfer hook can permanently lock funds.