Розробка протоколу кредитування
Типова ситуація: команда хоче запустити lending-протокол, форкує Compound v2, змінює параметри collateral factor, деплоїть — і через три тижні виявляє, що оракул працює через TWAP з 30-хвилинним вікном, а ліквідації не встигають при різких рухах ціни. Позиції йдуть в мінус, протокол несе збитки. Це не баг форка — це архітектурне рішення, яке в оригіналі компенсувалось іншими параметрами ризику.
Розробка lending-протоколу з нуля або адаптація існуючого — це насамперед робота з математикою ризиків та механікою ліквідацій, а не просто написання Solidity.
Де ломаються lending-протоколи
Маніпуляція оракулом через flash loan
Найруйнівніший вектор атаки в DeFi-лендингу — маніпуляція ціновим оракулом. Якщо протокол читає ціну безпосередньо з spot-ціни пулу Uniswap v2, атакуючий бере flash loan, рухає ціну в пулі, отримує недообезпечений кредит, повертає flash loan. Протокол втрачає collateral.
Атака на Mango Markets у 2022 році — 117 мільйонів доларів — працювала саме так. Атакуючий використовував власний токен як залог, штучно піднявши його ціну через спот-покупки, взяв кредити проти раздутого collateral.
Захист будується на кількох рівнях:
-
Chainlink price feeds з перевіркою
updatedAt— якщо дані старші за N секунд, транзакція реверсується - TWAP від Uniswap v3 як вторинний джерело з вікном мінімум 30 хвилин для неліквідних активів
- Deviation check — якщо Chainlink і TWAP розходяться більше ніж на X%, приймаємо менше значення
- Circuit breaker — тимчасова пауза нових запозичень при аномальному русі ціни
function getPrice(address asset) internal view returns (uint256) {
(, int256 answer, , uint256 updatedAt, ) = chainlinkFeed.latestRoundData();
require(block.timestamp - updatedAt <= STALENESS_THRESHOLD, "Stale price");
require(answer > 0, "Invalid price");
uint256 twapPrice = getTWAP(asset, TWAP_PERIOD);
uint256 chainlinkPrice = uint256(answer);
// Приймаємо мінімальне з двох — консервативна позиція
return twapPrice < chainlinkPrice ? twapPrice : chainlinkPrice;
}
Механіка ліквідацій і bad debt
Другий критичний момент — поріг ліквідації та health factor. Aave використовує healthFactor = (collateralETH * liquidationThreshold) / totalDebtETH. Як тільки health factor опускається нижче 1.0, позиція відкрита для ліквідаторів.
Проблема виникає при gap risk: актив падає на 30% за одну свічу (ліквідна криза, крах біржі), ліквідатори не встигають закрити позиції, протокол накопичує bad debt. Compound стикнувся з цим під час краху LUNA — деякі позиції пішли в мінус.
Архітектурні рішення:
| Механізм | Суть | Застосування |
|---|---|---|
| Liquidation bonus | Ліквідатор отримує collateral зі скидкою 5-10% | Incentive для швидкої ліквідації |
| Partial liquidation | Закривається тільки частина позиції | Зменшення gas cost для ліквідаторів |
| Dutch auction liquidation | Ціна бонусу росте з часом | Автоматична привабливість при волатильності |
| Insurance fund | Резерв з частини процентних доходів | Покриття bad debt при gap risk |
Ми імплементуємо dutch auction за образцем MakerDAO: якщо позиція не ліквідирована протягом N блоків, liquidation bonus починає рости. Це гарантує, що навіть при низькому інтересі ліквідаторів позиція в итогу закриється.
Interest rate model: kink і utilization
Процентна ставка в Compound v2 та Aave v3 рахується через utilization rate: U = totalBorrow / totalSupply. При низькій утилізації ставка низька, при високій — різко росте (kink model).
Параметр kink критичний. Якщо utilization досягає 100%, вкладники не можуть вивести кошти — ліквідності немає. Класична kink-модель ставить inflection point на 80-90% та різко піднімає ставку вище, щоб стимулювати нові депозити або погашення боргів.
function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves)
external view returns (uint256)
{
uint256 util = utilizationRate(cash, borrows, reserves);
if (util <= kink) {
return util * multiplierPerBlock / BASE + baseRatePerBlock;
} else {
uint256 normalRate = kink * multiplierPerBlock / BASE + baseRatePerBlock;
uint256 excessUtil = util - kink;
return excessUtil * jumpMultiplierPerBlock / BASE + normalRate;
}
}
Як ми будуємо lending-протоколи
Архітектура та стек
Базова архітектура розділяє логіку на кілька контрактів:
- LendingPool — точка входу, маршрутизує виклики
- ReserveLogic — розрахунок індексів, нарахування процентів
- ValidationLogic — перевірки перед операціями
- aToken / debtToken — ERC-20 токени позицій (стиль Aave v3)
- PriceOracle — агрегатор цін з fallback-логікою
- InterestRateStrategy — змінна стратегія ставок
Використовуємо Foundry для розробки та тестування. Fork-тесты проти Ethereum mainnet обов'язкові: потрібно перевіряти інтеграцію з реальними Chainlink feeds, реальними цінами активів.
Для апгрейдаємості — UUPS proxy (EIP-1822). Transparent proxy на цих обсягах логіки створює ризики storage колізій при апгрейдах. ERC-7201 namespaced storage ізолює змінні кожного логічного модулю.
Особливу увагу до reentrancy у cross-contract викликах: aToken.mint() при депозиті, transfer collateral при ліквідації — всі зовнішні виклики після оновлення state, nonReentrant на всіх точках входу.
Тестування
Property-based тесты через Echidna з інваріантами:
- Сума всіх боргів ніколи не перевищує суму всіх депозитів
- Health factor позиції після ліквідації завжди вище 1.0
- Interest index монотонно зростає
Fuzz-тесты у Foundry на функціях депозиту, запозичення, погашення — параметри: випадкові суми, випадкові послідовності операцій, випадкові значення оракула.
Процес роботи
Аналітика (3-5 днів). Визначаємо список активів, collateral factor для кожного, параметри ліквідацій, джерела оракулів. Моделюємо stress scenarios: що відбувається при -50% основного collateral активу за 1 блок.
Проектування (5-7 днів). Storage layout, інтерфейси контрактів, математичні моделі ставок. Formal verification для core invariants через Certora Prover або Halmos — для протоколів з TVL-цілью >10M USD це обов'язковий крок.
Розробка (4-8 тижнів). Core контракти + тесты. Fork-тесты на mainnet. Покриття >95%.
Внутрішній security review (1 тиждень). Slither, Mythril, ручний review за SWC checklist + DeFi-специфічні вектори: flash loan атаки, oracle маніпуляція, liquidation griefing.
Зовнішній аудит. Для lending-протоколу — обов'язково. Рекомендуємо Trail of Bits, Spearbit, або Code4rena contest залежно від бюджету.
Деплой. Спочатку testnet (Sepolia) з імітацією ринкових умов, потім mainnet через Gnosis Safe multisig. Параметри ризику встановлюються консервативно з можливістю корегування через governance.
Часові орієнтири
Мінімальна версія протоколу (один актив, базові операції) — 4-6 тижнів. Повнофункціональний multi-asset lending з governance та страховим фондом — 3-4 місяці. Часи аудиту не включені та залежать від вибраної компанії (зазвичай 2-6 тижнів у черзі).
Вартість розраховується після детального обговорення архітектури та вимог до безпеки.







