TESTNET BUILD — no mainnet deployment, no real value. Nothing on this site is an offer or a live financial product.

← Audit register

Round 10 · 29 July 2026

Protocol fee stack, ADR-0031

Internal review. This is an internal engineering review of source, not an independent external audit, and it does not by itself authorize a production launch. It reviews the source at the baseline below, which is not necessarily identical to the code deployed on any network. No mainnet deployment has been authorized or attempted. Nothing here is a securities-law representation; token characterization is a matter for counsel.

Scope
The introduction of protocol-level management and performance fees on the senior vault: the vault itself, the waterfall, the default manager, the redemption queue, the vault interface and the configuration library.
Method
Nine independent lenses over the diff — fee arithmetic and rounding, high-water-mark lifecycle, reentrancy and callbacks, liveness under the new universal checkpoint dependency, ERC-4626 conformance, checkpoint placement in each consumer, invariant regressions, upgrade and deployment wiring, and economic timing games. Two adversarial refuters per candidate, then synthesis and a completeness critic.

Findings and remediation history

What was in scope

This round reviewed a single change rather than the whole system: the introduction of protocol-level management and performance fees on the senior vault. The change touched sUSDfr, WaterfallEngine, DefaultManager, RedemptionQueue, the IsUSDfr interface and the configuration library, and it added roughly four hundred lines to the vault alone.

It deserved its own round for two reasons. The first is that it inserts a permissionless fee checkpoint onto the critical path of nearly every value-moving operation in the protocol — vault entry and exit, queue admission and settlement, waterfall distribution, and five separate paths through the default manager including the one the code documents as never pausable. Any new way for that checkpoint to revert is a protocol-wide liveness defect, so availability was treated as a first-class severity rather than an afterthought.

The second is that the fee is measured against the conservative marked NAV — the same base exits price against, net of declared-but-unrealized senior impairment — while vault entry still prices at the realized NAV. That asymmetry is deliberate and load-bearing, and it is exactly the kind of place where a correct-looking accounting rule can be wrong in one direction only.

How it was run

Nine reviewers worked independent lenses over the diff: fee arithmetic and rounding, the high-water-mark lifecycle, reentrancy and callback safety, liveness under the new universal checkpoint dependency, ERC-4626 conformance, the placement of each checkpoint in its consumer contract, regressions against the documented invariant list, upgrade and deployment wiring, and economic timing games.

Every candidate then faced two adversarial refuters with distinct briefs — one attacking reachability, one redoing the arithmetic from source — with instructions to default to refuted where they could not reconstruct the defect themselves. A synthesis pass merged duplicates and dropped survivors that did not hold up on re-inspection, and a completeness critic was asked what the round had missed.

Twenty-nine candidates were raised. Fifteen survived refutation. After merging, four code defects remained, alongside six findings about the adequacy of the tests.

The round ran read-only: no proof-of-concept tests were written, so several magnitudes below are static derivations from the source rather than executed results. That limitation is stated again where it matters.

What was refuted, and why that matters

Fourteen candidates were dismissed, and the pattern in them is worth recording because it describes the failure mode of this kind of review.

An early candidate held that a small token donation to the empty vault before its seed deposit, followed by a permissionless checkpoint, would pin the high-water mark astronomically high and disable the performance fee forever. The arithmetic was right. The finding was still wrong: the deployment seeds a permanently locked position atomically, and no third party can hold the underlying asset at that point in the sequence, so the state is unreachable.

Several others claimed arithmetic faults — a division underflow in the fee-share inversion, an overflow in the combined mint, an underflow in the performance attribution — that all dissolve once the actual bounds are derived. And a cluster of candidates mistook the par marked rate, reasoning against a scale a million times off because the vault's decimals are the underlying's plus the virtual-share offset. Refuters caught each of these.

The lesson is that a lens which reads carefully but does not do the algebra produces confident, specific, wrong findings. Every survivor below was reconstructed independently by at least one refuter working from source.

The findings

The headline defect is the one the asymmetry above predicts.

The vault protects holders from being charged a performance fee on mechanical accounting movements by ratcheting the fee hurdle upward, fee-free, after share flows. But the hurdle the fee calculation actually consumes is proportional to share supply, while share flows move assets — and during a live impairment they move them at a basis that differs from the hurdle's, because entry prices on realized NAV and exit prices on conservative NAV. The ratchet, keyed on a per-share rate, was therefore not asset-preserving in either direction.

On exit it was a complete no-op: a conservative-priced redemption leaves the marked rate where it was, so the ratchet never fires, yet the hurdle shrinks with the supply while less than a proportional share of assets leaves. On deposit it fired but reset the hurdle to the current conservative base plus the principal delivered, destroying whatever drawdown had accumulated below it. Either way the fee-free cushion that a live impairment is supposed to create was silently consumed, and when the mark later cured without ever being realized, the recovery was booked as ordinary profit and charged.

Worked through with exact integers on a one-million-unit vault carrying a three-hundred- thousand mark, a routine queue settlement followed by an ordinary cure charged roughly fifteen thousand units of fee against a vault that had earned no yield and realized no loss. The realized-loss path is genuinely unaffected, because a realized loss drops assets and the impairment together.

The second finding is the same class of error one layer out. The conservative NAV nets declared exposure against live junior loss-absorbing capacity — the curator first-loss pool and the backstop reserve — but none of the contracts that write those balances checkpointed the vault or ratcheted the hurdle. Posting first-loss capital during a live mark raises the marked NAV with nothing earned; a permissionless checkpoint books it as profit; withdrawing the capital returns it in full. The fee shares minted in between are not clawed back.

The remaining two are lower and both concern liveness rather than value. Every fee setter crystallized before writing its new state, which meant the setter that exists to rotate away from a fee recipient whose mint has been blocked was itself unusable in precisely that state. And the window between yield being delivered into the vault and the vault being told to defer its recognition was not closed by any vault-side lock, despite documentation asserting that it was — the guard it credited belongs to a different contract entirely.

What the tests did not cover

The more uncomfortable half of this round is not the code.

The entire exit half of the change had no value-asserting test. Six exit-side code sites were modified. The fee unit suite, seven hundred lines and twenty-four tests, contained no occurrence of a redemption, a withdrawal or a queue request — it never burned a share. Of every test file that exercised an exit, not one referenced any fee state. The queue's own stateful campaign ran with the launch performance fee live but compared the exchange rate against a constant captured at construction, so it could not observe fee dilution at all.

That is line coverage without assertions, on exactly the accounting core where the standard demands the most, and it is the direct reason the headline defect shipped green.

The rate-integrity invariant had been weakened rather than the code fixed. The quantitative bound was placed behind a condition that switched itself off whenever a management fee was due, so the invariant would have accepted an arbitrary collapse in the exchange rate — including to zero. And no handler in any campaign ever enabled the management fee, so the branch was simultaneously dead and unbounded.

Alongside those: the integration tier for the whole fee stack was a single thirty-eight-line happy path with no default, no queue and no second depositor; every fork test skipped, including the only test that routes the fee setters through the real governor and timelock; and the one branch of the new impairment-source probe that decides whether a source which answered can be discarded had no mock capable of reaching it.

Disposition

All four code findings and the test gaps were remediated. That remediation was then given its own round, which is the honest thing to do with a fix of this size — and which found that one of the four repairs had reintroduced the same defect class it was fixing, on a different axis. See the remediation re-check.

Earlier roundFull-system audit, round nine