Caps and liquidity
How much the protocol lends is a function of measured on-chain exit depth, not of a number anybody sets. The d2 measurement, the four-term ceiling, the ratchet, and the dated tiers.
The safety of a CDP backed by a thinly traded asset does not come from the loan-to-value ratio the borrower sees. It comes from whether the collateral can actually be sold when it has to be. Fyber therefore sets its debt ceiling from a measurement of exit depth, taken on-chain, and treats the visible collateral ratio as a product parameter rather than a risk one (principle P8).
Concretely: Tier 1 borrowers get up to 58% loan-to-value, which is competitive; and the branch as a whole never lends more than four times the depth its own liquidity oracle measured.
d2: depth at 2 % slippage
d2(token) is the notional amount of token, in USD, that can be sold against USDG across the reference Uniswap pools before the average execution price moves more than 2% from the mid. Only the sell side is measured, because that is the side a liquidation uses.
Two percent rather than one: at one percent, depth on a concentrated automated market maker is tiny and noisy; at two, the measurement is stable and lands close to the liquidation bonus, which is the number it has to cover.
The measurement is on-chain and cheap (Rule R-5.4.2):
- Uniswap v2 pairs: a closed-form calculation over the reserves.
- Uniswap v3 pools:
slot0plus iteration over initialised ticks viatickBitmapacross roughly ±198 ticks around the active tick. - Uniswap v4 pools: the same, read through
StateView.
The result is converted to USD at the oracle's last regular close, never at the DEX spot price. Using the spot price would make the cap a function of the same pool the cap is trying to measure.
Pool addresses are immutable, chosen seven days before deployment on measured depth, and never changed. A cost of roughly 150 000 to 300 000 gas per sample for three pools is expected.
Sampling and the ratchet
function poke() external; // permissionless; fills the current hourly slot if it is emptypoke() writes d2_now into a circular buffer of 168 hourly slots — seven days, packed. A slot is never rewritten within its hour. Every open and borrow calls poke() if the current slot is empty, so the borrower pays for the sample and the buffer fills without any keeper.
The effective value applies a 25th percentile and a one-way ratchet:
How it is calculated
d2_eff = min(d2_now, P25(buffer)), with: any fall applied immediately; a rise in P25 applied
only after 24 hours and capped at +20% per day; and, if no sample has been taken for 48 hours,
d2_eff decaying by 10% per day toward zero.
The 25th percentile rather than the mean or the peak is taken from the Ethena collateral framework, and for the same reason: automated market maker liquidity is extremely asymmetric over time, and a liquidation statistically arrives during a trough.
Guarantee
An attacker can lower the caps and cannot raise them. Lowering them means withdrawing real liquidity, which is a genuine signal rather than an attack. Raising them requires real capital in range for seven days, then 24 hours of delay, then a 20 %-per-day climb — and the downward ratchet closes the cap again the moment the capital leaves (Rule R-5.4.2, invariant 20).
There is no d2_floor and no d2_ceil set by anyone: the floor is zero, and the ceiling is implied by the absolute tier through the outer min.
Failure modes are all restrictive and none of them touch existing positions: a pool migrating to an unknown version, a redeployed StateView, liquidity moving to an unlisted pool all drive d2 toward zero, which closes minting and leaves positions untouched. The correction is a new version of the protocol, not a setter.
The debt ceiling
Four terms, each read on-chain, combined by a minimum (Rule R-5.4.1):
How it is calculated
D_max(t) = min( κ × d2_eff, σ × MC_onchain, C_abs(t), max(ρ, 1 / n_active) × Σ_active C_abs_i(t) ), and D_max(t) = 0 while the branch is dormant
with MC_onchain = token.totalSupply() × quote.price / 1e18.
| Term | Tier 1 | Tier 2 | What it constrains |
|---|---|---|---|
κ (multiple of d2_eff) | 4.0 | 2.5 | Exit liquidity: liquidating κ × d2 costs roughly 6% (A) or 4% (B) of slippage spread over hours, below the liquidation bonus in both cases |
σ (share of on-chain market cap) | 15% | 10% | Share of the token's supply the protocol may immobilise |
C_abs(t) | dated tiers | dated tiers | An absolute cap that opens on a schedule |
ρ (share of the sum of tiers) | 40% | 25% | Concentration between branches |
π (position maximum, × d2_eff) | 1.0 | 0.75 | No single position larger than the measured depth |
The ρ term applies to the sum of the absolute tiers of activated branches, not to live debt — a term on live debt would be circular. The max(ρ, 1/n) form exists so that with only two branches active, each can still reach its own tier (Rule R-5.4.1, decision D46).
Per-address cap
How it is calculated
addressCap(t) = min(50 000 USD, 10% × D_max(t)) until DEPLOY_TS + 90 days, then min(π × d2_eff, 10% × D_max(t))
This is a formula of time and state; there is nothing to raise (Rule R-5.4.3). It is trivially circumvented by using several addresses, and that is understood: its purpose is to make concentration visible on-chain during the first ninety days, not to prevent it.
Dated absolute tiers
C_abs(t) replaces the raise-the-ceiling-by-governance pattern. Each branch carries an immutable table of four tiers, dated from its own activation, with two on-chain guards (Rule R-5.4.4):
| Tier, from activation | SPY, QQQ | GLD, VTI | SLV, CSCO | Condition |
|---|---|---|---|---|
| 0 to +14 days | 100 k USD | 100 k USD | 100 k USD | Observation period |
| +14 to +90 days | 1.0 M | 500 k | 500 k | — |
| +90 to +180 days | 2.0 M | 1.0 M | 1.0 M | badDebtCumul == 0 |
| +180 days onward | 3.0 M | 1.5 M | 1.5 M | badDebtCumul == 0 and branch TCR ≥ 200% at the moment of the mint |
C_abs(t) is the current tier when its conditions hold; otherwise it is the last tier whose conditions were met, permanently. badDebtCumul never decreases, so a single episode of bad debt locks the branch at whatever tier it had reached — irreversibly, even if the bad debt is later covered or repaid in full. The TCR condition is re-evaluated at every mint and does not lock anything.
Events: CapTierReached, CapTierLocked.
Guarantee
A branch that has ever produced bad debt can never grow again. Its ceiling is frozen at the tier in force when the first entry was recorded, for every subsequent sequence including full repayment, backstop coverage and redistribution. This is a fuzzed invariant (Rule R-5.4.4, Rule R-16.3 item 21).
A tier that turns out too cautious is corrected only in a future version. A tier that turns out too generous is caught by κ × d2 and σ × MC in the same minimum.
The global ceiling
How it is calculated
globalCeiling(t) = Σ_{activated branches} C_abs_i(t)
That is 2 M USD from day 14 to day 90 with SPY and QQQ active, at most 6 M at day 180 with two branches, and up to 10.5 M if all twenty branches ever reach their final tier. It is never set and never raised — it is the sum of the tiers (Rule R-5.4.7).
The number is small by design. The whole on-chain market capitalisation of Robinhood Stock Tokens was roughly 42 M USD at the time the parameters were fixed. Designing for 50 M of debt on day one is the fastest route to being the protocol whose collateral cannot be sold.
When a cap falls below existing debt
Guarantee
A cap that drops below the branch's current debt — because d2_eff fell, or because a tier locked
— blocks new borrowing and nothing else. It never triggers a liquidation, never forces a
repayment, and never changes the terms of an open position (Rule R-5.4.5).
A capacity queue exists only in the front end: users can ask to be notified when debtCeiling() − getEntireDebt() rises above the amount they want. There is no on-chain queue and no reservation (Rule R-5.4.6).
Worked example
A branch at day 120 from activation, third tier, with d2_eff = 1 000 000 and an on-chain market capitalisation of 40 M USD, with two branches active and both at 2.0 M:
κ × d2_eff = 4.0 × 1 000 000 = 4 000 000
σ × MC_onchain = 15% × 40 000 000 = 6 000 000
C_abs(t) = 2 000 000
max(40%, 1/2) × Σ C_abs = 50% × 4 000 000 = 2 000 000
D_max = min(...) = 2 000 000
addressCap = min(π × d2_eff = 1 000 000, 10% × 2 000 000) = 200 000
positionMax = π × d2_eff = 1 000 000The binding term here is the absolute tier. A front end shows which term binds, together with the dates and conditions of the next tier, so a borrower can see not just the remaining capacity but why it is what it is (Rule R-15.1.5).
Last reviewed: 2026-09-07 · Spec v0.4
Interest distribution
Interest is minted at accrual, split by formula between the Stability Pool, the backstop, the treasury and liquidity incentives, and the rate floor is read from an on-chain reference.
Branches and versions
A closed registry, twenty branches deployed at genesis, eighteen dormant ones that activate on measured criteria, and how a version 2 replaces a version 1 without trapping anybody.