Створення ERC-4626 vault: токенізація прибуткових стратегій та аудит

Ми часто стикаємося з ситуацією, коли клієнт хоче об'єднати дохідність з різних DeFi-протоколів, але впирається в зоопарк несумісних інтерфейсів. До появи ERC-4626 кожен yield vault реалізовував власний інтерфейс: Yearn V2 мав `pricePerShare()`, Compound давав `exchangeRate()`, Aave працював через a

Напрямки блокчейн-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    998
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1267
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1003

Ми часто стикаємося з ситуацією, коли клієнт хоче об'єднати дохідність з різних DeFi-протоколів, але впирається в зоопарк несумісних інтерфейсів. До появи ERC-4626 кожен yield vault реалізовував власний інтерфейс: Yearn V2 мав pricePerShare(), Compound давав exchangeRate(), Aave працював через aToken з rebasing. Написати агрегатор, який працює з кількома vault-ами одночасно, означало підтримувати зоопарк адаптерів. ERC-4626 стандартизував це: один інтерфейс для всіх токенізованих vault-ів. Зараз цей стандарт використовують Yearn V3, Morpho Blue, більшість liquid staking протоколів та всі великі lending агрегатори. Це де-факто стандарт для yield-bearing токенів. Якщо ви розробляєте DeFi-продукт, замовте розробку vault під ключ — заощадите час на інтеграції та аудиті.

Що таке ERC-4626 і чому це важливо для інтеграцій

ERC-4626 — розширення ERC-20 з методами deposit/withdraw активами (underlying asset), mint/redeem shares (vault token), конвертацією між assets та shares. Vault token (shares) — звичайний ERC-20, який торгується та передається. Ціна share зростає в міру накопичення yield. Це фундаментально відрізняється від rebasing (stETH), де кількість токенів змінюється, а ціна постійна.

Математика vault: price per share

Ціна share в ERC-4626: pricePerShare = totalAssets / totalShares.

Сценарій Формула shares Особливість
Перший депозит shares = assets вимагається ініціалізація віртуальними shares
Наступні депозити shares = assets * totalShares / totalAssets округлення вниз
Зняття assets = shares * totalAssets / totalShares округлення вгору

При першому депозиті (totalShares = 0) виникає проблема: будь-яка формула з діленням на нуль невалідна. OpenZeppelin вирішує це через virtual shares: ініціалізуємо totalShares = 10^decimals, totalAssets = 10^decimals, що дає початковий pricePerShare = 1. Документація OpenZeppelin ERC4626

Інфляційна атака на vault

Це реальна вразливість, яка дозволяє першому depositor-у заробити за рахунок наступних. Сценарій: атакуючий депонує 1 wei, отримує 1 share, потім donates великий обсяг активу (минаючи deposit), різко підвищуючи pricePerShare. Наступний користувач депонує 1000 USDC, але через округлення вниз отримує 0 shares — його активи дістаються атакуючому.

Як захиститися від інфляційної атаки?

OpenZeppelin ERC4626 (v5.0+) захищає через віртуальні shares з _decimalsOffset(). Встановлення offset=3 створює віртуальний запас 10^(3+decimals) shares при 10^decimals assets. Атакуючому потрібно депонувати величезну суму для мінімальної вигоди — атака стає економічно невигідною.

function _decimalsOffset() internal view virtual returns (uint8) { return 0; // Збільште до 3 для додаткового захисту } 

Реалізація базового ERC-4626 vault

Ми використовуємо Foundry, Solidity 0.8.24, OpenZeppelin. Ключовий момент: vault перевизначає totalAssets(), враховуючи не тільки баланс vault, але й активи, задеплоєні в стратегію. Хуки _afterDeposit та _beforeWithdraw керують деплоєм/поверненням коштів.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract SimpleYieldVault is ERC4626, Ownable { address public strategy; uint256 public performanceFee; // 500 = 5% constructor( IERC20 asset_, string memory name_, string memory symbol_ ) ERC4626(asset_) ERC20(name_, symbol_) Ownable(msg.sender) {} function totalAssets() public view virtual override returns (uint256) { uint256 vaultBalance = IERC20(asset()).balanceOf(address(this)); uint256 strategyBalance = strategy != address(0) ? IStrategy(strategy).totalAssets() : 0; return vaultBalance + strategyBalance; } function _afterDeposit(uint256 assets, uint256) internal virtual { if (strategy != address(0)) { IERC20(asset()).approve(strategy, assets); IStrategy(strategy).invest(assets); } } function _beforeWithdraw(uint256 assets, uint256) internal virtual { uint256 vaultBalance = IERC20(asset()).balanceOf(address(this)); if (assets > vaultBalance && strategy != address(0)) { IStrategy(strategy).divest(assets - vaultBalance); } } } 

Чому важливі напрямки округлення?

ERC-4626 явно специфікує округлення: convertToShares та previewDeposit вниз (floor), previewWithdraw вгору (ceil), previewRedeem вниз. Порушення — це audit finding. Округлення завжди на користь vault, інакше можливий drain через безліч маленьких операцій.

Важливі edge cases

Якщо underlying asset — fee-on-transfer токен, vault отримує менше, ніж вказано. Рішення: заміряти реальний баланс після transfer і перераховувати shares. У коді це враховується.

Порівняння стандартів yield-токенів

Стандарт Тип Зручність інтеграції Ризик маніпуляцій
ERC-4626 Share-based Висока Низький (захист від інфляційної атаки)
Rebasing Balance-changing Середня Середній (складність агрегації)
Кастомний Різний Низька Високий (немає єдиного інтерфейсу)

ERC-4626 в 2-3 рази кращий для інтеграцій, ніж кастомні або rebasing-рішення. Це підтверджується практикою: багато протоколів переходять на цей стандарт, знижуючи витрати на розробку та аудит.

Тестування та аудит

Використовуємо офіційний набір property tests: ERC4626 Properties. Foundry fuzz-тести покривають roundtrip-властивості та інваріанти.

function testFuzz_DepositRedeem(uint256 assets) public { assets = bound(assets, 1, 1e30); vm.assume(assets <= token.balanceOf(user)); uint256 shares = vault.deposit(assets, user); uint256 assetsBack = vault.redeem(shares, user, user); // Втрати на округлення не більше 1 wei assertApproxEqAbs(assetsBack, assets, 1); } 

Гарантуємо проходження зовнішнього аудиту: контракти проходять Slither, Mythril, Echidna. Отримайте консультацію щодо підготовки до аудиту.

Що входить у розробку ERC-4626 vault

  1. Аналіз вимог — обговорюємо yield-стратегію, fee-модель, цільову мережу (Ethereum, Polygon, Arbitrum та ін.).
  2. Проектування архітектури — схема взаємодії vault, стратегій, harvester.
  3. Реалізація смарт-контрактів — Solidity 0.8.x, Foundry, OpenZeppelin.
  4. Тестування — модульні, fuzz, інтеграційні тести (покриття >95%).
  5. Розгортання та верифікація в Etherscan.
  6. Підтримка при проходженні зовнішнього аудиту — консультації та доопрацювання.
  7. Технічна документація — опис контрактів, схема викликів.

За 5 років роботи ми реалізували понад 30 DeFi-проєктів, включаючи vault-рішення для протоколів з TVL > $100M. Це дозволяє нам передбачати типові проблеми та давати рекомендації щодо архітектури.

Терміни та вартість

Базова реалізація ERC-4626 vault з однією стратегією: 3-5 робочих днів. Повноцінний vault з harvester, fee-механізмом та кількома стратегіями: 2-3 тижні. Вартість розраховується індивідуально після аналізу ваших вимог — зазвичай вона нижча, ніж розробка з нуля з використанням кастомних інтерфейсів.

Зв'яжіться з нами для оцінки вашого проєкту — ми підберемо оптимальну архітектуру. Замовте розробку vault під ключ і отримайте працюючий контракт з готовою тестовою базою.

Отримайте консультацію щодо вашого проєкту — наші інженери допоможуть обрати оптимальну стратегію та знизити ризики.