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

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

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

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

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

Governor + Timelock

Стандарт де-факто — OpenZeppelin Governor з TimelockController. Governor управляє життєвим циклом пропозицій (створення, голосування, постановка в чергу), Timelock додає затримку між прийняттям пропозиції та її виконанням.

// 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 токенів для пропозиції
        )
        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 — критично важливий компонент. Він дає спільноті час реагувати на прийняту пропозицію до її виконання. Мінімальна затримка для 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: пропозиція створена, чекає votingDelay блоків. Снімок голосів береться в останньому блоці перед переходом в Active.

Active: відкрито голосування на votingPeriod блоків. Голосування: For, Against, Abstain. Abstain вважається в кворумі, але не впливає на результат.

Succeeded: кворум досягнутий, For > Against. Пропозиція чекає queue в Timelock.

Queued: в Timelock черзі. Чекає minDelay. У цей період Guardian (якщо є) може скасувати.

Executed: виконаний on-chain.

Flash loan атаки: захист

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

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

Додаткові заходи:

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

Proposal threshold: мінімальний баланс для створення пропозиції (100K токенів у прикладі вище). Знижує спам та вимагає реального володіння токенами.

QuorumFraction: кворум прив'язаний до total supply на момент snapshot. Якщо supply 10M токенів, кворум 10% = 1M токенів. Малі пропозиції не проходять без широкої підтримки.

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 токенами може дати пропозиції максимум 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

Пропозиція виконується автоматично через delay, якщо не було достатнього veto. Зворотна модель: за замовчуванням «так», потрібно активне veto для блокування. Знижує voter apathy проблему (багато хто не голосує за рутинні пропозиції).

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

Multi-sig як Guardian

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

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

Guardian не повинен мати PROPOSER_ROLE або EXECUTOR_ROLE — тільки CANCELLER. Це створює asymmetric захист: 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 бюджет ($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 на одну пропозицію. Більшість DAO вирішує це через off-chain voting (Snapshot) з on-chain виконанням.

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

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

Токен делегування та voter apathy

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

Рішення:

Delegation UX: при першій взаємодії з протоколом або при отриманні токенів — prompt для делегування. Багато хто передають голоси активним delegates (аналог представницької демократії).

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

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

Delegate dashboard: публічні профілі delegates, їхні позиції щодо минулих пропозицій, їхні аргументи — знижує інформаційний бар'єр для делегування.

Стек та інструменти

Компонент Інструмент
Governor контракт OpenZeppelin Governor 5.x
Timelock OpenZeppelin TimelockController
Governance токен ERC20Votes + ERC20Permit
Off-chain голосування Snapshot.org
On-chain виконання 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 модель, параметри (delay, period, threshold, quorum), структура комітетів, Guardian схема, migration plan від мультисига до повного on-chain governance.

Розробка контрактів (2-3 тижні). Governor + Timelock + Governance токен (якщо немає) + тести атак сценарієв.

Безпека (1-2 тижні). Внутрішній review всіх proposal lifecycle сценаріїв, flash loan тести, timelock операції.

Аудит (2-3 тижні). Зовнішній аудит обов'язковий — governance контракти управляють всім протоколом.

Frontend та інтеграція (2-3 тижні). Tally.xyz інтеграція або кастомний UI, Snapshot space налаштування, SafeSnap налаштування.

Поступовий launch. Початок з Guardian мультисигом, зниження централізації за дорожною картою.

Повний цикл: 3-4 місяці. Вартість залежить від складності governance моделі та наявності існуючого токена.