Skip to content

contracts-bedrock: remove ReinitializableBase - #22124

Draft
claude[bot] wants to merge 2 commits into
developfrom
claude/remove-reinitializable-base
Draft

contracts-bedrock: remove ReinitializableBase#22124
claude[bot] wants to merge 2 commits into
developfrom
claude/remove-reinitializable-base

Conversation

@claude

@claude claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Requested by John Mardlin · Slack thread

Description

Removes the ReinitializableBase contract, which is vestigial now that OPCM upgrades reset the initialized slot instead of bumping reinitializer versions.

Before: every proxied L1/dispute contract inherited ReinitializableBase(N) and guarded initialize() with reinitializer(initVersion()). The version constant existed so that upgrades could force re-initialization by bumping N past the value stored in the proxy's _initialized slot.

After: initialize() uses the plain initializer modifier and the base contract, its interface, and the initVersion() getter are gone. This is safe because the OPCMv2 upgrade flow (OPContractsManagerUtils.upgrade) zeroes the _initialized byte via StorageSetter before calling initialize(), so any reinitializer version ≥ 1 behaved identically; the version value no longer gated anything. Fresh proxy deployments start with _initialized = 0, so they are unaffected. Access control on initialize() (ProxyAdmin / ProxyAdmin owner checks) is unchanged.

How

  • Deleted src/universal/ReinitializableBase.sol, interfaces/universal/IReinitializableBase.sol, and test/universal/ReinitializableBase.t.sol.
  • In the 10 inheriting contracts, removed the inheritance + constructor arg and replaced reinitializer(initVersion()) with initializer (minor version bumps, matching the convention used when the upgrade() functions were removed in feat: set up OPCM for U17 #17406):
    • SystemConfig 3.14.2 → 3.15.0
    • OptimismPortal2 5.8.0 → 5.9.0
    • L1CrossDomainMessenger 2.11.1 → 2.12.0
    • L1ERC721Bridge 2.9.1 → 2.10.0
    • L1StandardBridge 2.8.2 → 2.9.0
    • SuperchainConfig 2.4.3 → 2.5.0
    • ETHLockbox 1.3.1 → 1.4.0
    • AnchorStateRegistry 3.9.0 → 3.10.0
    • DelayedWETH 1.5.1 → 1.6.0
    • DisputeGameFactory 1.6.1 → 1.7.0
  • Removed initVersion() / ReinitializableBase_ZeroInitVersion() from the corresponding interfaces.
  • DeployUtils.assertInitialized now expects the proxy _initialized value to be exactly 1 (previously matched initVersion() with a fallback to 1).
  • scripts/checks/reinitializer: removed the reinitializer(initVersion()) special case; literal reinitializer values are still checked for upgrade/initialize parity.
  • Removed the ReinitializableBase.sol exclusion from the semgrep immutable-variables rule.
  • Updated docs: docs/ai/contract-dev.md (contract pattern) and book/src/contributing/opcm.md (upgrade guidance, which still described the pre-U17 upgrade() + reinitializer flow).
  • Updated tests that asserted the initialized slot equals initVersion() to assert it equals 1.
  • Regenerated ABI snapshots and semver-lock.json.

Intentionally untouched: op-challenger/game/fault/contracts/abis/DisputeGameFactory-1.2.0.json (frozen historical ABI) and the legacy generated binding op-e2e/bindings/systemconfig.go (no callers of InitVersion).

History


Generated by Claude Code

claude and others added 2 commits July 30, 2026 13:56
ReinitializableBase existed so that contracts could force re-initialization
during upgrades by bumping an INIT_VERSION constant passed to the
reinitializer() modifier. Since OPCM v2 (#18079), upgrades reset the
initialized slot via StorageSetter before calling initialize(), so the
version value no longer gates anything and the plain initializer modifier
is sufficient.

- Delete ReinitializableBase, IReinitializableBase, and their tests.
- Replace reinitializer(initVersion()) with initializer in the 10
  inheriting contracts and drop the initVersion() getter from their
  interfaces (minor semver bumps).
- Simplify DeployUtils.assertInitialized to expect an initialized value
  of exactly 1 for proxies.
- Drop the initVersion() special case from scripts/checks/reinitializer.
- Remove the semgrep immutables exclusion for ReinitializableBase.
- Update contract-dev and OPCM contributing docs accordingly.
- Regenerate ABI snapshots and semver-lock.

Co-Authored-By: Claude
Co-authored-by: John Mardlin <john@oplabs.co>
Collapse the initialize() signatures of ETHLockbox, L1ERC721Bridge, and
L1StandardBridge onto a single line now that dropping the
reinitializer(initVersion()) modifier makes them fit, matching forge fmt.
Whitespace-only: initCodeHash values are unchanged, only sourceCodeHash
entries in the semver lock move.

Co-Authored-By: Claude
Co-authored-by: John Mardlin <john@oplabs.co>
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