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

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы ликвидаций для perpetual DEX
Сложная
~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

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

В ноябре 2022 года, после краха FTX, GMX v1 испытал стресс-тест: цены резко двигались, объёмы торгов взлетели в 10x, и система ликвидаций держала нагрузку. Это потому что GMX использует keeper-based ликвидации с правильно выстроенными incentives: ликвидатор получает часть ликвидационного fee, но только если исполняет быстро. Плохо спроектированная система ликвидаций в такие моменты либо не успевает закрывать позиции, либо создаёт bad debt, который ложится на LP провайдеров.

Механика ликвидаций в perpetual DEX

Что такое ликвидируемая позиция

На perpetual DEX трейдер открывает позицию с leverage: 10x long ETH за 1000 USDC коллатераль означает позицию на 10,000 USDC notional. Если ETH падает на 9%, unrealized loss = 900 USDC (9% × 10,000), коллатераль уменьшается до 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 (резкий прыжок цены, например при новости) mark price прыгает через несколько уровней ликвидации одновременно. Позиция может уйти сразу в negative equity без возможности ликвидации по пути.

Как GMX v2 и dYdX v4 решают gap risk:

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

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

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(). Incentive: keeper fee. Это создаёт конкурентный рынок ликвидаторов.

Для построения keeper-сети нужна off-chain инфраструктура:

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 {
        // Приоритет: чем больше коллатераль — тем выше keeper fee
        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 AND наибольшим leverage первыми (наиболее рискованные для системы).

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

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

Стек

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

Процесс работы

Аналитика (3-5 дней). Параметры рисков: maintenance margin, ликвидационный fee, страховой фонд. Моделирование stress scenarios: что при -50% основного актива за один блок.

Разработка (2-4 недели). Ликвидационный контракт + keeper bot + oracle интеграция + insurance fund.

Тестирование (1 неделя). Fork-тесты с историческими price shocks (March 2020, LUNA crash, FTX). Инвариант: после каждой ликвидации margin ratio позиции не меньше 0.

Аудит. Для perpetual DEX с реальным TVL — обязательно.

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

Ликвидационная система для одного актива без ADL — 1-2 недели. Полная система с ADL, insurance fund, мульти-оракульным агрегатором и keeper инфраструктурой — 4-6 недель. Стоимость рассчитывается индивидуально.