Waterfalls
Every structured deal ends in the same question: who gets paid, in what order, out of what? A securitization's priority of payments, a fund's distribution clause, and a JV's promote are all the same shape: a pot of cash, and a sequence of claims, each taking what it is owed until the pot runs out. Spreadsheets model this shape with their most fragile machinery — chains of MIN(MAX(...)) cells where one wrong reference pays a junior claim ahead of a senior one. The language makes the shape a construct: the waterfall.
Pot, steps, payees
version 0.1
model "waterfall-first"
time calendar quarterly from 2026-01 for 8
// The trust collects; the parties are paid from what it collects.
entity asset trust : Asset.Financial
entity party servicer : Party
entity party lender : Party
entity party investor : Party
// The cash. The waterfall's pot is this, netted — the engine hands it over
// as `available`, so nothing restates it.
stream trust.collections on entity asset.trust inflow currency USD {
schedule every quarter from 2026-01 to 2027-10
amount = 100000
}
waterfall trust.distribution on entity asset.trust {
schedule every quarter from 2026-01 to 2027-10
from available
// Each step: pay <name> to <payee> = <amount it is owed>.
pay servicing_fee to party.servicer = 4500
pay debt_service to party.lender = 62000
pay residual to party.investor = remaining
}A waterfall has three parts. It has a schedule, because it distributes on dates like any claim. It has a pot, written as the from expression; available is the trust's own netted cash for the period, handed over by the engine the way remaining is. And it has ordered steps. Each step names itself, names its payee (an entity reference — this is where chapter 2's parties earn their place in the cast), and states what the step is owed as an ordinary expression.
The engine applies one rule at every step: the step receives min(max(0, owed), remaining). That single rule is the construct's guarantee — the pot cannot go negative, and no step can be paid more than what survives the steps above it — however any individual step is written. The seniority logic that a spreadsheet re-implements per cell, correctly or not, is here the meaning of the construct itself, proved once in the engine rather than per model. What is left after a step is remaining, and a final = remaining step sweeps the residual — the equity's position in one word.
Each step publishes as a series under the waterfall's name, so results show the full allocation grid: who was owed what, who received what, period by period.
owed and paid: shortfalls made visible
Steps can read each other through two special names: owed.<step> — what a step was entitled to this period — and paid.<step> — what it actually received. Their difference is the step's shortfall, and real documents are full of clauses about exactly that:
// A junior fee is deferred when funds run short; the deferral claim ranks
// lower than current fees, exactly as the indenture says.
pay junior_fee_current to party.manager = 8000
pay senior_note to asset.class_a = 55000
pay junior_fee_deferred to party.manager = owed.junior_fee_current - paid.junior_fee_currentEvery step also publishes its shortfall as a series of its own, shortfall.<waterfall>.<step>: what it was owed less what it took, each period. It is not cash and joins no total, but it is the first thing an analyst reads on a short distribution date, and a metric or a later waterfall reads it by that name.
A shortfall that must be paid on a later date is the claim's business, not the step's. Write the claim as what is owed to date less what the payee's account has received, prev.<account>, and an amount unpaid this period is still in the claim at the next.
Five expression shapes cover essentially every step a real priority of payments contains:
- A stated amount —
4500. - A capped amount —
min(fee, cap). - Pay-down-to-a-target —
balance - target. - An earlier step's shortfall —
owed.x - paid.x. - The sweep —
remaining.
Learn to see any indenture's payment section as combinations of these five, and transcription becomes mechanical: read a clause, write a step, in document order. The model reads in the same order the lawyer wrote, which is what makes review by the person who negotiated the document possible at all.
Accounts: cash that waits
When cash should accumulate between distribution dates rather than pay out each period, the accumulation has its own object: the account, a declared cash location whose balance carries across periods. The reserve pattern — fund to target, top up when short — is one account and one step:
version 0.1
model "waterfall-reserve"
time calendar quarterly from 2026-01 for 8
entity asset trust : Asset.Financial
entity party lender : Party
entity party investor : Party
stream trust.collections on entity asset.trust inflow currency USD {
schedule every quarter from 2026-01 to 2027-10
amount = 100000
}
// A reserve the structure holds, opening with 20,000 in it.
account reserve {
init 20000
}
waterfall trust.distribution on entity asset.trust {
schedule every quarter from 2026-01 to 2027-10
from available
pay debt_service to party.lender = 62000
// Top the reserve up to 50,000, reading the balance the quarter opened with.
pay reserve_top_up to account reserve = max(0, 50000 - prev.reserve)
pay residual to party.investor = remaining
}What an account can state, and how the rest of the model meets it:
initis the balance when the model opens; it defaults to zero.fromis an inflow each period, an expression over cash that has settled. It may be negative, and the balance has no floor.owner party.<name>makes the account hold what has been allocated to that party. A party may own several accounts, such as a noteholder's interest and its principal. A step writtento party.<name>then cannot tell which one is meant, and is refused (E1324); the step names its destination,to account <name>. A party's return,irr(party.<name>), folds every account the party owns.- A side. An account declared on an entity,
account balance owed init 1000000(chapter 8), is a claim:owedis a liability of its owner,duea receivable, and a stream thatmovesit changes it in the direction the side says. A pack contract opens its own accounts, one per contract. - Folds. A container's account of a name is the sum of its members' accounts of that name through
part of. It is declared nowhere and read asprev.container.<name>.<account>. - Reading it.
prev.<account>is the balance at the previous period's close, every allocation included. Nothing reads a same-period close. A waterfall can also draw from an account,from reserve, in place of a hand-written cumulative window: the pot is the accumulated balance, and what the steps leave stays for the next scheduled date.
available keeps meaning this period's netted cash. The account's balance publishes as its own series, account.reserve, and never enters a cash total: the step is the flow, the balance is the position.
Paying an agreement's line
In a structured deal, a step does not just pay a party; it pays a class of notes its interest, or an equity interest its distribution. When a pack contract declares a line allocated — paid by the priority of payments rather than by the contract's own rule — a step can say so:
waterfall notes.interest on entity container.trust {
schedule every month from 2026-01 to 2026-12
from interest_collections
pay a_interest to party.class_a_holder for contract credit.note.a line interest = inputs.a_coupon
pay for contract "credit.note.*" line principal
pay residual to party.equity = remaining
}for contract <name> line <role>attaches the step to the agreement and its line. The step's series then carries the contract and the line, and the results graph lists the step under the contract. A contract the model does not declare is refused (E1376), and so is a line the type does not declare allocated (E1377): a line the contract's rule already pays would be counted twice.- Without naming it. A step that pays a party the allocated line of exactly one agreement binding that party is attributed to that line as if it had named it. Where more than one could qualify, the step names the line.
pay for contract <name or selector> line <role>is one step per matching contract, each from the rule the contract's pack declares for that line, paid in its place among the other steps. The contributed steps are ordered by each contract'sseniority, 1 first, then the rest in declaration order.- Warnings. An allocated line no step pays is reported (
W1389), and so is a step paying a contract written on an entity outside the waterfall's subject and itspart offamily (W1390).
The promote: equity's waterfall
The same construct expresses the private-equity shapes. A simplified preferred-return-then-promote split over annual distributable cash:
version 0.1
model "waterfall-promote"
time calendar annual from 2026-01 for 4
entity asset venture : Asset.Financial {
distributable init 500000
next 500000
}
entity party lp : Party
entity party gp : Party
stream venture.cash_generated on entity asset.venture inflow currency USD {
schedule every year from 2026-01 to 2029-01
amount = asset.venture.distributable
}
waterfall venture.split on entity asset.venture {
schedule every year from 2026-01 to 2029-01
from asset.venture.distributable
// The LP's 8% preferred on committed capital, then capital back, then
// the GP's 20% promote on what remains, then the LP's share of the rest.
pay lp_preferred to party.lp = 4000000 * 0.08
pay lp_capital to party.lp = 100000
pay gp_promote to party.gp = remaining * 0.20
pay lp_residual to party.lp = remaining
}Note what remaining * 0.20 does: a step's owed amount can read the pot mid-flow, so proportional splits fall out of the same five shapes. A full promote with IRR hurdles and catch-up provisions is these pieces plus accrual fields, and the capstone's final chapter builds one over the whole deal.
Waterfalls also chain. Because steps publish as series, a waterfall can read the steps of a waterfall declared before it — a property-level distribution feeding a fund-level one. That is how multi-tier structures stay legible instead of collapsing into one giant priority list. The order is the declaration order: a read of a step from the same waterfall's later steps or from a later waterfall is refused (E1342), and so is a read of a step from a stream, a field, an event, an option or an account's inflow (E1346), since those run before any waterfall.
What the construct refuses
No step can overdraw the pot. No step can pay negatively: a step is a payment, not a clawback, and a true clawback is cash the other way — a stream. And no step can be referenced before it runs, because owed.x looks up the priority list and never down; a forward reference is refused at compile. Each refusal corresponds to a way spreadsheet waterfalls actually fail; each is impossible to express rather than checked after the fact.
What can go wrong
The pot is wrong. The waterfall allocates whatever from says, and if that expression misses a revenue line, every step downstream is quietly short. The pot deserves the chapter-3 treatment: one period, by hand, reconciled to the sources that feed it, before any step is trusted.
A step that reads like the document but ranks differently. The construct guarantees seniority within the order you wrote — it cannot know the indenture ordered things differently. Transcribe in document order, then have the person who knows the document read your steps top to bottom. That review is the point of the shape matching.
No sweep at all. A waterfall with no step that reads remaining is refused (E1344), so the residual always has a named payee instead of vanishing. The one exception is a waterfall that draws from an account: what its steps leave stays in the account for the next date. remaining mid-list is legal and sometimes correct (the promote above); check that the residual series is what equity expects.
Exercises
Transcribe the priority of payments
The trust receives 100,000 a quarter. The documents pay a 4,500 servicing fee, then 62,000 of debt service, then everything remaining to the investor.
- Write the waterfall in document order.
- Pay
from available- the trust's own cash, which the engine hands the waterfall.
Check by allocation: every quarter must account for exactly 100,000 across the three steps — 4,500 + 62,000 + 33,500.
Then stress the structure in your head. Set collections to 60,000 and name who is short, and by how much. The engine's answer, when you try it, is in the owed-versus-paid columns.
Then, on your own:
- In the exercise's solution, swap the order of the debt-service and management-fee steps and rerun. Watch which party's series changes and by how much — you have just measured what "seniority" is worth in dollars.
- Shrink the pot until the junior steps starve (set collections to 60,000) and read each step's
shortfall.series in the output. Then add a deferred-fee step that catches this period's shortfall below the senior note, usingowed.x - paid.x.