Розробка системи ліквідацій 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% вище поточної oracle) -
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 покривает газ, 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 механізм запрацовує без ліквідаторів
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 з реальними ціновими рухами (через fork). Потім mainnet з обмеженими debt ceiling для кожного типу залогу.
Ориентири по строкам
Система ліквідацій CDP з dutch auction для 1–3 типів залогу — 1–2 тижні. Розширена система з NFT залогом та кастомним auction механізмом — 3–4 тижні.







