Разработка системы ликвидаций для perpetual DEX

Разработка системы ликвидаций для perpetual DEX Flash crash на 50% за пару минут — и если ликвидационный модуль не успевает обработать позиции, протокол получает bad debt. Одна popular perpetual биржа в прошлом году столкнулась с этим, когда объёмы выросли на порядок, а keeper-сеть не справилась.

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

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

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

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1450
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1003
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1269
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    719
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1009

Разработка системы ликвидаций для perpetual DEX

Flash crash на 50% за пару минут — и если ликвидационный модуль не успевает обработать позиции, протокол получает bad debt. Одна popular perpetual биржа в прошлом году столкнулась с этим, когда объёмы выросли на порядок, а keeper-сеть не справилась. В таких сценариях правильно спроектированная система ликвидаций с инсентивами для ликвидаторов держит удар: ликвидатор получает долю комиссии, но только при быстром исполнении. Плохая архитектура либо пропускает позиции, либо генерирует необслуживаемый долг для LP. Мы проектируем решения, выдерживающие экстремальные движения рынка. Свяжитесь с нами для аудита вашего протокола.

Наши инженеры имеют 5+ лет опыта в DeFi разработке, реализовали более 15 решений для ликвидаций на Ethereum, Arbitrum и Polygon. Гарантируем корректную работу даже при резких скачках цены.

Как вычисляется ликвидационный порог?

На perpetual DEX (бессрочные фьючерсы) (Wikipedia) трейдер открывает позицию с leverage: 10x long ETH, внеся 1000 USDC коллатераль, позиция = 10,000 USDC notional. При падении ETH на 9% unrealized loss составляет 900 USDC, коллатераль уменьшается до 100 USDC. Margin ratio = 100/10,000 = 1%. Если это ниже maintenance margin (обычно 0.5-1%), позиция подлежит принудительному закрытию.

Формула margin ratio: marginRatio = (collateral + unrealized_pnl) / notional_value. Протокол должен ликвидировать позицию до того, как collateral + unrealized_pnl < 0 — иначе возникает bad debt.

Почему gap risk — главная угроза?

Gap (резкий прыжок цены, например при выходе новостей) перескакивает через несколько уровней ликвидации за один тик. Позиция может сразу уйти в negative equity без возможности промежуточной ликвидации. Разработчики dYdX указывают в документации к v4, что gap risk — основная причина bad debt.

GMX v2 и dYdX v4 применяют несколько механизмов для смягчения gap risk:

  • Insurance fund — резерв из части trading fees
  • ADL (Auto-Deleveraging) — если insurance fund не покрывает, принудительно закрываются прибыльные позиции противоположной стороны
  • Max open interest limits — ограничение совокупного OI по активу снижает потенциальный bad debt

Сравнение подходов: keeper vs on-chain ликвидация

Параметр Keeper-based On-chain автоматическая
Скорость реакции Зависит от gas и конкуренции Мгновенно при каждом блоке
Сложность Средняя (инфраструктура оффчейн) Высокая (газ, сложность)
Контроль протокола Косвенный (через incentives) Прямой
Риск MEV Высокий Низкий
Пример GMX, dYdX Synthetix (прошлые версии)

Keeper-based подход снижает газовые затраты на ликвидацию в 2-3 раза по сравнению с on-chain автоматическим. Это подтверждено на практике в наших проектах.

Архитектура системы ликвидаций

On-chain компонент

Контракт хранит позиции и постоянно обновляет mark price через оракул. Ликвидация проходит в два шага:

1. Проверка ликвидируемости (view function):

function isLiquidatable(uint256 positionId) public view returns (bool) { Position memory pos = positions[positionId]; uint256 markPrice = oracle.getMarkPrice(pos.indexToken); int256 unrealizedPnl = calculatePnl(pos, markPrice); int256 equity = int256(pos.collateral) + unrealizedPnl; // Вычитаем накопленный funding fee int256 pendingFunding = calculateFundingFee(pos); equity -= pendingFunding; uint256 notional = pos.size; // size = notional value // Ниже maintenance margin threshold return equity < int256(notional * MAINTENANCE_MARGIN_BPS / 10000); } 

2. Исполнение ликвидации:

function liquidate(uint256 positionId, address recipient) external nonReentrant { require(isLiquidatable(positionId), "Not liquidatable"); Position memory pos = positions[positionId]; uint256 markPrice = oracle.getMarkPrice(pos.indexToken); // Рассчитываем остаток коллатераля после убытков int256 remainingCollateral = calculateRemainingCollateral(pos, markPrice); uint256 liquidationFee = pos.collateral * LIQUIDATION_FEE_BPS / 10000; // Выплата keeper'у uint256 keeperFee = liquidationFee * KEEPER_SHARE / 100; token.transfer(recipient, keeperFee); // Остаток в insurance fund или протокол if (remainingCollateral > 0) { uint256 toInsurance = uint256(remainingCollateral) - keeperFee; insuranceFund.deposit(toInsurance); } else { // Bad debt — списываем из insurance fund insuranceFund.cover(uint256(-remainingCollateral)); } _closePosition(positionId); emit PositionLiquidated(positionId, msg.sender, keeperFee, block.timestamp); } 

Keeper система

Keeper — внешний участник, мониторящий позиции и вызывающий liquidate(). Инсентайв — keeper fee, создающий конкурентный рынок ликвидаторов.

Пример конфига keeper-бота на TypeScript с viem
class LiquidationKeeper { private positionCache: Map<bigint, Position> = new Map(); async monitorPositions(): Promise<void> { contract.on('PositionUpdated', (positionId, position) => { this.positionCache.set(positionId, position); }); provider.on('block', async (blockNumber) => { const markPrice = await oracle.getMarkPrice(INDEX_TOKEN); const liquidatable = [...this.positionCache.entries()] .filter(([_, pos]) => this.isLiquidatable(pos, markPrice)) .sort((a, b) => this.prioritize(a, b, markPrice)); // Самые выгодные первыми for (const [positionId] of liquidatable) { await this.attemptLiquidation(positionId); } }); } private prioritize(a: [bigint, Position], b: [bigint, Position], price: bigint): number { return Number(b[1].collateral - a[1].collateral); } } 

Оракул для mark price

Ключевой элемент: mark price не должен манипулироваться flash loan'ами. dYdX v4 использует Pyth oracle с aggregated median из нескольких источников. GMX v2 использует Chainlink (официальная документация) + custom keeper oracle с верификацией подписи.

Требования к оракулу:

  • Freshness check: цена не старше N секунд (обычно 30-60)
  • Deviation check: новая цена не более чем на X% отличается от предыдущей (circuit breaker)
  • Multi-source aggregation: медиана из 3+ источников
function getMarkPrice(address token) external view returns (uint256) { PriceData memory data = priceData[token]; require(block.timestamp - data.timestamp <= STALENESS_THRESHOLD, "Stale price"); require(data.numSources >= MIN_SOURCES, "Insufficient sources"); return data.medianPrice; } 

Что происходит при нехватке страхового фонда? (ADL)

Auto-Deleveraging — последняя линия защиты. Если insurance fund исчерпан, протокол принудительно закрывает прибыльные позиции по mark price (без slippage). Порядок закрытия: сначала позиции с наибольшим profit и leverage — как наиболее рискованные для системы.

ADL — болезненный механизм для трейдеров. Важно:

  • Четко раскрывать риск ADL в документации
  • Показывать ADL indicator на UI (как на Binance futures)
  • Ограничивать OI, чтобы минимизировать необходимость ADL

Что входит в разработку системы под ключ

Этап Длительность Результат
Анализ рисков и моделирование 3-5 дней Параметры maintenance margin, fee, размер insurance fund
Разработка смарт-контрактов 2-4 недели Контракты ликвидации, insurance fund, oracle adapter
Интеграция keeper-бота 1-2 недели Off-chain инфраструктура на TypeScript
Fork-тестирование 1 неделя Симуляция стресс-сценариев (flash crash и крах стейблкоина)
Аудит 2-3 недели Отчет независимого аудитора
Деплой и мониторинг 1 неделя Документация, скрипты, дашборд

Полный цикл занимает 8-12 недель. Стоимость рассчитывается индивидуально.

Стек

Solidity + Foundry — ликвидационные контракты, оракул, insurance fund. TypeScript + viem — keeper-бот, мониторинг. Chainlink + Pyth — price feeds. Gelato Network — fallback для вызова keeper-функций. Foundry fork tests — симуляция на mainnet fork.

Как мы гарантируем надёжность

Опираемся на 5-летний опыт в Web3 и десятки успешных аудитов. Внедряем формальную верификацию для критических контрактов. Предоставляем гарантию на код в течение 6 месяцев после деплоя.

Получите консультацию: опишите свой протокол, и мы оценим риски и предложим архитектуру.