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
| Parameter | Description |
|---|---|
creditAccount | The account to liquidate |
to | Where liquidator receives remaining assets |
calls | Multicall array for converting collateral |
lossPolicyData | Custom data for loss handling |
Liquidation Math
| Parameter | Description |
|---|---|
| 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
// 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
- Calculate payments via
CreditLogic.calcLiquidationPayments - Execute multicall (convert collateral to underlying)
- Transfer
amountToPoolto the Pool - Remove active quotas via PoolQuotaKeeper
Fee Types
| Fee Type | Description |
|---|---|
feeLiquidation | Standard liquidation fee to DAO |
feeLiquidationExpired | Higher fee for expired accounts |
liquidationDiscount | Discount for healthy liquidations |
liquidationDiscountExpired | Discount 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
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 interventionmaxHealthFactor: Maximum HF after partial liquidation (prevents over-liquidation)
Emergency Liquidations
Regular vs Emergency
| Type | When | Who |
|---|---|---|
| Regular | Protocol functioning normally | Anyone |
| Emergency | Protocol/Facade paused | EMERGENCY_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
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
- Credit Accounts - Account data and querying
- External Calls - Adapter calls used during liquidation multicalls
- Slippage & Safety - Price feeds and collateral checks