Разработка протокола флеш-займов

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка протокола флеш-займов
Сложная
~1-2 недели
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

Разработка протокола флеш-займов

Flash loan — это атомарный кредит: берёшь любую сумму, делаешь что угодно, возвращаешь в той же транзакции. Если возврат не произошёл — вся транзакция реверсируется. Никакого залога, никакой кредитной истории. Aave V3 держит в пулах флеш-займов сотни миллионов долларов — и это работает, потому что атомарность EVM является абсолютной гарантией.

Но та же атомарность делает flash loans главным инструментом атак на DeFi. Из 10 крупнейших взломов последних трёх лет — минимум 7 использовали flash loans как стартовый капитал для oracle manipulation, price manipulation или governance attacks.

Архитектура flash loan протокола

Механика исполнения

Классическая схема Aave V2: пул вызывает executeOperation() на адресе receiver, передаёт активы, receiver делает что нужно, возвращает assets + premium. Весь сценарий — один вызов flashLoan(), одна транзакция, один блок.

Aave V3 добавил flashLoanSimple() для одного актива (дешевле по газу) и переработал интерфейс receiver на IFlashLoanSimpleReceiver. EIP-3156 формализовал стандарт: flashLoan(receiver, token, amount, data) и обязательный коллбэк onFlashLoan(). Если строим протокол с расчётом на интеграцию — имеет смысл поддерживать оба интерфейса.

Типы реализаций

Single-asset flash loans (EIP-3156 compliant): самый простой вариант. Один токен, один receiver. Газ минимален. Подходит для протоколов, которые хотят монетизировать простаивающую ликвидность.

Multi-asset batch loans (Aave-style): несколько токенов в одной транзакции. Сложнее имплементация, зато открывает сценарии типа «занять ETH + USDC одновременно для арбитража на пуле». Реализуется через массивы assets/amounts в одном вызове.

Callback-less flash loans (Uniswap V2-style): пул отправляет токены сначала, receiver возвращает в конце транзакции через отдельный вызов. Менее безопасная конструкция — receiver должен сам проверять, что его не вызывают повторно.

Ключевые проблемы безопасности

Reentrancy через флеш-займ коллбэк

Стандартная ловушка: receiver контракт вызывает другую функцию пула внутри executeOperation(). Если пул не защищён reentrancy guard на уровне хранилища — атакующий может изменить состояние пула до завершения оригинальной транзакции.

// НЕПРАВИЛЬНО: reentrancy возможна
function flashLoan(address receiver, uint256 amount) external {
    uint256 balanceBefore = token.balanceOf(address(this));
    token.transfer(receiver, amount);
    IFlashLoanReceiver(receiver).executeOperation(amount, fee, msg.sender);
    // receiver мог вызвать deposit() и изменить balanceBefore-логику
    require(token.balanceOf(address(this)) >= balanceBefore + fee);
}

Решение: nonReentrant modifier от OpenZeppelin на flashLoan() и на все функции, меняющие state пула (deposit, withdraw, borrow).

Проверка caller в receiver контракте

Receiver должен проверять, что executeOperation() вызывает именно доверенный пул, а не произвольный адрес. Без этой проверки атакующий может напрямую вызвать executeOperation() на receiver, имитируя флеш-займ.

function executeOperation(
    address asset,
    uint256 amount,
    uint256 premium,
    address initiator,
    bytes calldata params
) external override returns (bool) {
    require(msg.sender == address(LENDING_POOL), "Invalid caller");
    require(initiator == address(this), "Invalid initiator");
    // логика
}

Fee accounting и precision issues

Типичная ошибка: fee считается как amount * FEE_BPS / 10000, где FEE_BPS = 9 (0.09%). При маленьких суммах результат может округлиться до 0 из-за целочисленного деления. Атакующий дробит один большой займ на тысячи маленьких и платит нулевую комиссию.

Защита: минимальный fee в абсолютном значении (например, 1 wei) и проверка amountOwed > amount — не просто amountOwed >= amount + fee_calculated.

Как строим флеш-займ протокол

Стек: Solidity 0.8.x, OpenZeppelin 5.x для ReentrancyGuard и SafeERC20, Foundry для тестирования.

Пул контракт хранит ликвидность провайдеров. Поддерживаем несколько токенов через маппинг token => PoolState. PoolState включает: totalLiquidity, totalBorrowed (для учёта одновременных займов), feeAccumulator для LP-наград.

Fee distribution: комиссия с флеш-займов накапливается в пуле и повышает exchange rate LP-токенов (как Compound cTokens). LP получают yield без отдельного claim — просто при выводе получают больше базового токена.

Access control: через OpenZeppelin AccessControl. Роли: PAUSER_ROLE (circuit breaker при атаке), FEE_SETTER_ROLE (под timelock governance), ASSET_MANAGER_ROLE (добавление новых токенов).

Circuit breaker: если за один блок из пула ушло более X% ликвидности — автоматическая пауза. Реализуется через _blockLoanVolume маппинг и проверку в начале flashLoan(). Ложные срабатывания возможны при легитимном использовании — порог выставляем через governance.

Тестирование

Fork-тесты на Ethereum mainnet критичны. Гоняем через Foundry:

  • Стандартный займ и возврат с комиссией
  • Попытка невозврата — транзакция должна реверснуться
  • Reentrancy атака на flashLoan() через вредоносный receiver
  • Нулевой fee при минимальной сумме (проверяем anti-dust логику)
  • Паника: 100 последовательных займов максимального объёма

Fuzzing в Echidna с инвариантом: totalLiquidity после любой последовательности операций не меньше суммы депозитов минус снятия.

Легитимные use cases — почему это нужно строить

Flash loans — это не только атаки. Протокол открывает:

Арбитраж без капитала: трейдер видит разницу цен между Uniswap и Curve, берёт займ, исполняет арбитраж, возвращает. Прибыль — spread минус gas. DEX-арбитраж выравнивает цены и делает рынки эффективнее.

Self-liquidation: пользователь с позицией в Aave, близкой к liquidation, берёт flash loan, погашает долг, выводит залог, возвращает займ. Избегает penalty от внешних ликвидаторов.

Collateral swap: заменить ETH залог на WBTC без закрытия позиции. Одна транзакция вместо четырёх.

Leverage unwinding: закрыть leveraged position в одной транзакции.

Ориентиры по срокам

Базовый EIP-3156 compliant протокол для одного токена — 3-5 дней включая тесты. Multi-asset пул с LP-токенами и fee distribution — 1-1.5 недели. Интеграция с существующим lending протоколом (добавление flash loans поверх) — 1-2 недели в зависимости от архитектуры базового протокола. Стоимость рассчитывается после анализа требований.