Contract and fees
Start with the scheduled cash flows of one Agreement: what the Buyer pays, what BTC Now retains, and what reaches the Holder. This chapter derives the payment schedule, implied financing rate, remaining balances and fee rounding.
Implementation: contract.rs, fees.rs, money.rs, and the origination and payment steps of engine.rs::run. The reference fixtures are M0_FIXTURES.md.
The worked numbers use the base terms throughout: a $60,000 coin, a 1.475× multiple, 60 monthly payments, the first payment to BTC Now, a flat 5% servicing fee on every dollar delivered to the Holder, and a Holder who buys at par. Every figure below is either printed by the engine, asserted by a test, or one line of arithmetic from a figure that is.
The terms in one line
An Agreement is a conditional sale of one coin. The Buyer pays a fixed dollar schedule; when the schedule is complete, title to the coin passes. The engine’s contract.rs::ContractTerms holds five fields:
| Field | Meaning | Base value |
|---|---|---|
strike | The coin’s dollar cost at origination, quantized to cents | $60,000.00 |
multiple | The price multiple over the strike | 1.475 |
term_months | Number of monthly payments | 60 |
origination_payments | First N payments routed whole to BTC Now (0 = off) | 1 |
servicing_fee_rate | Flat share of every delivered dollar | 0.05 |
Nothing in contract.rs may hard-code a term. “Sixty months” is a default, not an assumption (spec v1.1 change 1, Marc, 2026-07-10). Every quantity below is written for a general term \(n\) and then evaluated at \(n = 60\).
Money is rust_decimal::Decimal quantized to cents; rates and boundaries are f64. money.rs::cents rounds half-to-even. A ledger posting is never an f64 (project rule 5).
The terminal value
The terminal value is the Agreement’s full dollar price, the Purchase Price in the program’s contract language:
\[ P = \text{cents}(\text{strike} \times \text{multiple}) . \]
At the base terms \(P = 60{,}000 \times 1.475 = $88{,}500.00\). This is contract.rs::ContractTerms::terminal. The engine’s stop waterfall calls this quantity \(P\) as well; the letter is shared on purpose (see the stop waterfall).
The schedule and convention C1
The nominal payment is the terminal value divided by the term:
\[ \text{PMT} = \frac{P}{n} = \frac{\text{strike} \times \text{multiple}}{n} . \]
At the base terms \(\text{PMT} = 88{,}500 / 60 = $1{,}475.00\), a whole number of cents. At other terms it usually is not, and a schedule of sixty identical cent amounts would not sum to the terminal. Convention C1 fixes this (M0_FIXTURES.md, amended after adversarial review 2026-07-11):
- Quantize PMT to cents rounding toward zero (a floor, for positive money).
- Every payment but the last is that floored amount.
- The final payment absorbs the residual, so the schedule sums to \(P\) exactly.
In contract.rs::ContractTerms::schedule:
\[ \text{PMT}^* = \lfloor \text{PMT} \rfloor_{0.01}, \qquad p_t = \text{PMT}^* ;(t < n), \qquad p_n = P - (n-1),\text{PMT}^* . \]
The floor, rather than half-even rounding, is what makes \(p_n \ge \text{PMT}^*\) at every strike. With half-even rounding an upward round on a tiny strike could push \((n-1),\text{PMT}^*\) past \(P\) and make the last payment negative; the invariant tiny_strike_schedule_never_goes_negative runs a $10 coin over 84 months to hold the line.
The 36-month example shows the residual:
| Term | \(P/n\) unquantized | \(\text{PMT}^*\) | Payments 1 to \(n-1\) sum to | Final payment |
|---|---|---|---|---|
| 36 | 2,458.333… | $2,458.33 | $86,041.55 | $2,458.45 |
| 48 | 1,843.75 | $1,843.75 | $86,656.25 | $1,843.75 |
| 60 | 1,475.00 | $1,475.00 | $87,025.00 | $1,475.00 |
| 84 | 1,053.5714… | $1,053.57 | $87,446.31 | $1,053.69 |
At 36 months the last payment is twelve cents larger than the others; at 84 months, twelve cents as well. The unit test residual_absorbed_at_inexact_terms in contract.rs pins the 36-month case, and schedule_sums_to_terminal_any_term checks the sum at terms 1, 7, 24, 36, 48, 60, 84 and 120.
schedule()[t-1] is payment \(t\). The engine builds the vector once per Agreement at origination and never recomputes it.
The remaining nominal schedule
After \(t\) payments the Buyer still owes the tail of the schedule:
\[ R_t = \sum_{k=t+1}^{n} p_k . \]
This is contract.rs::ContractTerms::remaining_schedule, and inside the engine engine.rs::Agreement::remaining_schedule, which reads a suffix-sum table built at origination so the lookup is one index rather than a re-sum (spec v1.4 change 13; the values are identical). Because C1 makes all but the last payment equal, at the base terms \(R_t = 88{,}500 - 1{,}475,t\): $87,025 after payment 1, $70,800 after payment 12, $60,475 after payment 19, $35,400 after payment 36, zero after payment 60.
\(R_t\) is the dollar figure the program treats as “what remains.” It is what the Buyer pays at early completion (engine.rs::settle), what the stop waterfall pays the Holder first (engine.rs::stop_sale), and the numerator of the risk desk’s schedule line \(R_t / \text{strike}\).
The Buyer’s paid-in total is the complement, \(A_t = P - R_t\) (engine.rs::Agreement::paid_in, payment 1 included). The waterfall’s refund base is this \(A\).
The implied financing rate
The paper carries a rate even though the contract states none. It is the monthly rate \(i\) at which a level payment of PMT over \(n\) months has present value equal to the strike, the ordinary annuity identity:
\[ \text{PMT} = \text{strike} \cdot \frac{i,(1+i)^n}{(1+i)^n - 1} . \]
The engine calls \(12,i\) the nominal annual rate and \((1+i)^{12} - 1\) the effective annual rate, and the accepted name for either is the implied financing rate. contract.rs::ContractTerms::implied_monthly_rate solves the identity with the unquantized PMT (\(P/n\) as a float, so the rate does not jump with a cent of C1 residual) by bisection.
Two details of the solver matter for a desk that explores below-par pricing:
- The domain is signed. Bisection runs on \(i \in [-0.5, 1.0]\) for 200 halvings. The right-hand side is increasing in \(i\) on that interval, so the bracket always contains the root. A multiple of exactly 1.0 gives \(i = 0\), and a multiple below 1.0 gives a negative rate, which is the correct reading of paper priced below its coin: at 0.90× and 60 months the solver returns a nominal rate of about −4.07% per year (invariant
below_par_multiple_gets_a_negative_implied_rate). An earlier solver clamped at zero and corrupted the moneyness boundary for below-par inputs; the signed domain is the fix. - The zero point is guarded. When \(|i| < 10^{-12}\) the identity degenerates to \(\text{strike}/n\) rather than \(0/0\).
At the base terms:
| Quantity | Value | Where checked |
|---|---|---|
| \(i\) monthly | 0.0137481 | contract.rs::implied_monthly_rate |
| Nominal, \(12,i\) | 16.4978% (16.50% in the fixtures) | unit test known_60mo_values; fixture “Paper rate nom.” |
| Effective, \((1+i)^{12}-1\) | 17.80% | arithmetic from \(i\) |
The rate is an f64, a display and boundary quantity, never a ledger amount. The engine solves it lazily, once per Agreement, on the first moneyness check (engine.rs::Agreement::implied_rate, an OnceCell); a run with neither rational mode on never pays for the bisection at all. The simulate response does not carry the rate; the report view’s configuration line prints \((\text{multiple} - 1) / \text{term-years}\), 9.5% at the base terms, which is a simple markup per year and not this rate.
Note what this rate is not. It is not the Holder’s return. The Holder pays the purchase price, not the strike, misses the first N payments, and gives up 5% of every dollar. The flat single-Agreement run at par prints an effective IRR of 13.97% against the paper’s 17.80%; the gap is BTC Now’s take. The return figures are derived in Outputs.
The remaining amortized obligation and moneyness
If the paper is read as an annuity at rate \(i\), then after \(t\) payments the Buyer’s obligation in present-value terms is the standard amortization balance:
\[ B_t = \text{strike},(1+i)^t - \text{PMT},\frac{(1+i)^t - 1}{i}, \qquad B_t = \text{strike} - \text{PMT},t ;\text{ when } i = 0 . \]
This is contract.rs::ContractTerms::remaining_obligation, with the rate solved inside, and remaining_obligation_at(t, i), the same formula with the rate supplied by the caller for hot loops. \(B_0 = \text{strike}\) and \(B_n = 0\) (unit test obligation_endpoints).
Moneyness is spot over that balance:
\[ M_t = \frac{S_t}{B_t} , \]
contract.rs::ContractTerms::moneyness. \(M_t < 1\) means the coin is worth less than the discounted value of what the Buyer still owes; the rational-default mode reads this as “underwater” (engine.rs::Agreement::underwater tests \(S_t < B_t\)) and the walk-away frontier of boundary.rs reports its threshold in this moneyness too. Who stops paying uses it.
At the base terms, with the spot held at the $60,000 entry:
| After payment \(t\) | \(R_t\) (nominal) | \(B_t\) (amortized) | \(R_t / B_t\) | \(B_t / \text{strike}\) | \(M_t\) at $60,000 |
|---|---|---|---|---|---|
| 0 | 88,500.00 | 60,000.00 | 1.475 | 1.000 | 1.000 |
| 1 | 87,025.00 | 59,349.89 | 1.466 | 0.989 | 1.011 |
| 6 | 79,650.00 | 55,962.78 | 1.423 | 0.933 | 1.072 |
| 12 | 70,800.00 | 51,580.88 | 1.373 | 0.860 | 1.163 |
| 19 | 60,475.00 | 45,993.62 | 1.315 | 0.767 | 1.305 |
| 24 | 53,100.00 | 41,662.81 | 1.275 | 0.694 | 1.440 |
| 36 | 35,400.00 | 29,978.89 | 1.181 | 0.500 | 2.001 |
| 48 | 17,700.00 | 16,214.75 | 1.092 | 0.270 | 3.700 |
| 59 | 1,475.00 | 1,455.00 | 1.014 | 0.024 | 41.2 |
| 60 | 0.00 | 0.00 | 0 |
The \(B_t\) column is the formula evaluated at the solved \(i\); the other columns are ratios of the first three. Read the third column: the nominal tail exceeds the amortized balance by 47.5% at origination and the gap closes to zero at the last payment, because \(R_t\) still contains the paper’s future markup and \(B_t\) has discounted it away.
Two remaining quantities
The engine carries both \(R_t\) and \(B_t\) for one Agreement, and they answer different questions.
\(R_t\) is a contract amount. It is what a court, a Buyer and a Holder would agree is owed in dollars, and it is exact Decimal cents. Every cash event uses it: the early-completion payoff is \(R_t\), the stop waterfall pays the Holder \(\min(V, R_t)\) before any refund, the shortfall is \(\max(0, R_t - V)\), and the risk desk’s schedule line and put-ladder notional are sums of it.
\(B_t\) is an economic amount. It is the value of the remaining schedule at the paper’s own rate, an f64, and it exists so the engine can ask whether a Buyer who could reason like a desk would keep paying. A Buyer compares the coin to what the remaining payments are worth, not to their undiscounted sum; a coin at $65,000 after twelve payments is comfortably above \(B_{12} = $51{,}581\) even though it is below \(R_{12} = $70{,}800\). If the engine used \(R_t\) as the rational boundary, every Buyer would be “underwater” at a flat price through the nineteenth payment (\(R_{19} = $60{,}475\) still exceeds the $60,000 coin), and the rational mode would empty the book on a path that has not moved. Using \(B_t\) puts the boundary where a present-value thinker puts it.
So: nominal for the waterfall and the ledger, amortized for the boundary. One caveat for readers of the risk desk: the exposure ladder of spec v1.6 buckets Agreements by \(S_t / R_t\), the ratio a hedging desk maps onto listed strikes, and calls that “moneyness” as well. The two ratios differ by the \(R_t/B_t\) column above; the risk desk chapter says which one each exhibit uses.
The inverse input
Input #5 is specified in both directions: enter a multiple and see the rate above, or enter a nominal annual rate and derive the payment and the multiple. The engine’s half of the inverse direction is contract.rs::pmt_from_nominal_rate, which evaluates the annuity identity forward with \(i = r_{\text{nom}} / 12\). The function is not wired to an endpoint or a cockpit field yet; it is reached through its unit tests.
\[ \text{PMT}(r_{\text{nom}}) = \text{strike} \cdot \frac{i,(1+i)^n}{(1+i)^n - 1}, \qquad \text{multiple} = \frac{\text{PMT} \cdot n}{\text{strike}} . \]
At 0% the function returns \(\text{strike}/n\) directly (unit test inverse_input_zero_rate_degenerates: $1,000.00 at 60 months). At 16.50% nominal the M0 fixtures give:
| Term | PMT | Multiple |
|---|---|---|
| 36 | $2,124.26 | 1.2746× |
| 48 | $1,715.82 | 1.3727× |
| 60 | $1,475.07 | 1.4751× |
| 84 | $1,208.87 | 1.6924× |
The 60-month row is seven cents above the program’s $1,475.00 because 16.50% is the rounded display of 16.4978%; unit test inverse_input_matches_fixture holds the fixture to a cent. The output of the inverse input is unquantized; it becomes a schedule only when the derived multiple is fed back through C1.
The first N payments to BTC Now
Input #3 routes the first N scheduled payments whole to BTC Now (spec v1.1 change 2; N = 1 is the program). In the payment step of engine.rs::run, for a payment of age \(t \le N\) the entire \(p_t\) posts from the Buyer to BTC Now as OriginationFee, and the Holder’s stream begins at payment \(N+1\).
Three consequences the fee section relies on:
- Those N payments are never “delivered.” They do not pass through the fee split, so they carry no servicing fee. The dollars delivered to the Holder over a completed Agreement are \(P - \sum_{k \le N} p_k\), which at the base terms is \(88{,}500 - 1{,}475 = $87{,}025\).
- They are still in the Buyer’s paid-in total \(A\). Whether payment 1 sits in the stop refund base is flagged as a term-sheet item, modelled as yes (spec v1.5 change 8).
- Setting N to 0 recovers the pre-program “toggle off” case that the M0 fixtures and the memo-config badge use.
The §6.4 fixture identity, tested as n_payments_identity, says the Holder’s lifetime cash at N versus at 0 differs by \(\sum_{k \le N} p_k ,(1 - f)\): at the base terms $1,475 × 0.95 = $1,401.25, one net payment. The identity is exact in the fixtures’ rational arithmetic; the Rust test allows the fee’s one-cent wobble (a 2¢ tolerance) and runs at the fixture rates, N = 1 and N = 3, terms 36 to 84.
The servicing fee and convention C2
The servicing fee is a flat share \(f\) of every dollar delivered to the Holder: scheduled payments after the first N, early-completion payoffs, and stop-sale deliveries, the termination send included. Program: \(f = 5%\) (Marc, 2026-08-31; spec v1.5 change 2, applied 2026-09-03). The Holder receives \((1 - f)\) of each delivery and BTC Now the rest; on every dollar the program pays out, BTC Now’s cut is the same 5%, with no exemptions.
At the base terms one scheduled delivery of $1,475.00 splits into a fee of $73.75 and a net payment to the Holder of $1,401.25. Both are whole cents, so at these terms every posting is identical; the engine prints 59 PaymentDelivery postings of 1,401.25 and 59 FlowFee postings of 73.75 for a completed Agreement.
The rounding rule matters at other terms. Convention C2, in fees.rs::FeeState::split, is cumulative rounding. Each Agreement keeps a running total of dollars delivered, \(C_k\), and of fee posted, and the fee on delivery \(k\) is the difference of two rounded cumulatives:
\[ \text{fee}k = \text{round}(f , C_k) - \text{round}(f , C{k-1}), \qquad C_k = C_{k-1} + d_k, \qquad \text{net}_k = d_k - \text{fee}_k . \]
round is money.rs::cents, half-to-even. Per-posting conservation, \(\text{net}_k + \text{fee}_k = d_k\), holds by construction (unit test split_conserves_each_delivery, 84 deliveries at the historical 5.25%). The state is per Agreement (engine.rs::Agreement::fee), and every delivery kind flows through the same FeeState, so a stop-sale delivery after twelve payments continues the twelve-payment cumulative.
Proving the lifetime identity
Claim. Over any sequence of deliveries \(d_1, \dots, d_K\) to one Agreement, the total fee posted is exactly \(\text{round}(f , C_K)\), the rounded fee on the lifetime delivered total, while each individual posting is within one cent of \(\text{round}(f , d_k)\).
Lifetime exactness. The sum telescopes:
\[ \sum_{k=1}^{K} \text{fee}k = \sum{k=1}^{K} \big[\text{round}(f C_k) - \text{round}(f C_{k-1})\big] = \text{round}(f C_K) - \text{round}(f C_0) = \text{round}(f C_K), \]
since \(C_0 = 0\) and \(\text{round}(0) = 0\). No intermediate rounding survives.
Per-posting wobble. Write \(\text{round}(x) = x + \varepsilon(x)\) with \(|\varepsilon| \le \tfrac{1}{2}\) cent. Then \(\text{fee}k = f d_k + \varepsilon(f C_k) - \varepsilon(f C{k-1})\), and the two error terms differ by at most one cent. A posting may therefore sit one cent above or below the naive \(\text{round}(f d_k)\), and never further.
Sign and cap. \(f C_k \ge f C_{k-1}\) and rounding is monotone, so \(\text{fee}_k \ge 0\). For \(f < 1\) and any delivery of a few cents or more, \(\text{fee}_k \le f d_k + 1\text{¢} \le d_k\). split asserts both in debug builds.
The identity is what makes the fee testable to the cent. Invariant fee_identity_exact_to_the_cent runs the flat zero-exit path at terms 36, 48, 60, 84 and 120 and asserts flow_fees == cents(f × terminal) with N = 0 and cents(f × (terminal − p_1)) with N = 1, as equalities on Decimal, not tolerances.
Worked at the base terms with N = 1: delivered \(C_K = 87{,}025.00\), lifetime fee \(0.05 \times 87{,}025 = $4{,}351.25\), Holder’s lifetime cash \($82{,}673.75\). With N = 0: fee $4,425.00, Holder $84,075.00. The engine prints exactly these (origination_fees 1,475.00, flow_fees 4,351.25, owner_total_inflow 82,673.75 on the single-Agreement flat run).
Worked at 36 months, where the wobble is visible. Each delivery of $2,458.33 carries a fee of \(0.05 \times 2{,}458.33 = 122.9165\), not a whole cent. The engine’s FlowFee postings run 122.92, 122.91, 122.92, 122.92, 122.91, 122.92, …, alternating as the cumulative error crosses half a cent, and the net postings to the Holder run 2,335.41, 2,335.42, …. Summing naive per-posting rounding, 35 × $122.92, would give $4,302.20. The exact lifetime figure is \(0.05 \times 86{,}041.67 = 4{,}302.0835\), which rounds to $4,302.08, and that is what the engine posts in total. Twelve cents of drift over one Agreement, gone.
The historical basis shows the same thing at the base term. At the pre-program 3.75% the per-payment fee was $55.3125; the postings ran 55.31, 55.31, 55.32, and sixty of them summed to exactly $3,318.75, which is the lifetime_total_is_exact unit test in fees.rs.
The fee’s history
The fee has been restated three times. The engine’s method (C2, the flat skim on delivered dollars) did not change; the rate did, and where the rate comes from did.
| Basis | Rate at 60 months | Ruled | Spec |
|---|---|---|---|
| 0.75% per year × term-years, a skim on every delivered dollar | 3.75% | Marc, 2026-07-10 | v1.1 §3.2 |
| 1% per year × term-years (cockpit base case) | 5.00% | Marc, 2026-07-13 | v1.4 change 12 |
| Flat share of every delivered dollar, not derived from the term | 5.00% | Marc, 2026-08-31 | v1.5 change 2, applied 2026-09-03 |
The first form was written as fee_rate = base_fee_pa × (term_months / 12); the identifier base_fee_pa survives only in the M0 fixture file and in the spec’s §3.2 history paragraph, never in the engine. Its intent was that a completed Agreement paid a headline “0.75% per year of terminal value,” and the skim on delivered dollars was chosen over a time-based accrual because it earns the fee on stop-sale proceeds as well and stops earning on paper that has stopped. The second form raised the yearly figure and produced 5% at 60 months. The third dropped the term from the formula: “we retain 5% of each send,” uniform, at every term, with no exemptions. At the base term the last two are cash-identical; at 36 months the program now takes 5% where the July form took 3%, and at 84 months 5% where it took 7%.
ContractTerms::fee_rate remains a method rather than a field read so that the fee engine’s call sites read the same under either basis. The M0 fixtures keep their 0.75%-per-year figures by pinning the flat rate to the historical value per term (0.0225, 0.03, 0.0375, 0.0525, 0.075); the invariant suite constructs them that way (contract_math_config in tests/invariants.rs). Spec §6.5, which once asserted that the fee rate rises linearly with the term, now asserts the opposite.
The one property that has never moved: BTC Now takes fees only, the first N payments and the flat share of delivered dollars, never a share of a stop sale (project rule 2; spec v1.5 change 6). The stop chapter shows where the surplus of a sale goes instead.
The purchase price and the paper spread
The Holder pays the purchase price at origination, input #6b, expressed as a fraction of the strike:
\[ \text{purchase} = \text{cents}(\text{strike} \times \text{pct}) , \]
where \(\text{pct}\) is purchase_pct_of_strike.
The program default is par, 1.00× (Marc, 2026-07-12; spec v1.4 change 4, replacing the earlier 1.05×). At the base terms the Holder pays $60,000.00 for paper with a $88,500 schedule; the origination block of engine.rs::run posts it as PurchasePrice from Owner to BtcNow in the Agreement’s origination month. The fraction form, rather than a dollar input, is what keeps a 24-cohort paced book sane when each cohort strikes at a different price.
The paper spread is what BTC Now earns or gives up on the sale of the paper itself:
\[ \text{spread} = \sum_{\text{Agreements}} (\text{purchase} - \text{strike}) , \]
outputs.rs::BtcNowTake::paper_spread. At par it is zero, so the base case is unchanged; at 1.05× on the base coin it is $3,000 per Agreement and $720,000 on the default 240-Agreement book, and at 0.95× it is −$720,000 (invariant paper_spread_identity). It is reported separately from total_take, which stays fees-only so the M0 identities keep holding, and it enters the revenue timeline at each Agreement’s origination month.
For the Holder the purchase price is the whole of the outflow. On the flat single-Agreement run at par, $60,000 out and $82,673.75 in gives an undiscounted multiple of 1.3779×, payback in month 44, a weighted average life of 31.0 months and an effective IRR of 13.97%. The same run at 1.05× would multiply 1.3123× on $63,000. The M0 fixtures, generated at 105% and the historical 3.75% fee, print 1.3295× for the same Agreement; the program’s figures are the par-and-5% ones here. The Holder’s rate on the paper is derived in Outputs, and the inverse question, the price at which the paper clears a stated hurdle under a stated stop view, is input #19 in Every input.
Intramonth strike dispersion
Input #20. Real originations happen throughout a month, not at its close. With the toggle on (the cockpit’s base case since 2026-07-13, Marc; the engine’s own SimConfig::default leaves it off), each Agreement draws its own entry strike around the cohort month’s price instead of ten identical twins striking at one mark.
The spread is derived from what is known at entry, per cohort month, in engine.rs::run (engine.rs::entry_sigma_monthly). Let \(r_j\) be the path’s monthly log returns over the twelve months before the cohort month \(m\) (returns \(m-12 \dots m-1\), as many as exist) and \(\sigma_m^2\) their population variance; with fewer than three such returns, \(\sigma_m\) is the volatility the path mode states divided by \(\sqrt{12}\) (paths.rs::PathMode::stated_vol_annual: the bridge’s or the diffusion model’s σ, a replay’s realized volatility over the twelve recorded months before its start, the bootstrap’s regime; zero for a literal path, which states none). Before 2026-09-05 the spread was the whole generated path’s realized volatility, so a crash placed at month 24 moved the strikes struck at month 0 — the audit’s finding 2; the test finding_2_a_future_crash_cannot_move_month_zero_strikes pins the fix. An entry executed at a uniformly random time inside the month sees half the month’s variance on average, so
\[ \sigma_{\text{intra}} = \frac{\sigma_m}{\sqrt{2}} . \]
Each Agreement’s strike is then a mean-preserving log-normal draw from its own seeded stream:
\[ \text{strike} = \text{cents}\Big( S_m \exp\big(\sigma_{\text{intra}} z - \tfrac{1}{2}\sigma_{\text{intra}}^2\big) \Big), \qquad z \sim N(0,1) , \]
with \(S_m\) the month’s price. The half-variance term makes \(\mathbb{E}[\text{strike}] = S_m\), so dispersion changes the texture of a cohort without moving its average entry. On a 43%-per-year bridge the monthly deviation is about \(0.43/\sqrt{12} = 12.4%\) and \(\sigma_{\text{intra}}\) about 8.8%: the first three cohorts use exactly that, later cohorts the trailing year’s realized figure. On a flat path the stated and the realized variance are both zero, \(\sigma_{\text{intra}} = 0\), and the toggle changes nothing (invariant dispersion_is_inert_on_a_flat_path, so the fixtures stay valid either way).
The draw comes from the Agreement’s own ChaCha20 stream (engine.rs::agreement_rng, seeded from the run seed and the Agreement id), so a strike never depends on what the rest of the book drew earlier; that is what lets the risk desk’s bump-and-revalue Greeks be sensitivities rather than draw noise (spec v1.6). Everything downstream of the strike follows: the terminal, the schedule, the purchase price and the two remaining quantities are all per Agreement. The purpose is behavioral. Thresholds such as moneyness, the conviction rule and the coverage lines then fire across a cohort over a range of prices instead of all at once at a single price (Marc, 2026-07-12). The invariant intramonth_dispersion_smears_strikes_and_preserves_the_mean checks that a cohort’s strikes are distinct, that the book’s mean strike is within 3% of the undispersed book, and that the effective IRR moves by less than two points.
When the Greeks hold strikes fixed under a price bump, the dispersion draws come off the unbumped path, so the existing book’s strikes do not move with the bump; see Price paths, shocks and bumps.
The base Agreement in numbers
Everything above, for one Agreement at the base terms on a flat $60,000 path with no exits. Reproduce the table by posting the base configuration with one cohort of one Agreement, zero lifetime stop prior, zero early-completion propensity, vol_annual 0 and dispersion off to POST /api/forwardflow/simulate with include_postings: true (see The API); the run returns 120 postings. The identities behind it are pinned by cargo test --release (closed_form_contract_math_matches_m0_fixtures and fee_identity_exact_to_the_cent), which run at the fixtures’ own terms, 1.05× and the historical fee rates, not at the par-and-5% terms of this table.
| Quantity | Value | Source |
|---|---|---|
| Strike | $60,000.00 | input #1 |
| Terminal value \(P\) | $88,500.00 | terminal() |
| Payment, all 60 | $1,475.00 | schedule() |
| Implied financing rate, nominal / effective | 16.50% / 17.80% | implied_monthly_rate() |
| Payment 1 | $1,475.00 to BTC Now | OriginationFee posting, month 1 |
| Payments 2 to 60, each | $1,401.25 to the Holder, $73.75 to BTC Now | PaymentDelivery and FlowFee postings |
| Dollars delivered to the Holder | $87,025.00 | delivered_gross |
| Lifetime servicing fee | $4,351.25 | flow_fees |
| Holder’s lifetime cash | $82,673.75 | owner_total_inflow |
| BTC Now’s take | $5,826.25 | total_take (fees only) |
| Purchase price | $60,000.00 (par) | PurchasePrice posting, month 0 |
| Paper spread | $0.00 | paper_spread |
| Holder’s undiscounted multiple | 1.3779× | undiscounted_multiple |
| Holder’s effective IRR | 13.97% | irr_effective_pa |
| Payback month / WAL | 44 / 31.0 months | payback_month, wal_months |
Conservation: $88,500 of Buyer payments equals $82,673.75 to the Holder plus $5,826.25 to BTC Now. The ledger’s sum over every posting is zero to the cent (conservation_to_the_cent_across_scenarios). The figures in the Model Card are medians of stochastic runs with stops, early completions and a live price; this table is the contract with nothing happening to it, which is the right place to start reading the rest of the math.