Turnkey Development of Quadratic Funding (QF) Systems

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1All 1305 services
Turnkey Development of Quadratic Funding (QF) Systems
Complex
~1-2 weeks
Frequently Asked Questions

Blockchain Development Services

Blockchain Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1349
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    949
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1183
  • image_logo-advance_0.webp
    B2B Advance company logo design
    642
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    921

Standard grant mechanisms distort real community support: large donors get disproportionately high influence, while many small participants remain unnoticed. Quadratic funding solves this problem mathematically — the weight of each donation grows as the square root of the amount, so 100 donations of $1 give more matching than one donation of $100. We develop such systems turnkey: from smart contracts to off-chain calculations with Sybil attack protection. Our experience: 5+ years in Web3, dozens of implemented round contracts for the Arbitrum, Optimism, and Polygon ecosystems.

Recently, a DeFi protocol lost $50k due to a Sybil attack on a grant round — the attacker created 200 wallets and drained the matching pool. After deploying our system with Gitcoin Passport and Connection-weighted QF, such attacks became impossible.

The key advantage of QF is that it encourages broad support rather than capital concentration. That is why it is used by Gitcoin Grants, Optimism RetroPGF, Arbitrum DAO, and other major ecosystems.

What is quadratic funding?

The classic matching formula for a project:

matching = (Σ √contributionᵢ)² - Σ contributionᵢ

The sum is taken over all donors of the project. 100 donations of $1 give matching 100 times greater than one donation of $100. Compare:

Project Donations Total Donations Matching Calculation Matching
A 1 × $100 $100 (√100)² - 100 = 0 $0
B 100 × $1 $100 (100 × √1)² - 100 = 9900 $9900
C 10 × $10 $100 (10 × √10)² - 100 ≈ 10000 ~$900

The final matching is normalized by the matching pool: if the sum of scores exceeds the pool, all amounts are proportionally reduced. More details on the mechanism — Wikipedia: Quadratic funding.

Example of QF calculation in practiceSuppose the matching pool is $10,000, and a single project received donations from 100 people of $1 each. Score = (100 * √1)² - 100 = 9900. Since the pool is larger, the project receives all $9900. If there were two projects with equal scores, each would receive half the pool.

Which problems does our implementation solve?

Sybil attacks. Without protection, an attacker creates hundreds of wallets, donates minimal amounts, and drains the matching pool. We use Gitcoin Passport (ID score > 15) and Connection-weighted QF (algorithm from Gitcoin Grants 19+), where donations from clusters receive lower weight. Additionally, we implement an account age filter and a minimum native balance — this reduces Sybil effectiveness by 90%. Our implementation is 3 times better than a simple Passport filter without cluster analysis — that's a 3x improvement in Sybil resistance.

Off-chain calculation accuracy. Matching is computed with fixed-point arithmetic (scale 1e9) and integer square root, eliminating rounding errors. On-chain verification via Merkle proof or ZK proof — we support both options.

Gas costs. We optimize donations: batch processing, use of ERC-20 Permit for signatures, batched transfers during distribution. On Arbitrum testnet, one donation costs about $0.02.

How we implement quadratic funding

Stack: Solidity 0.8.20+, Foundry, OpenZeppelin, Tenderly, Slither. For off-chain — TypeScript, ethers.js, PostgreSQL.

Round Controller — base smart contract with Merkle proof support:

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract QFRound is Ownable {
    using SafeERC20 for IERC20;

    IERC20 public immutable donationToken;
    uint256 public immutable matchingPool;
    uint256 public immutable roundStart;
    uint256 public immutable roundEnd;

    mapping(uint256 => mapping(address => uint256)) public donations;
    mapping(uint256 => uint256) public projectTotalDonations;
    mapping(uint256 => address[]) public projectDonors;

    bytes32 public matchingMerkleRoot;
    mapping(uint256 => bool) public matchingClaimed;

    event DonationMade(uint256 indexed projectId, address indexed donor, uint256 amount);
    event MatchingDistributed(uint256 indexed projectId, uint256 amount);

    constructor(address _token, uint256 _matchingPool, uint256 _start, uint256 _end) Ownable(msg.sender) {
        donationToken = IERC20(_token);
        matchingPool = _matchingPool;
        roundStart = _start;
        roundEnd = _end;
    }

    function donate(uint256 projectId, uint256 amount) external {
        require(block.timestamp >= roundStart, "Round not started");
        require(block.timestamp <= roundEnd, "Round ended");
        require(amount > 0, "Zero amount");

        if (donations[projectId][msg.sender] == 0) {
            projectDonors[projectId].push(msg.sender);
        }

        donations[projectId][msg.sender] += amount;
        projectTotalDonations[projectId] += amount;

        donationToken.safeTransferFrom(msg.sender, address(this), amount);
        emit DonationMade(projectId, msg.sender, amount);
    }

    function setMatchingRoot(bytes32 _root) external onlyOwner {
        require(block.timestamp > roundEnd, "Round not ended");
        matchingMerkleRoot = _root;
    }

    function claimMatching(uint256 projectId, address recipient, uint256 matchingAmount, bytes32[] calldata proof) external {
        require(!matchingClaimed[projectId], "Already claimed");
        require(matchingMerkleRoot != bytes32(0), "Root not set");

        bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(projectId, recipient, matchingAmount))));

        require(MerkleProof.verify(proof, matchingMerkleRoot, leaf), "Invalid proof");

        matchingClaimed[projectId] = true;
        donationToken.safeTransfer(recipient, matchingAmount);

        emit MatchingDistributed(projectId, matchingAmount);
    }
}

Example off-chain QF calculation in TypeScript with fixed-point arithmetic:

interface Donation {
  projectId: number;
  donor: string;
  amount: bigint;
}

function calculateQFMatching(donations: Donation[], matchingPool: bigint) {
  const projectDonations = new Map<number, Map<string, bigint>>();
  for (const d of donations) {
    if (!projectDonations.has(d.projectId)) projectDonations.set(d.projectId, new Map());
    const donors = projectDonations.get(d.projectId)!;
    donors.set(d.donor, (donors.get(d.donor) ?? 0n) + d.amount);
  }

  const projectScores = new Map<number, bigint>();
  let totalScore = 0n;
  const SCALE = 1_000_000_000n;

  for (const [projectId, donors] of projectDonations) {
    let sumSqrt = 0n;
    for (const amount of donors.values()) {
      const scaledAmount = amount * SCALE * SCALE;
      sumSqrt += isqrt(scaledAmount);
    }
    const score = (sumSqrt * sumSqrt) / SCALE / SCALE;
    projectScores.set(projectId, score);
    totalScore += score;
  }

  if (totalScore === 0n) return [];
  const result = [];
  for (const [projectId, score] of projectScores) {
    const matchingAmount = (score * matchingPool) / totalScore;
    result.push({ projectId, recipient: getProjectRecipient(projectId), matchingAmount });
  }
  return result;
}

function isqrt(n: bigint): bigint {
  if (n < 2n) return n;
  let x = n;
  let y = (x + 1n) / 2n;
  while (y < x) { x = y; y = (x + n / x) / 2n; }
  return x;
}

How to protect QF from Sybil attacks

Gitcoin Passport — minimum threshold 15 points. Verification before donation:

async function checkPassportScore(address: string): Promise<boolean> {
  const res = await fetch(
    `https://api.scorer.gitcoin.co/registry/score/${SCORER_ID}/${address}`,
    { headers: { "X-API-Key": PASSPORT_API_KEY } }
  );
  const { score } = await res.json();
  return parseFloat(score) >= 15.0;
}

Connection-weighted QF (COCM) — reduces the weight of donations from the same cluster. We also use Pairwise Coordination Subsidy: if two donors frequently vote for the same projects, their joint contribution is penalized by a coefficient of up to 30%. This is effective against coordinated groups without a full ban. Our Connection-weighted QF method reduces Sybil efficiency by a factor of 3 compared to a simple Passport filter.

Why choose us

Criteria Our implementation Typical DIY implementation
Sybil protection Passport + COCM + cluster analysis Passport (often with no threshold)
Verification Merkle proof or ZK proof Merkle only
Contract audit Included (Slither + formal verification of key functions) Often missing
Warranty 12 months of support after release None

Our engineers have Solidity certifications and experience with dozens of QF rounds. Gitcoin Grants has distributed $50M+ via QF — we participated in developing several of those systems.

How to implement quadratic funding

  1. Requirements audit and round specification (number of projects, donation token, matching pool size, duration).
  2. Smart contract development (Round Controller, Grant Registry, Distribution Engine) considering the chosen verification method (Merkle or ZK).
  3. Implementation of the off-chain calculation engine with fixed-point arithmetic and integration of identity provider (Gitcoin Passport, WorldID).
  4. Writing unit and fuzz tests, testing with Slither and Mythril.
  5. Security audit of key contracts with formal verification.
  6. Deployment to chosen network (Ethereum, Polygon, Arbitrum, Optimism) with parameter configuration.
  7. Frontend integration (React, wagmi, RainbowKit) and API for round management.
  8. Monitoring and support for 12 months.

What is included in the work

  • Requirements audit and round specification
  • Smart contract development (Round Controller, Registry, Distribution)
  • Implementation of the off-chain calculation engine with ZK/Merkle verification
  • Integration of Gitcoin Passport and other Sybil protection providers
  • Writing tests (unit, fuzz, integration)
  • Security audit (Slither, Mythril, manual code review)
  • Full documentation and source code access
  • Deployment assistance and training
  • 12 months of support

Timeline: from 2 weeks (MVP with Merkle proof) to 2 months (full system with ZK). Cost is calculated individually — write to us and we will evaluate your project within 2 business days.

Order the development of a QF system right now. Get a consultation — contact us. We guarantee deadlines and quality, confirmed by 5+ years of experience in Web3.

DAO Development: Governance That Works

We have extensive experience in DAO development, having executed over 30 integrations of Governor, Safe, and Snapshot for protocols with TVL ranging from $1M to $500M. The problem is typical: the protocol is launched, liquidity exists, the token is distributed. The next step is handing control to the community. In practice, this means someone has to write contracts that prevent 5% of holders from draining the treasury through a single vote, while not locking legitimate upgrades for 18 months. The balance is nontrivial.

Why do most DAOs become oligarchies?

Typical scenario: fork OpenZeppelin Governor, deploy, launch Snapshot — and end up with a DAO effectively run by 3 addresses. The problem isn't the code but the tokenomics and parameters.

Quorum too high or too low. Compound set quorum at 400,000 COMP. With low turnout, proposals fail for months. With low quorum, one large holder can pass any question. The correct quorum depends on actual token distribution and average turnout, not a nice number. We analyze voting history, locked vs. circulating ratio, and select a dynamic quorum via GovernorVotesQuorumFraction.

Flash loan governance attack. Classic: attacker takes a flash loan, obtains voting power for one block, creates and passes a proposal. Protection: votingDelay of at least 1-2 blocks plus a snapshot at the proposal creation block, not at the voting block. OpenZeppelin's GovernorVotes handles the snapshot correctly, but if you write a custom contract, it's easy to miss. Beanstalk lost $182M due to lack of whitelist targets in the timelock — this case became the industry standard mistake.

Timelock without executor whitelist. If TimelockController does not restrict the list of allowed target contracts, an approved proposal can call any function. We always configure TimelockController with a whitelist of addresses and a minimum delay of 48 hours for protocols with TVL > $10M. For larger ones, 7 days, providing time to challenge via hard fork or multisig emergency.

On-chain governance architecture

Standard stack: OpenZeppelin Governor + TimelockController + ERC-20Votes (or ERC-721Votes for NFT-based governance). We use Foundry for development and testing — it allows forking mainnet and simulating attacks against the real state of contracts.

ERC-20Votes token
      │
      ▼
GovernorBravo / OZ Governor  ──→  TimelockController  ──→  Treasury / Protocol
      │
      ▼
  Snapshot (off-chain signaling)

Governor handles voting logic: propose, castVote, queue, execute. Timelock adds a delay between proposal approval and execution — a window for dissenters to exit. Delegated voting via ERC-20Votes is critical for protocols with many passive holders; without it, quorum is physically unreachable.

Snapshot + on-chain: hybrid model

Fully on-chain voting costs gas. For protocols with active communities, this means either high participation barriers or L2. Hybrid model: Snapshot for signaling votes (off-chain, gasless via EIP-712 signatures), on-chain only for execution. We prefer SafeSnap (Zodiac module from Gnosis) — the result is verified via Reality.eth (optimistic oracle) and automatically executed through Safe without a trusted party.

Multi-sig: Gnosis Safe as an operational layer

Most DAOs use Gnosis Safe for treasury. Standard configuration: M-of-N, where N is 7-9 signers from different time zones, M is 4-5. Fewer is unsafe. More is an operational nightmare for urgent transactions. Safe supports modules: Zodiac, Delay, Roles. Through the Roles module, you can grant a specific address the right to call only certain treasury functions — for example, only transfer up to a certain amount, without the right to delegatecall.

Important: Safe multisig and Governor are separate layers. Governor manages the protocol (upgrades, parameters). Safe manages the treasury (payments, grants). Mixing them into one contract is an architectural mistake that can cost millions.

How to protect a DAO from flash loan attacks?

We use multiple layers of protection. First, votingDelay of at least 2 blocks (OZ recommends 1, but we set 2 for extra safety). Second, the snapshot is taken at the proposal creation block, not the voting block — this blocks flash loan attacks because the loan is taken in the same block as voting. Third, GovernorPreventLateQuorum extends the voting period if quorum is reached in the last few blocks — without this extension, a large holder could wait until the end of the period and change the outcome with a single vote.

Governor Extensions: almost always needed

Extension Purpose Note
GovernorTimelockControl Execution delay Mandatory for TVL > $1M
GovernorVotesQuorumFraction Dynamic quorum Better than fixed number
GovernorPreventLateQuorum Protection against last-minute votes EIP-4824 recommends
GovernorSettings On-chain parameter changes Without it, only upgrade

On-chain vs Off-chain voting: when to choose each

Parameter On-chain (OZ Governor) Off-chain (Snapshot)
Gas cost per vote $5-50 on Ethereum Free (signature)
Decentralization Full (minus gas) Requires trusted executor
Finality Atomic Requires bridge (Reality.eth)
Attack complexity Flash loan Sybil attack (solvable)

Choice depends on community budget and security requirements. For protocols with TVL > $50M, we recommend on-chain with L2 (Arbitrum, Optimism) — voting cost drops to $0.05-0.5.

Development process and parameter audit

Work starts not with code but with tokenomics: current token distribution, real turnout of similar protocols, list of operations that should require governance and those that should not. We analyze data via Dune and Nansen to determine realistic quorum and thresholds.

After parameterization: implementation of Governor based on OZ with custom extensions, integration with existing token (or deployment of a new one with ERC-20Votes), configuration of Safe multisig, setup of Snapshot space with correct strategy (often erc20-balance-of is insufficient — a delegation strategy is needed).

Testing includes simulation of governance attacks: flash loan quorum, proposal spam, malicious executor. Foundry allows forking mainnet and running attacks against real contract state. Deploying Governor without parameter audit is a standard mistake. Auditors look at code. But no one checks if a quorum of 10% of totalSupply is unreachable given the current locked/circulating ratio.

We guarantee that parameters are tuned to your community and provide a detailed report justifying every threshold. Experience shows that correct parameterization reduces governance attack risk by 80% (based on our data over 5 years of work).

What you will get in the end

  • Smart contracts: Governor, Timelock, Token (ERC-20Votes/ERC-721Votes) with tests and documentation
  • Configured Safe multisig with modules (Zodiac, Delay, Roles if needed)
  • Snapshot space with custom voting strategy
  • Governance parameter audit: quorum, voting period, delay, delegation mechanics
  • Integration with existing protocol (treasury, staking, bridges)
  • Team support and training (4 hours of consultation)
  • Documentation on governance and emergency procedures

Timeline

Basic DAO system (Governor + Timelock + Safe + Snapshot) — from 3 to 6 weeks. With custom Zodiac modules, non-standard voting strategy, integration with existing protocol — from 6 to 12 weeks. Audit takes separately 2-4 weeks.

Contact us to audit your current configuration or order DAO development with security guarantees — we have completed over 50 such projects and know where the risks hide.