Liquidation System Development for Perpetual DEX

Liquidation System Development for Perpetual DEX Flash crash by 50% in a couple of minutes—and if the liquidation module doesn't process positions in time, the protocol incurs bad debt. One popular perpetual exchange faced this last year when volumes grew tenfold and the keeper network couldn't k

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1009

Liquidation System Development for Perpetual DEX

Flash crash by 50% in a couple of minutes—and if the liquidation module doesn't process positions in time, the protocol incurs bad debt. One popular perpetual exchange faced this last year when volumes grew tenfold and the keeper network couldn't keep up. In such scenarios, a properly designed liquidation system with incentives for liquidators holds up: the liquidator gets a fee share, but only upon fast execution. Poor architecture either misses positions or generates unserviceable debt for LPs. We design solutions that withstand extreme market movements. Contact us for an audit of your protocol.

Our engineers have 5+ years of experience in DeFi development and have implemented over 15 liquidation solutions on Ethereum, Arbitrum, and Polygon. We guarantee correct operation even during sharp price jumps.

How Is the Liquidation Threshold Calculated?

On a perpetual DEX (Wikipedia), a trader opens a position with leverage: 10x long ETH, depositing 1000 USDC collateral, position = 10,000 USDC notional. If ETH drops 9%, the unrealized loss is 900 USDC, collateral decreases to 100 USDC. Margin ratio = 100/10,000 = 1%. If this is below maintenance margin (usually 0.5-1%), the position is subject to forced closure.

Margin ratio formula: marginRatio = (collateral + unrealized_pnl) / notional_value. The protocol must liquidate the position before collateral + unrealized_pnl < 0—otherwise bad debt occurs.

Why Is Gap Risk the Main Threat?

A gap (sharp price jump, e.g., on news) skips several liquidation levels in one tick. A position can immediately go into negative equity without intermediate liquidation. The dYdX v4 documentation states that gap risk is the main cause of bad debt.

GMX v2 and dYdX v4 use several mechanisms to mitigate gap risk:

  • Insurance fund—a reserve from part of trading fees
  • ADL (Auto-Deleveraging)—if the insurance fund is insufficient, profitable positions of the opposite side are forcibly closed
  • Max open interest limits—restricting total OI per asset reduces potential bad debt

Comparison of Approaches: Keeper vs On-Chain Liquidation

Parameter Keeper-based On-chain automatic
Reaction speed Depends on gas and competition Instant per block
Complexity Medium (off-chain infrastructure) High (gas, complexity)
Protocol control Indirect (via incentives) Direct
MEV risk High Low
Example GMX, dYdX Synthetix (past versions)

Keeper-based approach reduces gas costs for liquidation by 2-3 times compared to on-chain automatic. This is confirmed in practice on our projects.

Liquidation System Architecture

On-Chain Component

The contract stores positions and constantly updates the mark price via an oracle. Liquidation occurs in two steps:

1. Liquidatability Check (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; // Subtract accumulated funding fee int256 pendingFunding = calculateFundingFee(pos); equity -= pendingFunding; uint256 notional = pos.size; // size = notional value // Below maintenance margin threshold return equity < int256(notional * MAINTENANCE_MARGIN_BPS / 10000); } 

2. Liquidation Execution:

function liquidate(uint256 positionId, address recipient) external nonReentrant { require(isLiquidatable(positionId), "Not liquidatable"); Position memory pos = positions[positionId]; uint256 markPrice = oracle.getMarkPrice(pos.indexToken); // Calculate remaining collateral after losses int256 remainingCollateral = calculateRemainingCollateral(pos, markPrice); uint256 liquidationFee = pos.collateral * LIQUIDATION_FEE_BPS / 10000; // Payment to keeper uint256 keeperFee = liquidationFee * KEEPER_SHARE / 100; token.transfer(recipient, keeperFee); // Remainder to insurance fund or protocol if (remainingCollateral > 0) { uint256 toInsurance = uint256(remainingCollateral) - keeperFee; insuranceFund.deposit(toInsurance); } else { // Bad debt—cover from insurance fund insuranceFund.cover(uint256(-remainingCollateral)); } _closePosition(positionId); emit PositionLiquidated(positionId, msg.sender, keeperFee, block.timestamp); } 

Keeper System

Keeper—an external participant monitoring positions and calling liquidate(). Incentive—keeper fee, creating a competitive market of liquidators.

Example keeper bot config in TypeScript with 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)); // Most profitable first 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 Oracle

Key element: the mark price must not be manipulable via flash loans. dYdX v4 uses Pyth oracle with aggregated median from multiple sources. GMX v2 uses Chainlink (official documentation) plus custom keeper oracle with signature verification.

Oracle requirements:

  • Freshness check: price not older than N seconds (usually 30-60)
  • Deviation check: new price no more than X% different from previous (circuit breaker)
  • Multi-source aggregation: median from 3+ sources
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; } 

What Happens When the Insurance Fund Runs Out? (ADL)

Auto-Deleveraging—the last line of defense. If the insurance fund is exhausted, the protocol forcibly closes profitable positions at mark price (no slippage). Closing order: positions with the highest profit and leverage first—as they are most risky for the system.

ADL is a painful mechanism for traders. Important:

  • Clearly disclose ADL risk in documentation
  • Show an ADL indicator on the UI (as on Binance futures)
  • Limit OI to minimize the need for ADL

What's Included in Turnkey System Development

Stage Duration Result
Risk analysis and modeling 3-5 days Parameters for maintenance margin, fee, insurance fund size
Smart contract development 2-4 weeks Liquidation contracts, insurance fund, oracle adapter
Keeper bot integration 1-2 weeks Off-chain infrastructure in TypeScript
Fork testing 1 week Simulation of stress scenarios (flash crash and stablecoin collapse)
Audit 2-3 weeks Independent auditor's report
Deployment and monitoring 1 week Documentation, scripts, dashboard

The full cycle takes 8-12 weeks. Cost is calculated individually.

Tech Stack

Solidity + Foundry—liquidation contracts, oracle, insurance fund. TypeScript + viem—keeper bot, monitoring. Chainlink + Pyth—price feeds. Gelato Network—fallback for calling keeper functions. Foundry fork tests—simulation on mainnet fork.

How We Ensure Reliability

We rely on 5 years of Web3 experience and dozens of successful audits. We implement formal verification for critical contracts. We provide a warranty on the code for 6 months after deployment.

Get a consultation: describe your protocol, and we will assess the risks and propose an architecture.