Розробка протоколу ліквідацій
Aave V3 втрачає ліквідатора швидше, ніж ви думаєте. При високій нагрузці на сеть газ на liquidationCall зростає до 400-600k газових одиниць — при цені 80 gwei це 0.03-0.05 ETH тільки на газ. Якщо спред між боргом та закладом менше цієї суми, ліквідація нерентабельна, і позиція зависає в стані bad debt. Саме тому дизайн інцентивів ліквідаторів — не деталь, а основа платоспроможності всього кредитного протоколу.
Механіка ліквідацій: чому стандартний підхід ломається
Health factor та liquidation threshold
Кожна позиція має health factor:
HF = Σ(collateral_i * LT_i) / total_debt
Коли HF < 1 — позиція ліквідируєма. Liquidation threshold (LT) задається окремо для кожного активу: ETH — 82.5%, USDC — 85%, більш волатильні активи — 65-75%. Це означає, що кастомний кредит з екзотичними активами потребує ретельної калібровки LT на основі історичної волатильності.
Проблема «пилових позицій»: якщо позиція маленька (борг $50), газ на ліквідацію ($30-80) з'їдає всю прибуток. Ліквідатори ігнорують такі позиції — протокол накопичує bad debt. Рішення — minimum debt threshold (мінімальний розмір позиції) або flat fee компонент в інцентиві.
Liquidation bonus та проблема великих позицій
Стандартний підхід: ліквідатор отримує liquidation bonus (5-10%) від ліквідованого закладу. Це працює для середніх позицій. Для позицій з закладом >$10M виникає інша проблема: ліквідатор не може ліквідувати відразу через slippage при продажі закладу — ціна активу падає в процесі, bonus нівелюється.
Aave V3 вирішує це через partial liquidation (до 50% за раз) та close factor. Для кастомних протоколів ми реалізуємо dutch auction: bonus стартує з 5% і зростає зі часом, поки позиція не ліквідирована. Це мінімізує переплату при нормальних умовах та гарантує ліквідацію при стресі.
Flash loan ліквідації та MEV
Професійні ліквідатори не тримають капітал — вони використовують flash loans. Схема: взяти flash loan активу, погасити борг позиції, отримати закладу з бонусом, продати закладу, повернути flash loan. Все в одній транзакції, нульовий капітал.
Це означає, що ваш протокол повинен бути сумісним з flash loan паттерном. Конкретно: liquidationCall повинен приймати collateralAsset та debtAsset окремо, повертати aToken або базовий актив на вибір ліквідатора, не блокувати виклики з смарт-контрактів.
MEV-аспект: більшість ліквідацій перехоплюються MEV-ботами через frontrunning. Це не обов'язково погано для протоколу — ліквідація все рівно відбувається. Але якщо хочете захистити «честних» ліквідаторів, інтегруйте Flashbots MEV Blocker або реалізуйте приватний mempool для ліквідацій.
Архітектура liquidation engine
Двохрівнева система ліквідацій
Ми будуємо два режими ліквідації в одному контракті:
Режим 1 — standard liquidation. Ліквідатор надає актив для погашення боргу, отримує закладу з бонусом. Простий, газоефективний, працює для більшості позицій.
Режим 2 — auction liquidation. Активується при позиціях з закладом вище порога (наприклад, $500K). Голландський аукціон: початкова ціна закладу = ринкова ціна * (1 - максимальний дисконт), ціна зростає кожні N блоків. Перший ліквідатор, який готов прийняти поточну ціну, перемагає аукціон.
function getAuctionPrice(
uint256 startPrice,
uint256 startBlock,
uint256 priceIncreasePerBlock
) public view returns (uint256) {
uint256 elapsed = block.number - startBlock;
return startPrice + (elapsed * priceIncreasePerBlock);
}
Оракульна інтеграція та захист від маніпуляції
Liquidation логіка критично залежить від цін oracle. Chainlink — основне джерело. Але для захисту від stale data:
function _getPrice(address asset) internal view returns (uint256) {
(, int256 price, , uint256 updatedAt, ) = AggregatorV3Interface(feed).latestRoundData();
require(block.timestamp - updatedAt <= MAX_STALENESS, "Stale oracle");
require(price > 0, "Invalid price");
return uint256(price);
}
MAX_STALENESS — параметр для кожного активу окремо: ETH/USD оновлюється кожні 27 секунд або при відхиленні >0.5%, більш екзотичні активи — рідше. Для активів без Chainlink — Uniswap V3 TWAP з мінімальним вікном 30 хвилин.
Bad debt socialisation
Якщо протокол всі-таки накопив bad debt (позиція стала неліквідируєма при падінні закладу нижче вартості боргу), потрібен механізм його покриття. Варіанти:
- Insurance module: окремий пул токенів протоколу, staker якого несуть перший убиток
- Reserve factor: частина процентних доходів йде в резерв
- Bad debt socialisation: убиток розмазується по всіх LP пропорційно
Aave використовує Insurance Module (Safety Module) зі staked AAVE. Compound V3 використовує reserve factor. Ми реалізуємо той варіант, який відповідає tokenomics протоколу.
Стек та інструменти
| Шар | Технологія |
|---|---|
| Контракти | Solidity 0.8.24, OpenZeppelin 5.x |
| Оракули | Chainlink AggregatorV3, Uniswap V3 TWAP |
| Flash loans | Aave V3 FlashLoanSimpleReceiver |
| Тестування | Foundry fork mainnet, Echidna |
| Моніторинг | The Graph subgraph, Tenderly Alerts |
| Деплой | Foundry forge script, Gnosis Safe |
Процес роботи
Аналітика. Моделюємо stress scenarios: падіння ETH на 40% за 1 годину (як у травні 2021). Рахуємо, при яких параметрах LT/bonus протокол залишається платоспроможним.
Розробка. Ліквідаційний engine + інтеграція з Chainlink + аукціонний модуль. Паралельно — off-chain liquidation bot для перших тижнів роботи протоколу (поки зовнішні ліквідатори не прийшли).
Тестування. Fork-тест на Ethereum mainnet: моделюємо масові ліквідації з березня 2020 (Black Thursday). Перевіряємо, що bad debt не накопичується при реалістичних сценаріях.
Орієнтири по срокам
Базовий liquidation модуль для вбудовування в кредитний протокол — 1-2 тижні. Автономний протокол ліквідацій з dutch auction та bad debt socialization — 3-4 тижні. Включаючи написання off-chain liquidation bot — плюс 1 тиждень.







