DocumentationOpen App

Liquidations

Liquidations close undercollateralized positions to ensure protocol solvency. Gearbox V3 supports both full liquidations (complete account closure) and partial liquidations (debt reduction while keeping the account open).

When Liquidations Occur

An account becomes liquidatable when:

  • Health Factor < 1.0 (undercollateralized)
  • Account has expired (past the configured expiration timestamp)

Anyone can liquidate an unhealthy account - there is no whitelist.

Full Liquidation

Liquidation Parameters

ParameterDescription
creditAccountThe account to liquidate
toWhere liquidator receives remaining assets
callsMulticall array for converting collateral
lossPolicyDataCustom data for loss handling

Liquidation Math

ParameterDescription
Liquidation Premium% of account value liquidator receives as reward
Liquidation Discount% used to cover debt and fees (100% - Premium)

Outcomes

Solvent Liquidation (totalFunds > liabilities):

  • Pool repaid in full
  • DAO receives liquidation fee
  • Remaining funds go to original borrower

Bad Debt (totalFunds < liabilities):

  • DAO profit reduced first
  • If insufficient, loss reported to Pool
  • Pool burns Treasury shares to cover
  • If Treasury empty: "uncovered loss" (socialized across LPs)

Executing a Full Liquidation

TypeScript
// Liquidation bot example const calls = [ // Swap collateral tokens to underlying via adapters { target: uniswapAdapterAddress, callData: encodeFunctionData({ abi: uniswapAdapterAbi, functionName: 'exactAllInputSingle', args: [{ tokenIn: wbtcAddress, tokenOut: usdcAddress, /* ... */ }] }) }, // Additional swaps as needed... ]; await creditFacade.write.liquidateCreditAccount([ creditAccountAddress, liquidatorAddress, // receives remaining assets calls, '0x' // lossPolicyData ]);

Internal Execution Steps

  1. Calculate payments via CreditLogic.calcLiquidationPayments
  2. Execute multicall (convert collateral to underlying)
  3. Transfer amountToPool to the Pool
  4. Remove active quotas via PoolQuotaKeeper

Fee Types

Fee TypeDescription
feeLiquidationStandard liquidation fee to DAO
feeLiquidationExpiredHigher fee for expired accounts
liquidationDiscountDiscount for healthy liquidations
liquidationDiscountExpiredDiscount for expired liquidations

Expired accounts have higher fees to incentivize timely liquidation.


Partial Liquidation

Partial liquidation reduces debt while keeping the account open. This is useful when market liquidity is insufficient for full conversion or a "deleverage" strategy is preferred.

Constraints

  • Account must remain open after liquidation
  • Must pass collateral check post-liquidation (HF >= 1)
  • Cannot leave "dust" debt below minDebt

Executing a Partial Liquidation

TypeScript
const seizedAmount = await creditFacade.write.partiallyLiquidateCreditAccount([ creditAccountAddress, wbtcAddress, // token to seize parseUnits('1000', 6), // repaid USDC amount parseUnits('0.03', 8), // min BTC to receive liquidatorAddress, [] // price updates ]);

Health Factor Thresholds

Protocol Level:

  • Liquidation Trigger: HF < 1.0
  • Post-Liquidation: HF >= 1.0 (enforced)

Bot-Specific (configurable in PartialLiquidationBotV3):

  • minHealthFactor: HF threshold for intervention
  • maxHealthFactor: Maximum HF after partial liquidation (prevents over-liquidation)

Emergency Liquidations

Regular vs Emergency

TypeWhenWho
RegularProtocol functioning normallyAnyone
EmergencyProtocol/Facade pausedEMERGENCY_LIQUIDATOR role only

Emergency liquidations ensure positions can be closed even during protocol pause, preventing bad debt accumulation.

Treasury Backstop

The TreasuryLiquidator contract allows the DAO treasury to provide emergency liquidity when external liquidators are absent, acting as a backstop during extreme market conditions.


Checking If an Account Is Liquidatable

TypeScript
const creditFacade = getContract({ address: facadeAddress, abi: creditFacadeV3Abi, client: publicClient, }); const creditManager = getContract({ address: cmAddress, abi: creditManagerV3Abi, client: publicClient, }); // Get health factor const debtData = await creditManager.read.calcDebtAndCollateral([ creditAccount, 2 // DEBT_COLLATERAL ]); const hf = debtData.twvUSD * 10000n / debtData.totalDebtUSD; // Check expiration const expirationDate = await creditFacade.read.expirationDate(); const isExpired = BigInt(Math.floor(Date.now() / 1000)) > expirationDate; const isLiquidatable = hf < 10000n || isExpired; console.log(`Liquidatable: ${isLiquidatable}, HF: ${Number(hf) / 100}%`);

Learn More