Разработка контрактов DAO

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

Разработка контрактов DAO

DAO на бумаге выглядит просто: токены = голоса, большинство решает. На практике это одна из наиболее сложных областей смарт-контрактов — не потому что код особенно трудный, а потому что цена ошибки в governance механике катастрофически высока. Proposal прошёл с ошибкой в логике кворума — и злоумышленник слил treasury. Так случилось с Beanstalk в апреле 2022: flash loan governance атака вывела $182M. Или Mango Markets в октябре того же года. Разработка контрактов DAO — это проектирование экономически-безопасной системы принятия решений.

Архитектурные компоненты

Governor + Timelock

Стандарт де-факто — OpenZeppelin Governor с TimelockController. Governor управляет lifecycle proposal-ов (создание, голосование, постановка в очередь), Timelock добавляет задержку между принятием proposal и его исполнением.

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

import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

contract DAOGovernor is
    Governor,
    GovernorSettings,
    GovernorCountingSimple,
    GovernorVotes,
    GovernorVotesQuorumFraction,
    GovernorTimelockControl
{
    constructor(
        IVotes _token,
        TimelockController _timelock
    )
        Governor("DAO Governor")
        GovernorSettings(
            1,          // votingDelay: 1 блок (~12 сек на Ethereum)
            50400,      // votingPeriod: ~7 дней в блоках
            100_000e18  // proposalThreshold: минимум 100K токенов для proposal
        )
        GovernorVotes(_token)
        GovernorVotesQuorumFraction(10)  // 10% от total supply = кворум
        GovernorTimelockControl(_timelock)
    {}

    // Обязательные override-ы при множественном наследовании
    function quorum(uint256 blockNumber)
        public view override(Governor, GovernorVotesQuorumFraction)
        returns (uint256)
    {
        return super.quorum(blockNumber);
    }

    function state(uint256 proposalId)
        public view override(Governor, GovernorTimelockControl)
        returns (ProposalState)
    {
        return super.state(proposalId);
    }

    function _execute(uint256 proposalId, address[] memory targets,
        uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
        internal override(Governor, GovernorTimelockControl)
    {
        super._execute(proposalId, targets, values, calldatas, descriptionHash);
    }

    function _cancel(address[] memory targets, uint256[] memory values,
        bytes[] memory calldatas, bytes32 descriptionHash)
        internal override(Governor, GovernorTimelockControl)
        returns (uint256)
    {
        return super._cancel(targets, values, calldatas, descriptionHash);
    }

    function _executor()
        internal view override(Governor, GovernorTimelockControl)
        returns (address)
    {
        return super._executor();
    }
}

TimelockController настройка

Timelock — критически важный компонент. Он даёт сообществу время среагировать на принятый proposal до его исполнения. Минимальная задержка для treasury операций — 48 часов, для обновления контрактов — 72 часа.

// Деплой TimelockController
// minDelay: 172800 (48 часов в секундах)
// proposers: [address(governor)]
// executors: [address(0)] — любой может исполнить после задержки
// admin: address(0) — нет суперадмина, только через Timelock

TimelockController timelock = new TimelockController(
    172800,
    proposers,  // только Governor может ставить в очередь
    executors,  // address(0) = любой может исполнить
    address(0)  // admin revoked
);

executors: [address(0)] означает что исполнить операцию после задержки может любой — это правильно. Иначе создаётся centralization point, где конкретный адрес должен нажать «execute».

Proposal lifecycle

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

Pending: proposal создан, ждёт votingDelay блоков. Snapshot голосов берётся в последнем блоке перед переходом в Active.

Active: открыто голосование на votingPeriod блоков. Голосование: For, Against, Abstain. Abstain считается в кворуме, но не влияет на результат.

Succeeded: кворум достигнут, For > Against. Proposal ждёт queue в Timelock.

Queued: в Timelock очереди. Ждёт minDelay. В этот период Guardian (если есть) может отменить.

Executed: исполнен on-chain.

Flash loan атаки: защита

Beanstalk-сценарий: злоумышленник берёт flash loan на огромную сумму, получает временный governance контроль (delegateVote для governance веса), создаёт и немедленно проводит malicious proposal, возвращает loan. Всё в одной транзакции.

Ключевая защита — snapshot timing. GovernorVotes использует getPastVotes(account, proposalSnapshot) — вес голоса определяется на блоке snapshot, а не на блоке голосования. votingDelay = 1 (один блок) уже ломает flash loan атаку: нельзя занять токены и использовать их в том же блоке для snapshot.

Дополнительные меры:

Timelock задержка: даже если злоумышленник прошёл голосование, 48-72 часа задержки дают время сообществу заметить и Guardian может отменить.

Proposal threshold: минимальный баланс для создания proposal (100K токенов в примере выше). Снижает спам и требует реального владения токенами.

QuorumFraction: кворум привязан к total supply на момент snapshot. Если supply 10M токенов, кворум 10% = 1M токенов. Мелкие proposals не проходят без широкой поддержки.

Delegation tracking: в базовом ERC20Votes баланс != voting power без explicit делегирования. Пользователь должен delegate(address(self)) или делегировать другому. Это фича, а не баг: снижает effective supply voting power.

Voting модели: что выбрать

Token-weighted voting (стандарт)

1 токен = 1 голос. Просто, предсказуемо, но plutocratic: крупные холдеры доминируют.

Quadratic voting

Стоимость N голосов = N². Пользователь с 100 токенами может дать proposal максимум 10 голосов (√100). Снижает доминирование крупных холдеров.

Проблема: требует Sybil resistance (иначе 1 крупный кошелёк делится на 100 маленьких). Gitcoin Passport, Worldcoin ID, NFT membership — возможные решения.

function _getVotes(address account, uint256 blockNumber, bytes memory)
    internal view override returns (uint256)
{
    uint256 balance = token.getPastVotes(account, blockNumber);
    // Квадратный корень (в fixed-point арифметике)
    return Math.sqrt(balance);
}

Optimistic governance

Proposal исполняется автоматически через delay, если не было достаточного veto. Обратная модель: по умолчанию «да», нужно активное veto для блокировки. Снижает voter apathy проблему (многие не голосуют за рутинные proposals).

Используется в Optimism Collective: Citizens' House имеет veto право на токен-weighted decisions.

Multi-sig как Guardian

Полностью on-chain governance уязвимо на ранних стадиях: мало токенов в обращении, низкая явка, легко манипулировать. Стандартная практика — Guardian мультисиг (Gnosis Safe 3/5 или 4/7), который может отменить queued proposals, но не может их инициировать или исполнять.

// В TimelockController: CANCELLER_ROLE для Guardian Safe
timelock.grantRole(timelock.CANCELLER_ROLE(), guardianSafe);

Guardian не должен иметь PROPOSER_ROLE или EXECUTOR_ROLE — только CANCELLER. Это создаёт asymmetric protection: Guardian защищает от атак, но не контролирует governance.

По мере роста сообщества Guardian постепенно выводится: сначала снижается threshold, затем полностью удаляется роль.

Sub-DAO и специализированные комитеты

Монолитный Governor для всех решений — антипаттерн. Ончейн голосование за каждую операцию убивает скорость. Типичная многоуровневая структура:

Core DAO Governor: крупные решения — изменение протокольных параметров, крупные treasury движения (> $100K), изменение контрактов. Долгий votingPeriod (7-14 дней).

Treasury Committee: Gnosis Safe 4/7 из выбранных DAO представителей. Быстрые treasury операции < $100K без on-chain голосования. Регулярный отчёт DAO.

Technical Committee: аудит контрактов, emergency pause. Отдельный Gnosis Safe с PAUSER_ROLE на критичных контрактах.

Grants Committee: небольшой grants budget ($5-20K), быстрые решения без full governance. Часто Snapshot (off-chain) голосование.

// Пример: pause механизм для emergency
contract ProtocolCore is Pausable {
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    // Timelock имеет DEFAULT_ADMIN_ROLE
    // Technical Committee Safe имеет PAUSER_ROLE
    // Только Timelock может назначать/снимать PAUSER_ROLE
}

Gasless voting через EIP-712

Основная проблема on-chain голосования — gas cost. На Ethereum mainnet один голос стоит $5-20. При 1000 активных участников это $5K-20K на один proposal. Большинство DAO решает это через off-chain voting (Snapshot) с on-chain execution.

Hybrid подход: голосование в Snapshot (бесплатно, подпись EIP-712), результат реализуется через SafeSnap — Gnosis Safe модуль, который автоматически ставит в очередь Timelock операции по итогам Snapshot proposal.

Для on-chain голосования на L2 (Arbitrum, Optimism, Base) gas уже приемлем — $0.05-0.50 за транзакцию.

Токен делегирование и voter apathy

Voter apathy — главная проблема работающих DAO. Uniswap governance: кворум 40M UNI при total supply 1B — реально участвует 4%. Часто proposal не проходит просто потому что никто не проголосовал.

Решения:

Delegation UX: при первом взаимодействии с протоколом или при получении токенов — prompt для делегирования. Многие передают голоса активным delegates (аналог представительной демократии).

Optimistic default: если кворум не достигнут за votingPeriod — proposal не провалился, а перенесён. Опционально.

Participation rewards: небольшое вознаграждение за голосование. Спорная механика — может привлечь бездумные голоса, но увеличивает явку.

Delegate dashboard: публичные профили delegates, их позиции по прошлым proposals, их аргументы — снижает информационный барьер для делегирования.

Стек и инструменты

Компонент Инструмент
Governor контракт OpenZeppelin Governor 5.x
Timelock OpenZeppelin TimelockController
Governance token ERC20Votes + ERC20Permit
Off-chain voting Snapshot.org
On-chain execution SafeSnap / Reality.eth
Frontend Tally.xyz (готовое) или кастомное
Multi-sig Gnosis Safe
Testnet Hardhat fork + Foundry

Tally.xyz — готовый UI для OpenZeppelin Governor-совместимых DAO. Если нет специфических требований к frontend — экономит 2-4 недели разработки.

Процесс работы

Дизайн governance (1-2 недели). Voting model, параметры (delay, period, threshold, quorum), структура committees, Guardian схема, migration plan от мультисига к полному on-chain governance.

Разработка контрактов (2-3 недели). Governor + Timelock + Governance token (если нет) + тесты атаки сценариев.

Безопасность (1-2 недели). Внутренний review всех proposal lifecycle сценариев, flash loan тесты, timelock операции.

Аудит (2-3 недели). Внешний аудит обязателен — governance контракты управляют всем протоколом.

Frontend и интеграция (2-3 недели). Tally.xyz интеграция или кастомный UI, Snapshot space настройка, SafeSnap настройка.

Постепенный launch. Начало с Guardian мультисигом, снижение централизации по roadmap.

Полный цикл: 3-4 месяца. Стоимость зависит от complexity governance модели и наличия существующего токена.