Розробка системи reputation-weighted голосування

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка системи reputation-weighted голосування
Складний
~1-2 тижні
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1218
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    920
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1147
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    610
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    885

Розробка системи reputation-weighted голосування

Token-weighted voting має фундаментальний недолік: покупку голосовою силою за гроші. Багатий учасник не зобов'язаний розбиратися в предметі — він просто перекриває всіх. Reputation-weighted voting вирішує цю проблему інакше: вага голосу визначається історією участі, якістю минулих рішень та внеском у протокол, не балансом кошелька.

Це значно складніше в реалізації. Потрібно вирішити три нетривіальні задачі: як вимірити репутацію без маніпуляцій, як зберігати та оновлювати її on-chain ефективно та як запобігти накопленню репутації через sybil атаки.

Моделі репутації: звідки береться вага

Репутація може будуватися з кількох джерел одночасно.

On-chain активність: частота та якість голосувань, своєчасність участі, слідування рішенням (голосував з більшістю vs contrarian). Останнє спірно — іноді праві саме несогласні.

Contribution-based: merged PR в протокол, написані propozals, організовані community calls, написані документи. Введення contribution складніше автоматизувати, потребує суб'єктивної оцінки.

Peer review: інші учасники оцінюють вклад, репутація будується соціально. Це модель SourceCred — граф розподілу репутації через взаємні оцінки.

Outcome-based: ретроактивна оцінка рішень. Якщо пропозал, за який голосував учасник, принес вимірюване користі протоколу — його репутаційна вага зростає. Потребує oracle метрик.

Soulbound tokens як носій репутації

EIP-5114 (Soulbound tokens) — нетрансферабельні NFT, прив'язані до адреси. Ідеальний носій для репутації: не можна купити та продати, не можна делегувати чужу репутацію.

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

contract ReputationToken {
    struct ReputationData {
        uint256 baseScore;           // накопилена репутація
        uint256 participationCount;  // число голосувань
        uint256 proposalsCreated;    // створені propozals
        uint256 proposalsPassed;     // прийняті propozals
        uint256 lastActivityBlock;
        uint256 decayFactor;         // множник decay (1000 = 1.0)
        bool exists;
    }
    
    mapping(address => ReputationData) public reputation;
    mapping(address => bool) public trustedIssuers;  // хто може виданяти репутацію
    
    uint256 public constant DECAY_PERIOD = 180 days;
    uint256 public constant DECAY_RATE = 50;    // 5% за період
    uint256 public constant BASE_VOTE_SCORE = 10;
    uint256 public constant PROPOSAL_BONUS = 100;
    uint256 public constant PASSED_PROPOSAL_BONUS = 500;
    
    event ReputationEarned(address indexed participant, uint256 amount, string reason);
    event ReputationDecayed(address indexed participant, uint256 newScore);
    
    modifier onlyIssuer() {
        require(trustedIssuers[msg.sender], "Not a trusted issuer");
        _;
    }
    
    // Soulbound: transfer заблокірован на рівні контракту
    // Реалізуємо через ERC-721 без функції transfer
    
    function awardParticipation(address participant, uint256 pollId) external onlyIssuer {
        _ensureExists(participant);
        _applyDecay(participant);
        
        ReputationData storage rep = reputation[participant];
        rep.baseScore += BASE_VOTE_SCORE;
        rep.participationCount++;
        rep.lastActivityBlock = block.number;
        
        emit ReputationEarned(participant, BASE_VOTE_SCORE, "participation");
    }
    
    function awardProposalCreation(address participant, bool passed) external onlyIssuer {
        _ensureExists(participant);
        _applyDecay(participant);
        
        ReputationData storage rep = reputation[participant];
        uint256 bonus = passed ? PASSED_PROPOSAL_BONUS : PROPOSAL_BONUS;
        rep.baseScore += bonus;
        rep.proposalsCreated++;
        if (passed) rep.proposalsPassed++;
        rep.lastActivityBlock = block.number;
        
        emit ReputationEarned(participant, bonus, passed ? "passed_proposal" : "created_proposal");
    }
    
    function awardContribution(
        address participant, 
        uint256 amount,
        string calldata reason
    ) external onlyIssuer {
        _ensureExists(participant);
        _applyDecay(participant);
        reputation[participant].baseScore += amount;
        emit ReputationEarned(participant, amount, reason);
    }
    
    function getVotingPower(address participant) external view returns (uint256) {
        if (!reputation[participant].exists) return 0;
        
        ReputationData memory rep = reputation[participant];
        uint256 currentScore = _calculateCurrentScore(participant);
        
        // Нелінійне масштабування: запобігає монополізації
        // power = sqrt(score) * 100, нормалізуємо до базу 1000
        return _sqrt(currentScore) * 100;
    }
    
    function _applyDecay(address participant) internal {
        ReputationData storage rep = reputation[participant];
        if (!rep.exists) return;
        
        uint256 inactiveTime = block.timestamp - 
            (rep.lastActivityBlock * 12); // ~12 sec per block
        
        if (inactiveTime > DECAY_PERIOD) {
            uint256 periods = inactiveTime / DECAY_PERIOD;
            uint256 decay = (1000 - DECAY_RATE) ** periods / (1000 ** (periods - 1));
            rep.baseScore = rep.baseScore * decay / 1000;
            emit ReputationDecayed(participant, rep.baseScore);
        }
    }
    
    function _calculateCurrentScore(address participant) internal view returns (uint256) {
        ReputationData memory rep = reputation[participant];
        uint256 inactiveTime = block.timestamp - (rep.lastActivityBlock * 12);
        
        if (inactiveTime <= DECAY_PERIOD) return rep.baseScore;
        
        uint256 periods = inactiveTime / DECAY_PERIOD;
        uint256 score = rep.baseScore;
        for (uint256 i = 0; i < periods && score > 0; i++) {
            score = score * (1000 - DECAY_RATE) / 1000;
        }
        return score;
    }
    
    function _sqrt(uint256 x) internal pure returns (uint256) {
        if (x == 0) return 0;
        uint256 z = (x + 1) / 2;
        uint256 y = x;
        while (z < y) {
            y = z;
            z = (x / z + z) / 2;
        }
        return y;
    }
    
    function _ensureExists(address participant) internal {
        if (!reputation[participant].exists) {
            reputation[participant].exists = true;
            reputation[participant].decayFactor = 1000;
            reputation[participant].lastActivityBlock = block.number;
        }
    }
}

Decay механізм: боротьба з накопленою владою

Без decay репутація накопиляється та не зникає. Учасник, активний три роки назад, зберігає домінуючий вес вічно. Це порушує інклюзивність: нові учасники ніколи не зможуть потрапити в коло прийняття рішень.

Decay — ключовий елемент репутаційної системи. Репутація зменшується при неактивності. Смисл: ви повинні продовжувати брати участь, щоб зберегти вплив.

Лінійний decay: найпростіший варіант. -X% на місяць при відсутності активності. Передбачуваний, але грубий.

Експоненціальний decay: більш природна модель. Репутація зменшується швидше при тривалій неактивності. Параметри підбираються під сообщество.

Activity-gated decay: decay починається тільки після порогу неактивності (наприклад, пропуск більш ніж 3 голосувань поспіль). Знижує тривогу для випадкових пропусків.

# Моделювання decay для підбору параметрів
import numpy as np
import matplotlib.pyplot as plt

def simulate_reputation(
    initial_score: float,
    monthly_activity_score: float,   # скільки репутації заробляє активний учасник
    decay_rate: float,               # коефіцієнт decay за період неактивності
    decay_period_months: int,
    simulation_months: int = 60,
    active_months: list = None       # місяці з активністю
) -> list:
    """
    Симуляція репутації учасника
    active_months: список місяців, коли учасник був активний
    """
    if active_months is None:
        active_months = list(range(simulation_months))
    
    score = initial_score
    history = [score]
    
    inactive_periods = 0
    
    for month in range(1, simulation_months):
        if month in active_months:
            score += monthly_activity_score
            inactive_periods = 0
        else:
            inactive_periods += 1
            if inactive_periods >= decay_period_months:
                score *= (1 - decay_rate)
        
        history.append(max(0, score))
    
    return history

# Приклад: учасник активен перші 12 місяців, потім пропадає на рік, повертається
active = list(range(12)) + list(range(24, 36))
scores = simulate_reputation(
    initial_score=0,
    monthly_activity_score=50,
    decay_rate=0.08,      # 8% за період неактивності
    decay_period_months=3,
    simulation_months=48,
    active_months=active
)

Підбирати параметри decay слід так, щоб: активний учасник підтримував stable score, три місяці неактивності знижували score на ~20–30%, повернення до участі давав можливість відновити позицію за розумний час.

Voting Power Computation: нелінійне масштабування

Лінійне відповідність репутації голосовою силі відтворює проблему токен-weighted voting: той, у кого найбільша репутація, повністю домінує.

Квадратний корінь: voting_power = √(reputation_score). Класика quadratic voting. Людина з репутацією 10,000 має силу 100, людина з репутацією 100 — силу 10. Розрив зберігається, але пропорційно менше.

Логарифмічний масштаб: voting_power = log2(reputation_score + 1) * scale. Ще більш згладжений. При дуже великому spread репутації — оптимальний вибір.

Threshold тири: репутація ділить учасників на категорії (Junior, Member, Senior, Core). Всередині категорії — equal voting power, але різні права (створювати propozals, накладати veto та т.д.).

Репутація Тир Права
0–99 Observer Тільки голосування
100–499 Participant Голос + коментарі в propozals
500–1999 Member Створення propozals
2000–9999 Core Veto право, зміни параметрів
10000+ Maintainer Екстренні дії

Делегування репутації

Репутацію не можна продати (soulbound), але можна делегувати голосову силу — аналогічно delegated voting у Governor Bravo. Делегат голосує від вашого імені, але репутація залишається у вас.

contract ReputationDelegation {
    mapping(address => address) public delegates;
    mapping(address => uint256) public delegatedPower;
    
    function delegate(address delegatee) external {
        address previousDelegate = delegates[msg.sender];
        uint256 myPower = reputationToken.getVotingPower(msg.sender);
        
        // Убираємо делегування у попереднього делегата
        if (previousDelegate != address(0)) {
            delegatedPower[previousDelegate] -= myPower;
        }
        
        delegates[msg.sender] = delegatee;
        
        if (delegatee != address(0)) {
            delegatedPower[delegatee] += myPower;
        }
        
        emit DelegateChanged(msg.sender, previousDelegate, delegatee);
    }
    
    function getEffectivePower(address account) public view returns (uint256) {
        return reputationToken.getVotingPower(account) + delegatedPower[account];
    }
}

Делегування критично для протоколів з технічними рішеннями: багато токен-холдерів не розбиратимуться в деталях конкретного пропозалу, вони делегують довіреним експертам.

Інтеграція з Governor

OpenZeppelin Governor підтримує кастомний розрахунок voting power через інтерфейс IVotes. Репутаційний контракт повинен його реалізовувати:

contract ReputationVotes is IVotes, ReputationToken {
    function getVotes(address account) external view override returns (uint256) {
        return getEffectivePower(account);
    }
    
    function getPastVotes(address account, uint256 blockNumber) 
        external view override returns (uint256) 
    {
        // Для точності потрібен checkpoint mechanism
        return _getPastVotingPower(account, blockNumber);
    }
    
    function getPastTotalSupply(uint256 blockNumber) 
        external view override returns (uint256) 
    {
        return _getPastTotalPower(blockNumber);
    }
    
    // Checkpoint: снапшоти voting power для кожного блоку
    // Використуємо паттерн ERC20Votes з OpenZeppelin
}

Checkpoint механізм — обов'язковий елемент. Governor перевіряє voting power на блоці створення пропозалу, не на поточному блоці. Без чекпоінтів система не працює коректно.

Anti-sybil захист

Репутаційна система особливо уразлива до sybil атак: створити 100 адрес з мінімальною репутацією простіше, ніж набрати велику репутацію на одному адресі.

Proof of Humanity / Worldcoin: верифікація унікальності через biometrics. Кожна верифікована людина отримує один репутаційний аккаунт. Жорсткий, але ефективний.

Gitcoin Passport: м'який підхід. Агрегація identity proof з багатьох джерел (ENS, GitHub, Twitter, Lens та ін.). Чим більш джерел — тим вищий «humanness score». Нижній поріг для отримання репутації.

Social graph analysis: учасники з однаковим паттерном голосування можуть бути однією людиною. Статистичний аналіз on-chain поведінки.

Stake-based admission: для отримання початкової репутації потребує застейкати невелику суму. Створює фінансовий бар'єр для sybil при low cost на real accounts.

Governance параметри та їх настройка

Reputation-weighted governance вимагає ретельної настройки числових параметрів. Неправильні значення призводять або до централізації (кілька учасників з величезною репутацією контролюють все), або до паралічу (репутація розподілена так рівномірно, що кворум недосяжний).

Quorum: мінімальний % від total voting power для валідності голосування. Для reputation-weighted систем зазвичай нижче (5–10%), ніж для token-weighted (вимагаючих 4–20% circulating supply).

Proposal threshold: мінімальний voting power для створення пропозалу. Повинен бути достатнім, щоб відсіяти спам, але не настільки високим, щоб виключити нових активних учасників.

Timelock: обов'язковий. Навіть при децентралізованому governance критично важливо мати час на реакцію сообщества перед виконанням.

// Приклад конфігурації для середнього DAO
const governanceConfig = {
    // Репутаційні параметри
    baseVoteScore: 10,              // очків за кожний голос
    proposalCreationBonus: 100,
    passedProposalBonus: 500,
    contributionMultiplier: 1.5,    // x для верифікованих вкладів
    
    // Decay
    decayPeriodDays: 90,            // 3 місяці неактивності = початок decay
    decayRatePerPeriod: 0.07,       // 7% за кожен період неактивності
    
    // Voting
    quorumPercent: 8,               // 8% від total voting power
    proposalThreshold: 200,         // мінімальний score для створення пропозалу
    votingPeriodDays: 7,
    timelockDays: 2,
    
    // Anti-sybil
    minPassportScore: 15,           // Gitcoin Passport minimum score
    minStakeAmount: '100',          // 100 токенів для admission
};

Мониторинг та аналітика

Reputation-weighted система вимагає постійного мониторингу здоров'я governance:

Концентрація: індекс Джині voting power. Якщо Gini > 0.7 — система де-факто централізована.

Participation rate: % від eligible voters, що беруть участь у середньому пропозалу. Цільовий показник — 20–40%.

New entrant mobility: як швидко новий активний учасник набирає значиму голосову силу. Якщо це займає >12 місяців — система закрита для newcomers.

Proposal success rate: % propozals, що досягли кворума. Занадто низький (< 50%) — кворум завищений. Занадто високий (> 95%) — кворум занижений або сообщество занадто однорідне.

Стек і сроки розробки

Смарт-контракти: Solidity + OpenZeppelin Governor + кастомний IVotes. Hardhat/Foundry для тестування. 10–14 тижнів включаючи checkpoint mechanism та тести.

Off-chain інфраструктура: індексер (The Graph subgraph) для історичних даних репутації, API для frontend, сервіс нарахування репутації за off-chain вклади.

Frontend: DAO dashboard з репутаційними профілями, lifecycle propozals, аналітикою. React + wagmi.

Аудит: обов'язковий. Логіка нарахування та decay репутації — потенціальна точка атаки.

Повний цикл розробки: 5–8 місяців для production-ready системи з аудитом.