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

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы reputation-weighted голосования
Сложная
~1-2 недели
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

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

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

Это значительно сложнее в реализации. Нужно решить три нетривиальные задачи: как измерить репутацию без манипуляций, как хранить и обновлять её on-chain эффективно, и как предотвратить накопление репутации через sybil-атаки.

Модели репутации: откуда берётся вес

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

On-chain активность: частота и качество голосований, своевременность participation, следование решениям (voted with majority vs contrarian). Последнее спорно — иногда правы именно несогласные.

Contribution-based: смерженные PR в протокол, написанные proposals, организованные community calls, написанные документы. Ввод contribution сложнее автоматизировать, требует субъективной оценки.

Peer review: другие участники оценивают вклад, репутация строится социально. Это модель SourceCred — grafo распределения репутации через взаимные оценки.

Outcome-based: ретроактивная оценка решений. Если предложение, за которое голосовал участник, принесло измеримую пользу протоколу — его репутационный вес растёт. Требует оракула метрик.

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;    // созданные предложения
        uint256 proposalsPassed;     // принятые предложения
        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 голосований подряд). Снижает anxiety для случайных пропусков.

# Моделирование 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, но разные права (создавать proposals, накладывать veto и т.д.).

Репутация Тир Права
0–99 Наблюдатель Только голосование
100–499 Участник Голос + комментарии в proposals
500–1999 Член Создание proposals
2000–9999 Ядро Veto право, временные параметры
10000+ Мейнтейнер Экстренные действия

Делегирование репутации

Репутацию нельзя продать (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];
    }
}

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

Интеграция с 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 mechanism — обязательный элемент. Governor проверяет voting power на блоке создания proposal, не на текущем блоке. Без чекпоинтов система не работает корректно.

Anti-sybil защита

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

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

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

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

Stake-based admission: для получения начальной репутации требуется застейкать небольшую сумму. Создаёт финансовый барьер для sybil при low cost on real accounts.

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

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

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

Proposal threshold: минимальный voting power для создания proposal. Должен быть достаточен, чтобы отсеять спам, но не настолько высок, чтобы исключить новых активных участников.

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 для создания proposal
    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, участвующих в среднем proposal. Целевой показатель — 20–40%.

New entrant mobility: как быстро новый активный участник набирает значимую голосовую силу. Если это занимает >12 месяцев — система закрыта для newcomers.

Proposal success rate: % proposals, достигших кворума. Слишком низкий (< 50%) — кворум завышен. Слишком высокий (> 95%) — кворум занижен или сообщество слишком однородно.

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

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

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

Frontend: DAO dashboard с репутационными профилями, proposal lifecycle, аналитикой. React + wagmi.

Аудит: обязателен. Логика начисления и decay репутации — потенциальная точка атаки.

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