Разработка системы ликвидаций CDP
MakerDAO в марте 2020 года (Black Thursday) потерял $5.4M из-за сбоя в системе ликвидаций: сетевые задержки не позволили ликвидаторам вовремя участвовать в аукционах, часть аукционов прошла по нулевой цене — 0 DAI за залог ETH. Это была прямая ошибка в дизайне auction system, где ставку в 0 DAI технически принималась как валидная. Сегодня MakerDAO использует Liquidations 2.0 с Clip аукционом. Правильная CDP-ликвидация — это не «продать залог», а сложная многоуровневая система с auction house, dog и clipper.
Механика CDP ликвидаций в деталях
Collateralization Ratio и момент триггера
CDP (Collateralised Debt Position) — позиция с залогом и долгом в синтетическом активе. Позиция ликвидируема, когда:
CR = (collateral_value / debt_value) < liquidation_ratio
Liquidation ratio зависит от актива: для ETH обычно 150%, для более волатильных — 175-200%, для stablecoins — 105-110%. Правильный выбор liquidation ratio — это балансирование между защитой протокола (слишком высокий LR — пользователи держат меньше долга, плохая capital efficiency) и риском bad debt (слишком низкий — позиции не успевают ликвидироваться при быстром падении).
Триггер ликвидации происходит при вызове liquidate() кем угодно (permissionless). Вызывающий получает keeper incentive (kick reward) — небольшое вознаграждение за инициацию аукциона.
Dutch auction (Clip): почему лучше английского
MakerDAO Liquidations 1.0 использовал английский аукцион (ставки растут). Проблема — нужно ждать конца аукциона (до 6 часов), gas wars между ботами, и уязвимость к ситуации «нет участников».
Liquidations 2.0 (Clip) — голландский аукцион по цене: стартует выше рыночной, цена экспоненциально падает со временем. Любой может купить залог в любой момент, когда цена стала привлекательной. Параметры аукциона:
-
buf— начальный мультипликатор цены (например, 1.2 = стартует на 20% выше текущей оракульной цены) -
tail— максимальная продолжительность аукциона (например, 3600 секунд) -
cusp— максимальное падение цены как доля от начальной (например, 0.4 = до 40% от стартовой цены) -
chip— процент от залога как kick reward -
tip— фиксированный flat incentive в DAI/stablecoin
Если аукцион достигает tail или цена падает до cusp без завершения — это reset: цена сбрасывается обратно к рыночной * buf. Это защита от ситуации MakerDAO March 2020.
Flash loan ликвидации через take()
Clip.take() поддерживает callback: ликвидатор может получить залог, сделать что-то (например, продать через DEX), и вернуть долг — всё в одной транзакции. Это стандартный flash loan паттерн для ликвидаций.
interface ClipperCallee {
function clipperCall(
address sender,
uint256 owe, // долг для погашения
uint256 slice, // полученный залог
bytes calldata data
) external;
}
Интеграция с Uniswap V3 или 1inch для продажи залога внутри clipperCall — стандартная практика для ликвидационных ботов.
Архитектура системы
Компоненты
Dog.sol — реестр активных CDP, триггер ликвидаций
Clip.sol — dutch auction engine (один на тип залога)
Abacus.sol — price calculator (exponential/linear decrease)
Spotter.sol — оракульный адаптер, подаёт цену в Dog
Vat.sol — core accounting, хранит все CDP и долги
Мы реализуем аналогичную модульную архитектуру, но адаптированную под конкретный протокол. Ключевое: Vat (или его аналог) — единственное место, где хранятся балансы. Все остальные контракты только записывают в Vat через авторизованные вызовы.
Оракульная безопасность
Dog получает цену через Spotter из двух источников: OSM (Oracle Security Module) — с задержкой 1 час, и текущая цена для emergency liquidations. Задержка OSM даёт время пользователям добавить залог при резком падении. Это trade-off: защита пользователей vs. риск для протокола при быстрых движениях.
Для кастомных протоколов решаем этот trade-off исходя из типа залога. Для stablecoins — задержка не нужна. Для волатильных активов — 30-60 минут. Для NFT/RWA — специальная логика.
Liquidator incentive калибровка
Ключевой вопрос: сколько платить ликвидаторам? Слишком мало — нет ликвидаторов при стрессе. Слишком много — протокол переплачивает, пользователи теряют больше залога, чем нужно.
Оптимальный incentive = gas cost ликвидации + premium за риск + profit margin. При газе 300k units и 50 gwei = 0.015 ETH. Kick reward должен покрывать это при минимальном размере позиции.
Для flat tip + chip комбинации: tip покрывает gas, chip (% от залога) дает profit margin. Типичные значения: tip = 300 DAI, chip = 0.02% (2 bps).
Тестирование: что нельзя пропустить
Симуляция March 2020 через Foundry fork:
forge test --fork-url $ETH_MAINNET_RPC --fork-block-number 9763200 --match-test testBlackThursdayScenario
Тест: ETH падает на 40% за 100 блоков, проверяем что:
- Все CDP с CR < LR уходят на аукцион
- Аукционы завершаются (не достигают tail) при наличии ликвидаторов
- Bad debt = 0 при нормальных условиях
- Reset mechanism срабатывает при отсутствии ликвидаторов
Echidna property: totalSystemDebt <= totalSystemCollateralValue * (1 / minimumCR) при любой последовательности операций.
Процесс разработки
Аналитика (2-3 дня). Параметры аукциона для каждого типа залога. Моделирование incentive structure.
Разработка (1-2 недели). Dog + Clip + Abacus + оракульная интеграция. Liquidator bot (off-chain) для первых недель работы.
Тестирование (3-5 дней). Fork-тесты stress scenarios. Unit тесты граничных случаев аукциона.
Деплой. Сначала testnet с реальными ценовыми движениями (через форк). Затем mainnet с ограниченными debt ceiling для каждого типа залога.
Ориентиры по срокам
Система ликвидаций CDP с dutch auction для 1-3 типов залога — 1-2 недели. Расширенная система с NFT залогом и кастомным auction механизмом — 3-4 недели.







