Paboxo

Liquidation math

When a position can be liquidated, how much one liquidation may repay, how much is seized, how the bonus is split, and exactly where bad debt starts.

The narrative — why liquidation is partial, why it pauses while the market is closed — is on liquidations. This page is the arithmetic, in the order the contract runs it (LendingPoolRouter).

Eligibility

After accruing interest, the position must satisfy

BV>MLTBV > M_{\text{LT}}

strictly, with both sides as on position health; otherwise the call reverts AssetNotLiquidatable. Also required: the borrower has shares, the liquidator asks to repay more than zero, both prices are Fresh when requireFreshForLiquidation is set (it is, on every market), and the collateral token's issuer has not paused transfers.

The liquidator chooses how many shares srs_r to repay. The contract caps that at the borrower's ss and then at the close factor below, so liquidation(borrower) — which asks for everything — repays as much as the close factor allows, not necessarily the whole debt.

Close factor

One liquidation takes what is needed to make the position healthy again, with a margin, and no more. Write the health factor and the market's bad-debt line as

hf=MLTBV,k=LT (1+b)hf = \frac{M_{\text{LT}}}{BV}, \qquad k = \text{LT}\,(1 + b)

Repaying a fraction ff of the debt removes f⋅BVf \cdot BV of debt and f⋅BV(1+b)f \cdot BV(1 + b) of collateral value, so the health factor afterwards is

hf′=hf−f k1−fhf' = \frac{hf - f\,k}{1 - f}

It reaches the target T=1.05T = 1.05 at the restoring fraction

f=T−hfT−k=1.05−hf1.05−LT (1+b)f = \frac{T - hf}{T - k} = \frac{1.05 - hf}{1.05 - \text{LT}\,(1 + b)}

computed as a WAD and rounded up. The most shares one liquidation may repay is (IsHealthy · 0x9259…F9a1, a view; the router applies the same rule to every liquidation through the shared CloseFactor library, LendingPoolRouter):

Positionsmax⁡s_{\max}
hf≤0.95hf \le 0.95ss — the whole debt
hf>0.95hf > 0.95 and f≥1f \ge 1 (only when k≥1.05k \ge 1.05, which no market allows)ss
hf>0.95hf > 0.95, and repaying ⌈s⋅f⌉\lceil s \cdot f \rceil would leave dust (below)ss
hf>0.95hf > 0.95 otherwise⌈s⋅f/1018⌉\left\lceil s \cdot f / 10^{18} \right\rceil

A request above smax⁡s_{\max} is capped to it, the same way a request above ss is: the call does not revert. Rounding up to a whole share means the position ends at 1.05, not one wei below it.

Why a target. A target is a state, not a share of the debt. After a first, smaller liquidation, the allowance is exactly what is still needed to reach 1.05, so splitting a liquidation into several calls never repays more than one call would. In practice it repays less: each slice raises the health factor, and once it is back above 1 the position is not liquidatable at all.

Why 1.05. Exactly 1 would leave the borrower one tick from the next liquidation. 1.05 is a 5% margin, small enough that the borrower keeps most of the position.

Dust

A partial liquidation — one that leaves shares (srep<ss_{\text{rep}} < s) and does not take the whole Position (σ<1018\sigma < 10^{18}) — must leave at least minBase/2\text{minBase} / 2 of debt and of collateral:

⌊BV (s−srep)s⌋≥minBase2and⌊CV′ (1018−σ)1018⌋≥minBase2\left\lfloor \frac{BV\,(s - s_{\text{rep}})}{s} \right\rfloor \ge \frac{\text{minBase}}{2} \quad\text{and}\quad \left\lfloor \frac{CV'\,(10^{18} - \sigma)}{10^{18}} \right\rfloor \ge \frac{\text{minBase}}{2}

otherwise the call reverts MustNotLeaveDust(leftoverDebt, leftoverCollateral, minLeftover). minBase\text{minBase} is IsHealthy.closeFactorMinBase(), one value for every market: $10 on mainnet (read on 27 October 2026), so the minimum left behind is $5. The owner can change it.

If even ⌈s⋅f⌉\lceil s \cdot f \rceil would leave less than that, the whole position may go — that is the third row of the table — so an unhealthy position can always be liquidated by someone. "Small" is judged by what reaching the target would leave, never by the position's size now, which is what keeps the rule split-proof. Repaying exactly smax⁡s_{\max} never reverts as dust; only a smaller partial can.

A liquidation the Position cannot cover (the bad-debt case below) takes all of the collateral and is never refused as dust.

Live markets

MarketLTbbk=LT(1+b)k = \text{LT}(1 + b)ff from hf=0.99hf = 0.99ff from hf=0.96hf = 0.96
NVDA / USDG0.650.080.70217.24%25.86%
SPY / USDG0.750.060.79523.53%35.29%
WETH / USDG0.800.050.84028.57%42.86%
SPCX / USDG0.500.100.55012.00%18.00%
TSLA / USDG0.500.100.55012.00%18.00%
MSFT / USDG0.650.080.70217.24%25.86%
AAPL / USDG0.650.080.70217.24%25.86%
QQQ / USDG0.700.070.74919.93%29.90%
GOOGL / USDG0.650.080.70217.24%25.86%
AMD / USDG0.500.100.55012.00%18.00%

Mainnet's parameters, read at block 94915008; MSFT/USDG and AAPL/USDG at block 99393260, QQQ/USDG, GOOGL/USDG and AMD/USDG at block 113204091. Every kk is below 0.95, so a position in bad debt (hf<khf < k) can always be liquidated in full.

Example

1 NVDA against 100 USDG of debt on NVDA/USDG. NVDA falls to $150:

hf=0.65×150100=0.975,f=1.05−0.9751.05−0.702=0.0750.348=21.55%hf = \frac{0.65 \times 150}{100} = 0.975, \qquad f = \frac{1.05 - 0.975}{1.05 - 0.702} = \frac{0.075}{0.348} = 21.55\%
Liquidator repays21.55 USDG
Liquidator receives0.155172 NVDA, worth $23.28 (21.55 × 1.08)
Borrower keeps0.844828 NVDA, worth $126.72, against 78.45 USDG of debt
Health factor after0.65×126.72/78.45=1.050.65 \times 126.72 / 78.45 = 1.05

Without the close factor, the same liquidation could have repaid all 100 USDG and taken $108 of NVDA.

The same position at a tenth of the size — 0.06 NVDA ($9) against 6 USDG, also at hf=0.975hf = 0.975 — would keep only 4.71 USDG of debt after reaching 1.05, below the $5 minimum. So it may be liquidated in full (6 USDG repaid, $6.48 of NVDA seized), and a request to repay 3 USDG reverts MustNotLeaveDust.

Seize fraction

The contract works out what fraction σ\sigma of the Position to hand over, as a WAD (LendingPoolRouter), on the shares left after the cap:

CV′=⌊MLT⋅1018LT⌋,SV=⌊⌊BV⋅srs⌋⋅1018+b1018⌋CV' = \left\lfloor \frac{M_{\text{LT}} \cdot 10^{18}}{\text{LT}} \right\rfloor, \qquad SV = \left\lfloor \left\lfloor \frac{BV \cdot s_r}{s} \right\rfloor \cdot \frac{10^{18} + b}{10^{18}} \right\rfloor if SV<CV′:σ=⌊SV⋅1018CV′⌋,srep=sr\text{if } SV < CV':\quad \sigma = \left\lfloor \frac{SV \cdot 10^{18}}{CV'} \right\rfloor,\quad s_{\text{rep}} = s_r otherwise:σ=1018,srep=min⁡(⌈s⋅⌊CV′⋅1018/(1018+b)⌋BV⌉, s)\text{otherwise}:\quad \sigma = 10^{18},\quad s_{\text{rep}} = \min\left(\left\lceil \frac{s \cdot \lfloor CV' \cdot 10^{18} / (10^{18} + b) \rfloor}{BV} \right\rceil,\ s\right)

Where:

  • CV′CV' — the Position's value rebuilt from MLTM_{\text{LT}} (at most one unit below CVCV).
  • SVSV — the value to seize: the repaid share of the debt value, plus the bonus bb.
  • sreps_{\text{rep}} — the shares actually repaid. When the Position cannot cover repaid×(1+b)\text{repaid} \times (1 + b), the liquidator takes all of it and repays only what it is worth at the bonus.

The liquidator then pays, rounded up in the lenders' favour:

arep=min⁡(⌈srep⋅TBATBS⌉, TBA)a_{\text{rep}} = \min\left(\left\lceil \frac{s_{\text{rep}} \cdot \text{TBA}}{\text{TBS}} \right\rceil,\ \text{TBA}\right)

Protocol split

A share π\pi of the bonus — never of the repaid value — can go to the protocol (LendingPoolRouter):

σp=⌊⌊σ b1018+b⌋⋅π1018⌋,σl=σ−σp\sigma_p = \left\lfloor \left\lfloor \frac{\sigma\,b}{10^{18} + b} \right\rfloor \cdot \frac{\pi}{10^{18}} \right\rfloor, \qquad \sigma_l = \sigma - \sigma_p

π\pi is liquidationProtocolShare, at most 100% (IsHealthy · 0x9259…F9a1), and 0% on every market. The Position then transfers ⌊q σl/1018⌋\lfloor q\,\sigma_l / 10^{18} \rfloor to the liquidator and ⌊q σp/1018⌋\lfloor q\,\sigma_p / 10^{18} \rfloor to the protocol (Position).

Bad debt

If the whole Position was taken (σ=1018\sigma = 10^{18}) and the borrower still has shares, the rest of their debt is written off in the same transaction (LendingPoolRouter):

Dbad=min⁡(⌈sleft⋅TBATBS⌉, TBA)D_{\text{bad}} = \min\left(\left\lceil \frac{s_{\text{left}} \cdot \text{TBA}}{\text{TBS}} \right\rceil,\ \text{TBA}\right)

Supply absorbs it first, S−=min⁡(Dbad,S)S \mathrel{-}= \min(D_{\text{bad}}, S); anything beyond supply is charged to reserves, capped at what they hold; a shortfall beyond both is not recorded anywhere. Since a market's supply is the Earn vault's claim, the loss lands on every peUSDG holder.

Where it starts. A liquidation leaves bad debt as soon as the collateral cannot pay the debt plus the bonus:

CV<BV (1+b)⟺HF<LT (1+b)CV < BV\,(1 + b) \quad\Longleftrightarrow\quad HF < \text{LT}\,(1 + b)

not when collateral falls below the debt. The liquidator is still paid their bonus on whatever is there, so lenders lose

Dbad≈BV−CV′1+bD_{\text{bad}} \approx BV - \frac{CV'}{1 + b}

— which can be large even while CV>BVCV > BV. Mainnet thresholds: 0.702 for NVDA/USDG, MSFT/USDG, AAPL/USDG and GOOGL/USDG, 0.749 for QQQ/USDG, 0.795 for SPY/USDG, 0.840 for WETH/USDG, 0.550 for SPCX/USDG, TSLA/USDG and AMD/USDG. Market creation requires LT(1+b)<1\text{LT}(1 + b) < 1 (LendingPoolFactory · 0x7a2b…b1C6), so there is always a band of health factors in which liquidation clears a position without loss.

Partial liquidation

Repaying a fraction ff of the debt removes f⋅BVf \cdot BV of debt and f⋅BV(1+b)f \cdot BV (1 + b) of collateral value. The health factor afterwards is

HF′=LT (CV−f BV(1+b))BV (1−f)HF' = \frac{\text{LT}\,\big(CV - f\,BV(1 + b)\big)}{BV\,(1 - f)}

and HF′>HFHF' > HF exactly when CV>BV(1+b)CV > BV(1 + b), i.e. HF>LT(1+b)HF > \text{LT}(1 + b). Above that line, a partial liquidation improves the position, and the close factor stops it at 1.05. Below it, each partial liquidation makes the health factor worse, and the only clean outcome is a full one — which the close factor always allows there.

The chart shows a full liquidation, the only kind allowed at a health factor of 0.95 or below.

Full liquidation outcome by health factor, per 1 USDG of debt
Market
Protocol share of the bonus
To liquidatorBorrower keepsBad debt (lenders lose)
Below a health factor of 0.702 a full liquidation takes all the collateral and leaves bad debt; above it the borrower keeps the remainder.-0.50.00.51.01.50.30.40.50.60.70.80.9Health factor before liquidationdebt = 1LT·(1+b) = 0.702
Health factor
0.600
Collateral / debt
0.923
To liquidator
0.923
Borrower keeps
0.000
Bad debt
0.145
Show as a table
HFCollateralLiquidatorProtocolBorrower keepsBad debt
0.4000.6150.6150.0000.0000.430
0.5000.7690.7690.0000.0000.288
0.6000.9230.9230.0000.0000.145
0.7021.0801.0800.0000.0000.000
0.8001.2311.0800.0000.1510.000
0.9001.3851.0800.0000.3050.000
0.9501.4621.0800.0000.3820.000
Liquidation threshold and bonus as read on mainnet 4663 at block 86868761. The live protocol share of the bonus is 0%; the 20% setting is illustrative. Values are fractions of the debt's USD value. Everything is continuous here; the contracts round each step (liquidator repayment up, seize fraction down). Health factors stop at 0.95: above it the close factor lets one liquidation repay only what brings the position back to 1.05.

Worked example

The illustrative Position from position health: 20 NVDA, 2400000000 borrow shares, debt 2402294128 (2,402.294128 USDG) after accrual, with TBA=\text{TBA} = 20019117741, TBS=\text{TBS} = 20000000000, LT=65%\text{LT} = 65\%, b=8%b = 8\%. The prices below are hypothetical too.

At $180, capped by the close factor. CV=$3,600CV = \$3{,}600, MLT=$2,340<BV=$2,402.294128M_{\text{LT}} = \$2{,}340 < BV = \$2{,}402.294128: HF=0.97407HF = 0.97407, liquidatable, and above 0.95. The liquidator asks for every share; the close factor allows

f=⌈(1.05−0.974068900525572945)⋅10181.05−0.702⌉=21.8193%,smax⁡=⌈2400000000×f⌉=523662755f = \left\lceil \frac{(1.05 - 0.974068900525572945) \cdot 10^{18}}{1.05 - 0.702} \right\rceil = 21.8193\%, \qquad s_{\max} = \lceil 2400000000 \times f \rceil = 523662755
RawHuman
sreps_{\text{rep}}52366275521.82% of the shares (capped from 2400000000)
SVSV566096382624961187999$566.10 = 1.08 × the repaid debt
σ\sigma15724899517360032915.72490% of the Position
arepa_{\text{rep}}524163318524.163318 USDG (rounded up)
To liquidator31449799034720065803.144980 NVDA, worth $566.10
Borrower keeps16.855020 NVDA ($3,033.90) against 1,878.130811 USDG of debt
Health factor after16.855020×180×0.65/1,878.130811=1.050016.855020 \times 180 \times 0.65 / 1{,}878.130811 = 1.0500
Bad debt0none: 0.974>0.7020.974 > 0.702

Both sides stay far above the $5 minimum, so the cap is the restoring fraction. A second liquidation right after reverts AssetNotLiquidatable: the position is healthy.

Same, with π=20%\pi = 20\%: σp=\sigma_p = 2329614743312597 (0.23296%), so 0.046592 NVDA goes to the protocol and 3.098388 NVDA to the liquidator. The liquidator still repays the same 524.163318.

At $180, split in two. A first liquidation of 240000000 shares (10%) already lifts the health factor above 1, so the second is refused: 240,000,000 shares in total against 523,662,755 for one call. Asking for half the shares (1200000000) is capped to 523662755, like asking for all of them.

At $120, full liquidation. CV=$2,400CV = \$2{,}400 — just 2.29 below the debt — and HF=0.649HF = 0.649: at or below 0.95, so the close factor allows every share, and below 0.702. SV=$2,594.48≥CV′SV = \$2{,}594.48 \ge CV', so everything is seized:

RawHuman
σ\sigma1000000000000000000100%
sreps_{\text{rep}}⌈2400000000×⌊2400⋅1018/1.08⌋/BV⌉=\lceil 2400000000 \times \lfloor 2400 \cdot 10^{18} / 1.08 \rfloor / BV \rceil = 2220100059
arepa_{\text{rep}}22222222242,222.222224 USDG for all 20 NVDA
Bad debt180071906180.071906 USDG

The collateral was short of the debt by 2.29 USDG, but lenders lose 180.07: the 2.29 shortfall plus the liquidator's 8% bonus on $2,222.22 of repayment (177.78).

On this page