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

How to Implement a Quadratic Funding Mechanism

This guide provides a technical blueprint for deploying a quadratic funding round. It covers the core algorithm, contract architecture, voter verification with Gitcoin Passport, sybil resistance strategies, and operational steps to run a funding round.
Chainscore Š 2026
introduction
DEVELOPER TUTORIAL

How to Implement a Quadratic Funding Mechanism

A technical guide to building a quadratic funding (QF) system from scratch, covering core concepts, smart contract logic, and a step-by-step implementation.

Quadratic funding (QF) is a democratic mechanism for allocating a matching pool of funds to public goods projects based on the number of contributors, not just the total amount contributed. The core formula is: Match ∝ (sum of square roots of contributions)^2. This amplifies the impact of a large number of small donations, making it a powerful tool for community-driven funding in Web3 ecosystems like Gitcoin Grants. Implementing QF requires a smart contract to securely collect contributions, calculate matches, and distribute funds.

The implementation logic centers on two main phases: the contribution phase and the matching calculation. During the contribution phase, the contract records each donor's contribution to a specific project. A critical security consideration is preventing Sybil attacks; this is typically addressed by integrating with a proof-of-personhood system like World ID or BrightID to verify unique contributors. The contract must store contributions in a way that allows efficient calculation of the square root sum per project.

After the contribution period ends, the matching calculation is performed off-chain for gas efficiency and then verified on-chain. A common pattern is to use a merkle tree to commit to the final matching amounts. The steps are: 1) For each project, sum the square roots of all individual contributions. 2) Square that sum to get the "quadratic sum." 3) Allocate the matching pool proportionally based on each project's share of the total quadratic sum. This calculation is done in a script (e.g., using TypeScript and the ethers library) that reads the on-chain contribution data.

Here is a simplified smart contract snippet for the core contribution logic, excluding the matching distribution for brevity. It uses a Project struct to track funds and a mapping to record individual contributions to prevent double-counting in calculations.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract QuadraticFundingRound {
    struct Project {
        uint256 totalFunding;
        uint256 matchAmount;
        bool exists;
    }

    mapping(uint256 => Project) public projects;
    // Nested mapping: projectId -> contributor -> amount
    mapping(uint256 => mapping(address => uint256)) public contributions;
    
    function contribute(uint256 _projectId) external payable {
        require(projects[_projectId].exists, "Project does not exist");
        require(msg.value > 0, "Contribution must be > 0");
        
        contributions[_projectId][msg.sender] += msg.value;
        projects[_projectId].totalFunding += msg.value;
    }
}

To finalize the round, the off-chain calculation script generates a merkle root of the final match amounts. A distribute function in the contract would then allow project owners to claim their matched funds by providing a merkle proof. For production, you must integrate oracle services like Chainlink for secure off-chain computation or use a zk-SNARK circuit (e.g., with Circom) to verify the quadratic calculation on-chain privately. Key resources include the CLRFund protocol for a complete implementation and the QF research paper for theoretical foundations.

prerequisites
QUADRATIC FUNDING IMPLEMENTATION

Prerequisites and Required Knowledge

Before building a quadratic funding mechanism, you need a solid foundation in smart contract development, decentralized finance concepts, and the mathematical principles behind the algorithm.

Quadratic funding (QF) is a mechanism for democratically allocating a matching pool of funds to public goods projects based on the number of contributors, not just the total amount contributed. The core formula calculates a project's matching amount as the square of the sum of the square roots of individual contributions. To implement this, you must understand the key components: a registry for projects, a mechanism for collecting contributions (often in a stablecoin like USDC), a matching pool, and the off-chain or on-chain computation of the QF algorithm. Familiarity with platforms like Gitcoin Grants, which popularized the model, provides essential context for real-world constraints and user expectations.

You need proficiency in smart contract development using Solidity (for Ethereum/EVM chains) or Rust (for Solana). Essential skills include writing secure, upgradeable contracts, implementing access control (e.g., OpenZeppelin's Ownable), and handling ERC-20 token transfers. A basic implementation involves a QuadraticFunding contract with functions to registerProject(bytes32 projectId), contribute(address project, uint256 amount), and distributeFunds(uint256[] calldata amounts). You must also plan for round management, setting clear start/end times and finalizing results. Security is paramount; common pitfalls include reentrancy attacks, rounding errors in the square root calculation, and front-running during the distribution phase.

The QF algorithm requires significant computation, especially the iterative calculation of match amounts using the Clarke pivot mechanism to find the optimal distribution. This is often performed off-chain for gas efficiency. You'll need to write a script (in Python or JavaScript) that fetches all contribution data, solves the quadratic funding optimization problem, and generates a Merkle root for on-chain verification. Understanding libraries like MACI (Minimal Anti-Collusion Infrastructure) is crucial for preventing collusion and sybil attacks, where a user splits funds across multiple wallets to game the matching formula. Tools like SnarkJS for zero-knowledge proofs may be required for private voting rounds.

Finally, you must integrate with the broader Web3 stack. This includes a frontend (using a framework like React with wagmi or ethers.js), an indexer (like The Graph) to query contributions efficiently, and a decentralized storage solution (like IPFS or Arweave) for project metadata. Testing your contracts thoroughly with Hardhat or Foundry, including fuzzing tests for the matching algorithm, is non-negotiable. You should also understand the regulatory and operational aspects of managing a grants round, including KYC/AML considerations for large matches and the design of a clear user interface for both contributors and project owners.

core-algorithm-explanation
IMPLEMENTATION GUIDE

The Quadratic Funding Algorithm

A technical guide to implementing Quadratic Funding (QF), the democratic matching mechanism used by Gitcoin Grants and other public goods funding platforms.

Quadratic Funding (QF) is a mechanism for optimally allocating a matching pool to a set of public goods projects based on community contributions. The core principle is that the matching amount for a project is proportional to the square of the sum of the square roots of individual contributions. This formula, (sum(√contribution))², mathematically favors projects with broad-based community support over those funded by a few large donors. The algorithm's goal is to maximize the "perceived value" created for the community, making it a powerful tool for decentralized grant programs and democratic capital allocation.

To implement QF, you need to define the core data structures and calculate the matching amounts. The essential inputs are: a list of projects, a list of contributions (each with amount, contributor, and projectId), and a total matching pool amount. The calculation is performed in two main steps. First, for each project, sum the square roots of all contributions to it. Second, square that sum to get the project's QF match coefficient. The total matching pool is then distributed proportionally based on these coefficients. A basic implementation in Solidity would store contributions in a mapping and iterate through them to perform these calculations, though this can be gas-intensive for on-chain execution.

A critical implementation detail is handling the pairwise coordination or clr.fund optimization. The naive calculation scales quadratically (O(n²)) with the number of contributions, which is prohibitive. The optimized algorithm, as described by Vitalik Buterin, Zoe Hitzig, and Glen Weyl, uses vector math. It constructs a matrix where each row represents a contributor and each column a project, with cell values being √contribution. The matching amounts are derived from the matrix's pairwise dot products. Libraries like quadratic-funding provide optimized JavaScript implementations of this algorithm, which are essential for any production-grade QF round.

When deploying QF on-chain, developers must consider gas costs and data availability. Full on-chain calculation is often too expensive. A common pattern is to compute the final results off-chain using the optimized algorithm and a verifiable data set (like a Merkle tree of contributions), then post the results and a proof on-chain for distribution. Platforms like Allo Protocol abstract this complexity by providing smart contract infrastructure to create and manage QF rounds. Key contract functions include allocate for registering contributions and distribute for executing the matching payout, often integrating with Superfluid for streaming distributions.

Security and sybil-resistance are paramount. A naive QF implementation is vulnerable to collusion and fake accounts. Implementations must integrate a sybil defense layer, such as Gitcoin Passport, BrightID, or proof-of-personhood protocols. Each contribution's weight is often multiplied by a trust score from this layer. Furthermore, the use of capital-constrained matching pools can limit the impact of large, manipulative donations. Auditing the rounding logic and ensuring no single project can drain the entire pool through edge cases are critical steps before launching a round.

To test your implementation, simulate rounds with varied contribution patterns: many small donations to one project, a few large donations to another, and a mix. Verify that the matching amplifies the project with broader support. For further learning, review the source code of Gitcoin Grants rounds, the clr.fund protocol, and the documentation for Allo Protocol. These real-world systems provide battle-tested patterns for handling everything from user interfaces and contribution aggregation to final trust-minimized distribution on Ethereum L2s like Optimism or Arbitrum.

contract-architecture-components
QUADRATIC FUNDING IMPLEMENTATION

Smart Contract System Architecture

A technical guide to building a decentralized quadratic funding protocol, covering core contracts, matching pool mechanics, and security considerations.

01

Core Round Manager Contract

The central coordinator contract that defines funding rounds. It handles:

  • Round lifecycle: registration, submission, voting, and payout phases.
  • Project registry to whitelist eligible recipients.
  • Timelocks and admin controls for secure round management.
  • Integration with a price oracle (e.g., Chainlink) to calculate matching amounts in a stable denomination.

This contract is the system's state machine, ensuring rounds proceed in the correct order.

02

Quadratic Voting & Funding Formula

Implements the mathematical core that allocates matching funds proportionally to the square of the sum of square roots of contributions.

Key functions include:

  • calculateMatchAmount: Computes the provisional match for a project based on current votes.
  • applyVote: Updates a user's voting power and project totals, often using a commit-reveal scheme or MACI (Minimal Anti-Collusion Infrastructure) to prevent sybil attacks.
  • The contract must track totalContributions and sumOfSquareRoots per project to efficiently calculate matches.

Example: A project with two contributions of $1 and $4 has a match weight of (√1 + √4)² = 9.

03

Matching Pool & Fund Allocation

A vault contract that holds the matching funds (e.g., from a DAO treasury or grant) and executes the final distribution.

Architecture considerations:

  • Token agnostic design: Can hold ETH, ERC-20 tokens, or stablecoins like USDC.
  • Pull vs. push payments: Projects often claim funds after the round to save gas.
  • Matching cap logic: Implements limits (e.g., a 100% match cap per project) to prevent a single project from draining the pool.
  • After the round ends, the manager contract calls distributeFunds to calculate final matches and transfer tokens from the pool to projects.
04

Sybil Resistance & User Identity

Preventing collusion and fake identities is critical for quadratic funding's legitimacy. Implementation strategies:

  • Integration with Proof-of-Personhood protocols like Worldcoin or BrightID to issue unique voting credentials.
  • Semaphore or MACI for anonymous voting where users sign votes with a private key but cannot prove how they voted, disrupting bribery.
  • Passport by Gitcoin: A decentralized identity protocol that aggregates stamps (verifications from other platforms) to compute a unique, non-sybil score for each participant.
  • The voting contract must verify a user's credential or passport score before accepting their contribution.
05

Reference Implementations & Audits

Study and fork audited code from established protocols to bootstrap development.

Critical: Any production deployment requires a professional smart contract audit from firms like OpenZeppelin, Quantstamp, or Code4rena.

EXPLORE
06

Frontend & Indexing Integration

Building the user interface and data layer to interact with the contracts.

  • Frontend Library: Use wagmi and viem to connect wallets, call contract functions, and switch networks.
  • Subgraph (The Graph): Indexing is essential for displaying real-time leaderboards. A subgraph will index events like ProjectCreated, Voted, and FundsClaimed to show contribution totals and matching estimates.
  • IPFS/Arweave: Store round metadata (project descriptions, banners) and final results on decentralized storage.
  • RPC Providers: Use reliable providers like Alchemy or Infura for consistent read/write access to the blockchain.
step-by-step-implementation
STEP-BY-STEP GUIDE

How to Implement a Quadratic Funding

A technical walkthrough for developers to build a basic quadratic funding mechanism, from theory to a functional smart contract prototype.

Quadratic funding (QF) is a democratic mechanism for allocating capital to public goods, where the collective preference of many small contributors is amplified. The core formula calculates a matching pool contribution to a project as the square of the sum of the square roots of individual contributions. In practice, this means a project with ten $1 donations receives more matching funds than a project with one $100 donation, even though the total contributed is the same. This design strongly incentivizes broad-based community support. To implement this, you'll need a system to collect contributions, calculate the QF match, and distribute funds from a matching pool.

Start by designing your data structures and state variables in a smart contract. You'll need to track projects, contributions, and the matching pool. A minimal Solidity setup might include:

solidity
struct Project {
    uint256 id;
    address payable recipient;
    uint256 totalContributions;
    uint256 sumOfSqrtContributions;
}

struct Contribution {
    address contributor;
    uint256 amount;
    uint256 projectId;
}

Project[] public projects;
Contribution[] public contributions;
mapping(uint256 => uint256[]) public projectContributions; // projectId -> contribution indices
uint256 public matchingPool;

The sumOfSqrtContributions is a key metric, updated with each new donation using sqrt(contributionAmount). Storing this running sum is more gas-efficient than recalculating from all contributions later.

The contribution function is the heart of the on-chain interaction. When a user donates, you must update the project's totals, record the individual contribution, and collect the funds. Crucially, you must prevent manipulation by ensuring contributions are final and cannot be withdrawn to game the square root calculation. A basic contribute function looks like this:

solidity
function contribute(uint256 _projectId) external payable {
    require(_projectId < projects.length, "Invalid project");
    require(msg.value > 0, "Contribution must be > 0");

    Project storage p = projects[_projectId];
    p.totalContributions += msg.value;
    // Using fixed-point math library (like PRBMath) for sqrt is recommended
    p.sumOfSqrtContributions += sqrt(msg.value);

    contributions.push(Contribution(msg.sender, msg.value, _projectId));
    projectContributions[_projectId].push(contributions.length - 1);

    emit Contributed(msg.sender, _projectId, msg.value);
}

After the contribution period ends, you must calculate the QF match for each project. This is done off-chain for gas efficiency, but the logic must be verifiable. For each project i, calculate its match: (sumSqrt_i ^ 2) * (matchingPool / totalSumSqrtSquared). The denominator is the sum of sumSqrt_i ^ 2 for all projects. This ensures the entire matching pool is distributed proportionally.

Finally, implement a distributeFunds function that allows the owner or a trusted round manager to execute the payout based on the pre-calculated matches. This function transfers both the collected contributions and the allocated matching funds to each project's recipient. Always include access control (like OpenZeppelin's Ownable) for this sensitive operation. After distribution, consider adding a timelock or multi-sig requirement for the matching pool funds to enhance security and trust in the mechanism. For production use, integrate with existing frameworks like CLRFund or Gitcoin Grants Stack which provide battle-tested contracts, frontends, and round management tools, rather than building everything from scratch.

COMPARISON

Sybil Resistance and Identity Verification Methods

Methods to prevent duplicate or fake identities in a Quadratic Funding round, balancing security, cost, and user experience.

MethodGitcoin PassportBrightIDProof of HumanityCaptcha / Social Graph

Core Mechanism

Aggregated Web2/Web3 identity attestations

In-person verification via video calls

Kleros-curated registry of unique humans

Algorithmic challenge or social connections

Sybil Resistance Strength

High

Very High

Very High

Low to Medium

User Onboarding Friction

Low (non-custodial, self-sovereign)

Medium (requires scheduling a verification party)

High (requires deposit, video submission, challenge period)

Very Low (instant, familiar UX)

Implementation Cost for Round

~$0.10 - $1 per verification (Stamp costs)

Free for users, grant funding for verifiers

~$1.50 + gas fees for user deposit

< $0.01 per verification

Decentralization

Hybrid (centralized attestations, decentralized aggregation)

Decentralized (peer-to-peer verification network)

Decentralized (curated by Kleros court)

Centralized (service provider)

Privacy Model

Selective disclosure of stamps; ZK-proofs possible

No personal data stored on-chain; graph-based identity

Public video profile and personal details

Varies; often collects behavioral data

Integration Complexity

Medium (API, scoring, custom weighting)

Medium (BrightID node or API integration)

High (smart contract integration, dispute handling)

Low (standard API or widget)

Best For

Large-scale, recurring rounds with broad participation

High-value rounds where strongest Sybil resistance is critical

Rounds requiring strong legal identity binding

Low-stakes rounds or as a secondary filter

integrating-gitcoin-passport
QUADRATIC FUNDING GUIDE

Integrating Gitcoin Passport for Verification

This guide explains how to use Gitcoin Passport to verify unique human users, a critical component for securing a quadratic funding mechanism against Sybil attacks.

Quadratic Funding (QF) is a democratic mechanism for allocating capital to public goods, where the influence of a contribution is proportional to the square root of its amount, weighted by the number of contributors. This design amplifies the power of a broad base of small donors. However, it is highly vulnerable to Sybil attacks, where a single entity creates many fake identities to manipulate the matching pool. To ensure the integrity of a QF round, you must verify that each participant is a unique human. Gitcoin Passport provides a decentralized identity verification service that aggregates stamps from various Web2 and Web3 sources to compute a trust score.

Gitcoin Passport operates by allowing users to connect accounts from services like Google, Discord, BrightID, and Ethereum to prove their humanity. Each connection acts as a 'stamp' of verification. The Passport SDK aggregates these stamps and calculates a score. In a QF context, you set a minimum score threshold (e.g., 20 points) that a user must meet to be eligible to donate or receive matching funds. This process, known as Sybil resistance, ensures that funding distribution reflects genuine community support rather than manipulation by a few wealthy or malicious actors.

To integrate Passport, you first need to install the required packages. For a JavaScript/TypeScript project, you can use the official @gitcoin/passport-sdk. Begin by installing it via npm: npm install @gitcoin/passport-sdk. The core components you will interact with are the Passport and Scorer classes. You must configure the SDK with your Scorer ID and API key, which you obtain by creating a Scorer in the Gitcoin Passport dashboard. This Scorer defines the stamp weights and the scoring mechanism your application will use.

The verification flow involves two main steps: fetching a user's Passport and checking their score. First, when a user connects their wallet, you call Passport.getPassport(stampAddress) to retrieve their aggregated stamps. Then, you use Scorer.getScore(passport) to calculate their score based on your configured Scorer. Below is a simplified code example of this check:

javascript
import { Passport, Scorer } from '@gitcoin/passport-sdk';

const scorer = new Scorer('<YOUR_SCORER_ID>', '<YOUR_API_KEY>');

async function verifyUser(donorAddress) {
  const passport = await Passport.getPassport(donorAddress);
  const score = await scorer.getScore(passport);
  
  const MINIMUM_THRESHOLD = 20;
  if (score >= MINIMUM_THRESHOLD) {
    console.log('User is verified for Quadratic Funding.');
    return true;
  } else {
    console.log('User does not meet the Passport score threshold.');
    return false;
  }
}

When designing your QF application, you must decide when to perform this verification. The most secure pattern is to check the Passport score on-chain at the moment a donation is made or a project is submitted. You can achieve this by having your smart contract call an off-chain API endpoint (or oracle) that runs the verification logic. Alternatively, for a simpler initial implementation, you can perform the check off-chain in your frontend application and only allow verified wallets to interact with the donation interface. Remember to re-verify scores periodically, as stamps can expire.

Beyond the basic integration, consider these advanced practices. Use incremental scoring to allow users who don't meet the threshold to be guided to add more stamps. Implement caching for Passport data to reduce API calls and improve UX, but respect data freshness. For maximum decentralization, explore using the Passport Verifier to generate zero-knowledge proofs of humanity, though this is more complex. Proper integration of Gitcoin Passport transforms your quadratic funding mechanism from a theoretical model into a practical, Sybil-resistant tool for funding public goods.

QUADRATIC FUNDING

Common Implementation Mistakes and Pitfalls

Implementing a quadratic funding mechanism involves complex smart contract logic and economic design. Developers often encounter specific, recurring issues that can compromise security, fairness, or functionality. This guide addresses the most frequent mistakes.

This is often caused by using Solidity's native integer types for calculations involving large sums or the quadratic formula. The matching amount is calculated as (sum of square roots)^2, which can easily exceed uint256 limits.

Common pitfalls:

  • Performing sqrt(sum) instead of sum(sqrt).
  • Not using a fixed-point math library (like PRBMath or ABDK) for precision.
  • Calculating on-chain without scaling decimals, leading to rounding errors.

How to fix:

  1. Use a proven square root library designed for uint256.
  2. Perform the summation of square roots in a scaled-up number space (e.g., multiply by 1e18).
  3. Consider calculating the final match off-chain via a trusted oracle or a zk-SNARK verifier for large-scale rounds.
QUADRATIC FUNDING

Frequently Asked Questions

Common questions and technical hurdles developers face when implementing a quadratic funding mechanism for grants, public goods, or community funding rounds.

The core mechanism calculates a project's matching amount based on the square of the sum of the square roots of individual contributions. The formula for a project's total funding is:

code
Total_Funding = Sum(Contributions) + Matching_Pool * ( (Sum(sqrt(Contribution_i)))^2 / Sum_over_all_projects( (Sum(sqrt(Contribution_i)))^2 ) )

Key components:

  • Sum(Contributions): The direct donations a project receives.
  • Matching Pool: The total funds available for matching (e.g., from a protocol treasury).
  • Sum(sqrt(Contribution_i)): For each project, you take the square root of each individual contribution, then sum those values.
  • The squared sum of square roots is then divided by the sum of this value across all projects to determine the matching share. This formula rewards projects with a broad base of support (many small contributions) over those with a few large contributions.
conclusion-next-steps
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have now explored the core components for building a quadratic funding (QF) mechanism, from vote aggregation to subsidy calculation. This guide provides a foundational implementation to build upon.

A production-ready QF system requires significant enhancements beyond this basic implementation. Key considerations include sybil resistance through identity verification (e.g., Gitcoin Passport, BrightID), secure and transparent fund management via a multi-sig treasury or vesting contract, and robust front-end design for user-friendly project discovery and donation. The on-chain calculation shown is intentionally simplified; for large rounds, consider using a merkle tree to batch votes and reduce gas costs, or moving the quadratic math off-chain with verifiable proofs.

To test and extend your implementation, start by forking the example repository and deploying it to a testnet. Experiment with different matching pool sizes and contribution curves (e.g., using a different exponent in the power calculation). Integrate a price oracle like Chainlink to handle donations in stablecoins. For deeper learning, study the source code of established protocols like Gitcoin Grants, which uses a round manager contract and a complex data layer (the "QF super app") to coordinate community rounds.

The next logical step is to design the governance layer. Who controls the parameters like the matching cap, round duration, and eligible project lists? Consider implementing a DAO using a framework like OpenZeppelin Governor to let token holders vote on these decisions. Furthermore, analyze the data generated by your round. Tools like The Graph can be used to index contribution events, enabling powerful dashboards that show funding distribution and community impact, which is essential for attracting future donors and participants.

Finally, remember that quadratic funding's power lies in its community. A successful round depends on clear communication, accessible documentation for project creators, and transparent reporting of results. Use the verified contract addresses on a block explorer like Etherscan to provide full transparency. By combining a secure technical implementation with strong community practices, you can leverage quadratic funding to democratically allocate resources and fund public goods effectively.

How to Implement a Quadratic Funding Mechanism | ChainScore Guides