evm-audit-notes

Pattern: Bad-Debt Socialization via Earnings Accumulator

Pattern notes from reading Exactly Protocol’s Market.sol (clearBadDebt, ~line 605). Part of the working notes.

The Pattern

When a borrower’s collateral is exhausted by liquidation, the remaining debt doesn’t vanish and isn’t written off against a treasury. It is socialized into the floating pool’s earnings accumulator: future floating-pool earnings absorb the loss, diluting all floating depositors’ yield rather than any single party’s principal.

Core flow (Exactly’s implementation):

  1. Gated entry — only the Auditor can call clearBadDebt (the Auditor itself is invoked at the end of every liquidation via handleBadDebt, which decides when an account is underwater enough to clear).
  2. Fixed-rate legs first — the borrower’s fixed borrow positions are iterated via a packed 32-bit maturity bitmap. For each maturity, if earningsAccumulator >= badDebt, the position is fully cleared.
  3. Backup-debt yield routing — when a fixed pool’s repay returns a backup-debt reduction, the corresponding share of that pool’s unassignedEarnings is moved into the earnings accumulator (proportional, mulDivDown).
  4. Floating leg last — remaining floating debt is cleared through previewRepay + noTransferRefund.
  5. Settlement — earningsAccumulator -= totalBadDebt, one SpreadBadDebt event.

What to Check When You See This Pattern

Generalization

Socialize-the-earnings is one of three common bad-debt endgames:

Endgame Loss lands on Fragile when
Earnings accumulator (Exactly) floating depositors’ future yield earnings < bad debt for long periods
Mint-backstop / insurance pool backstop LPs backstop drains; incentive to drain
Inflate share price (protocol debt token) all shareholders at once death-spiral correlation with the loss event

The audit question is always who is the residual claimant, and whether that party has consented (via disclosed docs) to holding that tail risk.