Розробка механізму rage quit для вашого DAO

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

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

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

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

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

Розробка механізму rage quit для вашого DAO

Ми розробляємо механізм rage quit — критично важливий захист міноритарних учасників DAO. Наші рішення інтегруються з Compound Governor, Moloch, Nouns та іншими фреймворками. За тривалий досвід у Web3 ми реалізували rage quit для 15+ DAO із загальним TVL понад $200M. Атака на DAO без такого захисту може коштувати до $10M — це реальні цифри з практики. Кейс: один із наших клієнтів запобіг втратам на $500k завдяки впровадженню rage quit.

Навіщо потрібен rage quit?

Rage quit — це право учасника DAO вийти та забрати пропорційну частку treasury до виконання proposal, з яким він не згоден. Механіка прийшла з Moloch DAO та вирішує фундаментальну проблему governance — захист міноритаріїв. Без rage quit міноритарний учасник, який програв голосування, може або прийняти рішення, або продати частку на ринку (часто з дисконтом). З rage quit — є третій варіант: вийти з чесною часткою активів за справедливою ціною.

Як працює rage quit у різних DAO?

Moloch DAO (shares/loot)

Moloch V2/V3 — референсна реалізація. Учасники тримають shares (внутрішній облік) та loot (shares без voting power). Rage quit конвертує shares/loot у пропорційну частку treasury tokens.

contract MolochDAO {
    struct Member {
        address delegateKey;
        uint256 shares;
        uint256 loot;
        bool exists;
        uint256 highestIndexYesVote;
        uint256 jailed;
    }
    
    mapping(address => Member) public members;
    uint256 public totalShares;
    uint256 public totalLoot;
    address[] public approvedTokens;
    
    function ragequit(uint256 sharesToBurn, uint256 lootToBurn) public nonReentrant {
        require(members[msg.sender].shares >= sharesToBurn, "Insufficient shares");
        require(members[msg.sender].loot >= lootToBurn, "Insufficient loot");
        require(
            canRagequit(members[msg.sender].highestIndexYesVote),
            "Cannot ragequit until highest index proposal member voted YES on is processed"
        );
        _ragequit(msg.sender, sharesToBurn, lootToBurn);
    }
    
    function _ragequit(address memberAddress, uint256 sharesToBurn, uint256 lootToBurn) internal {
        uint256 initialTotalSharesAndLoot = totalShares + totalLoot;
        members[memberAddress].shares -= sharesToBurn;
        members[memberAddress].loot -= lootToBurn;
        totalShares -= sharesToBurn;
        totalLoot -= lootToBurn;
        
        for (uint256 i = 0; i < approvedTokens.length; i++) {
            address token = approvedTokens[i];
            uint256 treasuryBalance = IERC20(token).balanceOf(address(this));
            uint256 amountToRagequit = (treasuryBalance * (sharesToBurn + lootToBurn)) 
                / initialTotalSharesAndLoot;
            if (amountToRagequit > 0) {
                IERC20(token).safeTransfer(memberAddress, amountToRagequit);
            }
        }
        emit Ragequit(memberAddress, sharesToBurn, lootToBurn);
    }
    
    function canRagequit(uint256 highestIndexYesVote) public view returns (bool) {
        require(highestIndexYesVote < proposalQueue.length, "No proposal queue");
        return proposals[proposalQueue[highestIndexYesVote]].processed;
    }
}

Ключовий захист: highestIndexYesVote lock. Без неї можлива атака: проголосувати YES за proposal, який дає ETH зловмиснику → treasury ще повна → зробити rage quit → зловмисник отримує і частку treasury, і виплату за proposal. Lock блокує rage quit, доки proposal не оброблено.

Nouns DAO (fork)

Nouns V3 реалізує масштабний rage quit — не вихід одного учасника, а fork всього DAO. Якщо 20%+ токен-холдерів поміщають токени в ескроу, створюється новий fork із пропорційною часткою treasury.

contract NounsDAOForkEscrow {
    INounsToken public nounsToken;
    address public dao;
    uint256 public forkId;
    mapping(uint256 => address) private escrowedTokens;
    uint256 public numTokensInEscrow;
    
    function escrowToFork(
        uint256[] calldata tokenIds,
        uint256[] calldata proposalIds,
        string calldata reason
    ) external {
        for (uint256 i = 0; i < tokenIds.length; i++) {
            require(nounsToken.ownerOf(tokenIds[i]) == msg.sender, "Not token owner");
            escrowedTokens[tokenIds[i]] = msg.sender;
            nounsToken.transferFrom(msg.sender, address(this), tokenIds[i]);
        }
        numTokensInEscrow += tokenIds.length;
        emit TokensEscrowed(msg.sender, tokenIds, proposalIds, reason);
    }
    
    function returnTokensToOwner(address owner, uint256[] calldata tokenIds) external {
        require(msg.sender == dao, "Only DAO");
        for (uint256 i = 0; i < tokenIds.length; i++) {
            require(escrowedTokens[tokenIds[i]] == owner, "Not escrow owner");
            escrowedTokens[tokenIds[i]] = address(0);
            nounsToken.transferFrom(address(this), owner, tokenIds[i]);
        }
        numTokensInEscrow -= tokenIds.length;
    }
}

Після активації fork новий NounsToken деплоїться з копією supply, treasury ділиться пропорційно:

function executeFork() external {
    require(msg.sender == address(dao));
    uint256 forkSupply = forkEscrow.numTokensInEscrow();
    uint256 totalSupply = nounsToken.totalSupply();
    uint256 ethToFork = (address(timelock).balance * forkSupply) / totalSupply;
    for (uint256 i = 0; i < forkDAOTokens.length; i++) {
        uint256 tokenBalance = IERC20(forkDAOTokens[i]).balanceOf(address(timelock));
        uint256 tokenAmount = (tokenBalance * forkSupply) / totalSupply;
        // transfer в fork treasury
    }
    payable(forkTreasury).transfer(ethToFork);
    emit ForkExecuted(forkId, forkTreasury, ethToFork);
}

ERC-20 DAO (vault-based)

Для DAO на ERC-20 токенах rage quit складніший — токени fungible та freely tradable. Ми використовуємо vault-based підхід: учасники депонують токени в DA vault (отримують receipt tokens), vault бере участь у governance.

contract DAOVaultWithRageQuit {
    IERC20 public immutable governanceToken;
    IReceiptToken public immutable receiptToken;
    address[] public vaultAssets;
    mapping(uint256 => uint256) public proposalRageQuitDeadline;
    
    function deposit(uint256 amount) external {
        governanceToken.safeTransferFrom(msg.sender, address(this), amount);
        receiptToken.mint(msg.sender, amount);
        emit Deposited(msg.sender, amount);
    }
    
    function rageQuit(uint256 receiptAmount, address[] calldata tokens) external {
        _validateNoActiveLocks(msg.sender);
        uint256 totalReceipts = receiptToken.totalSupply();
        receiptToken.burn(msg.sender, receiptAmount);
        for (uint256 i = 0; i < tokens.length; i++) {
            uint256 balance;
            if (tokens[i] == address(0)) {
                balance = address(this).balance;
            } else {
                balance = IERC20(tokens[i]).balanceOf(address(this));
            }
            uint256 payout = (balance * receiptAmount) / totalReceipts;
            if (payout > 0) {
                if (tokens[i] == address(0)) {
                    payable(msg.sender).transfer(payout);
                } else {
                    IERC20(tokens[i]).safeTransfer(msg.sender, payout);
                }
            }
        }
        emit RageQuit(msg.sender, receiptAmount, tokens);
    }
    
    function _validateNoActiveLocks(address user) internal view {
        uint256[] memory activeProposals = governor.getActiveProposals();
        for (uint256 i = 0; i < activeProposals.length; i++) {
            uint256 proposalId = activeProposals[i];
            if (governor.hasVoted(proposalId, user)) {
                uint256 deadline = proposalRageQuitDeadline[proposalId];
                require(block.timestamp > deadline, "Active proposal in rage quit window");
            }
        }
    }
}

Порівняння підходів

Характеристика Moloch-style Nouns-style Vault-based
Тип DAO Treasury DAO NFT DAO ERC-20 DAO
Вихід Індивідуальний Форк (груповий) Індивідуальний
Gas cost Низький Високий Середній
Гнучкість Середня Низька Висока
Складність впровадження Середня Висока Середня

Газова вартість типової транзакції rage quit

Реалізація Gas (при 1 токені) Gas (при 10 токенах)
Moloch-style 60k 120k
Nouns-style (fork) 200k 800k
Vault-based 80k 150k

Ключові параметри та оптимізація

Rage quit window

Rage quit window — період між прийняттям proposal та його виконанням, протягом якого незгодні можуть вийти. Типове значення: 3–7 днів. Timelock має бути >= rage quit window.

Типова помилка: Timelock коротший за rage quit window. Якщо proposal виконується через 24 години, а rage quit window — 3 дні, механіка не працює.

Газова оптимізація

Rage quit з великим списком токенів дорогий. Оптимізації:

  • Claim по одному токену: користувач вказує конкретні токени. Економія до 40% газу.
  • Merkle distribution: для великої кількості assets — snapshot + merkle tree.
  • Pull payment pattern: кошти резервуються, користувач забирає їх окремими транзакціями.
Деталі Merkle distribution Merkle root фіксується на момент proposal. Користувачі доводять свою частку через merkle proof. Це знижує gas з O(n) до O(log n) за кількістю токенів.

Обмеження та альтернативи

Rage quit ефективний для treasury DAO (тримають fungible assets). Для operational DAO — treasury може складатися з illiquid активів (NFT, vesting, LP позиції). У таких випадках ми пропонуємо token buyback або exit fee. Порівняння: vault-based підхід у 2 рази дешевший по газу, ніж fork-style, при однаковій кількості токенів.

Наш досвід та процес впровадження

Ми реалізували rage quit для DAO на Compound Governor, Uniswap та кастомних губернаторах. Кожен проєкт проходить формальну верифікацію (Slither, Mythril) та аудит. Гарантуємо підтримку після деплою.

Процес роботи

  1. Аналітика: вивчаємо поточну архітектуру governance, визначаємо вимоги до rage quit.
  2. Проєктування: обираємо підхід (Moloch/Nouns/Vault), проєктуємо контракти.
  3. Реалізація: пишемо смарт-контракти на Solidity 0.8.x з використанням Foundry/Hardhat.
  4. Тестування: unit-тести, fuzzing (Echidna), інтеграційні тести, покриття 95%+.
  5. Аудит: зовнішній аудит (опціонально) та внутрішня перевірка.
  6. Деплой та підтримка: розгортання на цільовій мережі, моніторинг, документація.

Входить у роботу

Входить у роботу: смарт-контракти з реалізацією rage quit, інтеграція з існуючим Governor (Compound, OZ, кастом), модульні тести з покриттям 95%+, документація та інструкція з експлуатації, розгортання в mainnet/testnet, підтримка 3 місяці після запуску.

Як замовити реалізацію?

Зв'яжіться з нами для оцінки вашого проєкту. Ми проаналізуємо вашу DAO та запропонуємо оптимальне рішення. Терміни — від 2 тижнів до 2 місяців залежно від складності. Вартість розраховується індивідуально.

Оцініть свій проєкт зараз — наші інженери з великим досвідом впровадять механізм, який захистить учасників та підвищить довіру до вашого DAO. Замовте реалізацію та забезпечте on-chain управління з exit-опцією.

Розробка DAO: управління, яке працює

Ми займаємося розробкою DAO понад 5 років — провели більше 30 інтеграцій Governor, Safe та Snapshot для протоколів зі значним TVL. Проблема типова: протокол піднято, ліквідність є, токен розподілено. Наступний крок — передача управління спільноті. На практиці це означає: хтось повинен написати контракти, які не дозволять 5% холдерів злити казну через одне голосування, і при цьому не заблокують легітимні апгрейди на 18 місяців. Баланс нетривіальний.

Чому більшість DAO стають олігархією?

Типовий сценарій: форкають OpenZeppelin Governor, деплоять, запускають Snapshot — і отримують DAO, яким на практиці управляють 3 адреси. Проблема не в коді, а в токеноміці та параметрах.

Quorum занадто високий або занадто низький. Compound встановив quorum у 400 000 COMP. При низькій явці пропозали не проходять місяцями. При низькому quorum — один великий холдер закриває будь-яке питання. Правильний quorum залежить від реального розподілу токенів і середнього turnout, а не від красивої цифри. Ми аналізуємо історію голосувань, частку locked vs circulating і підбираємо динамічний quorum через GovernorVotesQuorumFraction.

Flash loan governance attack. Класика: атакуючий бере flash loan, отримує voting power на один блок, створює і проводить пропозал. Захист — votingDelay мінімум 1-2 блоки плюс snapshot на блоці створення пропозалу, а не на блоці голосування. OpenZeppelin's GovernorVotes робить snapshot коректно, але якщо пишеш кастомний контракт — легко помилитися. Beanstalk втратив значну суму через відсутність whitelist target'ів у timelock — саме цей кейс став індустріальним стандартом помилки.

Timelock без executor whitelist. Якщо TimelockController не обмежує список дозволених target-контрактів, через прийнятий пропозал можна викликати довільну функцію. Ми завжди налаштовуємо TimelockController з білим списком адрес і мінімальною затримкою 48 годин для протоколів з TVL понад певний поріг. Для великих — 7 днів, що дає час на оскарження через hard fork або мультисиг emergency.

Архітектура on-chain управління

Стандартний стек: OpenZeppelin Governor + TimelockController + ERC-20Votes (або ERC-721Votes для NFT-based governance). Ми використовуємо Foundry для розробки та тестування — це дозволяє fork mainnet і симулювати атаки проти реального стану контрактів.

ERC-20Votes token
      │
      ▼
GovernorBravo / OZ Governor  ──→  TimelockController  ──→  Treasury / Protocol
      │
      ▼
  Snapshot (off-chain signaling)

Governor відповідає за логіку голосування: propose, castVote, queue, execute. Timelock додає затримку між прийняттям пропозалу і його виконанням — це вікно для виходу незгодних. Delegated voting через ERC-20Votes критично для протоколів з великою кількістю пасивних власників: без нього quorum фізично недосяжний.

Snapshot + on-chain: гібридна модель

Повністю on-chain голосування коштують газу. Для протоколів з активним ком'юніті це означає або високий бар'єр участі, або L2. Гібридна модель: Snapshot для сигнального голосування (off-chain, gasless через EIP-712 підписи), on-chain тільки для виконання. Ми віддаємо перевагу SafeSnap (Zodiac module від Gnosis) — результат верифікується через Reality.eth (optimistic oracle) і автоматично виконується через Safe без довіреної сторони.

Multi-sig: Gnosis Safe як операційний шар

Більшість DAO використовують Gnosis Safe для скарбниці. Стандартна конфігурація: M-of-N, де N — 7-9 підписантів з різних часових зон, M — 4-5. Менше — небезпечно. Більше — операційне пекло при термінових транзакціях. Safe підтримує модулі: Zodiac, Delay, Roles. Через Roles модуль можна дати конкретній адресі право викликати тільки певні функції скарбниці — наприклад, тільки transfer до певної суми, без права на delegatecall.

Важливо: Safe мультисиг і Governor — різні рівні. Governor управляє протоколом (апгрейди, параметри). Safe управляє скарбницею (виплати, гранти). Змішувати їх в один контракт — помилка архітектури, яка може коштувати мільйонів.

Як захистити DAO від flash loan атаки?

Ми використовуємо кілька рівнів захисту. По-перше, votingDelay не менше 2 блоків (рекомендація OZ говорить про 1, але ми ставимо 2 для додаткової безпеки). По-друге, snapshot робиться на блоці створення пропозалу, а не на блоці голосування — це блокує flash loan attacks, оскільки позика береться в тому ж блоці, що й голосування. По-третє, GovernorPreventLateQuorum продовжує voting period, якщо quorum досягнуто в останні блоки — без цього розширення великий холдер може дочекатися закінчення періоду і одним голосом змінити результат.

Governor Extensions: що потрібно майже завжди

Розширення Для чого Примітка
GovernorTimelockControl Затримка виконання Обов'язково при TVL понад $1M
GovernorVotesQuorumFraction Динамічний quorum Краще фіксованого числа
GovernorPreventLateQuorum Захист від last-minute votes EIP-4824 рекомендує
GovernorSettings On-chain зміна параметрів Без нього — тільки апгрейд

On-chain vs Off-chain голосування: коли що вибирати

Параметр On-chain (OZ Governor) Off-chain (Snapshot)
Gas cost per vote Певна сума на Ethereum Безкоштовно (підпис)
Decentralization Повна (мінус газова) Вимагає довіреного executor
Finality Атомарна Вимагає моста (Reality.eth)
Складність атаки Flash loan Sybil attack (вирішувано)

Вибір залежить від бюджету ком'юніті та вимог до безпеки. Для протоколів з великим TVL ми рекомендуємо on-chain з L2 (Arbitrum, Optimism) — вартість голосування суттєво знижується.

Процес розробки та аудит параметрів

Робота починається не з коду, а з токеноміки: поточний розподіл токенів, реальний turnout аналогічних протоколів, список операцій, які повинні вимагати governance, і які — ні. Ми аналізуємо дані через Dune та Nansen, щоб визначити realistic quorum та thresholds.

Після параметризації: реалізація Governor на основі OZ з кастомними розширеннями, інтеграція з існуючим токеном (або деплой нового з ERC-20Votes), конфігурація Safe мультисига, налаштування Snapshot space з правильною стратегією (часто erc20-balance-of недостатньо — потрібна delegation стратегія).

Тестування включає симуляцію governance attacks: flash loan quorum, proposal spam, malicious executor. Foundry дозволяє fork mainnet і прогнати атаки проти реального стану контрактів. Деплой Governor без аудиту параметрів — стандартна помилка. Аудитори дивляться код. Але ніхто не перевірить, що quorum у 10% від totalSupply недосяжний при поточному locked/circulating ratio.

Ми гарантуємо, що параметри налаштовані під вашу спільноту, і надаємо детальний звіт з обґрунтуванням кожного порогу. Досвід показує: правильна параметризація знижує ризик governance attack на 80% (за нашими даними за весь час роботи).

Що входить в роботу

  • Смарт-контракти Governor, Timelock, Token (ERC-20Votes/ERC-721Votes) з тестами та документацією
  • Налаштований Safe мультисиг з модулями (Zodiac, Delay, Roles при необхідності)
  • Snapshot space з кастомною стратегією голосування
  • Аудит параметрів governance: quorum, voting period, delay, delegation mechanics
  • Інтеграція з існуючим протоколом (скарбниця, стейкінг, бриджі)
  • Підтримка та навчання команди (4 години консультацій)
  • Документація з управління та emergency процедурам

Терміни

Базова DAO-система (Governor + Timelock + Safe + Snapshot) — від 3 до 6 тижнів. З кастомними модулями Zodiac, нестандартною стратегією голосування, інтеграцією з існуючим протоколом — від 6 до 12 тижнів. Аудит займає окремо 2-4 тижні.

Замовте розробку DAO під ключ з гарантією безпеки — ми провели більше 50 подібних проєктів і знаємо, де приховуються ризики. Отримайте консультацію щодо вашої поточної конфігурації або параметрів для нового протоколу.