supply_index and borrow_index.
Read first: Markets.
The pool never iterates accounts. It stores supply and debt as scaled
amounts and applies interest to everyone at once by advancing two indexes,
supply_index and borrow_index. A position’s actual balance is always
derived from its scaled amount and the current index.
Scaled balances
Every supply and debt amount is stored as a scaled RAY value. The actual amount is the scaled value multiplied by the relevant index:supply_index; debt positions and totals
use borrow_index. RAY is 10^27. Both indexes start at RAY (1.0) when
a market is created and only ever rise from interest — except the supply index,
which a bad-debt cleanup can lower (see below). Views reconstruct actual
supplied and borrowed amounts on demand from the current index and the asset’s
decimals.
Utilization
Utilization is the fraction of supplied liquidity that is currently borrowed, in RAY:1 RAY. Utilization drives the borrow rate and, through it, the
supply rate.
Borrow-rate model
The annual borrow rate is a piecewise-linear curve with two kinks —mid_utilization and optimal_utilization — producing three regions. It
starts at base_borrow_rate and adds slope1, then slope2, then slope3 as
utilization climbs (calculate_borrow_rate):
max_borrow_rate (≤ 2·RAY). Parameters must
satisfy base ≤ slope1 ≤ slope2 ≤ slope3 ≤ max and 0 < mid < optimal < 1 RAY,
so the curve is non-decreasing.
Accrual
On every mutating pool call, and onupdate_indexes, the pool advances the
borrow index by compounding the rate over the elapsed time.
The rate compounds per millisecond. Elapsed time is processed in chunks of at
most one year each, and each chunk uses an 8-term Taylor approximation of e^x:
1e36 (MAX_BORROW_INDEX_RAY) — a 1e9x growth
budget from its starting RAY.
Every dropped Taylor term is positive, so the truncation always under-accrues
interest — never over-accrues — and the bias collapses as the rate falls
(2.4e-4 relative shortfall at 200% APR, 1.2e-12 at 20%).
Splitting interest
The interest accrued on outstanding debt is split byreserve_factor into a
protocol fee and supplier rewards (calculate_supplier_rewards):
supply_index. Every supplier’s position appreciates
at once, with no per-account write.
The update is conservative. If the index move cannot express the full reward, the
leftover is recorded as revenue rather than lost. The supply index shares the
borrow index’s 1e36 ceiling, and accrual never lowers it.
The protocol fee is added to revenue and held as a scaled supply claim.
The display supply APR follows directly (calculate_deposit_rate):
80%, the borrow rate is 5%, and the
reserve factor is 1000 BPS (10%). Then:
3.6% supply rate against a 5% borrow rate.
Protocol revenue
Protocol revenue is not a separate token balance. It is held as a scaled supply claim inrevenue, bounded by total supply (0 ≤ revenue ≤ supplied). It
appreciates with the supply index until claimed.
On claim_revenue the pool does four things: sync the indexes, reconstruct the
claimable amount, cap it at available cash, and burn enough revenue shares to
cover the payout. It transfers to its owner, the controller, which forwards the
proceeds to the configured accumulator. See
Controller ABI.
Recapitalization
There is noadd_rewards entrypoint. The one external top-up path is
recapitalize(payer, hub_asset, amount) on the controller.
Anyone can call it. It applies only up to the market’s actual shortfall,
refunds the excess, and returns the amount actually applied. Credit is measured,
not requested. It is not pause-gated.
Bad debt
When an account’s total collateral is≤ $5 WAD (BAD_DEBT_USD_THRESHOLD = 5·WAD) and its debt exceeds that collateral, the position is unrecoverable.
Cleanup runs either inline during a liquidation, or when anyone calls
clean_bad_debt. Both do the same four things:
- Seize all of the account’s remaining supply and debt.
- Remove the account and burn its position NFT.
- Lower the affected market’s supply index to absorb the shortfall.
- Emit
CleanBadDebtEvent.
remaining_value is the total supplied value less the bad debt, capped at that
total.
The two floors compound. That makes the written-down index at most the
single-step value, never more. The extra truncation falls on suppliers, never on
the protocol.
The result is clamped at SUPPLY_INDEX_FLOOR_RAW = RAY / 1_000 (0.001) — not
at WAD. The floor keeps the index above zero, so the division in
calculate_scaled_supply can never trap.
That floor also caps share inflation. At the floor, a deposit mints 1,000× the
shares it would mint at index 1.0. No amount of socialization can push a share
below one thousandth of a token — that 1,000× is the whole budget.
The cost is deposit headroom. A market written down to the floor can accept only
a thousandth of the usual maximum single deposit.
Only suppliers of that one market absorb the loss. CleanBadDebtEvent records
the cleared totals. See Liquidations.
Fixed-point units
Multiply and divide helpers use half-up rounding by default, flooring where it
protects the protocol and ceiling for amounts a user owes.
Next
Markets
What a market is and how its rate model is configured.
Risk parameters
Reserve factor, caps, dust floors, and the rate-model constraints.
Liquidations
How bad debt is triggered and socialized into the supply index.

