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 a Quadratic Funding Mechanism for Community Projects

A technical tutorial for implementing a quadratic funding round to allocate community treasury funds based on contributor support.
Chainscore © 2026
introduction
GUIDE

Introduction to Quadratic Funding Implementation

A technical walkthrough for developers to build a quadratic funding mechanism for community grant programs.

Quadratic funding (QF) is a democratic mechanism for allocating community funds, where the collective preferences of many small donors are amplified. Unlike simple vote-counting, QF uses a matching pool to square the sum of the square roots of individual contributions to a project. This mathematically favors projects with broad support over those funded by a few large donors. It's the core mechanism behind major ecosystems like Gitcoin Grants and Optimism's RetroPGF. Implementing it requires a smart contract to handle contributions, calculate matches, and distribute funds.

The core logic resides in a smart contract. You need to track contributions per project in a mapping, calculate the match using the quadratic formula, and manage a matching pool. A basic contract structure includes functions to donate(uint256 projectId), finalizeRound(), and withdrawMatch(uint256 projectId). Security is paramount: the contract must prevent reentrancy, ensure only the round operator can finalize it, and use pull-over-push patterns for withdrawals to avoid gas limit issues and failed transfers.

Here is a simplified Solidity snippet for the critical match calculation. This function iterates through projects after a funding round, sums the square roots of contributions, and determines the match from the pool.

solidity
function calculateMatch(uint256 projectId) public view returns (uint256) {
    uint256 sumOfSquareRoots = 0;
    uint256 totalMatch = 0;
    // First loop: calculate total sum of square roots for all projects
    for(uint256 i = 0; i < projectCount; i++) {
        sumOfSquareRoots += sqrt(contributions[i]);
    }
    // Calculate match for specific project
    uint256 projectSqrt = sqrt(contributions[projectId]);
    if (sumOfSquareRoots > 0) {
        totalMatch = (matchingPool * (projectSqrt ** 2)) / (sumOfSquareRoots ** 2);
    }
    return totalMatch;
}

Note: A production implementation requires a secure sqrt function (consider using prb-math library) and careful fixed-point math to avoid precision loss.

A full implementation requires several key components beyond the core contract. You'll need a subgraph (using The Graph) to index donation events for efficient querying by a frontend. A user interface, typically built with a framework like React and wagmi, allows users to connect wallets, view projects, and contribute. For data integrity, consider using IPFS (via Pinata or web3.storage) to store project metadata like descriptions and logos, storing only the content identifier (CID) on-chain.

Before launching, you must address critical design decisions. These include: the round duration and finalization timing, the source and size of the matching pool, the token used for contributions (native ETH, stablecoins, or ERC-20), and sybil resistance measures. For sybil resistance, integrate with BrightID or Gitcoin Passport to verify unique humanness, ensuring the mechanism isn't gamed by users creating multiple wallets to manipulate the quadratic formula.

To test your implementation, deploy it on a testnet like Sepolia or Goerli. Use a framework like Hardhat or Foundry to write comprehensive tests that simulate multiple donors and projects, verifying the match distribution is correct. After testing, you can deploy the final contract on a mainnet like Ethereum, Polygon, or Optimism. Monitor the contract with tools like Tenderly for real-time analytics and error tracking. The complete code and further resources are often shared on GitHub for community audit and reuse.

prerequisites
QUADRATIC FUNDING

Prerequisites and Setup

This guide details the technical prerequisites and initial setup required to deploy a Quadratic Funding (QF) mechanism for community grant allocation.

Quadratic Funding is a democratic mechanism for funding public goods, where the allocation of a matching pool is determined by the square of the sum of the square roots of individual contributions. To implement this, you will need a foundational understanding of smart contract development on a blockchain like Ethereum, Polygon, or Optimism. Essential tools include Node.js (v18+), a package manager like npm or yarn, and a code editor such as VS Code. You will also need a basic grasp of Git for version control and accessing open-source QF repositories.

The core of a QF system consists of several interoperable components. You will need a registry contract to manage rounds and projects, a voting contract to record contributions and calculate the QF algorithm, and a distributor contract to allocate the matching pool funds. For development and testing, set up a local blockchain environment using Hardhat or Foundry. Configure your environment to connect to a testnet (e.g., Sepolia) using an RPC provider like Alchemy or Infura, and fund a test wallet with faucet ETH for deploying contracts and simulating transactions.

A critical prerequisite is securing an API key for IPFS (InterPlanetary File System), as QF rounds typically store project metadata—like descriptions and images—decentrally. Services like Pinata or web3.storage provide managed IPFS solutions. Additionally, you will need to set up a subgraph using The Graph protocol to index and query on-chain event data (contributions, projects) efficiently for your application's front-end. This involves defining a schema and mapping event handlers in AssemblyScript.

For the application layer, you'll build a front-end interface, often using a framework like Next.js or Vite with React. Essential libraries include wagmi and viem for wallet connection and blockchain interaction, and Tailwind CSS for styling. The front-end must interact with your deployed smart contracts, the IPFS gateway for metadata, and the GraphQL endpoint of your subgraph to display real-time round data and contribution totals.

Finally, comprehensive testing is non-negotiable. Write and run unit tests for your smart contracts using Hardhat's testing environment or Foundry's Forge to verify the correctness of the QF matching calculation, access controls, and fund distribution logic. Perform integration tests by simulating a full round lifecycle—project registration, user contributions, round closing, and fund distribution—on a testnet before considering a mainnet deployment.

key-concepts-text
KEY CONCEPTS

How Quadratic Funding Works

Quadratic Funding (QF) is a democratic mechanism for allocating community funds, mathematically designed to maximize the number of people who benefit, not just the amount of money they contribute.

Quadratic Funding is a capital allocation formula pioneered by Glen Weyl, Vitalik Buterin, and Zoë Hitzig. It is the core mechanism behind major public goods funding platforms like Gitcoin Grants. The system operates on a simple but powerful principle: the amount of matching funds a project receives is proportional to the square of the sum of the square roots of contributions. This formula creates a subsidy that amplifies the impact of small, grassroots donations relative to large, single-source donations.

The mechanism works through a matching pool. Contributors donate directly to projects they support. A separate pool of funds (e.g., from a DAO treasury or protocol) is then distributed as matching funds according to the QF algorithm. For example, if Alice donates $1 and Bob donates $4 to a project, the sum of square roots is √1 + √4 = 1 + 2 = 3. The square of this sum is 3² = 9. The matching amount is calculated as (9) minus the total direct contributions ($5), resulting in $4 of matching funds. This $4 subsidy is vastly larger than the direct $5, demonstrating the power of broad-based support.

This design creates unique economic incentives. It rewards projects that build a broad base of community support rather than courting a few wealthy backers. A project with 100 donations of $1 each will receive significantly more matching funds than a project with one donation of $10,000, even though the total direct contribution is the same. This makes QF exceptionally effective for funding public goods—projects like open-source software, community infrastructure, or educational content that benefit many people but are traditionally underfunded.

Implementing QF requires careful design to prevent sybil attacks, where a single entity creates many fake identities to manipulate the matching formula. Standard defenses include using brightID, Gitcoin Passport, or other proof-of-personhood systems to verify unique contributors. The matching calculation is typically performed at the end of a funding round, with results verified on-chain before funds are distributed via a smart contract to ensure transparency and trustlessness.

For developers, setting up a QF round involves several key components: a contribution contract to collect donations, a registry of verified participants, an off-chain oracle (like the QF clr algorithm) to compute the matching distribution, and a distribution contract to allocate the matching pool. Platforms like Allo Protocol provide modular, audited smart contract infrastructure to build custom QF rounds without reinventing the cryptographic and economic safeguards.

MODEL COMPARISON

Quadratic Funding vs. Other Grant Models

A feature and outcome comparison of popular grant distribution mechanisms for community projects.

Feature / MetricQuadratic FundingDirect Grants (Committee)Retroactive Funding

Core Allocation Principle

Crowd-matching based on unique contributor count

Centralized committee decision

Retroactive reward for proven work

Democratic Participation

Sybil Attack Resistance

Requires identity verification (e.g., Gitcoin Passport)

Low risk

Low risk

Funding Efficiency (Signal vs. Noise)

High - amplifies broad community support

Medium - depends on committee insight

Very High - rewards tangible results

Typical Grant Size Range

$1k - $50k (matching pool dependent)

$5k - $100k+

$10k - $1M+

Time to Decision/Funding

1-4 weeks (round-based)

1-3 months (application review)

Post-delivery (months after work)

Best For

Early-stage ideas, community sentiment

Strategic, high-capital projects

Completed work, infrastructure, public goods

Primary Platform Examples

Gitcoin Grants, clr.fund

Uniswap Grants, Compound Grants

Optimism RetroPGF, Arbitrum Grants

contract-setup
FOUNDATION

Step 1: Smart Contract Architecture

This section details the core smart contract components required to build a secure and efficient quadratic funding mechanism on-chain.

A quadratic funding (QF) mechanism is governed by a set of smart contracts that manage the entire funding round lifecycle. The core architecture typically consists of three primary contracts: a Round Factory for deployment, a Voting/Vault Contract to handle contributions and matching calculations, and a Project Registry to manage the list of eligible projects. This separation of concerns enhances security, upgradability, and gas efficiency. For production, consider using established frameworks like OpenZeppelin for access control and security patterns.

The Project Registry is a critical on-chain directory. Each project submits a profile containing a recipient address (e.g., a multisig or smart wallet), a metadata pointer (like an IPFS hash for details), and a status flag. Only approved projects can receive votes and funding. This contract should implement a permissioned addProject function, often gated by a round manager or a governance vote, to prevent spam. Storing metadata off-chain (using IPFS or Arweave) is standard to minimize gas costs while maintaining verifiable project information.

The heart of the system is the Voting/Vault Contract. It must securely accept contributions in a native token or ERC-20, record each individual's donations to specific projects, and calculate the quadratic match. A key security pattern is to use a pull-over-push architecture for fund distribution. Instead of sending tokens during the round, the contract holds all funds and allows approved projects to withdraw their allocated share after the round concludes. This prevents reentrancy attacks and simplifies the logic for handling failed transactions.

Implementing the quadratic formula on-chain requires careful gas optimization. The matching calculation sums the square root of each contribution to a project, squares the total, and sums across all projects. Performing this for every vote is prohibitively expensive. The standard solution, pioneered by Gitcoin Grants, is to use a Merkle root distributor. All contributions are compiled off-chain, the quadratic matches are calculated off-chain, and a Merkle root of the final distribution is posted on-chain. Projects can then claim their funds by submitting a Merkle proof, reducing gas costs by orders of magnitude.

Finally, the Round Factory contract streamlines the creation of new funding rounds with preset parameters. It deploys new instances of the voting contract and project registry, initializing them with round-specific configurations: the matching pool size, the token address, and the start/end timestamps. Using a factory pattern ensures each round is isolated, preventing cross-round contamination of funds or state. This contract is also the natural place to implement upgradeable proxies if you plan to iterate on the core logic without migrating historical round data.

voter-verification
ENSURING INTEGRITY

Step 2: Implementing Voter Verification

This step establishes the rules for who can vote and how their voting power is calculated, moving from a simple one-person-one-vote model to a more nuanced system that prevents Sybil attacks.

The core challenge in any on-chain voting system is Sybil resistance—preventing a single entity from creating many fake identities to manipulate the outcome. For quadratic funding, where the goal is to measure the breadth of community support rather than the depth of capital, this is critical. Simple token-based voting gives disproportionate power to whales. Instead, we implement a verification mechanism that ties voting power to a unique, provable human or entity, often through proof of personhood or soulbound tokens.

A common implementation uses Gitcoin Passport or World ID to issue a verifiable credential (VC) upon successful verification. This credential, often a non-transferable ERC-1155 or SBT (Soulbound Token), is minted to the voter's wallet and serves as their passport to participate. The smart contract's verifyVoter function checks for the presence of this credential. Only addresses holding a valid, unexpired credential can call the vote or allocateFunds function, effectively creating a permissioned set of verified participants.

Here is a simplified Solidity example of a voter verification check using an external credential contract. The core voting contract stores the address of the verifier and checks balances in the vote function.

solidity
interface ICredentialVerifier {
    function balanceOf(address account, uint256 id) external view returns (uint256);
}

contract QuadraticFundingRound {
    ICredentialVerifier public verifier;
    uint256 public constant PASSPORT_TOKEN_ID = 1;

    constructor(address _verifierAddress) {
        verifier = ICredentialVerifier(_verifierAddress);
    }

    function vote(uint256 projectId, uint256 amount) external {
        require(
            verifier.balanceOf(msg.sender, PASSPORT_TOKEN_ID) > 0,
            "QF: Sender lacks verification credential"
        );
        // ... rest of voting logic
    }
}

This setup delegates trust to the external verifier, which manages the complexity of identity checks off-chain.

With verified voters, we can now implement the quadratic cost function. A voter's influence is the square root of their contributed amount. Contributing 9 units of currency costs the voter 9, but only adds 3 (√9) units of "voice" to the matching calculation. This mathematically favors projects with many small contributions over those with few large ones. The contract must track the sum of square roots of contributions per project, not the raw sums, to calculate the final matching distribution from the pool.

It is essential to make the verification process and rules transparent before the round begins. Participants should know: the verification method (e.g., Gitcoin Passport), the deadline to get verified, the cost function formula, and the token used for contributions (e.g., ETH, USDC). This transparency, combined with the on-chain verification check, builds trust in the round's legitimacy and ensures the outcome reflects genuine community sentiment.

vote-aggregation
IMPLEMENTATION

Step 3: Calculating the Quadratic Match

This step details the core algorithm that determines how a matching pool is distributed among projects based on community contributions.

The quadratic funding match is not a simple proportional split. It uses a formula to amplify the impact of the number of contributors, not just the total amount contributed. The fundamental calculation for a project's match is the sum of the square roots of each individual contribution, squared. For a project receiving contributions c1, c2, ..., cn, its match M is calculated as: M = (sqrt(c1) + sqrt(c2) + ... + sqrt(cn))^2. This formula is applied to every project in the round.

To implement this, you must first aggregate contributions per project. For example, if Project A receives 4 donations of $1 each, its match factor is (sqrt(1)+sqrt(1)+sqrt(1)+sqrt(1))^2 = (1+1+1+1)^2 = 16. If Project B receives 1 donation of $16, its factor is (sqrt(16))^2 = (4)^2 = 16. Both have the same match factor despite the 4x difference in raw contribution totals, demonstrating the power of broad support.

After calculating the match factor for all projects, the total required matching pool is the sum of all these factors. Since the available matching pool is a fixed amount (e.g., $50,000 from a protocol grant), a matching coefficient is derived: coefficient = total_matching_pool / sum_of_all_match_factors. Each project's final match is then: final_match = project_match_factor * coefficient. This ensures the entire pool is distributed proportionally to the calculated community signal.

Here is a simplified JavaScript function demonstrating the core logic:

javascript
function calculateMatches(contributions, totalPool) {
  // contributions: { projectId: [amount1, amount2, ...] }
  let matchFactors = {};
  let sumFactors = 0;

  for (let projectId in contributions) {
    let factor = Math.pow(
      contributions[projectId].reduce((sum, amount) => sum + Math.sqrt(amount), 0),
      2
    );
    matchFactors[projectId] = factor;
    sumFactors += factor;
  }

  let coefficient = totalPool / sumFactors;
  let finalMatches = {};
  for (let projectId in matchFactors) {
    finalMatches[projectId] = matchFactors[projectId] * coefficient;
  }
  return finalMatches;
}

Critical considerations for production use include: - Using fixed-point or decimal math to avoid floating-point errors (consider libraries like bignumber.js). - Verifying on-chain data by recalculating from event logs to ensure integrity. - Handling zero contributions and division by zero if no projects receive funds. Platforms like Gitcoin Grants and clr.fund implement these checks, and their open-source repositories are valuable references for robust implementations.

The output of this calculation is the definitive allocation of the matching pool. This data is typically published on-chain or to a verifiable storage layer like IPFS, creating a transparent and auditable record of the round's outcome. The next step involves distributing these funds to project owners, which may require integrating with a multi-sig wallet or a vesting contract for the final payout.

fund-distribution
IMPLEMENTING THE ALGORITHM

Step 4: Executing the Fund Distribution

This step covers the core computational logic for calculating final grant allocations based on the quadratic funding formula and executing the distribution.

With the funding round closed and all contributions tallied, you now execute the quadratic funding (QF) algorithm to determine the final distribution. The core formula calculates a project's allocation from the matching pool as the square of the sum of the square roots of individual contributions: Matching = (Σ √contribution_i)². This mathematically amplifies the impact of a broad base of small donors, rewarding projects with widespread community support. You must process this calculation for every eligible project in the round using the verified contribution data from your subgraph or database.

Implementing this requires careful handling of financial precision and rounding. In Solidity, you would use a fixed-point math library like PRBMath to avoid floating-point errors and overflows when calculating square roots and squares of large sums. For off-chain execution in a script, a library like big.js in JavaScript is essential. A critical step is to normalize all contribution amounts to a common base unit (e.g., wei for ETH) before performing calculations to ensure consistency. The final output is a list of project addresses and their corresponding matching amounts in the base token.

After calculating the allocations, you must execute the actual fund transfer from the matching pool to the grant recipients. If using a smart contract-based round, this typically involves calling a distributeFunds() function that iterates through the allocation list and performs safeTransfer calls. You must ensure the contract holds sufficient matching pool funds and implement access control so only the round operator can trigger distribution. For off-chain managed rounds, you would use a multi-signature wallet or a batch transfer tool like the Safe{Wallet} transaction builder to securely send the calculated amounts to each project's treasury address in a single, verifiable transaction.

Transparency is paramount. After distribution, you should publish the final results, including each project's total contributions, calculated matching amount, and the transaction hash of the distribution. Platforms like Gitcoin Grants and clr.fund provide public interfaces for this. This audit trail allows the community to verify that the QF algorithm was executed correctly and funds were distributed as promised, maintaining trust in the mechanism for future rounds.

QUADRATIC FUNDING SETUP

Frequently Asked Questions

Common technical questions and solutions for developers implementing a quadratic funding mechanism for community grant rounds.

The quadratic funding (QF) formula determines the final allocation of matching funds to projects based on the square root of the sum of contributions. The core calculation for a project's match is:

solidity
match = (sum(sqrt(contribution_i)))^2 - sum(contribution_i)

This is typically implemented using a commit-reveal scheme or a Merkle root to batch calculations off-chain for gas efficiency. The key steps are:

  • Contribution Period: Users send contributions, which are recorded.
  • Tallying: After the round ends, the sqrt of each contribution is summed off-chain.
  • Matching Distribution: The matching pool is distributed proportionally to the squared sums. On-chain verification often involves submitting a Merkle proof of the correct calculation for each project. Libraries like OpenZeppelin's MerkleProof are commonly used.
QUADRATIC FUNDING

Common Issues and Troubleshooting

Practical solutions for developers implementing QF rounds. This guide addresses frequent technical hurdles, from contract deployment to matching pool calculations.

A zero or incorrect matching pool total is often due to incorrect data aggregation or a mismatch in the round contract and voting strategy. Check these points:

  • Data Source: Ensure your QV strategy contract (e.g., using RoundImplementation from Allo v2) correctly pulls contributions from the QFVotingStrategy. Verify the strategy's getRecipientAmounts function.
  • Contribution Timing: Contributions must be made within the round's active period (roundStartTime to roundEndTime). Votes cast outside this window are ignored.
  • Token Decimals: Mismatched decimals between the matching token (e.g., USDC with 6 decimals) and the voting strategy's calculations can cause scaling errors. Normalize all amounts to a common base (e.g., 18 decimals) before applying the QF formula.
  • Formula Application: The QF formula is sum(sqrt(contributions_i))^2. Implement this off-chain using a subgraph or indexer. On-chain calculation is gas-prohibitive.
conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have now configured the core components of a quadratic funding (QF) mechanism, from smart contracts to frontend integration. This guide covered the essential steps to launch a community-driven funding round.

Your deployed system now includes a QuadraticFundingV1 contract for managing rounds, a VotingToken for contribution power, and a basic frontend for user interaction. The key security features you implemented are the use of a commit-reveal scheme for vote privacy and a timelock on fund distribution to allow for challenge periods. Remember that the matchAmount in your contract must be funded before the round ends for the quadratic matching to execute correctly. For production, consider adding a sanity check to revert transactions if the match pool is insufficient.

To extend this basic setup, several next steps are critical for a robust deployment. First, integrate a price oracle like Chainlink to denominate contributions in a stable value (e.g., USD) rather than native ETH, protecting against volatility. Second, implement Sybil resistance. While beyond this tutorial, you can integrate with services like Gitcoin Passport, BrightID, or use a proof-of-personhood protocol to weight votes. Third, add frontend analytics to display real-time funding graphs and participant statistics, which are vital for community transparency.

For further learning and advanced patterns, explore the following resources. Study the Gitcoin Grants smart contract architecture on GitHub for a battle-tested QF implementation. Review the clr.fund documentation for its use of MACI (Minimal Anti-Collusion Infrastructure) to prevent vote buying. To understand the economic theory, read Vitalik Buterin's original post on Liberal Radicalism. Finally, test your contracts extensively on a testnet like Sepolia or Holesky, and consider an audit from a firm like OpenZeppelin or Code4rena before a mainnet launch with significant funds.

How to Implement Quadratic Funding for Community Projects | ChainScore Guides