Skip to content

feat(invariants): repoint STOX_PROD_AUTHORISER to the V4 clone — RED until swap - #254

Merged
thedavidmeister merged 3 commits into
mainfrom
feat/20260715-repoint-authoriser-invariants
Jul 23, 2026
Merged

feat(invariants): repoint STOX_PROD_AUTHORISER to the V4 clone — RED until swap#254
thedavidmeister merged 3 commits into
mainfrom
feat/20260715-repoint-authoriser-invariants

Conversation

@hardyjosh

@hardyjosh hardyjosh commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

The pre-authored post-execution pin: repoints every invariant to the state that holds after the 20260623 upgrade + swap bundle executes on Base.

DELIBERATELY RED until the bundle executes — every production vault still reports the retired V3 authoriser, so CI shows exactly:

ReceiptVaultAuthoriserMismatch(
  vault,
  expected = 0x315b16faa6eE413faBCa877d3851B3818369f0cD,  // V4 clone
  actual   = 0x35f9fA9d80aAF2B0fB27f0FF015641B3408d7456   // retired V3
)

Merge after runbook step 5 (the Safe ceremony); this goes green automatically at execution.

The single current-authoriser entrypoint

  • LibAuthoriserInvariants.STOX_PROD_AUTHORISER now aliases LibProdDeployV4.STOX_PROD_AUTHORISER_V4_CLONE — the deploy lib is the single source for the address; this constant is the semantic name every invariant and script reads.
  • One master expectedGrants() (13 entries): 7 _ADMIN roles on the Safe (incl. the two corporate-action admins, per RAI-731), 3 service-EOA ops, 3 Safe ops.
  • assertAll() = codehash-vs-deploy-pin + master map on STOX_PROD_AUTHORISER. All V3 checks deleted (STOX_PROD_AUTHORISER_IMPL, assertImplPinned, the V3 grant leg) — nothing references the retired clone.
  • LibInvariants returns to the simple strict shape: assertUniformAuthoriser(current) — the migration window on the authoriser leg is gone (superseded by this red-until-executed PR, per review).
  • 20260619 deploy-script slices follow the 13-map reorder; the 20260623 script's redundant inline 7-role block is dropped (the master map covers it).

Stack: #252 (clone pin, green) → #255 (3-beacon bundle, green) → this PR (red until execution).

Summary by CodeRabbit

  • Enhancements

    • Updated authorisation validation to include corporate-action administrator permissions.
    • Improved deployment and receipt-vault upgrade checks to verify the complete expected permission set.
    • Production authoriser verification now checks the current deployed authoriser and its code integrity.
  • Bug Fixes

    • Corrected permission mirroring so administrator and operational grants are evaluated in the proper order.
    • Removed outdated migration-window assumptions from authoriser and token validation.
  • Tests

    • Expanded coverage for missing permissions, incorrect code, and post-upgrade authoriser state.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@thedavidmeister, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c518afdc-1f2e-41c7-a5bc-26e96afde6b5

📥 Commits

Reviewing files that changed from the base of the PR and between 3d8368a and 634f7a7.

📒 Files selected for processing (6)
  • script/20260619-deploy-v4-authoriser-clone.s.sol
  • script/20260623-upgrade-receipt-vaults-to-v4.s.sol
  • src/lib/LibAuthoriserInvariants.sol
  • src/lib/LibInvariants.sol
  • test/script/20260623-upgrade-receipt-vaults-to-v4.t.sol
  • test/src/concrete/deploy/StoxProdV4PostSwap.t.sol
📝 Walkthrough

Walkthrough

The changes repin authoriser invariants to the generated V4 clone, expand expected grants, remove migration-window validation, update deployment checks and mirroring indexes, and revise deployment, fork, and library tests accordingly.

Changes

Authoriser invariant alignment

Layer / File(s) Summary
Production authoriser pins and grant map
src/lib/LibAuthoriserInvariants.sol
Production authoriser address and codehash pins now come from LibProdDeployV4; expectedGrants() includes the two corporate-action admin roles.
Current authoriser invariant orchestration
src/lib/LibInvariants.sol
Token validation uses the current production authoriser, while migration-window checks are removed from both invariant overloads.
Deployment and upgrade validation
script/20260619-deploy-v4-authoriser-clone.s.sol, script/20260623-upgrade-receipt-vaults-to-v4.s.sol
Operational grant mirroring starts at index 7, and clone validation checks the complete expectedGrants() map.
Deployment behavior tests
test/script/20260619-deploy-v4-authoriser-clone.t.sol
Deployment tests update mirror indexes and missing-grant expectations for the expanded grant map.
Fork and library invariant tests
test/script/20260623-upgrade-receipt-vaults-to-v4.t.sol, test/src/concrete/deploy/StoxProdV4PostSwap.t.sol, test/src/lib/*
Tests validate the current production authoriser, V4 clone codehash, expected grants, and updated invariant harness entry point.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant InvariantSuite
  participant LibTokenInvariants
  participant LibAuthoriserInvariants
  participant ProductionAuthoriser
  InvariantSuite->>LibTokenInvariants: validate token state against production authoriser
  InvariantSuite->>LibAuthoriserInvariants: assertAll()
  LibAuthoriserInvariants->>ProductionAuthoriser: read codehash and expected roles
  LibAuthoriserInvariants-->>InvariantSuite: return invariant result
Loading

Possibly related issues

Possibly related PRs

Suggested labels: ai:ready

Suggested reviewers: thedavidmeister

Poem

A rabbit checks the grants in line,
Seven admins, six grants align.
The clone’s codehash shines bright,
Migration windows leave the night.
V4 hops through tests with cheer—
Every role is accounted here!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: repointing STOX_PROD_AUTHORISER to the V4 clone and noting the expected pre-swap failure state.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/20260715-repoint-authoriser-invariants

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.

hardyjosh commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@hardyjosh
hardyjosh changed the base branch from feat/20260715-pin-v4-authoriser-clone-address to graphite-base/254 July 15, 2026 16:00
@hardyjosh
hardyjosh force-pushed the feat/20260715-repoint-authoriser-invariants branch from 2564d1d to a0a391b Compare July 15, 2026 16:00
@hardyjosh
hardyjosh changed the base branch from graphite-base/254 to feat/20260715-upgrade-all-three-beacons July 15, 2026 16:00
@hardyjosh
hardyjosh marked this pull request as ready for review July 15, 2026 16:01
@hardyjosh
hardyjosh force-pushed the feat/20260715-repoint-authoriser-invariants branch from a0a391b to 422a36d Compare July 15, 2026 16:22
@hardyjosh
hardyjosh force-pushed the feat/20260715-upgrade-all-three-beacons branch from d54ee0d to 3564aa6 Compare July 15, 2026 16:22
@hardyjosh
hardyjosh changed the base branch from feat/20260715-upgrade-all-three-beacons to graphite-base/254 July 15, 2026 16:36
hardyjosh added a commit that referenced this pull request Jul 15, 2026
#255)

## Summary

The swap bundle previously upgraded only the receipt-vault beacon. Every live production token proxies through **three** V1 beacons — receipt (ERC-1155), receipt vault (ERC-20), wrapped token vault (ERC-4626) — whose V4 implementations assume each other's V4 behaviour, so they must move together.

**New bundle shape (23 txs):**
1. receipt beacon → `STOX_RECEIPT_0_1_1`
2. receipt-vault beacon → `STOX_RECEIPT_VAULT_0_1_1`
3. wrapped-token-vault beacon → `STOX_WRAPPED_TOKEN_VAULT_0_1_1`
4. …23. `setAuthorizer(V4 clone)` × 20 production vaults

Per beacon: pre-flight (Safe-owned via `LibBeaconInvariants.PROD_BEACON_OWNER` + still at V1 impl; V4 impl deployed with the audited codehash), post-state (at V4 impl, still Safe-owned), and n+1 reversibility (the Safe rolls each back to its V1 impl under the live threshold).

`run()` split into `_preflightBeaconsAndImpls` / `_preflightClone` / `_buildBundle` helpers (stack-too-deep with the beacon arrays inline).

**GREEN**: `testRunCompletesAndWritesArtifact` proves the 23-tx bundle authors end-to-end against unmodified live Base state — this is the exact dry-run the `run-script` dispatch executes. Merge before dispatching runbook step 5.

Stack: `#252 (clone pin) → this PR → #254 (invariant repoint, red until execution)`.
@hardyjosh
hardyjosh force-pushed the feat/20260715-repoint-authoriser-invariants branch from 422a36d to f41b819 Compare July 15, 2026 16:37
@hardyjosh
hardyjosh force-pushed the graphite-base/254 branch from 3564aa6 to 8cae29b Compare July 15, 2026 16:37
@graphite-app
graphite-app Bot changed the base branch from graphite-base/254 to main July 15, 2026 16:38
…until swap

The single "current authoriser" entrypoint now points at the clone the
swap script upgrades every vault onto:

- LibAuthoriserInvariants.STOX_PROD_AUTHORISER aliases
  LibProdDeployV4.STOX_PROD_AUTHORISER_V4_CLONE (deploy lib = single
  source for the address; this constant = the semantic name).
- One master expectedGrants() (13 entries: 7 _ADMIN roles on the Safe
  incl. the two corporate-action admins per RAI-731, 3 service ops,
  3 Safe ops).
- assertAll() = codehash-vs-deploy-pin + master map on
  STOX_PROD_AUTHORISER. V3 checks deleted entirely
  (STOX_PROD_AUTHORISER_IMPL, assertImplPinned, the V3 grant leg) —
  nothing references the retired clone.
- LibInvariants returns to the simple strict shape:
  assertUniformAuthoriser(current) — no migration window on the
  authoriser leg.
- 20260619 script slices follow the 13-map reorder (ops at 7..12);
  20260623 script's inline 7-role block dropped (master map covers).
- StoxProdV4PostSwap + 20260623 test assert the strict post-swap
  state.

DELIBERATELY RED until the 20260623 swap bundle executes on Base:
every vault still reports the retired V3 authoriser
(ReceiptVaultAuthoriserMismatch expected=0x315b16fa actual=0x35f9fA9d).
This is the pre-authored post-execution pin — merge after the swap.
@hardyjosh
hardyjosh force-pushed the feat/20260715-repoint-authoriser-invariants branch from f41b819 to 2ec9345 Compare July 15, 2026 16:38
thedavidmeister and others added 2 commits July 23, 2026 12:32
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…c form

Resolves the divergence between this branch's flat Base-only 13-entry
expectedGrants and main's Safe-parametric 11-entry overload. Every chain
targets the 0.1.1 authoriser impl, so every chain carries the two
corporate-action admins: expectedGrants(address tokenOwnerSafe) now
returns 13 entries and stays the single map every consumer reads.

The deploy script's post-state sweep and StoxProdV4PostSwap no longer
hand-list the seven auto-granted _ADMIN roles separately — that list only
existed because the 11-entry map omitted the corporate-action admins, and
asserting it alongside the map made two sources of truth for one fact.

Both LibInvariants.assertAll overloads now assert the V4 clone outright.
The V3-or-V4 migration window is gone: the swap has executed, so the
window only served to keep a retired clone in the assertion path while
leaving the live authoriser's grant map unchecked. main's chain-agnostic
assertProductionState is untouched.

MIRROR_START_INDEX stays 7, matching the reordered map; the existing
assertGrantsSliceInvariant pins that coupling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thedavidmeister

Copy link
Copy Markdown
Contributor

Reviewed 634f7a7: approve

Green by the rule. rainix-sol / static, legal and Graphite mergeability all pass. The two reds are inherited — main's tip 3b6fca4 fails the identical jobs:

  • rainix-sol / test — sole failure testDeployTag (0_1_8 != 0_1_28), the soldeer autopublish version drift.
  • git-clean — "Assert committed artifacts match freshly built".

The four BeaconImplementationMismatch failures on the pre-merge head are gone, confirming they were drift from an eight-day-old branch rather than anything in the change.

The merge resolution unifies the grant map rather than picking a side: expectedGrants keeps main's Safe-parametric (address tokenOwnerSafe) signature and carries 13 entries, since every chain targets the 0.1.1 authoriser impl and so carries the two corporate-action admins. That let the hand-listed seven-_ADMIN sweeps in the 20260619 script's post-state check and in StoxProdV4PostSwap be deleted — they existed only because the 11-entry map omitted those admins, and asserting them alongside the map made two sources of truth for one fact. MIRROR_START_INDEX stays 7 for the reordered map, with assertGrantsSliceInvariant() pinning that coupling structurally.

Both LibInvariants.assertAll overloads now assert the V4 clone outright. That is the substantive win: while the V3-or-V4 migration window stood, LibAuthoriserInvariants.assertAll() validated the retired V3 clone — which still holds its grants, since the swap revoked nothing — so it passed green while the live authoriser's grant map went unchecked. main's chain-agnostic assertProductionState is untouched.

Known gap, not a blocker and not introduced here: assertExpectedGrants is presence-only over the map, plus DEFAULT_ADMIN_ROLE negatives limited to the Safe and service EOA. The comment states the deploy key renounced all seven _ADMIN roles, but nothing asserts it — if renunciation had silently failed, the deploy key would retain admin over every action role and every assertion here would still pass.

@thedavidmeister
thedavidmeister merged commit 64a0d24 into main Jul 23, 2026
4 of 6 checks passed
hardyjosh pushed a commit that referenced this pull request Jul 23, 2026
…ning, post-swap test retirement

Rebased onto the #254 grant-map restructure (13-entry parametric form,
STOX_PROD_AUTHORISER repointed to the live authoriser upstream).

GRANTEE_SERVICE_3D0C joins GRANTEE_SERVICE_1C66 as an ADDITIONAL service
signer with the same three action roles:

- expectedGrants() 13 -> 16; every consumer (parity authoriser leg,
  production-state bundle, per-chain prod pins) is red per chain until the
  provisioning bundle executes there, drift-guarded after. 3D0C joins the
  DEFAULT_ADMIN absence checks. Map docs state purpose, not contents.
- 20260619 clone-deploy MIRROR_COUNT 6 -> 9 (+ suite): the ceremony runs
  again on future chains and its slice guard forces the constant to track
  the canonical map; executed chains refuse re-runs via hydrated pins.
- 20260723-provision-additional-service-signer (run-script, registered):
  authors the per-chain grant bundle, work items derived from the map,
  chain-aware (base/ethereum network selector added to the dispatcher),
  self-scoping, n+1-proven reversible. Fork suite green on live Base +
  Ethereum.
- Post-execution retirement: the executed swap authorings' one-shot test
  suites deleted; live-state coverage is carried by the standing
  invariants.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPs1hCTxusmaSeFKvoc4Kr
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.

2 participants