Разработка системы proposals DAO

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы proposals DAO
Сложная
~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

Интеграция с OpenZeppelin Governor

OpenZeppelin Governor — это модульный фреймворк для on-chain governance, реализующий стандарт совместимый с Compound Governor Bravo. Большинство DeFi-протоколов с on-chain governance построены на этой базе или совместимы с ней: Uniswap, Compound, Gitcoin, ENS используют Governor-совместимые контракты. Поэтому интеграция с Governor — это не просто добавление governance к вашему протоколу, но и совместимость с экосистемой инструментов: Tally, Boardroom, Snapshot (для off-chain signaling).

Архитектура Governor

Governor — это не один контракт, а набор модулей через Solidity multiple inheritance.

contract MyGovernor is
    Governor,
    GovernorSettings,         // voting delay, voting period, proposal threshold
    GovernorCountingSimple,   // For, Against, Abstain подсчёт
    GovernorVotes,            // интеграция с ERC-20Votes токеном
    GovernorVotesQuorumFraction, // кворум как % от total supply
    GovernorTimelockControl  // исполнение через Timelock
{
    constructor(IVotes _token, TimelockController _timelock)
        Governor("MyProtocol Governor")
        GovernorSettings(
            1 days,   // voting delay: сколько ждать после создания пропозала
            1 weeks,  // voting period: сколько длится голосование
            10_000e18 // proposal threshold: минимум токенов для создания пропозала
        )
        GovernorVotes(_token)
        GovernorVotesQuorumFraction(4) // 4% от circulating supply = кворум
        GovernorTimelockControl(_timelock)
    {}
}

Каждый модуль решает отдельную задачу. Если нужна кастомная логика подсчёта голосов (например, квадратичное голосование) — заменяете GovernorCountingSimple своей реализацией.

Жизненный цикл пропозала

Пропозал проходит через строго определённые состояния:

Pending → Active → Succeeded/Defeated/Canceled → Queued → Executed

Создание → [voting delay] → Голосование → [voting period] → Подсчёт →
[timelock delay] → Исполнение

votingDelay — защита от flash loan атак. Если голосование начинается сразу после создания пропозала, атакующий может купить большой объём токенов в тот же блок, проголосовать, и продать. С voting delay в 1–2 дня это невозможно: нужно удерживать токены до snapshot-блока.

GovernorVotes фиксирует voting power каждого адреса на блоке начала голосования через ERC-20Votes checkpoint механизм. Изменения баланса после этого блока не влияют на vote weight.

Timelock интеграция

TimelockController — отдельный контракт, который является владельцем ваших протокольных контрактов. Governor отправляет транзакции в Timelock очередь; после delay (обычно 48–72 часа) исполнение становится возможным.

// Деплой TimelockController
TimelockController timelock = new TimelockController(
    2 days,           // minDelay
    proposers,        // только Governor может ставить в очередь
    executors,        // любой может исполнить (или конкретный адрес)
    admin             // после setup admin = address(0), убираем admin права
);

// Governor получает PROPOSER_ROLE
timelock.grantRole(timelock.PROPOSER_ROLE(), address(governor));
// Executor — open (address(0)) или конкретный address
timelock.grantRole(timelock.EXECUTOR_ROLE(), address(0));
// Отзываем admin (важно!)
timelock.revokeRole(timelock.DEFAULT_ADMIN_ROLE(), deployer);

Почему важно отозвать admin-роль: если у deployer остаётся DEFAULT_ADMIN_ROLE, он может в любой момент обойти governance и напрямую выдать себе PROPOSER_ROLE. Финальный шаг — revokeRole admin от deployer.

Propose, Vote, Execute

Создание пропозала

Пропозал — это один или несколько вызовов функций, которые будут исполнены если голосование пройдёт.

// Пример: пропозал на изменение fee параметра протокола
address[] memory targets = new address[](1);
targets[0] = address(protocolContract);

uint256[] memory values = new uint256[](1); // ETH value, обычно 0
values[0] = 0;

bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSignature("setFee(uint256)", 30); // 0.3%

string memory description = "Proposal #1: Set protocol fee to 0.3%";

uint256 proposalId = governor.propose(targets, values, calldatas, description);

proposalId вычисляется как keccak256(abi.encode(targets, values, calldatas, keccak256(bytes(description)))). Это важно: description входит в id, поэтому изменение описания создаёт другой пропозал.

Голосование

// 0 = Against, 1 = For, 2 = Abstain
governor.castVote(proposalId, 1);

// С обоснованием (on-chain, дорого по газу)
governor.castVoteWithReason(proposalId, 1, "Increases protocol competitiveness");

// EIP-712 подпись для gasless голосования через relayer
governor.castVoteBySig(proposalId, 1, v, r, s);

castVoteBySig — критичная функция для UX. Большинство holders не будут платить $5–20 за on-chain vote. Gasless voting: пользователь подписывает vote off-chain, relayer (или сам протокол) отправляет транзакцию и платит газ.

Исполнение

// После успешного голосования и timelock delay
governor.execute(targets, values, calldatas, keccak256(bytes(description)));

Кастомизация: что можно менять

Voting power источник. По умолчанию — ERC-20Votes токен. Можно заменить на: ERC-721Votes (NFT governance), custom weighting (locked tokens весят больше), veToken модель (Curve style).

Quorum. GovernorVotesQuorumFraction считает кворум от total supply. Проблема: если большая часть токенов не делегирована, кворум никогда не достигается. Решение — считать от delegated supply, а не total. Требует override quorum() функции.

Proposal threshold. Высокий порог (например, 1% supply) защищает от спам-пропозалов, но исключает мелких holders. Альтернатива: delegation threshold — любой holder может создать пропозал если соберёт достаточно делегатов.

Tally и экосистема инструментов

Tally — web3 governance дашборд, который работает с любым Governor-совместимым контрактом out of the box. После деплоя Governor на Tally появляется автоматически через их indexer. Это важно: не нужно строить custom UI для голосования с нуля.

Snapshot для off-chain signaling использует EIP-712 signatures без газа. Интеграция Governor + Snapshot: Snapshot результаты могут использоваться как signal перед on-chain пропозалом, или через Governor-style модуль Snapshot можно делать binding голосования с on-chain исполнением.

Распространённые ошибки при интеграции

Забыть transferOwnership на Timelock. Governor + Timelock бесполезны, если ваши протокольные контракты по-прежнему принадлежат deployer-кошельку. Нужно явно передать ownership.

Неправильный quorum. 4% от total supply при 30% circulation rate означает реальный порог в 13% от circulating — трудно достижимо. Тестируйте на реальных данных распределения токенов.

Отсутствие ERC-20Votes в токене. Стандартный ERC-20 не поддерживает чекпоинты. Либо токен должен наследовать ERC20Votes, либо нужен wrapper (как wToken). Retrofit существующего токена — через ERC20VotesWrapper.

Сроки интеграции: стандартная Governor интеграция с существующим токеном — 1–2 недели разработки + 1 неделя тестирования. Кастомная voting механика — 3–4 недели.