Розробка квадратичного голосування (quadratic voting)
Quadratic voting вирішує фундаментальну проблему токен-взвешеного голосування: у кита 1000x токенів → 1000x впливу. QV встановлює інше правило: сила голосу пропорційна кореню квадратному від витраченого ресурсу. 100 голосувальних кредитів дають 10 одиниць голосовой сили. 900 кредитів — 30. Для такої самої сили, що 9 людей з 1 кредитом, потрібно витратити 81 кредит.
Математика: вплив = √credits. Це робить економічно невигідним домінування одного учасника порівняно з широкою коаліцією.
Теоретична база
QV був запропонований економістами Еріком Познером та Гленом Вейлом у книзі «Radical Markets». Інтуїція за механізмом: у стандартному голосуванні 1 людина = 1 голос, але інтенсивність переваг не обраховується. Той, кому дуже важливий результат, та той, кому байдужо, мають однаковий вес. QV дозволяє виражати інтенсивність через кількість витрачених кредитів — це ближче до реальних економічних переваг.
Приклад: 100 людей трохи переважають варіант A. 10 людей дуже хочуть варіант B. У стандартному голосуванні перемагає A. В QV, якщо кожен з 10 витратить 100 кредитів на B (сила = 10 × √100 = 100), вони можуть переголосувати коаліцію з 100, кожен з яких витратив 1 кредит (сила = 100 × √1 = 100). При балансі переваг перемагає більш інтенсивно бажаний результат.
Системи голосувальних кредитів
Voice Credits модель
Стандартна схема: кожен учасник отримує фіксований бюджет voice credits на період голосування. Кредити не переносяться та не передаються — кожен період fresh allocation.
contract QuadraticVoting {
struct VotingRound {
uint256 startTime;
uint256 endTime;
mapping(uint256 => int256) optionVotes; // optionId => сумарні голоси (sqrt-взвешені)
}
uint256 public constant CREDITS_PER_ROUND = 100;
// Витрачені кредити учасника в поточному раунді
mapping(address => mapping(uint256 => uint256)) public creditsSpent;
function vote(
uint256 roundId,
uint256 optionId,
uint256 credits, // credits для витрати на цей варіант
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: голосовая сила = 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;
}
}
}
Токен-взвешені кредити
Альтернативна схема: кредити пропорційні балансу токенів (як в Gitcoin Grants). Держатель 1000 токенів має 1000 кредитів. Але голосовая сила все одно √ від витрачених кредитів. Це дає багатим учасникам більш кредитів, але не лінійний вплив.
Порівняння: при кредитах пропорційних балансу та балансі 10,000 vs 100 (100x різниця) — голосовая сила відрізняється в √100 = 10x, не в 100x. Значно краще ніж стандартне token-weighted.
Delegated QV
Учасник може делегувати свої кредити іншому учаснику. Делегат голосує пакетом кредитів, але все одно застосовується коренева функція до суммарних кредитів на кожен варіант від кожного першоначального власника.
Важливий нюанс: агрегація кредитів від делегатів повинна зберігати інформацію про джерело. Якщо просто сумувати кредити делегатора в пулі делегата — теряється QV властивість.
// Правильна агрегація: кожен delegation entry окремо
struct Delegation {
address delegator;
uint256 credits;
}
// Голосування делегата: застосовує QV до кожного делегування окремо
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;
}
Sybil resistance: головна проблема QV
QV повністю ломається без захисту від Sybil атак. Один учасник з 100 кредитами отримує силу 10. Сто учасників з 1 кредитом кожен отримують сумарну силу 100. Розділивши ідентичність на N адрес, атакуючий множить свою силу в √N раз.
Proof of Humanity
Зареєстрована унікальна особа в Proof of Humanity або Worldcoin отримує 1 allocation кредитів. Не піддається Sybil — створити тисячу реальних людей неможливо.
Інтеграція через on-chain перевірку:
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;
}
}
Проблема PoH: охват обмежений, реєстрація займає час, оспорювана. Для DAO з глобальною аудиторією — бар'єр входу.
Worldcoin World ID
Більш масштабоване рішення. Iris scan → ZK proof унікальності. Верифікація on-chain через semaphore протокол без розкриття особистих даних.
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 {
// Перевіряє ZK proof унікальності
worldId.verifyProof(
root,
groupId,
abi.encodePacked(signal).hashToField(),
nullifierHash,
externalNullifierHash,
proof
);
require(!nullifierUsed[nullifierHash], "Already registered");
nullifierUsed[nullifierHash] = true;
// видати кредити
}
}
Stake-based anti-sybil
Для DeFi-oriented DAO: вимагати stake токенів для участі. Створення багатьох Sybil аккаунтів стає дорогим. Комбінація з QV: stake визначає базовий кредит, але голосовая сила все одно √ від витраченого.
Quadratic Funding (розширення QV)
Gitcoin використовує QF (Quadratic Funding) — похідну від QV. Механізм для громадського фінансування: проекти отримують matching funds пропорційно квадрату суми квадратних коренів від індивідуальних взносів.
Matching = (Σ √contribution_i)²
Приклад: проект A отримав 100 взносів по $1. Matching ∝ (100 × √1)² = 10,000. Проект B отримав 1 взнос на $100. Matching ∝ (1 × √100)² = 100. При одинаковій сумі взносів проект з широкою підтримкою отримує в 100x більш matching.
Gitcoin Grants реалізував це на Ethereum (Optimism для зниження gas витрат). Це найвідоміша production реалізація QV/QF в crypto.
Повна архітектура системи
On-chain компоненти
- QuadraticVoting.sol: core контракт з логікою кредитів та голосування
- IdentityRegistry.sol: зв'язок адрес з верифікованими ідентичностями (PoH/Worldcoin)
- VotingRoundFactory.sol: створення раундів з параметрами (duration, options, credit allocation)
Off-chain компоненти
Snapshot інтеграція: більшість DAO використовують Snapshot для off-chain QV голосувань — безплатно та без ограничень по числу учасників. Snapshot підтримує QV стратегію.
Results calculator: off-chain сервіс для складних QF розрахунків, з подальшою публікацією результатів on-chain.
Frontend: інтерфейс, де учасник бачить свій бюджет кредитів, слайдери для розподілу по варіантах, live preview голосовой сили кожного рішення.
Параметри та настройка
| Параметр | Рекомендація | Обґрунтування |
|---|---|---|
| Базові кредити | 99-100 | Зручні для √ розрахунків |
| Тривалість раунду | 7-14 днів | Час для осмисленої участі |
| Перенос кредитів | Нім | Запобігає накопленню та атакам |
| Мінімальний stake | 0.01-0.1% supply | Базовий anti-sybil без високого бар'єру |
| Sybil protection | PoH + stake | Багатошарова захист |
Обмеження та чесний погляд
QV не вирішує всі проблеми governance. Слабкі місця:
Collusion: група учасників може координувати розподіл кредитів для максимізації суммарного впливу. Складніше ніж у стандартному голосуванні, але не неможливо. MACI (Minimum Anti-Collusion Infrastructure) вирішує це через ZK cryptography.
Rational ignorance: більшість учасників не будуть витрачати час на вивчення 20 пропозалів у раунді. QV знижує вартість ігнорування, але не усуває її.
Оптимальна стратегія: математично оптимальна стратегія для учасника — не очевидна. Це може знижувати participation у нетехнічних учасників.
QV краще підходить для обмежених наборів варіантів (вибір приоритетів, розподіл грантів) ніж для бінарних так/ні рішень по протоколу.
Розробка повної системи QV з PoH/Worldcoin інтеграцією: 8-12 тижнів. Базовий on-chain QV без anti-sybil — 3-4 тижні.







