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

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

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

Часто задаваемые вопросы

Последние работы

  • 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 documentation

Инфляционная атака на 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 под ключ и получите работающий контракт с готовой тестовой базой.

Получите консультацию по вашему проекту — наши инженеры помогут выбрать оптимальную стратегию и снизить риски.