Quadratic voting is a mechanism designed to more accurately reflect the intensity of voter preferences while limiting the influence of large token holders. In a quadratic reputation voting system, a user's voting power is calculated as the square root of their reputation tokens, which are typically non-transferable. This means a user with 100 reputation points gets 10 votes, while a user with 10,000 points gets only 100 votes. This mathematical curve heavily penalizes concentration, making it far more expensive for a single entity to dominate a vote compared to a simple token-weighted system. It's a core primitive for plural funding and decentralized governance in projects like Gitcoin Grants.
How to Implement a Quadratic Reputation Voting System
How to Implement a Quadratic Reputation Voting System
A technical guide to building a Sybil-resistant governance mechanism that weights votes by the square root of a user's reputation tokens.
Implementing this system requires a secure source of reputation. Reputation is often issued as a non-transferable ERC-20 or ERC-1155 token (a soulbound token) via a merkle drop or through a protocol's activity-based reward system. The key is ensuring the token cannot be bought or sold, as transferability would break the Sybil-resistance model. For on-chain voting, you can use a modified version of OpenZeppelin's ERC20Votes or ERC721Votes contracts. The critical override is in the _getVotingUnits function, where you must return the square root of the holder's balance instead of the raw amount.
Here is a simplified Solidity example for a quadratic voting power calculator within a governance contract:
solidityfunction getQuadraticVotes(address account) public view returns (uint256) { uint256 reputation = reputationToken.balanceOf(account); // Calculate square root using Babylonian method or a library like PRBMath uint256 sqrtVotes = sqrt(reputation); return sqrtVotes; }
A robust implementation should use a fixed-point math library, such as PRBMath, for precision and gas efficiency when calculating the square root. The actual voting logic then uses this derived power instead of the raw token balance.
The major challenge is preventing Sybil attacks, where one user creates many wallets to split their reputation and gain more aggregate voting power. If a whale splits 10,000 tokens across 100 wallets, each gets 10 votes (sqrt of 100), totaling 1000 votesāten times their legitimate power. Mitigations include: a per-wallet minimum reputation threshold to vote, identity verification through services like Worldcoin or BrightID, and costly reputation issuance mechanisms. The choice of mitigation depends on your protocol's trade-off between decentralization and security.
To deploy a complete system, integrate the quadratic voting power module with a governance framework like OpenZeppelin Governor. You would create a custom GovernorVotesQuadratric contract that extends the standard governor and overrides the _getVotes function to use your getQuadraticVotes logic. Voting strategies can be further refined with time-weighted reputation or conviction voting to measure sustained commitment. For gas-efficient off-chain voting, implement the quadratic calculation within a Snapshots provider for Snapshot.org or use ERC-6372 for token state standardization.
Testing is critical. Use Foundry or Hardhat to simulate attacks, especially the Sybil splitting scenario. Benchmark gas costs for the square root operation at scale. Real-world audits, like those for Gitcoin Grants rounds, highlight the importance of securing the reputation issuance contract. Ultimately, quadratic reputation voting is a powerful tool for fairer governance, but its security is entirely dependent on the integrity and Sybil-resistance of its underlying reputation system.
Prerequisites and Setup
This guide details the technical requirements and initial setup for building a quadratic reputation voting system on-chain, focusing on smart contract development and key dependencies.
A quadratic reputation voting system requires a foundational understanding of smart contract development and the Ethereum Virtual Machine (EVM). You should be proficient in Solidity (v0.8.x+) and have experience with development frameworks like Hardhat or Foundry. Essential tools include Node.js (v18+), npm or yarn, and a code editor such as VS Code. For testing, familiarity with Chai or the native testing in Foundry is necessary. This setup ensures you can compile, deploy, and interact with the voting contracts on a local or test network before mainnet deployment.
The core logic of quadratic voting is implemented in a smart contract that manages voter reputation scores and vote weight calculations. You will need to integrate or build upon existing standards, primarily ERC-20 for a governance token and potentially ERC-1155 for non-transferable reputation badges. The contract must handle: - Mapping addresses to a reputation score (often based on past contributions or staked tokens). - Calculating vote weight as the square root of the reputation points spent. - Ensuring non-transferability of voting power to prevent sybil attacks. A common reference is the OpenZeppelin Contracts library for secure, audited base implementations of access control and token standards.
For the quadratic formula, the contract requires a square root function. Since Solidity lacks a native sqrt for integers, you must implement one. A gas-efficient method is to use the Babylonian method (also known as Heron's method) or utilize a fixed-point math library like ABDKMathQuad or PRBMath. For example, a basic implementation checks that sqrt(x) * sqrt(x) <= x and (sqrt(x) + 1) * (sqrt(x) + 1) > x. This function is critical for calculating voteWeight = sqrt(reputationSpent) and must be tested extensively to prevent rounding errors or integer overflows.
Before writing the main voting contract, establish the reputation source. This could be a separate staking contract where users lock tokens to earn reputation, a manual attestation system managed by a decentralized autonomous organization (DAO), or an on-chain activity oracle. The reputation contract should mint non-transferable tokens (e.g., using OpenZeppelin's ERC721 or ERC1155 with minting restrictions) to represent voting power. This separation of concernsāreputation issuance versus vote castingāimproves security and upgradability. Consider integrating with Snapshot for off-chain signaling or Tally for on-chain governance frontends.
Finally, set up a comprehensive testing environment. Write unit tests for all functions: reputation minting, vote weight calculation, and tallying results. Use Hardhat's mainnet forking to simulate real token balances or integrate with The Graph for indexing vote events. For frontend interaction, you'll need a Web3 library like ethers.js or viem and a wallet connection provider such as WalletConnect or MetaMask SDK. Deploy first to a testnet like Sepolia or Base Sepolia, and verify your contract source code on Etherscan or Blockscout to ensure transparency and allow for community audit.
The Quadratic Voting Mathematical Model
A technical guide to implementing a quadratic voting system for reputation-weighted governance, including the core mathematical model and Solidity code examples.
Quadratic voting (QV) is a collective decision-making mechanism designed to more accurately reflect the intensity of participant preferences. Unlike one-person-one-vote, QV allows voters to allocate multiple votes to a single proposal, but the cost increases quadratically. The fundamental formula is Cost = (Number of Votes)². This means buying 1 vote costs 1 credit, 2 votes cost 4 credits, and 3 votes cost 9 credits. This convex cost curve prevents a wealthy minority from dominating outcomes, as the cost of casting a large number of votes becomes prohibitively expensive, forcing a more equitable distribution of influence. It's particularly suited for reputation-based systems where voting power is derived from a user's contribution score rather than token holdings.
Implementing QV requires managing a voter's credit budget and calculating costs. A user with a reputation score R might be allocated a voting budget of āR credits, directly linking influence to contribution. The core function must validate that a voter has sufficient budget for their desired vote allocation. The check is: require(votes² <= remainingBudget). After voting, the budget is deducted by votes². Here is a simplified Solidity function stub:
solidityfunction castVote(uint proposalId, uint votes) external { uint cost = votes * votes; require(balance[msg.sender] >= cost, "Insufficient budget"); balance[msg.sender] -= cost; // Record vote... }
This ensures the quadratic cost is enforced on-chain.
A critical consideration is preventing Sybil attacks, where a user creates multiple identities to split their budget and circumvent the quadratic cost. Without mitigation, an attacker with 100 credits could cast 10 votes across 10 identities (cost: 10 * 1² = 10) instead of 10 votes from one identity (cost: 10² = 100). The standard defense is to use a unique-human or reputation-based identity system like BrightID, Gitcoin Passport, or a non-transferable soulbound token (SBT). The voting contract must verify that each Ethereum address is tied to a unique, verified identity before allocating a budget. This ensures the cost curve applies per person, not per wallet.
Beyond basic implementation, systems like Quadratic Funding demonstrate QV's power for public goods financing. In a grants round, contributions are matched based on the square of the sum of square roots of individual contributions. The matching formula is more complex, but it leverages the same principle: many small contributions are valued more highly than a few large ones. For governance, you can extend the model with time decay on reputation to prevent stagnation, or partial lockup of funds to signal commitment. When integrating, consider using established libraries like OpenZeppelin for secure math operations to prevent overflows in the votes * votes calculation, especially in early Solidity versions.
To deploy a production system, start with a thorough audit of the voting logic and identity verification layers. Use testnets to simulate attack vectors like flash loan attacks on budget allocation. Key metrics to track include the Gini coefficient of vote distribution and the average cost per vote cast to ensure the quadratic mechanism is functioning as intended. For further reading, review Vitalik Buterin's original post on quadratic payments and the Gitcoin Grants implementation, which has allocated over $50 million using this model. The code and concepts here provide a foundation for building more expressive and fair on-chain governance systems.
Core Smart Contract Components
A quadratic voting system weights votes by the square root of the voter's stake or reputation tokens, reducing whale dominance. This guide covers the essential smart contract modules to build one.
Voice Credit Allowance
To prevent spam, users are allocated a budget of voice credits per proposal, typically equal to their reputation token balance. Casting a vote with weight w costs w² credits.
For example, a user with 100 credits can cast one vote with weight 10 (cost 100) or ten votes with weight 1 (cost 10 total). This contract tracks spent credits per user per proposal.
Tally & Result Aggregation
After voting ends, this module calculates the final result. It sums the square root weights for each option. The core formula is:
total_for_option = sum( sqrt(voter_i_balance) ) for all voters who chose that option.
Ensure the function is callable by anyone and resistant to reentrancy. Emit clear events with the final tallies for off-chain indexing.
How to Implement a Quadratic Reputation Voting System
A practical guide to building a Sybil-resistant, reputation-based governance mechanism using smart contracts.
A Quadratic Reputation Voting (QRV) system is a governance mechanism designed to reduce the influence of whales and Sybil attacks by weighting votes based on the square root of a user's reputation tokens. Unlike one-token-one-vote, where a user with 100 tokens gets 100 votes, QRV gives them only 10 votes (ā100). This promotes more egalitarian outcomes. The core components are a reputation token (non-transferable, soulbound), a voting contract that calculates quadratic weights, and a proposal lifecycle. This guide implements a basic version using Solidity, suitable for DAOs or community grants.
First, deploy the reputation token contract. It must be non-transferable (soulbound) to prevent reputation trading. Use OpenZeppelin's ERC20 with a modified _transfer function that reverts all transfers. Mint reputation based on verifiable, on-chain actions like protocol usage, contributions, or attestations. For example, users could earn 1 reputation point per week of active participation, capped to prevent inflation. Store the minting logic in a separate, upgradeable contract controlled by the DAO to adjust distribution rules over time.
Next, implement the core voting contract. The key function is calculateVotePower, which takes the voter's reputation balance and returns its square root. Use Solidity's sqrt function from a library like prb-math. The contract must track proposals with fields for description, voteStart, voteEnd, forVotes, and againstVotes. When a user casts a vote with castVote(proposalId, support), the contract fetches their current reputation, calculates the quadratic weight, and adds it to the respective tally. Ensure votes cannot be changed once cast.
To prevent Sybil attacks where users split reputation across multiple addresses, the system must use a unique identity proof. Integrate with a Sybil-resistance layer like BrightID, Gitcoin Passport, or Worldcoin. The voting contract should include a mapping address => bool isVerified and a function verifyIdentity(bytes proof) that checks an oracle or verifier contract. Only verified addresses can vote, and reputation should be minted solely to verified identities. This ensures one-human-one-identity, making quadratic costing effective.
Finally, add proposal creation and execution logic. Proposals can be created by any address meeting a minimum reputation threshold (e.g., 100 points). After the voting period ends, a queue function checks if the proposal passed (e.g., forVotes > againstVotes and quorum met). Successful proposals are queued for execution after a timelockāa critical security measure that allows users to exit if a malicious proposal passes. The execute function then calls the target contract with the encoded calldata. Use OpenZeppelin's TimelockController for robust, battle-tested delay logic.
For a production deployment, consider gas optimization and user experience. Pre-calculate and store vote power at the time of voting to prevent manipulation from changing reputation balances. Use snapshotting (like the snapshot() function in many governance tokens) to lock reputation at a specific block. Provide a frontend that fetches user reputation, active proposals, and verification status. Tools like Tally or Boardroom can be forked for the interface. Always audit the contracts, especially the square root math and identity verification integration, before mainnet launch.
Preventing Sybil Attacks with Quadratic Voting
Quadratic voting is a governance mechanism that uses cost functions to make Sybil attacks economically prohibitive, ensuring one-person-one-vote principles in decentralized systems.
A Sybil attack occurs when a single entity creates many fake identities to gain disproportionate influence in a system, such as a token-based governance vote. Traditional one-token-one-vote models are highly vulnerable, as wealth directly translates to power. Quadratic voting (QV) introduces a cost function to mitigate this: the cost to cast n votes scales quadratically with n. For example, buying 1 vote might cost 1 unit of credit, but buying 10 votes costs 100 credits. This rapidly increasing cost makes large-scale vote manipulation economically irrational for an attacker.
The core mechanism relies on a cost function, typically cost = votes². Users are often allocated a budget of voice credits. To implement this, a smart contract calculates the cost for a user's voting power. A basic Solidity structure might involve a mapping to track credits and a function to calculate vote cost:
soliditymapping(address => uint256) public voiceCredits; function calculateCost(uint256 votes) public pure returns (uint256) { return votes * votes; }
When a user submits votes for a proposal, the contract checks if voiceCredits[msg.sender] >= calculateCost(votes) before deducting the cost and recording the vote. This ensures the quadratic cost is enforced on-chain.
For the system to be effective, it requires a sybil-resistant identity layer to distribute the initial voice credits. This prevents an attacker from simply creating thousands of wallets with small credit allocations. Projects often integrate with Proof of Personhood systems like Worldcoin, BrightID, or Gitcoin Passport to issue one set of credits per verified human. Alternatively, a trusted committee or existing token holder snapshot can perform the initial distribution. The identity solution is critical; QV's cost function secures the voting process, but the identity layer secures the initial state.
A key advantage of QV is that it efficiently captures the intensity of preference. A user who feels strongly about a proposal can spend more of their credit budget to cast more votes, but at a steeply increasing marginal cost. This leads to more optimal collective decision-making compared to simple plurality voting. However, challenges include the complexity of explaining the mechanism to users and the potential for collusion or vote buying off-chain, which the on-chain system cannot prevent. Designs like quadratic funding for public goods extend this concept, making the funding match for a project proportional to the square of the sum of square roots of contributions.
To implement a full system, you would need to: 1) Integrate an identity oracle for credit distribution, 2) Deploy the voting contract with the quadratic cost function, 3) Create a front-end that clearly displays the cost of additional votes, and 4) Possibly include a commit-reveal scheme to prevent strategic voting based on early results. Frameworks like MACI (Minimal Anti-Collusion Infrastructure) combine quadratic voting with cryptographic techniques to enhance privacy and reduce collusion. By making the cost of influence scale quadratically, this mechanism remains one of the most promising defenses against Sybil attacks in decentralized governance.
Voting Mechanism Comparison
A comparison of core voting mechanisms for on-chain governance, highlighting trade-offs for reputation-based systems.
| Feature / Metric | One-Token-One-Vote (1T1V) | Quadratic Voting (QV) | Conviction Voting |
|---|---|---|---|
Sybil Attack Resistance | |||
Capital Efficiency | High | Medium | Low |
Voter Turnout Bias | High (whales) | Reduced | Time-based |
Implementation Complexity | Low | Medium | High |
Gas Cost per Vote | $2-5 | $5-15 | $10-30 (streaming) |
Real-Time Result Clarity | |||
Best For | Token-weighted decisions | Community sentiment | Continuous funding |
Code Example: Tallying Votes
This guide walks through the implementation of a quadratic reputation voting tally, a core mechanism for Sybil-resistant governance.
Quadratic voting (QV) is a mechanism designed to more accurately reflect the intensity of voter preferences while limiting the influence of wealthy or malicious actors. Instead of one person, one vote, each voter receives a budget of voice credits. The cost to cast n votes for a single proposal is n² credits. This quadratic cost curve makes it exponentially expensive to concentrate voting power, promoting a more equitable distribution of influence. In blockchain governance, this is often paired with a reputation or proof-of-personhood system to allocate the initial credit budget, mitigating Sybil attacks.
The core logic for tallying quadratic votes can be implemented in a smart contract. The contract must track each voter's remaining voice credit balance and calculate the cost of their votes. Below is a simplified Solidity function demonstrating the tallying logic for a single proposal. It assumes a voter's voiceCredits are stored in a mapping and that we are calculating the cost for their new votes on a proposal.
solidityfunction castVotes(address voter, uint256 proposalId, uint256 voteAmount) public { uint256 cost = voteAmount * voteAmount; // Quadratic cost: n² require(voiceCredits[voter] >= cost, "Insufficient voice credits"); // Deduct the cost from the voter's balance voiceCredits[voter] -= cost; // Record the weighted vote (e.g., sqrt for sum, or store raw amount) votes[proposalId] += voteAmount; // Or use sqrt(voteAmount) for sum of square roots }
This function enforces the quadratic cost: casting 1 vote costs 1 credit, 2 votes cost 4, 3 votes cost 9, and so on. To get the final tally for a proposal, you would sum the voteAmount for each voter. In some implementations, the sum of the square roots of the votes is used to preserve the quadratic property when aggregating.
For a complete governance system, you need to integrate this with a reputation registry. A contract like ERC-20 or a custom ERC-1400-style security token could represent reputation scores, where a user's balance defines their voice credit budget for a voting round. The tallying contract would check allowances or hold tokens in escrow during the vote. Off-chain, platforms like Tally or Snapshot with the QV module handle the complex UI and credit calculations, querying on-chain reputation data to initialize voting sessions.
Key considerations for production include: - Gas optimization for summing votes, - Preventing double voting, - Setting a clear voting period, and - Using a secure oracle or on-chain registry for the reputation data source. The quadratic formula is simple, but its power lies in dramatically altering the game theory of collective decision-making, making coordinated Sybil attacks economically prohibitive and favoring broad, decentralized participation.
Frequently Asked Questions
Common technical questions and implementation challenges for developers building quadratic reputation voting systems.
Quadratic voting (QV) is a governance mechanism where the cost of casting votes increases quadratically with the number of votes allocated to a single option. Unlike one-person-one-vote (1p1v), which grants equal, discrete voting power, QV allows participants to express the intensity of their preferences. A user's voting power is derived from a budget of voice credits (e.g., 99 credits). The cost to cast n votes for a proposal is n². This means 1 vote costs 1 credit, 2 votes cost 4 credits, 3 votes cost 9 credits, and so on. This quadratic cost function makes it economically prohibitive for a single entity to dominate voting, promoting more proportional and nuanced outcomes that reflect collective preference strength rather than simple headcounts.
Resources and Further Reading
These resources focus on the theory, implementation, and security considerations behind quadratic reputation voting systems. Each card points to concrete tools, papers, or codebases that help developers design, audit, or deploy quadratic voting with reputation weighting.
Conclusion and Next Steps
You have now built the core components of a quadratic reputation voting system. This guide covered the foundational smart contract logic, frontend integration, and key security considerations.
The system you've implemented uses a QuadraticVoting contract to manage a reputation-weighted voting mechanism. Key functions include castVote to apply quadratic cost, getVotingPower to calculate a user's influence based on a reputation score (e.g., from a token or non-transferable NFT), and administrative controls for setting proposals and tallying results. The quadratic formula cost = (votes)^2 ensures that distributing votes across multiple options is cheaper than concentrating them on one, promoting more nuanced decision-making. Remember to thoroughly test the contract's arithmetic to prevent overflow and ensure the reputation source is secure and sybil-resistant.
For frontend integration, you connected a dApp using ethers.js or viem to interact with the contract. The process involves fetching the user's reputation balance from a separate ReputationToken contract, displaying available voting power, and submitting transactions for castVote. A critical step is calculating and displaying the quadratic cost dynamically before the user submits, improving UX. Consider using a subgraph from The Graph protocol to index and query vote histories and proposal results efficiently, as on-chain event parsing can be slow for complex data displays.
The next logical step is to enhance the system's robustness and features. Explore integrating time-locked votes using OpenZeppelin's TimelockController to prevent last-minute manipulation. Implement delegation mechanics, allowing users to delegate their quadratic voting power to representatives. For production, a rigorous security audit is essential; services like CertiK, OpenZeppelin, or Code4rena can review the contract for vulnerabilities in the quadratic math and access controls. Finally, consider the governance framework: will proposals be created by token holders, a multisig, or via a proposal submission deposit?