Ончейн-управление: DAO, голоса, таймлоки и захват протокола
Весь трек мы говорили, что контракт неизменяем и в этом его ценность. Пора признаться: в проде это почти никогда не так. Подавляющее большинство работающих протоколов имеет право на обновление кода, изменение параметров риска, паузу, смену оракула и распоряжение казной. Иногда это два адреса в конструкторе, иногда — стек из мультисига, таймлока и голосования держателей токена. Но право есть почти всегда, и именно оно, а не байткод, определяет реальную модель доверия.
Это тот случай, когда человек с бэкенд-опытом обычно недооценивает риск. В обычной системе «у кого есть доступ к проду» — вопрос эксплуатации: неприятно, но восстановимо. Здесь право обновления контракта — это право переписать логику, охраняющую чужие деньги, за одну транзакцию и без возможности откатить последствия. В статье о масштабировании мы уже видели крайнюю форму: идеальный ZK-роллап с безупречной математикой защищён ровно тремя подписями, если обновлять его контракты может мультисиг три из пяти.
Дальше — инженерный разбор: из каких деталей собирают управление, как его читают в чужом протоколе, какими способами его ломают и что из этого следует, когда управление проектируете вы. Экономику протоколов, которыми управляют, мы разобрали в предыдущей статье — там параметры вроде порога ликвидации выглядели константами; здесь выяснится, что у каждой из них есть владелец.
1. Карта власти: кто вообще может что-то сделать
Начинать анализ надо не с токена управления, а с вопроса «какие действия способны навредить» и «кто их может совершить».
пороги, потолки, комиссии"] O["Сменить адрес оракула"] T["Распорядиться казной"] P2["Поставить протокол на паузу"] M["Выпустить токены"] end A["Держатели токена"] -->|голосуют| G["Governor:
предложение и подсчёт"] G -->|ставит в очередь| TL["Timelock:
задержка исполнения"] TL -->|исполняет| U TL --> P TL --> O TL --> T TL --> M MS["Мультисиг команды
m из n"] -->|быстрый путь| P2 MS -.->|антипаттерн:
прямой доступ| U GD["Гардиан"] -->|отменяет операцию| TL D["Деплойер / EOA"] -.->|забытая роль| P style D stroke-dasharray: 5 5 style MS stroke-dasharray: 3 3
Сплошные стрелки — это заявленная модель. Пунктирные — то, что находят при проверке: забытая роль у EOA деплойера, «временный» прямой доступ мультисига к прокси, гардиан без ограничений. Практический критерий зрелости: любой путь к опасной возможности должен проходить через задержку, за время которой пользователь успевает выйти.
Полезно также разделять два разных вида власти. Право менять правила (обновление кода, параметры) опасно долгосрочно и лечится задержкой. Право экстренно остановить (пауза) опасно краткосрочно, но обязано быть быстрым — таймлок на паузу означает, что вы будете смотреть на утечку средств двое суток. Отсюда стандартная асимметрия: пауза — быстрая и у узкого круга, возобновление и всё остальное — через полный процесс.
2. Как прочитать чужое управление за пятнадцать минут
Это не теория, а обязательная процедура перед интеграцией. Всё читается публично.
# 1. Прокси: адрес реализации и адрес админа лежат в фиксированных слотах EIP-1967
cast storage 0xПРОТОКОЛ 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc --rpc-url "$ETH_RPC_URL"
cast storage 0xПРОТОКОЛ 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 --rpc-url "$ETH_RPC_URL"
# 2. Кто владелец и какие роли розданы
cast call 0xПРОТОКОЛ "owner()(address)" --rpc-url "$ETH_RPC_URL"
cast call 0xПРОТОКОЛ "hasRole(bytes32,address)(bool)" 0xDEFAULT_ADMIN_ROLE 0xКАНДИДАТ --rpc-url "$ETH_RPC_URL"
# 3. Если владелец — таймлок, узнаём реальную задержку и кто может предлагать
cast call 0xТАЙМЛОК "getMinDelay()(uint256)" --rpc-url "$ETH_RPC_URL"
# 4. Если предлагающий — Safe, смотрим порог и подписантов
cast call 0xSAFE "getThreshold()(uint256)" --rpc-url "$ETH_RPC_URL"
cast call 0xSAFE "getOwners()(address[])" --rpc-url "$ETH_RPC_URL"
# 5. Модули Safe обходят порог подписей — их наличие обязательно к проверке
cast call 0xSAFE "getModulesPaginated(address,uint256)(address[],address)" 0x0000000000000000000000000000000000000001 20 --rpc-url "$ETH_RPC_URL"
Дальше цепочка разматывается рекурсивно: владелец → таймлок → его PROPOSER_ROLE → мультисиг → подписанты. Останавливаться нужно на людях. Если в конце цепочки два адреса, у которых, судя по истории транзакций, одинаковый источник финансирования — «мультисиг два из трёх» стоит читать как «один человек».
Три вопроса, ответы на которые нужно получить обязательно: какова минимальная задержка на опасное действие, сколько независимых людей нужно скомпрометировать, есть ли путь в обход задержки (модуль Safe, роль гардиана, отдельный «экстренный» контракт).
3. Мультисиг: минимальная работающая форма
До всякого DAO почти всё управляется мультисигом, и чаще всего — Safe. Модель простая: контракт-кошелёк хранит список владельцев и порог m из n; чтобы исполнить транзакцию, нужно собрать m подписей по EIP-712 над структурой SafeTx (адрес, значение, calldata, операция, газовые параметры, nonce).
самый опасный флаг в этой структуре
Что здесь регулярно ломается на практике:
- Слепая подпись. Подписант видит в интерфейсе «перевод 10 ETH», а подписывает хеш структуры, содержимое которой не проверил. Именно так был устроен взлом Bybit в феврале 2025 года (≈1.5 млрд USD): подменённый интерфейс показывал одно, а подписывалась операция, менявшая логику кошелька через
delegatecall. Защита — независимая сверка хеша и calldata на аппаратном устройстве и вторым инструментом; см. кошельки и ключи. - Ненезависимые подписанты. Пять ключей в одном офисе, в одном облаке или у одной команды — это один ключ с лишними шагами. Ronin в марте 2022 года потерял 624 млн USD, когда атакующий получил пять из девяти ключей валидаторов, четыре из которых контролировались одной организацией.
- Модули. Модуль Safe исполняет транзакции в обход порога подписей. Это легитимный механизм (например, для рекуррентных платежей), но любой модуль — самостоятельный путь к деньгам, который нужно аудировать как основной.
- Отсутствие ротации. Ушедший сотрудник в списке владельцев — типовая находка. Список подписантов должен пересматриваться так же регулярно, как доступы в прод.
Мультисиг — честная и рабочая конструкция, если о нём говорят прямо: «этим протоколом управляют вот эти люди». Проблема начинается там, где мультисиг называют DAO.
4. Таймлок: задержка как право выхода
Таймлок не защищает от плохого решения — он даёт время его заметить. Операция сначала ставится в очередь, публикуется целиком (адрес, calldata, значение), и только по истечении задержки может быть исполнена.
TimelockController из OpenZeppelin — фактический стандарт. Устройство:
- роли
PROPOSER_ROLE(ставит в очередь),EXECUTOR_ROLE(исполняет; часто выдаётся всем),CANCELLER_ROLE(отменяет); minDelay— минимальная задержка; операция идентифицируется хешем от параметров вместе сpredecessor(зависимость от другой операции) иsalt(различение одинаковых вызовов);- батчи:
scheduleBatch/executeBatch— набор вызовов исполняется атомарно, иначе обновление из трёх шагов может застрять на середине.
// Постановка обновления в очередь: содержимое становится публичным немедленно.
bytes memory payload = abi.encodeCall(IProxyAdmin.upgradeAndCall, (proxy, newImpl, ""));
bytes32 salt = keccak256("upgrade-v3-risk-params");
timelock.schedule(
address(proxyAdmin), // цель
0, // value
payload, // calldata — читаемо в эксплорере с этой секунды
bytes32(0), // predecessor: зависимости нет
salt,
timelock.getMinDelay() // задержка не меньше минимальной
);
// ...спустя minDelay секунд, если операцию не отменили
timelock.execute(address(proxyAdmin), 0, payload, bytes32(0), salt);
Антипаттерны, которые превращают таймлок в декорацию:
- Задержка меньше времени реакции. Час ночью в выходные — это ноль. Осмысленный минимум для действий с деньгами — двое суток; для L2 и мостов индустриальная норма выше.
- Роль PROPOSER у EOA. Тогда весь процесс защищён одним приватным ключом.
- Право менять
minDelayбез задержки. Классическая рекурсивная дыра: сначала снижаем задержку, потом делаем что угодно.minDelayобязан меняться через сам таймлок. - Никто не смотрит очередь. Задержка полезна, только если существует мониторинг, который присылает уведомление о каждой поставленной операции с расшифрованным calldata (см. наблюдаемость dApp).
- Гардиан без границ. Право отмены обычно нормально; право исполнить в обход задержки — нет.
5. Токен голосования: почему вес берут из прошлого
Наивная реализация «вес голоса равен текущему балансу» ломается за одну транзакцию: занять токены флеш-займом, проголосовать, вернуть. Поэтому голосование обязано опираться на снимок в прошлом.
ERC20Votes из OpenZeppelin решает это чекпоинтами: при каждом изменении баланса или делегирования в массив записывается пара «момент времени → вес». Запрос getPastVotes(account, timepoint) бинарным поиском находит вес на нужный момент — O(log n) по числу чекпоинтов аккаунта.
Две важные детали. Первая: вес имеет только делегированный голос. Пока держатель не вызвал delegate (хотя бы на себя), его токены не голосуют вообще — это защищает от учёта монет на биржах, но обеспечивает вечно низкую явку. Вторая: единица времени задаётся ERC-6372 (clock() и CLOCK_MODE) — номер блока или timestamp. На L2 с плавающим временем блока это не формальность: голосование, отмеренное в блоках, там растягивается или сжимается непредсказуемо.
// Токен: балансы + чекпоинты весов + делегирование
contract ProtocolToken is ERC20, ERC20Permit, ERC20Votes {
constructor() ERC20("Protocol", "PRT") ERC20Permit("Protocol") {}
// ERC-6372: считаем время в секундах, а не в блоках — переносимо между сетями
function clock() public view override returns (uint48) { return uint48(block.timestamp); }
function CLOCK_MODE() public pure override returns (string memory) { return "mode=timestamp"; }
}
// Governor: параметры процесса и связь с таймлоком
contract ProtocolGovernor is
Governor, GovernorSettings, GovernorCountingSimple,
GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl
{
constructor(IVotes token_, TimelockController timelock_)
Governor("ProtocolGovernor")
GovernorSettings(
1 days, // votingDelay: пауза до старта — за неё фиксируется снимок
5 days, // votingPeriod: сколько идёт голосование
100_000e18 // proposalThreshold: минимальный вес, чтобы вообще предложить
)
GovernorVotes(token_)
GovernorVotesQuorumFraction(4) // кворум 4 % от всего предложения токена
GovernorTimelockControl(timelock_)
{}
}
Здесь каждый параметр — компромисс, который стоит проговорить вслух:
| Параметр | Слишком мало | Слишком много |
|---|---|---|
votingDelay |
нет времени изучить предложение и делегировать голос | процесс тормозит на неделю |
votingPeriod |
решают часовые пояса, а не участники | реакция на проблему запаздывает |
proposalThreshold |
спам предложениями, размывание внимания | предлагать может только крупный держатель |
| кворум | решение принимает горстка адресов | ничего не проходит, протокол парализован |
minDelay таймлока |
нет времени выйти | нельзя быстро починить параметры |
Ключевая линия на этой диаграмме — TimelockController как единственный владелец всего опасного. Как только у казны или прокси появляется второй владелец, вся схема сводится к нему.
6. Жизненный цикл предложения
снимок весов зафиксирован Active --> Defeated: против больше, чем за,
или не набран кворум Active --> Succeeded: за больше и кворум набран Succeeded --> Queued: queue() — операция в таймлоке,
calldata публична Queued --> Executed: прошёл minDelay,
вызов execute() Queued --> Canceled: отмена гардианом
или самим DAO Queued --> Expired: не исполнили в окне —
процесс придётся начинать заново Active --> Canceled: предлагающий потерял
требуемый вес Executed --> [*] Defeated --> [*] Expired --> [*] Canceled --> [*]
Три состояния, о которых обычно забывают при интеграции. Expired — предложение может «протухнуть», и это не ошибка, а защита от исполнения старых, потерявших актуальность решений. Canceled — операция исчезает из очереди, и мониторинг обязан это различать. Succeeded без Queued — типичная ситуация, когда решение принято, но никто не заплатил газ за постановку в очередь: в DAO нет диспетчера, который сделает это за вас.
Голосование вне цепи. Полностью ончейн-процесс дорог: каждый голос — транзакция. Отсюда популярность Snapshot (docs.snapshot.box): подпись EIP-712 вместо транзакции, вес читается из снимка состояния на заданном блоке, газ нулевой. Честная оценка: Snapshot сам по себе ничего не исполняет. Результат приводит в действие мультисиг — значит, реальная модель безопасности определяется этим мультисигом, а не голосованием. Промежуточный вариант — оптимистичное исполнение (oSnap и подобные схемы на UMA): предложенный результат исполняется автоматически, если за окно оспаривания никто не поставил залог против; та же логика доказательств мошенничества, что у оптимистичных роллапов из статьи о масштабировании.
7. Атаки на управление
7.1. Захват флеш-займом
Канонический случай — Beanstalk, апрель 2022 года, около 182 млн USD. Схема была уязвима сочетанием двух свойств: вес голоса считался в момент голосования, а «экстренное» исполнение не требовало ожидания.
Что именно ломает эту атаку — и должно быть в любой схеме:
- Снимок весов в прошлом (
getPastVotesна блоке до подачи предложения): токены, купленные сейчас, не голосуют. - Таймлок без исключений: «экстренный» путь исполнения без задержки — это отсутствие таймлока.
- Порог предложения и период голосования, измеряемые днями, а не блоками.
7.2. Вредоносное предложение, которое выглядит нормальным
Голосующие читают заголовок, изредка — описание, и почти никогда — calldata. Отсюда класс атак «безобидное предложение». В мае 2023 года управление Tornado Cash было захвачено предложением, чей код на момент голосования выглядел безвредным: атакующий использовал selfdestruct и повторный деплой по тому же адресу через CREATE2, подменив логику после одобрения. Урок универсален: проверять нужно не исходник, приложенный к описанию, а фактический байткод по адресу, который будет вызван, и все его зависимости — включая возможность их подмены.
Практические защиты: запрет delegatecall в исполняемых операциях; проверка, что все вызываемые адреса имеют неизменяемый код; публикация расшифрованного calldata и дифа реализации перед голосованием; независимая симуляция предложения на форке мейннета до исполнения (Tenderly, forge script --fork-url).
7.3. Покупка голосов и рынки взяток
Если голос — это передаваемый токен, у него есть цена. Существуют легальные и открытые рынки: держатель делегирует голос и получает вознаграждение (Curve и Convex вокруг распределения эмиссии — самая известная экосистема такого рода). Технически это не атака, экономически — механизм, при котором решение принимает не тот, кто несёт последствия. Заимствование голосов вообще может стоить дешевле, чем владение: аренда токенов на срок голосования иногда дешевле их покупки, что делает атаку рациональной.
Смягчения: vote-escrow (вес растёт с длиной блокировки — Curve с veCRV; блокировка привязывает интерес голосующего к будущему), кворум и супербольшинство для критичных действий, отдельный «совет безопасности» с правом вето на явно враждебные решения, ограничение классов решений, доступных голосованию (см. раздел 10).
7.4. Прочее, что стоит держать в модели угроз
| Вектор | Суть | Защита |
|---|---|---|
| Социальная инженерия подписантов | фишинг, подменённый интерфейс, слепая подпись | сверка calldata на устройстве, независимая проверка, разнесённые подписанты |
| Забытая роль | у EOA деплойера остался DEFAULT_ADMIN_ROLE |
инвентаризация ролей и её проверка в CI |
| Кросс-чейн исполнение | решение с L1 исполняется на L2 через мост | доверие к мосту наследуется целиком (https://courses.digitable.life/post/web3/10-scaling/) |
| Апатия и низкий кворум | решение принимает 1–2 % предложения токена | кворум от делегированного веса, программы делегирования |
| Слитый ключ гардиана | «экстренная» пауза как оружие | ограничить гардиана только паузой, ротация ключей |
| Управление зависимостью | вы зависите от параметров чужого протокола | мониторинг их очереди таймлока, лимиты со своей стороны |
8. Патологии: почему «управление сообществом» редко работает
Инженеру полезно смотреть на управление как на систему с обратными связями, а не как на политику.
- Апатия. Голосование стоит времени и газа, а вес одного держателя ничего не решает — классическая рациональная неучастие. Явка в 3–7 % от предложения токена в крупных DAO — нормальное состояние.
- Плутократия. «Один токен — один голос» означает, что решение принимает капитал. Это не всегда плохо (у капитала есть шкура на кону), но это точно не «децентрализация».
- Делегаты. Профессиональные делегаты решают проблему явки и создают новую: концентрацию влияния у нескольких публичных лиц, чьи стимулы не совпадают со стимулами держателей.
- Гудхарт. Как только «участие в голосованиях» становится метрикой, появляются участники, оптимизирующие метрику: голоса без чтения, предложения ради активности (см. метрики и закон Гудхарта).
- Театр управления. Формально голосование есть, фактически исполнение — за мультисигом фонда. Спор вокруг AIP-1 в Arbitrum в марте 2023 года показателен: сообщество обнаружило, что средства были распределены до завершения голосования.
Правый нижний угол — не поражение, а осознанный выбор: чем больше распределена власть, тем медленнее реакция. Верхний правый угол пытаются занять гибридом «медленное голосование для правил плюс быстрый совет безопасности для аварий», и это сегодня практический потолок отрасли.
9. Сивилы и идентичность: почему нет «один человек — один голос»
Естественное желание — уйти от плутократии к «одному голосу на человека». В цепи это невозможно напрямую: адрес создаётся бесплатно и в любом количестве. Любая схема с равным весом требует внешнего источника уникальности личности — устойчивости к сивил-атаке.
| Подход | Как работает | Чем платит |
|---|---|---|
| Токен-вес | вес равен капиталу | плутократия, но сивилы бессмысленны |
| Аттестации (EAS) | доверенные стороны подписывают утверждения об адресе | доверие к аттестующим, приватность |
| Веб доверия (BrightID и подобные) | граф социальных связей | атаки на граф, сложность входа |
| Биометрия (Worldcoin) | доказательство уникальности человека | приватность, оператор устройств, доступность |
| Репутация и SBT | непередаваемые токены достижений | «непередаваемое» ломается через контрактные кошельки |
| Квадратичное голосование | n голосов стоят n² — меньшинству легче быть услышанным |
без сивил-устойчивости ломается тривиально |
Квадратичное голосование заслуживает точной формулировки, потому что его часто рекламируют как решение: оно усиливает проблему сивил, а не решает её. Разделив капитал на сто адресов, участник получает не корень из суммы, а сто корней — то есть в десять раз больше влияния. Работоспособность квадратичных схем целиком зависит от качества фильтра личностей (так работает квадратичное финансирование Gitcoin с его Passport и постоянной борьбой с фермами адресов).
Второй сюжет — приватность голоса. Публичность голосования делает возможным подкуп: платящий видит, как вы проголосовали. Криптографический ответ известен — тайное голосование с доказательствами (MACI и схемы на ZK): голоса шифруются, корректность подсчёта доказывается, а доказать третьей стороне, как именно вы голосовали, невозможно. Обзорный текст Виталика Бутерина по этой теме — vitalik.eth.limo/general/2021/08/16/voting3.html; там же честный разбор пределов монетного голосования.
И отдельно: ENS — это имя, а не идентичность. Читаемое name.eth не подтверждает ничего, кроме факта регистрации; оно решает задачу UX (вместо сорока hex-символов) и упрощает фишинг похожими именами. Не стоит строить на нём модели доверия.
10. Казна, операции и внешний мир
- Где лежит казна. Ответ «в контракте, которым владеет таймлок» — хороший. Ответ «на мультисиге фонда» — честный, но это не DAO. Ответ «часть на бирже» — открытая уязвимость.
- Состав. Казна, состоящая из собственного токена, стоит ноль в тот момент, когда нужна: продажа обваливает цену того же токена. Диверсификация в стейблкоины — не роскошь, а требование к непрерывности разработки.
- Выплаты. Разовые крупные переводы заменяют потоковыми выплатами и грантовыми комитетами с лимитом; для каждого лимита должен быть отдельный, более быстрый и менее опасный путь одобрения.
- Отчётность. Все движения публичны, но не осмысленны без разметки: индексируйте казначейские адреса и события так же, как продуктовые (см. архитектуру dApp).
- Юридическая обёртка. DAO без юридической формы в ряде юрисдикций трактуется как обычное товарищество с солидарной ответственностью участников — это не абстракция: дело CFTC против Ooki DAO (2022–2023) закончилось решением, в котором ответственность возлагалась на голосующих держателей токена. Обычная практика — фонд или LLC, представляющие DAO вовне. Это вопрос к юристам, но инженер обязан знать, что он существует.
Минимизация управления. Лучший ответ на вопрос «как защитить право обновления» — не иметь его там, где можно обойтись. Идея сформулирована в тексте Фреда Эрсама и Дэна Робинсона Governance Minimization и на практике выглядит так: ядро протокола иммутабельно, изменяемы только периферийные параметры, у каждого параметра есть жёсткие границы прямо в коде (порог ликвидации не может быть установлен ниже 50 % никаким голосованием), а новые версии выкатываются как отдельные развёртывания, в которые пользователь мигрирует сам. Это сильно менее удобно и радикально сокращает поверхность атаки.
11. Чек-лист проверки управления перед интеграцией
- Кто владелец каждого контракта, с которым вы взаимодействуете (проверено чтением слотов и
owner(), а не документацией). - Есть ли таймлок, какова минимальная задержка, кто может ставить в очередь и кто исполнять.
- Существует ли путь в обход таймлока: модули Safe, «экстренные» контракты, гардиан с расширенными правами.
- Сколько независимых людей нужно скомпрометировать, чтобы получить контроль; насколько независимы подписанты на самом деле.
- Берётся ли вес голоса из прошлого блока (
getPastVotes) и какова длина голосования. - Каков кворум в абсолютных числах и сколько адресов реально его составляют — распределение токена по топ-10 держателей важнее процентов в документации.
- Может ли голосование менять параметры без ограничений, или в коде есть жёсткие границы.
- Есть ли кросс-чейн исполнение и через какой мост.
- Мониторится ли очередь таймлока — и настроен ли у вас алерт на постановку операции в очередь у чужого протокола, от которого вы зависите.
- Что произойдёт с вашими средствами и вашим приложением, если управление будет захвачено сегодня: какие лимиты, паузы и пути выхода есть с вашей стороны.
12. Частые заблуждения
- «Есть токен управления — значит, децентрализовано». Токен управления совместим с полной централизацией исполнения. Смотрите на владельцев контрактов, а не на голосования.
- «Мультисиг безопаснее одного ключа». Только если подписанты независимы, а транзакции проверяются. Пять слепых подписей хуже одного внимательного ключа.
- «Таймлок задерживает злоумышленника». Таймлок ничего не задерживает без наблюдателя. Он покупает вам время, только если кто-то смотрит.
- «Голосование в цепи защищено криптографией». Криптографией защищён подсчёт. Что именно исполняется — вопрос внимательности читающих calldata.
- «Снапшот-голосование — это ончейн-управление». Это опрос, исполняемый людьми.
- «Иммутабельность — всегда лучше». Иммутабельный протокол не чинится. Это осознанный размен, а не универсальная добродетель.
- «Плохое управление — не техническая проблема». Это самая техническая из проблем: она выражается в адресах, ролях и задержках, и все они читаются публично.
Мини-итог
- Реальную модель доверия протокола определяет не байткод, а список тех, кто может его изменить, и время, за которое они это сделают.
- Карта власти строится от опасных возможностей (обновление, параметры, оракул, казна, эмиссия, пауза), а не от токена управления.
- Мультисиг — рабочая честная форма; его слабые места операционные: слепая подпись, зависимые подписанты, модули в обход порога, отсутствие ротации.
- Таймлок не запрещает вредное решение, а даёт пользователю время выйти. Без мониторинга очереди он бесполезен, а без запрета на обходные пути — фиктивен.
- Вес голоса обязан браться из прошлого: снимок весов плюс задержка — это то, что делает захват флеш-займом невозможным.
- Атака на управление обычно не ломает криптографию: она эксплуатирует невнимательность к calldata, низкий кворум, покупку голосов или человека с ключом.
- Равный вес на человека требует внешней устойчивости к сивилам; квадратичные схемы без такого фильтра ухудшают ситуацию, а не улучшают.
- Лучшее управление — то, которого мало: иммутабельное ядро, жёсткие границы параметров в коде, миграция вместо обновления.
Источники
- OpenZeppelin Governance — Governor, ERC20Votes, TimelockController: docs.openzeppelin.com/contracts/5.x/governance
- Compound Governance — Governor Bravo и Timelock: docs.compound.finance/governance
- Safe — контракты, модули, сервис транзакций: docs.safe.global
- ERC-6372 (clock для голосований) и ERC-5805 (делегирование весов): eips.ethereum.org
- Виталик Бутерин, Moving beyond coin voting governance: vitalik.eth.limo/general/2021/08/16/voting3.html
- Фред Эрсам, Дэн Робинсон, Governance Minimization: paradigm.xyz/2020/10/870
- Decentralized Society: Finding Web3’s Soul (SBT), Weyl, Ohlhaver, Buterin: papers.ssrn.com/sol3/papers.cfm?abstract_id=4105763
- Ethereum Attestation Service — схемы аттестаций: docs.attest.org
- MACI — тайное голосование с защитой от сговора: maci.pse.dev
- Snapshot — офчейн-голосование по подписи: docs.snapshot.box
- Tally и Boardroom — витрины предложений и делегатов: tally.xyz, boardroom.io
- L2BEAT — модели управления L2 и права обновления: l2beat.com
- Rekt News — разборы Beanstalk, Ronin, Bybit и других инцидентов: rekt.news
Что дальше
Трек закончен. Мы прошли путь от хеш-цепочки и подписи до работающего приложения и того, кто им управляет: как устроен блок, криптография, консенсус, EVM, контракты и их безопасность, ключи, токены, хранилища, масштабирование, архитектура dApp, финансовые примитивы и управление ими.
Главный вывод трека простой: почти всё в Web3 — это обычная распределённая система, к которой добавили один необычный компонент — реплицированную машину состояний с открытым доступом на запись. Поэтому дальше полезнее всего идти не «глубже в блокчейн», а вширь — туда, откуда взяты все остальные детали:
- Распределённые системы — согласованность, консенсус, отказы и время. Половина сложности этого трека родом отсюда.
- Базы данных — индексы, планы запросов, транзакции: без этого свой индексатор не построить.
- Архитектурные паттерны — CQRS, event sourcing, устойчивость: индексатор и проекции ровно об этом.
- Фронтенд — состояние, загрузка данных, обработка ошибок; интерфейс dApp остаётся обычным фронтендом с необычной моделью задержек.
- Дата-инженерия — пайплайны, идемпотентность, качество данных: индексация цепи по сути ETL.
- Теория игр и системное мышление — стимулы, равновесия и обратные связи: язык, на котором вообще имеет смысл обсуждать консенсус, ликвидации и управление.
- Моделирование угроз, DevOps и тестирование — эксплуатация узлов, секреты, мониторинг и способы проверять систему, в которой нельзя нажать «отменить».
Общая карта портала и порядок изучения — в дорожной карте.