Skip to main content

Vault Fee Waterfall

Signals v1 realizes maker-side performance once per day. At that daily batch boundary, trading PnL and gross fees are turned into an explicit allocation across the maker capital stack.

This page describes the fee waterfall as an algorithm. It is the accounting rule that maps a day into:

  • the LP credit for the day,
  • the new backstop balance,
  • and the new treasury balance.

Ordering and rounding are fixed so the same day inputs produce the same outputs. The waterfall is defined as an algorithm, not as a discretionary process.

State and notation

The waterfall takes a pre-batch state and a day input.

Pre-batch state:

  • Nt1N_{t-1}: maker NAV before the day, WAD
  • Bt1B_{t-1}: backstop NAV before the day, WAD
  • Tt1T_{t-1}: treasury NAV before the day, WAD

Day inputs:

  • LtL_t: maker trading PnL for the day, signed WAD
  • FttotF^{\text{tot}}_t: gross fees generated during the day, WAD

Policy and safety configuration:

  • ΔEt\Delta E_t: tail budget available for backstop support, WAD
  • pdd(1,0)\text{pdd} \in (-1, 0): drawdown floor parameter, WAD
  • ρBS\rho_{BS}: backstop coverage ratio, WAD
  • ϕLP,ϕBS,ϕTR\phi_{LP}, \phi_{BS}, \phi_{TR}: residual fee split weights, WAD

Throughout, "WAD" means 101810^{18} fixed-point units. Token-level rounding is a separate surface; the waterfall itself is defined at WAD precision.

Two validity constraints are enforced by the mechanism:

ϕLP+ϕBS+ϕTR=1\phi_{LP} + \phi_{BS} + \phi_{TR} = 1 1<pdd<0-1 < \text{pdd} < 0

Algorithm

The waterfall is easiest to read as five steps. Each step produces intermediate values that also act as safety checks.

Step 1: Loss compensation from fees

Define the negative part of the day PnL:

Lt=max(0,Lt)L^-_t = \max(0, -L_t)

Use gross fees to compensate losses first, up to the magnitude of the loss:

Ftloss=min(Fttot,Lt)F^{\text{loss}}_t = \min\left(F^{\text{tot}}_t, L^-_t\right)

The remaining fee pool is:

Ftpool=FttotFtlossF^{\text{pool}}_t = F^{\text{tot}}_t - F^{\text{loss}}_t

Define NAV after applying trading PnL and loss compensation:

Ntraw=Nt1+Lt+FtlossN^{\text{raw}}_t = N_{t-1} + L_t + F^{\text{loss}}_t

Catastrophic losses that would make NtrawN^{\text{raw}}_t negative are rejected by reverting the batch.

Step 2: NAV floor and backstop grant

The waterfall enforces a NAV floor derived from the prior NAV:

Ntfloor=Nt1(1+pdd)N^{\text{floor}}_t = \left\lceil N_{t-1} \cdot (1 + \text{pdd}) \right\rceil

The ceiling is intentional. It makes the floor conservative in the direction that increases the required grant.

Grant need is the shortfall below the floor:

Gtneed=max(0,NtfloorNtraw)G^{\text{need}}_t = \max\left(0, N^{\text{floor}}_t - N^{\text{raw}}_t\right)

Two safety constraints are enforced as hard reverts:

GtneedΔEtG^{\text{need}}_t \le \Delta E_t GtneedBt1G^{\text{need}}_t \le B_{t-1}

If both hold, the grant is applied without further capping:

Gt=GtneedG_t = G^{\text{need}}_t

After the grant:

Ntgrant=Ntraw+GtN^{\text{grant}}_t = N^{\text{raw}}_t + G_t Btgrant=Bt1GtB^{\text{grant}}_t = B_{t-1} - G_t

Step 3: Backstop coverage fill from fees

The backstop has a target balance proportional to maker NAV:

Bttarget=ρBSNtgrantB^{\text{target}}_t = \rho_{BS} \cdot N^{\text{grant}}_t

The amount needed to reach the target is:

ΔBtneed=max(0,BttargetBtgrant)\Delta B^{\text{need}}_t = \max\left(0, B^{\text{target}}_t - B^{\text{grant}}_t\right)

Fees fill the backstop toward the target before any residual split:

Ftfill=min(ΔBtneed,Ftpool)F^{\text{fill}}_t = \min\left(\Delta B^{\text{need}}_t, F^{\text{pool}}_t\right)

The remaining fee amount after fill is:

Ftremain=FtpoolFtfillF^{\text{remain}}_t = F^{\text{pool}}_t - F^{\text{fill}}_t

Step 4: Residual split with dust to LP

Residual fees are split by weights. The split uses floor arithmetic:

FLPcore=FtremainϕLPF^{\text{core}}_{LP} = \left\lfloor F^{\text{remain}}_t \cdot \phi_{LP} \right\rfloor FBScore=FtremainϕBSF^{\text{core}}_{BS} = \left\lfloor F^{\text{remain}}_t \cdot \phi_{BS} \right\rfloor FTRcore=FtremainϕTRF^{\text{core}}_{TR} = \left\lfloor F^{\text{remain}}_t \cdot \phi_{TR} \right\rfloor

Because each component is floored, a remainder exists:

Ftdust=FtremainFLPcoreFBScoreFTRcoreF^{\text{dust}}_t = F^{\text{remain}}_t - F^{\text{core}}_{LP} - F^{\text{core}}_{BS} - F^{\text{core}}_{TR}

That dust is assigned to LP.

Step 5: Output balances

Define the total fee credited to LP:

Ft=Ftloss+FLPcore+FtdustF_t = F^{\text{loss}}_t + F^{\text{core}}_{LP} + F^{\text{dust}}_t

The pre-batch NAV used by vault share accounting is:

Ntpre=Ntgrant+FLPcore+FtdustN^{\text{pre}}_t = N^{\text{grant}}_t + F^{\text{core}}_{LP} + F^{\text{dust}}_t

The next backstop and treasury balances are:

Bt=Btgrant+Ftfill+FBScoreB_t = B^{\text{grant}}_t + F^{\text{fill}}_t + F^{\text{core}}_{BS} Tt=Tt1+FTRcoreT_t = T_{t-1} + F^{\text{core}}_{TR}

Revert surface and hard constraints

The waterfall executes as contract logic and has explicit revert conditions.

Parameter validity:

  • The residual weights must sum to one exactly at WAD precision: ϕLP+ϕBS+ϕTR=1\phi_{LP} + \phi_{BS} + \phi_{TR} = 1.
  • The drawdown floor parameter must satisfy 1<pdd<0-1 < \text{pdd} < 0.

Day safety:

  • Catastrophic loss that would push maker NAV negative causes a revert.
  • Tail budget violation causes a revert:
Gtneed>ΔEt  revertG^{\text{need}}_t > \Delta E_t \ \Rightarrow\ \text{revert}
  • Backstop insufficiency causes a revert:
Gtneed>Bt1  revertG^{\text{need}}_t > B_{t-1} \ \Rightarrow\ \text{revert}

These constraints define what it means for a day to be processable by the maker accounting layer.

Rounding and dust

Rounding is part of the contract.

Two details are easy to miss:

  • The NAV floor uses a ceiling. It is computed conservatively high, which can increase grantNeed by at most one unit of WAD rounding.
  • The residual split uses floor arithmetic. The remainder becomes FtdustF^{\text{dust}}_t and is assigned to LP.

Dust is bounded by fixed-point arithmetic. It is not a discretionary pool and it does not accumulate as an ambiguous residual.

Worked examples

Examples are shown in whole tokens for readability. Internally they correspond to WAD values.

Example A: Gain day with residual split

Assume:

  • Nt1=1,000N_{t-1} = 1{,}000
  • Bt1=200B_{t-1} = 200
  • Tt1=0T_{t-1} = 0
  • Lt=+8L_t = +8
  • Fttot=12F^{\text{tot}}_t = 12
  • ρBS=0.2\rho_{BS} = 0.2
  • ϕLP=0.7, ϕBS=0.2, ϕTR=0.1\phi_{LP} = 0.7,\ \phi_{BS} = 0.2,\ \phi_{TR} = 0.1

Loss compensation is zero because Lt=0L^-_t = 0, so Ftloss=0F^{\text{loss}}_t = 0 and Ftpool=12F^{\text{pool}}_t = 12. NAV after the day is Ntraw=1008N^{\text{raw}}_t = 1008.

With no grant, Ntgrant=1008N^{\text{grant}}_t = 1008 and Btgrant=200B^{\text{grant}}_t = 200. Backstop target is Bttarget=0.21008=201.6B^{\text{target}}_t = 0.2 \cdot 1008 = 201.6, so ΔBtneed=1.6\Delta B^{\text{need}}_t = 1.6 and Ftfill=1.6F^{\text{fill}}_t = 1.6.

Residual fees are Ftremain=10.4F^{\text{remain}}_t = 10.4. The floor split gives:

FLPcore=10.40.7,FBScore=10.40.2,FTRcore=10.40.1F^{\text{core}}_{LP} = \lfloor 10.4 \cdot 0.7 \rfloor,\quad F^{\text{core}}_{BS} = \lfloor 10.4 \cdot 0.2 \rfloor,\quad F^{\text{core}}_{TR} = \lfloor 10.4 \cdot 0.1 \rfloor

Any rounding remainder becomes FtdustF^{\text{dust}}_t and is credited to LP. The outputs follow mechanically from the formulas above.

Example B: Loss day that triggers a grant

Assume:

  • Nt1=1,000N_{t-1} = 1{,}000
  • Bt1=200B_{t-1} = 200
  • Tt1=0T_{t-1} = 0
  • Lt=450L_t = -450
  • Fttot=10F^{\text{tot}}_t = 10
  • pdd=0.3\text{pdd} = -0.3
  • ΔEt=200\Delta E_t = 200

Loss compensation uses fees first:

Lt=450,Ftloss=min(10,450)=10,Ftpool=0L^-_t = 450,\quad F^{\text{loss}}_t = \min(10, 450) = 10,\quad F^{\text{pool}}_t = 0

NAV after loss compensation is:

Ntraw=1000450+10=560N^{\text{raw}}_t = 1000 - 450 + 10 = 560

The NAV floor is Ntfloor=10000.7=700N^{\text{floor}}_t = \lceil 1000 \cdot 0.7 \rceil = 700, so the grant need is:

Gtneed=700560=140G^{\text{need}}_t = 700 - 560 = 140

Both safety constraints hold in this setup: 140ΔEt140 \le \Delta E_t and 140Bt1140 \le B_{t-1}. The batch applies Gt=140G_t = 140, bringing maker NAV back to the floor for the next day:

Ntgrant=560+140=700,Btgrant=200140=60N^{\text{grant}}_t = 560 + 140 = 700,\quad B^{\text{grant}}_t = 200 - 140 = 60

With Ftpool=0F^{\text{pool}}_t = 0, there is no backstop fill and no residual split on this day. The update is entirely the PnL realization plus the floor grant.

Example C: Loss day that reverts under tail budget

Assume:

  • Nt1=1,000N_{t-1} = 1{,}000
  • Bt1=200B_{t-1} = 200
  • Lt=700L_t = -700
  • Fttot=0F^{\text{tot}}_t = 0
  • pdd=0.3\text{pdd} = -0.3
  • ΔEt=100\Delta E_t = 100

Then Ntraw=300N^{\text{raw}}_t = 300 and Ntfloor=700N^{\text{floor}}_t = 700, so Gtneed=400G^{\text{need}}_t = 400. Because 400>ΔEt400 > \Delta E_t, the batch reverts.

This is intended behavior. Tail budget is the mechanism-level bound on how much backstop support can be required by the NAV floor rule for that batch.