Skip to content

docs+test: reservation release completeness (M-09) - #1095

Draft
mswilkison wants to merge 13 commits into
feat/utxo-reservation-guardsfrom
docs/utxo-reservation-release
Draft

docs+test: reservation release completeness (M-09)#1095
mswilkison wants to merge 13 commits into
feat/utxo-reservation-guardsfrom
docs/utxo-reservation-release

Conversation

@mswilkison

Copy link
Copy Markdown
Contributor

Stacked on #1094 (guards) — top of the settlement-rework stack. Closes the M-09 release-completeness items.

Contents

  • Release/upgrade runbook (docs/utxo-reservation-release-runbook.md): the deploy-inert-then-activate sequencing (reservations never go live on a temporary storage layout), the transparent-proxy upgrade procedures for the Bridge (six-library link map, EIP-170 pre-flight, the upgrades-core delegatecall shim, one-time setReservationRouter) and the RedemptionWatchtower (external-library-linking allowance, per-generation objection surface, no reinitializer), the BridgeGovernance replacement plan (it is non-upgradeable — deploy new + transferGovernance), ReservationVault fee-reserve operations, the keep-core follow-up, and a pre-audit checklist.
  • Frozen parameter/economic spec (docs/utxo-reservation-frozen-spec.md): every governable value pinned with a sign-off ledger, the fee/backing model frozen, the reserved-fraction target documented as an accepted off-chain governance operating rule (no trustless aggregate backing figure exists on-chain), and the open economics items recorded (senior-liquidity option pricing; updateFees governance-delay + initiation-fee snapshot follow-ups).
  • Global supply-equals-backing invariant test (Bridge.ReservationInvariants.test.ts): across accept → re-anchor → dissolve → in-kind redeem → redemption timeout → late settlement, total TBTC supply equals accounted Bitcoin backing (live anchors + dissolved-to-pool) at every quiescent point, financed fees the only supply reductions, zero uncovered fee debt.

Stack status (all green: full suite + slither 0.9.0)

PR Scope Findings
#1090 delegatecall router (EIP-170) + RFC 13 prerequisite
#1091 two-phase settlement C-01, H-01, H-02, H-03, H-05*, H-07, M-01, M-02, M-03
#1092 bounded renewal + strict expiry M-07 (mechanics), H-05 lifecycle
#1093 claim≡anchor backing + financed fees + caps H-04, M-06
#1094 wallet binding, pending-deposit guard, stranding, monitoring H-06, M-04, M-05, L-01
this runbooks, frozen spec, invariant test M-09

H-08 was fixed pre-stack. Full suite 3094 passing / 0 failing at the stack tip.

Re-review

A re-run of the external (Codex) review confirming the settlement class is resolved will be posted as a comment on this PR once complete.

Add the M-09 release-completeness docs: an upgrade/activation runbook
(Bridge and RedemptionWatchtower proxy procedures, BridgeGovernance
replacement plan, deploy-inert-then-activate sequencing, vault fee
reserve operations, keep-core follow-up, pre-audit checklist) and a
frozen parameter/economic spec that pins every governable value with an
explicit governance sign-off ledger, documents the reserved-fraction
target as an accepted off-chain operating rule, and records the open
economics items (senior-liquidity option pricing, updateFees delay).
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 706144be-3ee1-443b-9d91-542c45356c7e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mswilkison

Copy link
Copy Markdown
Contributor Author

Re-run adversarial review — settlement class resolved

A four-track adversarial re-review (mirroring the original Codex pass, max effort, read-only) re-verified every finding against the full stack and hunted for regressions and new bugs in each class. All fourteen findings (C-01, H-01…H-07, M-01…M-06) are confirmed genuinely closed, and the delegatecall router / storage-append architecture is sound. One new Medium was found and fixed during the review; the rest are low-severity notes.

Findings verified closed (with the mechanism that closes each)

# Verified closed by
C-01 Per-generation records + terminal TimedOut; late proof settles with no second refund (if (!late) gates the burn/refund), marks spentMainUTXOs on the spent outpoint (so Fraud.defeatFraudChallenge works), closes the lineage. A matching newer pending generation must settle instead (revert forces it); a non-matching one is Superseded + escrow refunded. Veto → Vetoed, never settleable.
H-01 Immutable actionType per generation + type-checked dispatch; re-anchor/dissolution require the output to pay the recorded target; same-wallet re-anchor removed; Live-source rotation needs governance; dust floor bounds grind.
H-02 Capacity reserved at request, snapshots read at proof; no cap re-checked at proof time; release/re-take accounting is underflow-safe and balanced.
H-03 Bridge proof path enforces now ≥ requestedAt + delay(key,nonce); vetoed generation never settles; delay=0 only when no guardian can object.
H-04 claim ≡ anchor at every settlement; re-anchor/dissolution miner fees financed by the vault (unmint + decreaseBalance), reserve shortfall → public inKindFeeDebtSat; settlement never reverts on reserve poverty.
H-05 Redemption hard-gated now < expiresAt (retry path included); post-expiry only dissolution; term + dissolution-delay + one action-timeout is a hard bound.
H-06 beginWalletClosing reverts with live anchors; terminated-with-anchors reachable only via slashing paths, recoverable by permissionless notifyReservationStranded with consistent accounting.
H-07 Per-wallet dissolution lock + snapshotted expected main UTXO; lock released on every exit; drift re-registers as a moved-funds sweep request.
M-01 Per-position (dissolutionEligibleAt) and per-generation (txMaxFee, timeoutAt, …) snapshots; live params never read at settlement.
M-02 retryCredit minted only on a fee-paid timeout, consumed once; veto mints nothing.
M-03 Veto/objection keyed (reservationKey, requestNonce); reservation-scoped safety is ban-only; fresh generation starts clean.
M-04 pendingReservedDeposits guard blocks vault change while reservationTotalAmount != 0 or pending deposits exist; single-count discipline, no underflow.
M-05 reservedDepositWallet bound at reveal (cryptographically tied to the deposit script); acceptance requires the named == designated wallet; proof pays that wallet.
M-06 claim ≡ anchor makes one number both asset- and liability-side; per-wallet amount + single-reservation caps enforced/reserved at request; walletReservationsAmount tracked symmetrically.

Architecture: storage parity real (self at the same slot in Bridge and router; router declares only the shared storage), no standalone authority (direct router calls run on empty storage and revert), one-time governance-gated setReservationRouter, non-payable fallback reverting before the router is set, append-only storage layout, no selector shadowing.

New Medium — found and fixed in this review

Acceptance late-settlement reserved-capacity leak (independently surfaced by three of the four tracks). settleAcceptance was the only late-settlement path that did not resolve a newer pending generation: after an acceptance timed out, a re-authorized generation N+1's reserved capacity leaked permanently when generation N's anchor settled late — and a leaked reservationTotalAmount in particular permanently blocks reservation-vault migration. Fixed by unwinding a still-pending newer acceptance generation on late settle (releasing its capacity, marking it Superseded), with a regression test; commit 1fc85a6e on the guards PR, merged to this tip. Full suite 3096 passing, slither 0.9.0 clean.

The same review also hardened the late credit to route through the deposit's immutable revealed vault (not the live reservationVault), closing a governance-mistiming edge where a late acceptance could credit a re-pointed vault.

Residual low-severity notes (documented, not blocking)

  • Re-anchor is not expiry-gated and not slashed on timeout. On a MovingFunds source (permissionless), a griefer could cycle request→timeout to keep an expired reservation ActionPending and delay dissolution — but the wallet remains subject to movingFundsTimeout → terminate → strand, so the stranding bound still holds. The H-05 docstring's "after expiry only dissolution" is imprecise for MovingFunds wallets.
  • Veto delay vs redemptionTimeout. If governance set a reserved-redemption veto delay greater than redemptionTimeout, a redemption could time out before the veto window closes. Safe under defaults; worth a documented delay < redemptionTimeout operating invariant (added to the frozen spec's sign-off items).
  • Re-anchor CEI hygiene. financeInKindFee is called just before action.state = Settled; not exploitable (the anchor input is already consumed and marked spent, the vault is trusted), but moving the state write above the external call is cleaner.
  • Doc drift: requestReservationDissolution docstring claims it clears retryCredit; the credit is unusable post-expiry regardless, so it is harmless doc/code drift.

Verdict

The settlement state-machine class the original review flagged as not audit-ready is resolved: the single-phase lifecycle is now a two-phase, nonce-bound authorize-then-prove machine with terminal, late-proof-safe settlement records and a claim-equals-anchor backing model. No exploitable High or Critical remains across the stack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant