Quadratic voting solves a fundamental problem of token-weighted voting: a whale with 1000x tokens gets 1000x influence. We design systems where voting power is proportional to the square root of the spent resource. 100 voting credits give 10 units of voting power. 900 credits — 30. To get the same power as 9 people with 1 credit each, you need to spend 81 credits. Math: influence = √credits. This makes it economically unattractive for a single participant to dominate compared to a broad coalition. Our experience — 5+ years in blockchain development, over 10 implemented voting systems. We guarantee code audit and protection against attacks.
How quadratic voting solves the whale dominance problem
In standard voting, a holder of 10,000 tokens has 100 times more influence than a holder of 100 tokens. QV changes this: with credits proportional to balance, voting power differs by √100 = 10 times. For DAOs with uneven token distribution, this significantly improves fairness.
QV was proposed by economists Eric Posner and Glen Weyl in the book Radical Markets. The intuition behind the mechanism: in standard voting, 1 person = 1 vote, but preference intensity is not considered. Someone who cares deeply about the outcome and someone indifferent have the same weight. QV allows expressing intensity through the number of credits spent — closer to real economic preferences.
Example: 100 people slightly prefer option A. 10 people strongly want option B. In standard voting, A wins. In QV, if each of the 10 spends 100 credits on B (power = 10 × √100 = 100), they can outvote a coalition of 100 each spending 1 credit (power = 100 × √1 = 100). At balance, the more intensely desired outcome wins.
| Criteria | Standard (1 token = 1 vote) | Quadratic (QV) |
|---|---|---|
| Whale influence | Linear (1000x tokens = 1000x power) | Sublinear (1000x tokens ≈ 31.6x power) |
| Preference intensity expression | Impossible | Via credits spent |
| Sybil resistance | Low (one address = one vote) | Requires external verification |
| Gas costs | Low | Higher (sqrt computation) |
| Participant complexity | Simple | Medium (allocation strategy) |
Voting credit systems
Voice Credits model
Standard scheme: each participant receives a fixed budget of voice credits per voting round. Credits are non-transferable and expire each round.
contract QuadraticVoting {
struct VotingRound {
uint256 startTime;
uint256 endTime;
mapping(uint256 => int256) optionVotes; // optionId => total votes (sqrt-weighted)
}
uint256 public constant CREDITS_PER_ROUND = 100;
// Participant's spent credits in current round
mapping(address => mapping(uint256 => uint256)) public creditsSpent;
function vote(
uint256 roundId,
uint256 optionId,
uint256 credits, // credits to spend on this option
bool support
) external {
VotingRound storage round = rounds[roundId];
require(block.timestamp >= round.startTime && block.timestamp < round.endTime, "Round inactive");
uint256 totalSpent = creditsSpent[msg.sender][roundId] + credits;
require(totalSpent <= CREDITS_PER_ROUND, "Exceeds budget");
// QV: voting power = sqrt(credits)
uint256 votes = sqrt(credits);
creditsSpent[msg.sender][roundId] = totalSpent;
if (support) {
round.optionVotes[optionId] += int256(votes);
} else {
round.optionVotes[optionId] -= int256(votes);
}
emit VoteCast(msg.sender, roundId, optionId, credits, votes, support);
}
// Integer square root (Babylonian method)
function sqrt(uint256 x) internal pure returns (uint256 y) {
if (x == 0) return 0;
uint256 z = (x + 1) / 2;
y = x;
while (z < y) {
y = z;
z = (x / z + z) / 2;
}
}
}
Token-weighted credits
Alternative scheme: credits are proportional to token balance (as in Gitcoin Grants). A holder of 1000 tokens gets 1000 credits. But voting power is still √ of credits spent. This gives wealthy participants more credits, but not linear influence.
Comparison: with credits proportional to balance and a balance of 10,000 vs 100 (100x difference) — voting power differs by √100 = 10x, not 100x. This is significantly better than standard token-weighted.
Delegated QV
A participant can delegate their credits to another participant. The delegate votes with a pool of credits, but the square root function is applied to the total credits spent on each option from each original owner.
Important nuance: aggregation of credits from delegates must preserve source information. Simply summing credits in the delegate's pool loses the QV property.
// Correct aggregation: each delegation entry separately
struct Delegation {
address delegator;
uint256 credits;
}
// Delegate voting: applies QV to each delegation individually
function voteAsDelegate(
uint256 roundId,
uint256 optionId,
Delegation[] calldata delegations
) external {
int256 totalVotes = 0;
for (uint i = 0; i < delegations.length; i++) {
require(
delegatedCredits[delegations[i].delegator][msg.sender][roundId]
>= delegations[i].credits,
"Insufficient delegated credits"
);
totalVotes += int256(sqrt(delegations[i].credits));
}
rounds[roundId].optionVotes[optionId] += totalVotes;
}
Why Sybil attack is critical for QV and how we prevent it
QV completely breaks without Sybil protection. One participant with 100 credits gets power 10. One hundred participants with 1 credit each get total power 100. By splitting identity into N addresses, an attacker multiplies his power by √N.
Proof of Humanity
A registered unique identity in Proof of Humanity or Worldcoin gets 1 credit allocation. Sybil impossible — creating a thousand real people is not feasible.
Integration via on-chain check:
interface IProofOfHumanity {
function isRegistered(address _submissionID) external view returns (bool);
}
contract QVWithPoH {
IProofOfHumanity public poh;
function registerForRound(uint256 roundId) external {
require(poh.isRegistered(msg.sender), "Not registered in PoH");
require(!registeredForRound[roundId][msg.sender], "Already registered");
registeredForRound[roundId][msg.sender] = true;
creditsBalance[roundId][msg.sender] = CREDITS_PER_ROUND;
}
}
Problem with PoH: limited coverage, registration takes time, challengeable. For a DAO with global audience — a barrier to entry.
Worldcoin World ID
More scalable solution. Iris scan → ZK proof of uniqueness. On-chain verification via semaphore protocol without revealing personal data.
import "@worldcoin/world-id-contracts/src/interfaces/IWorldID.sol";
import { ByteHasher } from "@worldcoin/world-id-contracts/src/helpers/ByteHasher.sol";
contract QVWithWorldID {
using ByteHasher for bytes;
IWorldID internal worldId;
uint256 internal groupId = 1; // Orb-verified
uint256 internal externalNullifierHash;
function registerWithWorldID(
address signal,
uint256 root,
uint256 nullifierHash,
uint256[8] calldata proof
) external {
// Verifies ZK proof of uniqueness
worldId.verifyProof(
root,
groupId,
abi.encodePacked(signal).hashToField(),
nullifierHash,
externalNullifierHash,
proof
);
require(!nullifierUsed[nullifierHash], "Already registered");
nullifierUsed[nullifierHash] = true;
// issue credits
}
}
Stake-based anti-sybil
For DeFi-oriented DAOs: require a token stake to participate. Creating many Sybil accounts becomes expensive. Combining with QV: stake determines base credits, but voting power is still √ of spent.
Complete system architecture
On-chain components
- QuadraticVoting.sol: core contract with credits and voting logic
- IdentityRegistry.sol: links addresses to verified identities (PoH/Worldcoin)
- VotingRoundFactory.sol: creates rounds with parameters (duration, options, credit allocation)
Off-chain components
Snapshot integration: most DAOs use Snapshot for off-chain QV voting — free and unlimited participants. Snapshot supports QV strategy.
Results calculator: off-chain service for complex QF calculations, with subsequent on-chain publication.
Frontend: an interface where participant sees their credit budget, sliders to allocate across options, live preview of voting power per decision.
| Parameter | Recommendation | Rationale |
|---|---|---|
| Base credits | 99-100 | Convenient for √ calculations |
| Round duration | 7-14 days | Time for informed participation |
| Credit carryover | No | Prevents accumulation and attacks |
| Minimum stake | 0.01-0.1% supply | Basic anti-sybil without high barrier |
| Sybil protection | PoH + stake | Multi-layered defense |
Limitations and honest view
QV does not solve all governance issues. Weak points:
- Collusion: a group of participants can coordinate credit allocation to maximize total influence. This is harder than in standard voting but not impossible. MACI (Minimum Anti-Collusion Infrastructure) addresses this with ZK cryptography.
- Rational ignorance: most participants won't spend time studying 20 proposals in a round. QV reduces the cost of ignorance but doesn't eliminate it.
- Optimal strategy: the mathematically optimal strategy for a participant is not obvious. This may reduce participation from non-technical members.
QV is better suited for limited option sets (priority selection, grant distribution) than binary yes/no protocol decisions.
What’s included in the work
- Audit of current governance structure and problem statement
- Smart contract architecture design (Solidity/Foundry or Rust/Anchor)
- Implementation of core QV contracts with voice credits and quadratic counting
- Sybil protection integration (PoH, Worldcoin, or stake-based)
- Frontend development (React/viem/RainbowKit) with influence visualization
- Unit and integration tests (Foundry/Tenderly)
- Deployment and voting round configuration
- User and admin documentation
- Post-release support for 1 month
How we develop a quadratic voting system: step by step
- Analytics (2-3 days): review current processes, identify pain points and voting requirements.
- Design (3-5 days): create smart contract architecture, select Sybil protection methods and platform.
- Development (14-30 days): write Solidity contracts, integrate PoH/Worldcoin, develop frontend.
- Testing (5-7 days): run unit and integration tests, use Slither and Mythril for static analysis.
- Deployment (1-2 days): deploy contracts to mainnet, configure voting round.
- Post-release support: 1 month monitoring and fixes.
Timeline: from 3 weeks (basic QV without anti-sybil) to 12 weeks (full product with PoH/Worldcoin and delegation). Cost is calculated individually — investment in fair voting pays off through reduced conflicts and increased community activity.
Example vote calculation
A participant with 9 credits gets 3 votes (√9). If they want to support two options, distributing 4 and 5 credits gives 2 + 2.236 = 4.236 votes, more than 3 when concentrating on one. This encourages spreading credits rather than concentrating.Get a consultation on implementing quadratic voting in your DAO. Our engineers will propose the optimal solution for your tasks. Contact us to discuss details.







