All articles
The BuildMay 20, 20269 min read

Why Compound V2's Close Factor Caps Liquidations at 50%

Compound V2 caps single-liquidation seizure at 50% of borrower debt. Why partial liquidations beat one-shot total liquidations, and the trade-offs.

By Carlos (Bloqarl)

TL;DR

  • Compound V2's closeFactor caps a single liquidation transaction at 50% of the borrower's debt in the targeted asset. A liquidator cannot wipe out the position in one shot.
  • The protocol pays the liquidator an 8% incentive (liquidationIncentive = 1.08) for closing the partial debt. This is the discount on the seized collateral.
  • Partial liquidation gives the borrower a recovery window: they can repay between liquidations, top up collateral, or watch a price recovery without losing their entire position to one transaction.
  • The trade-off: it takes multiple sequential liquidations to fully close a deeply underwater position, and the protocol absorbs slippage between them.
  • Forks that change the close factor (typically up to 100%) are choosing harsher borrower experience for faster bad-debt recovery.

Why this matters

Liquidations are the moment a lending protocol's incentive design gets tested in production. Done right, they protect lender capital and discourage reckless borrowing without crushing borrowers who hit a temporary bad patch. Done wrong, they wipe out borrowers who would have recovered, or fail to wipe out borrowers who needed to be wiped, leading to bad debt that lenders eat.

Compound V2's choices, the 50% close factor and 8% liquidation incentive, are some of the most copied parameters in DeFi lending. Understanding them is necessary to:

  • Audit a Compound V2 fork without missing a livelock or insolvency vector.
  • Decide what to change if you operate or build a Compound-style protocol.
  • Reason about your own borrow position's liquidation exposure on Compound itself.

What the close factor actually does

The close factor lives in the Comptroller. In its raw form, it's a 18-decimal mantissa equal to 0.5e18, representing a 50% cap.

When a liquidator calls liquidateBorrow(borrower, repayAmount, cTokenCollateral), the Comptroller's liquidateBorrowAllowed hook checks:

maxClose = closeFactorMantissa * borrower.borrowBalance(cTokenBorrowed)
require(repayAmount <= maxClose, "TOO_MUCH_REPAY")

Where borrowBalance is the borrower's current debt in the asset being repaid. If the liquidator tries to repay more than half the borrower's debt in that asset, the liquidation reverts.

This is per-asset, per-call. A borrower with debt in three different markets has each debt subject to its own close-factor cap. A liquidator who wants to liquidate two of the three markets needs two separate transactions.

What the liquidation incentive does

The 8% liquidation incentive is the liquidator's compensation. It works as a discount on the seized collateral: when the liquidator repays X dollars of debt, they receive collateral worth X * 1.08.

The math lives in liquidateCalculateSeizeTokens:

seizeAmount = (repayAmount * priceBorrowed * liquidationIncentive)
              / (priceCollateral * exchangeRate)

Step by step:

  1. repayAmount * priceBorrowed: dollar value of the debt being repaid.
  2. Multiply by liquidationIncentive (1.08): the dollar value of collateral the liquidator is entitled to.
  3. Divide by priceCollateral: convert dollar value to underlying collateral asset units.
  4. Divide by exchangeRate: convert underlying collateral to cToken units (the actual seized asset).

The 8% gives the liquidator a positive expected return on the transaction, accounting for gas, MEV competition (other bots will try to liquidate the same position), and the collateral asset's price volatility while they hold the seized cTokens before exiting them.

Why partial liquidation

A protocol that allows full liquidation in one transaction (close factor = 100%) is choosing speed of bad-debt cleanup over borrower experience. A borrower 1% underwater gets fully liquidated by the first MEV bot to spot them, paying 8% of their entire collateral as a fee on a 1% deficit.

A protocol with a 50% close factor (Compound V2's choice) accepts that the liquidation process takes multiple steps in exchange for:

1. Borrower recovery window

A borrower 5% underwater after a sudden price move gets liquidated for 50% of their debt, not 100%. They can:

  • Repay the remaining debt manually (now they're back to healthy collateralization).
  • Add collateral (now they're back to healthy collateralization).
  • Wait for price recovery (if the asset rebounds, they may not need a second liquidation at all).

This is the protocol explicitly choosing to leave borrowers some agency. The 50% number is a trade-off: it has to be high enough that one liquidation meaningfully restores protocol solvency, but low enough that the borrower retains enough position to want to recover it.

2. Liquidation cascade dampening

In a market crash, liquidations cascade: collateral asset drops → underwater borrowers get liquidated → liquidators sell seized collateral → asset drops further → more borrowers underwater → more liquidations. Each liquidation accelerates the next.

A 100% close factor maximizes the per-liquidation collateral hitting the market. A 50% close factor halves it. The cascade still happens but slower, giving market makers and arbitrageurs time to absorb selling pressure.

This was a real consideration in the March 2020 crash and the May 2022 Terra collapse. Protocols with smaller close factors had measurably less catastrophic cascades.

3. Bad-debt recovery via repeated calls

When a position gets deeply underwater (price moves faster than liquidations can keep up), the protocol still has a path to recovery: liquidators can chain calls. Bot 1 liquidates 50%, then a few seconds later bot 2 liquidates 50% of what's left (which is 25% of the original), then bot 3 takes 12.5%, etc.

After 5-6 sequential liquidations, the position is effectively closed even with a 50% per-transaction cap. The cascade just takes minutes instead of seconds.

When forks change the close factor

Some forks raise the close factor toward 100%. Common reasons:

  • Faster bad-debt recovery. Pure speed argument. Faster wipe of underwater borrowers means less time for the position to drift further underwater.
  • Long-tail asset markets. Less liquid collateral means harder for liquidators to exit; some forks compensate with a higher close factor to make each liquidation more profitable per call.
  • Stablecoin-only markets. Less price volatility, so the borrower-recovery window argument carries less weight.

The risk: a 100% close factor on a volatile asset market is brutal. A borrower who's 0.5% underwater gets wiped 100% with an 8% fee. The economic cost-benefit favors very conservative borrowing positions, which depresses borrow demand and hurts protocol revenue.

The middle ground (some forks use 75% or 80%) attempts to retain partial-liquidation properties while speeding bad-debt recovery. There's no canonical answer, only trade-offs.

What the liquidation incentive interacts with

The 8% liquidation incentive interacts with the protocol's reserve factor and its liquidation-incentive-distribution policy.

In Compound V2 specifically, the 8% goes entirely to the liquidator. The protocol does not take a cut. This is unlike some forks (Aave V2, for example) where part of the bonus is split between the liquidator and the protocol's safety module.

Implications for Compound V2 forks:

  • If you change the liquidation incentive, you affect liquidator competition. A 5% incentive draws fewer bots; a 12% incentive draws more (and probably leads to MEV cannibalism, where bots front-run each other).
  • If you split the incentive between liquidator and protocol, you reduce the per-call profitability for liquidators, which may slow liquidations during a cascade. Forks that did this discovered the hard way that during the May 2022 cascade, slower liquidations meant deeper bad-debt accumulation.

Liquidation eligibility check

Before close factor and liquidation incentive matter, the position has to be liquidatable. Compound V2's eligibility check happens in liquidateBorrowAllowed:

(Error err, , uint shortfall) = comptroller.getAccountLiquidity(borrower);
require(err == Error.NO_ERROR, "ERROR");
require(shortfall > 0, "NO_SHORTFALL");

A position is liquidatable only when the borrower's collateral value (after applying collateralFactors) is below their borrow value. We covered the math of this check in our accountLiquidity article.

Common porting mistakes

Mistake 1: close factor outside [0, 1]

A fork sets close factor to a value greater than 1.0 (intended as a percentage but stored as a mantissa). The Comptroller's setter has bounds checks (closeFactorMaxMantissa = 0.9e18, closeFactorMinMantissa = 0.05e18), but if those bounds are removed in the fork's setter, you can end up with a close factor that allows liquidating more debt than the borrower has. The math gets weird, but the practical effect is the cap becomes effectively infinite.

Mistake 2: liquidation incentive less than 1.0

A fork sets liquidation incentive to 0.95 ("liquidator pays a 5% premium"). This makes liquidations unprofitable; bots won't run them. The position drifts underwater unbounded. The protocol accumulates bad debt and becomes insolvent for lenders.

The Comptroller's bounds (liquidationIncentiveMinMantissa = 1.0e18, liquidationIncentiveMaxMantissa = 1.5e18) prevent this in the original Compound V2. Forks that override the bounds need to verify they don't introduce a sub-1.0 incentive.

Mistake 3: changing the close factor mid-flight without notification

Governance can lower the close factor on Compound V2. If they do so during an active liquidation campaign (multiple positions underwater, bots actively liquidating), the lower factor takes effect immediately. Bots that had pre-computed transactions for 50% close factor will hit the new lower factor mid-flight and waste gas on reverts.

Real-world: this happened on a Compound V2 fork during a small price crash in 2023. Governance lowered close factor in response to "borrower complaints" about partial liquidations being too aggressive. The change broke active liquidations, bad debt accumulated during the next 30 minutes, and the protocol ate ~$200K of bad debt that should have been liquidated cleanly.

Related questions

What's the difference between close factor and collateral factor? Close factor caps how much of a borrower's debt can be liquidated in one call (per debt asset). Collateral factor (a separate parameter) determines how much of an asset's value counts toward borrow capacity. Different concepts, often confused.

Why is the close factor not 100%? The protocol explicitly chose to leave borrowers a recovery window. See the section above on borrower recovery, cascade dampening, and bad-debt recovery via repeated calls.

Can a liquidator liquidate the same borrower in two different markets in the same transaction? Yes. Each market's debt is subject to its own close-factor cap, so a liquidator can chain liquidations across markets in a single transaction. They cannot liquidate more than 50% of a single market's debt per call.

What happens if a borrower goes bankrupt (collateral worth less than debt)? This is the bad-debt scenario. Liquidators stop liquidating because the 8% incentive on partial debt isn't enough to cover the negative-equity gap. The protocol carries bad debt until governance intervenes (typically with a backstop fund that absorbs the gap and protects lenders from the loss).

Does Compound V3 use the same close factor? Compound V3 (Comet) uses absolute liquidation thresholds rather than a multiplicative close factor. Different design, different mechanics. The V2 walkthrough above doesn't transfer directly.

Where to see this in Academy

The Compound V2 reconstruction in Zealynx Academy includes the full liquidation flow: eligibility check, close-factor cap, liquidation-incentive math, and the seize-tokens calculation. The test suite validates each piece independently and then in combination, including the cascading-liquidation pattern (multiple sequential calls bringing a deeply underwater position back to health).

When you rebuild this, the trickiest part isn't the math; it's the ordering of state updates within liquidateBorrow. Get the order wrong (update balances before the seize, or vice versa) and you can either pay the liquidator twice or fail to credit them at all. The test suite catches both failure modes.

Tagged

Compound V2LiquidationsDeFi