Ethereum contracts deployedTransactions may use real assets. Primary-market minting and instant redemption are KYC-gated; deployment does not mean every product or entry path is open. Review the legal and risk disclosures.

Protocol fee stack, full-delta review

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. Forest Road Vault is live on Ethereum mainnet; its Solana curator vault remains on devnet and BSC has its own deployment status. An open finding applies only to the product, version and deployment state named by this review. Each review's scope bounds what its clean result is worth. Nothing here is a securities-law representation; token characterization is a matter for counsel.

Scope
The entire ADR-0031 workstream reviewed at once rather than incrementally, 14 changed production contracts, +1,130/−99 lines of Solidity, from the commit before the work began to the current tree.
Method
Twelve lenses partitioning the whole delta so nothing fell between them, instructed to assume nothing any prior round concluded. Two adversarial refuters per candidate, an explicit unverified bucket so a failed refuter could not be scored as a refutation, then synthesis and a completeness critic. Eighteen candidates, thirteen survivors; five of the twelve lenses returned nothing.

Findings and remediation history

  • R15-01HighRemediated

    Instant yield recognition voids the degenerate-entry band, leaving a point test that one unit of a permissionless transfer steps past

    `_isDegenerate()` closes vault entry on two clauses: a zero-base point and a stranded-stream band. Setting the launch vesting window to zero makes the quantity the band measures identically zero, so the band cannot fire and the predicate reduces to the point test its own sixty-line rationale argues is insufficient ("the hazard is NOT the point: it is the whole neighbourhood"). The wipe state is reached by ordinary operation: the loss-realization bound refuses anything above the vault's whole balance, so the servicer's only permitted maximal action lands exactly on the point with all shares outstanding. Entry is correctly closed there; one wei of a permissionless token transfer moves the vault off it and re-opens entry at a still-degenerate price. Nothing is taken at that instant and no rate guarantee breaks: the harm is the ownership split, after which every later inflow accrues to the entrant rather than the written-down holders. ATTRIBUTION, stated plainly: the guard is byte-identical to its pre-ADR-0031 form; this work did not create the bypass, it made it universal. Reproduced in contracts/test/audit/R15_01-DegenerateEntryAtLaunchConfig.t.sol with a control. The covering invariant cannot detect it, it re-implements the same predicate, and every existing band test runs with streaming switched on rather than at the shipped configuration. The recommended fix keys the band on the stored high-water mark; it was implemented and measured at 116 bytes against 88 bytes of remaining size, taking the vault 28 bytes over the deployment limit, so applying it requires freeing space first. Whether to do that or to accept and mitigate operationally is a Forest Road decision. REMEDIATED on 30 July 2026. Space was freed by lowering the optimizer run target from 1,000 to 500, measured at 1,816 bytes of headroom for a 0.29%-0.40% runtime gas increase on the fee-stack suite, with no code change and every gate re-run at the new setting per CLAUDE.md 1.4. A collapsed-price band now closes entry once the realized per-share rate falls below 1% of PAR. The stored high-water mark was tried as the reference first and REJECTED: `_accrueFees`'s empty-supply branch ratchets it to `(assets + 1) * 1e18` whenever any balance exists while supply is zero, so a pre-seed donation could inflate the hurdle and then permanently brick entry through the new band. The invariant suite caught that within one run, a handler revert at supply 1, assets 1, which is the argument for `fail_on_revert` on these campaigns. Par is derived from the token's own decimals, is scale-free, and no actor can move it. The three reproduction tests were INVERTED rather than deleted and now form the regression, including a case proving the band cannot be escaped by donating more and that it releases on genuine recapitalization rather than latching closed. The 1-in-100 multiple is recorded as an economic-review item alongside the existing K = 3.

  • R15-02MediumRemediated

    The corrected acceptance bound reached the decision record but not the register, the safety specification or the runbook

    The previous round corrected the recorded bound for the accepted fee-share denomination residual: the published condition described only the payment-driven family and was blind to mark release, which is unconditional and carries the larger effect. That correction landed in ADR-0031 alone. The published register still stated the superseded necessary condition, the safety specification still presented the rate-integrity invariant as enforcement, and the runbook still carried only the monitoring trigger the decision record now calls blind, while the repository's own passing round-trip test falsifies it at ten times the published threshold. All three corrected in this round, and the runbook gains explicit gates for mark-release alerting, for treating a performance-rate increase as re-opening the acceptance, and for quantifying any fee waived by an emergency valuation-source clear.

  • R15-03MediumRemediated

    The evidence artifacts describe an older tree than the code, and were regenerated partially

    The identity manifest is complete and fails honestly, the inventory matches exactly and only content hashes diverge, but partial regeneration is the harmful shape: the contract hashes verify while the evidence summary above them does not, so a reviewer confirms a source file clean against the manifest and then reads a coverage figure measured before that same file changed. Directly measured contradictions included the test count and a contract runtime margin. This is entirely understatement rather than overstatement and contains no code defect, but the documented onboarding path begins with the manifest check, so it is the first thing an external reviewer meets. Regenerated in this round with the reproducible figures corrected.

  • R15-04LowOpen

    The queue-side rate invariant re-anchors its own reference point after every action, so it compares a value against itself

    The handler's floor-advancing helper assigns the post-action rate to its own reference unconditionally, and that assignment is the last state-touching statement on the terminating path of every registered action. At the launch configuration the reported rate carries no time term, so the top-level assertion reduces to a trivially true comparison and makes no cross-call statement at all. The substantive per-call checks inside the handler are real and do constrain behaviour; it is the invariant named in the safety specification that is vacuous. Recorded rather than fixed because a correct cumulative bound has to be derived per transition, which is the same open work the decision record already carries for its sibling invariant.

  • R15-05LowRemediated

    The role gating the cross-module fee lock is absent from the generic privilege scanners

    This work introduced a role that authorises the fee-neutral bracket around junior-capacity writes, and wired it correctly, granted to exactly three module contracts, asserted both positively and negatively in post-deploy validation. But it was missing from the generic privilege enumerator and from the handover script's role sets, whose own documentation states they mirror the roles library. The consequence was narrow and specific: targeted validation covered the role, so a misgrant would still have been caught, but the durable handover receipt could not name it, so the artifact retained as evidence of who held what at genesis was silently incomplete. FIXED: the role was added to both the privilege enumerator and the handover role sets, so the enumerator now covers all eleven roles the library declares and the genesis receipt is complete. This entry was left reading 'Open' for longer than it should have been: the code was corrected without the register following, which is the same drift in the opposite direction to the one this register exists to prevent, and it was caught only when the enumerator became a published file and visibly contradicted its own finding.

Why this round is different

The six preceding rounds each reviewed a slice of the protocol-fee work as it landed. That is the right way to review changes as they are made, and it found real defects every time. It is also structurally unable to find one particular thing: a defect that is invisible in each slice and present only in their composition.

This round took the whole change at once, every changed production contract, from the commit before the work began to the current tree, and was instructed to assume nothing that any prior round concluded. Twelve reviewers partitioned the delta so nothing fell between them. Five of the twelve found nothing, which is worth stating because it is evidence about the code rather than about the reviewers.

The fee stack composes correctly

The properties that a slice-by-slice review cannot check were re-derived from scratch, and the load-bearing ones hold.

The most important is an ordering between the two impairment views, because the vault reverts when it is violated and that revert sits on the loss-realization path the design documents as never suppressible. It holds by construction rather than by luck: the gross figure is a plain per-class sum, and the conservative figure is that same sum after two reductions that can only ever subtract, each floored at zero. For the governance-assessment wrapper all four gate combinations were enumerated individually, including proving the fourth unreachable. So the worst liveness outcome in the design: a protocol that cannot recognize a loss, is not reachable through the valuation wiring.

Two other things were checked rather than assumed. The fee-share arithmetic cannot divide by zero: doing so would require roughly eighty years without a single checkpoint, against a checkpoint that anyone may call and that every value-moving path already performs. And all eight sites that take the cross-module fee lock open and close it inside one function body, with no early return and no swallowed error, so the lock cannot survive a transaction.

The cross-slice defect

It is not in the fee stack. It is in a control the fee work never touched.

Vault entry is closed when share pricing becomes degenerate. That guard has two clauses: a point test for a fully written-down vault, and a band for the neighbourhood around it. The rationale written above it argues at length that the point alone is insufficient: the hazard is the whole neighbourhood, not the single value at its limit.

The launch decision to recognize yield instantly rather than streaming it sets the vesting window to zero. With no window, the quantity the band clause measures is identically zero, so the band can never fire. At launch the guard is the point test its own author rejected.

Neither decision is wrong alone. The vesting window is a documented economic parameter with its own reasoning. The guard is byte-for-byte what it was before this work began. Their composition converts a deliberate security control into one that a single token transfer of one unit steps past.

The state that matters is reached by ordinary operation rather than by contrivance. When a loss exceeds what the senior layer can absorb, the realization function refuses anything larger than the vault's whole balance, so the servicer's only permitted action lands the vault exactly on the point, with all shares still outstanding. Entry is correctly closed there. One unit of the underlying token, transferred by anyone, moves it off the point and re-opens entry at a price that is still degenerate.

Nothing is taken at that instant, and no rate guarantee breaks: the incumbent shares are worth nothing before and nothing after. The harm is the ownership split it establishes. An entrant paying one unit acquires essentially the entire pool, so every later inflow, servicing income on the surviving book, a workout recovery, a governance recapitalization, accrues to them instead of to the written-down holders who have the only real claim on it.

Three executable tests accompany this report: one confirming the guard fires correctly at the exact point, one demonstrating the one-unit bypass, and one measuring the resulting split. They document current behaviour and must be inverted, not deleted, when the guard is widened.

The existing assurance cannot see any of this. The invariant covering the guard builds its reference model by re-implementing the same predicate, so it agrees with whatever the predicate says. And every test of the band runs with streaming explicitly switched on, none at the configuration that actually ships.

The fix does not currently fit

The recommended repair keys the band on the stored high-water mark, which no investment loss lowers, so the guard stays armed whatever the vesting setting. It was implemented and measured rather than merely proposed: it costs 116 bytes, and the vault has 88 before it exceeds the contract size limit. Applied: the implementation becomes undeployable by 28 bytes.

That converts the size margin from a maintenance note into a live constraint on remediation, and it means the choice is now explicit: free space in the vault first, or accept the exposure and mitigate it operationally. Both are decisions for Forest Road rather than for a reviewer, and the size measurement is what makes the choice concrete.

Corrections carried from the previous round

The correction to the accepted denomination residual, that its recorded bound described only one of two families, and missed the one with the larger effect, had been applied to the architecture decision record but nowhere else. The published register, the safety specification and the launch runbook all still carried the superseded version, including a monitoring trigger the record itself now describes as blind. All three are corrected here, and the runbook gains explicit gates for the monitoring obligations the acceptance created.

Assurance and evidence

The evidence artifacts describe a slightly older tree than the code. The identity manifest is complete and fails honestly, but it was regenerated partially, so the contract hashes verify while the summary above them does not. A reviewer following the documented onboarding path meets that failure as their first command.

That understates the work rather than overstating it, and none of it is a code defect. It is still the first thing an external reviewer will encounter, and a stale figure in the file the security page names as the evidence of record invites discounting everything downstream of it, including the parts that are genuinely strong.

Two narrower assurance gaps: the queue-side rate invariant re-anchors its own reference point after every action, so at the launch configuration it compares a value against itself; and the role that gates the cross-module fee lock is absent from the generic privilege scanners, so the durable handover receipt cannot name it.

Status

One High, open, with an executable reproduction and a measured reason it cannot be fixed in place. Two Medium, both concerning propagation rather than behaviour, corrected here. Two Low. The fee stack itself, after seven rounds, composes correctly.

Earlier roundProtocol fee stack, instant-recognition re-check→