CFDL

Waterfalls

A waterfall is a priority of payments: an ordered list of steps sharing out a pot of cash. Each step takes what it is owed, up to what is left, and the remainder passes down.

It is how a securitisation pays its tranches, how a fund pays a preferred return before carry, and how a project pays lenders before equity.

The shape

waterfall deal.distribution on entity asset.trust {
  schedule every month from 2026-01 to 2030-12
  from asset.trust.available_funds

  pay servicing to party.servicer    = 12500.0
  pay senior    to asset.class_a     = 6250.0
  pay residual  to party.certificate = remaining
}

Three parts:

  • on entity — whose cash this is.
  • schedule — when it runs. The same construct a stream takes.
  • from — the pot.

Then the steps, in the order they are paid.

One form for every step

A step is pay <name> to <payee> = <expr>. There is no separate syntax per kind of payment, because every kind is arithmetic:

what you wanthow to write it
a fixed amount= 12500.0
capped at a limit= min(fee, cap)
pay a balance down to a target= asset.class_a.balance - asset.trust.pool_balance
top an account up to a level= inputs.specified_reserve - asset.reserve.balance
only on a certain date= if(time.t >= 24, balance, 0.0)
an earlier step's shortfall= owed.trustee_fee - paid.trustee_fee
everything left= remaining

Three names a step can read

On top of everything an ordinary expression sees:

remainingwhat is still in the pot at this step
paid.<step>what an earlier step actually paid
owed.<step>what an earlier step would have paid, unbounded

A step also reaches any other entity's declared properties by naming it — asset.class_a.original_balance — which is how one tranche's step reads another's balance. entity.asset.class_a.original_balance is the same read spelled the long way.

owed and paid differ exactly when a step could not be paid in full, so their difference is the shortfall. That is how a capped fee gets its overflow paid later, and how a step measures a balance "after giving effect to" the payments above it.

A step may only read steps declared before it. Reading a later one is a compile error, because a priority of payments is an order, not a system of equations.

The pot never goes negative

Every step pays min(max(0, your expression), remaining).

You do not have to write min(..., remaining) yourself, and a step that asks for more than is left simply takes what is left. A negative expression pays nothing rather than clawing cash back.

That also makes = remaining mean exactly what it says.

Say where the remainder goes

At least one step must read remaining, or the model does not compile.

Without it, whatever survives the last step would vanish with nothing to show for it. Naming the residual is the difference between a model that says the sponsor keeps the excess and one that quietly loses it.

When it runs

A waterfall is a post-cash-flow distribution: it runs after the period's streams and states are known, so it allocates money that already exists. It never feeds a stream in the same period.

Two shapes cover most deals, and a model can use both at once:

// Every period — a distribution date, a debt service cascade.
schedule every month from 2026-01 to 2030-12

// Once — an exit, a liquidation, a final recoupment.
schedule on 2030-12

What comes out

Each step publishes as a series named stream.<waterfall>.<step>, and its cash counts toward the payee's total. A waterfall is not a separate kind of output: statements, metrics and the results document read it the way they read anything else.

One waterfall's output as another's pot

Because steps publish as series, a later waterfall can draw on an earlier one:

waterfall fund.distribution on entity asset.fund {
  schedule on 2025-01
  from inputs.proceeds
  pay carry    to party.gp = remaining * 0.20
  pay lp_share to party.lp = remaining
}

waterfall firm.carry_split on entity asset.mgmt_co {
  schedule on 2025-01
  from series_sum("fund.distribution.carry", 0, 5)
  pay team_pool  to party.team     = remaining * 0.40
  pay firm_share to party.founders = remaining
}

The rule is the same order that governs steps: a waterfall may read any waterfall declared before it. That is what a fund carry rolling into a management company and out again to a stakeholder needs, and it keeps the second pot as a computed number rather than an assumption holding a stale copy of it.

Worked structures

Six real waterfalls are encoded in the test suite, and between them they use only the rules above.

A 22-step consumer ABS priority of payments — servicer and trustee ahead of the notes, five rated classes taking interest then principal in strict seniority, a reserve topped to its specified level, an overcollateralisation target, and a certificateholder taking what survives.

A private fund carry waterfall — capital back, a compounding 8% preferred return, a full GP catch-up, then 80/20. It reproduces its published figures exactly, and one definition covers three published structures: the only thing separating them is what the catch-up is computed on, which is an argument.

An LBO exit split — the sponsor's converted preferred against management's rollover and exercised options.

An IRR-hurdle waterfall — three participants whose vested percentages step up as the LP's return crosses eight hurdles.

A GP stakes nested split — a fund waterfall, then the management company's split with the deal team, then the founders against a passive minority investor. Three waterfalls, each drawing on the one above.

A partial catch-up — the same fund waterfall where the GP takes half of each dollar above the preferred instead of all of it. Set the catch-up rate to 1 and it returns the full catch-up's numbers exactly; the two structures are one expression with a different argument.

On hurdles and catch-ups

Both of the last two are commonly said to need an iterative solver. Neither does, and the reason is worth knowing before you reach for one.

A catch-up that pays the GP 20% of everything distributed in two tiers combined is X / (pref + X) = 0.20, so X = pref / 4. One division.

An IRR hurdle does not solve for a rate — the rate is an input. What is unknown is the payment that reaches it, and present value is linear in a payment at a fixed rate. Where a hurdle also selects among tiers, the thresholds are computable in advance and choosing between them is an ordered comparison.

So a waterfall step stays an expression, and the language needs no solver to carry these structures.