Розроблення vault-контрактів
Vault — це контракт, який приймає токени від користувачів, розміщує їх у стратегіях (Aave, Compound, Curve, Convex, Yearn) і видає share-токени взамін. Звучить просто. На практиці 80% проблем vault-архітектури — це не помилки в самій стратегії, а помилки в логіці розрахунку shares при депозитах/виводах, або неправильний облік fee при harvesting. Кілька протоколів втратили користувацькі кошти саме тут, не в самій стратегії.
Проблема інфляційної атаки та ERC-4626
Перший депозит та атака на shares
ERC-4626 — стандарт tokenized vault, прийнятий у квітні 2022. До цього кожен vault винаходив своє колесо для розрахунку convertToShares / convertToAssets. Після — з'явився консенсус, але не зникли вразливості.
Класична атака на vault без ERC-4626 захисту: атакуючий робить перший депозит на 1 wei, отримує 1 share. Потім донатить напрямку (не через deposit) 1000 USDC у vault, піднімаючи totalAssets без зміни totalSupply. Наступний користувач депонує 1999 USDC — при діленні 1999e6 * 1 / 1000e6 отримує 1 share (integer division). Атакуючий з 1 share отримує половину пулу при withdrawall — 1499 USDC. Жертва втратила 500 USDC.
OpenZeppelin в ERC4626.sol закрив це через віртуальні shares та assets: _decimalsOffset() додає 10^N до знаменника, роблячи атаку економічно невигідною. Але це працює тільки якщо _decimalsOffset підібраний під токен з урахуванням його decimals.
Ми використовуємо ERC-4626 як базу та додаємо _decimalsOffset = 3 для більшості ERC-20 токенів, що робить вартість атаки ~1000x дорожчою за profit.
Harvest та розрахунок fee — де зазвичай помиляються
При harvesting vault збирає награди (наприклад, CRV + CVX з Convex), конвертує їх у underlying asset та додає у пул. У момент між harvesting та re-deposit share ціна зростає. Якщо fee беруть після цього росту як відсоток від profit — все коректно. Якщо fee беруть у момент harvest до re-deposit — management fee з'їдає частину principal, а не тільки profit.
Типова помилка: performanceFee = (totalAssets() - lastHarvestTotalAssets) * feePercent / 10000. Тут totalAssets() може включати unrealized gains, які потім уйдуть при ринковій волатильності. Правильніше: fee від realized profit після конвертації наград.
Reentrancy у vault через ERC-777 / ERC-1363
Якщо underlying asset — токен з transfer hook (ERC-777 або ERC-1363), то при deposit() хук може бути викликаний до оновлення totalSupply. Атакуючий у хуку викликає deposit() знову — отримує shares по старому курсу до обліку свого першого депозиту.
Захист: nonReentrant на deposit, withdraw, redeem, mint. Foundry fuzz-тест з mock ERC-777 токеном, який викликає повторний deposit з transfer hook.
Як ми будуємо vault-контракти
Архітектура: vault + strategy separation
Vault зберігає assets та управляє shares. Strategy — окремий контракт з логікою розміщення. Це не просто архітектурна чистота: при взломі стратегії vault може бути зупинений (pausable), а funds — у теорії — евакуйовані через emergencyWithdraw. Якщо все в одному контракті — ні.
Vault (ERC-4626)
└── Strategy
├── Aave v3 supply/withdraw
├── Curve LP deposit
└── Convex staking
Yearn v2/v3 використовує цю ж концепцію. Ми адаптуємо під конкретні вимоги, не копіюємо Yearn — там ~5000 рядків, з яких клієнту зазвичай потрібна третина.
Стек
Solidity 0.8.x + OpenZeppelin 5.x (ERC4626, AccessControl, Pausable, ReentrancyGuard). Інтеграції: Aave v3 через IPool, Compound v3 через IComet, Curve через ICurvePool, Convex через IConvex. Оракули для swap наград: Chainlink або Uniswap v3 TWAP залежно від ліквідності токена.
Тесты у Foundry: fork mainnet Ethereum/Arbitrum, 100+ fuzz runs на deposit/withdraw/harvest з рандомними сумами та послідовностями. Property-based інваріант: convertToAssets(totalSupply()) >= totalUserDeposits після будь-якої операції.
Таблиця vault типів
| Тип | Стратегія | Складність | Типичний APY джерело |
|---|---|---|---|
| Simple lending | Aave/Compound | Низька | Supply rate |
| LP vault | Curve + Convex | Середня | CRV + CVX rewards |
| Multi-strategy | 3+ протокола | Висока | Weighted allocation |
| Leverage vault | Aave self-borrow | Висока | Leveraged yield |
Процес роботи
Проектування (3-5 днів). Вибір стратегії, аналіз інтеграцій, storage layout vault + strategy. Визначення fee структури: management fee (% від AUM в рік), performance fee (% від прибутку), withdrawal fee (рідко, але бувает).
Розроблення (1-3 тижні). Vault core + одна-дві стратегії. Fork-тесты на Ethereum mainnet або Arbitrum (де дешевше газ для тестування).
Аудит-підготовка. Slither, тест-покриття >95%, перевірка всіх fee розрахунків на граничних випадках (0 assets, 1 wei deposit, harvest відразу після деплоя).
Деплой. Gnosis Safe для owner/admin функцій. Timelock на зміну стратегії — мінімум 24 години.
Орієнтири за часом
Vault з однією стратегією (Aave/Compound): 1-2 тижні. Multi-strategy vault з rebalancing: 3-5 тижнів. Складні leverage-стратегії з liquidation protection: 6-8 тижнів.







