Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
25d2cf5
feat(L1): add ProtocolVersions upgrade schedule contract
PelleKrab Jun 25, 2026
1b89555
fix(L1): refine ProtocolVersions with reproducible scheduleId and rep…
PelleKrab Jun 25, 2026
b8e9c39
feat(L1): add getSchedule view to ProtocolVersions
PelleKrab Jun 25, 2026
e30e60c
chore(L1): apply forge fmt and update semver-lock for ProtocolVersions
PelleKrab Jun 25, 2026
018ca7c
refactor(L1): cache hash chain seed as immutable in ProtocolVersions
PelleKrab Jun 26, 2026
50a37cd
chore(L1): update semver-lock for ProtocolVersions
PelleKrab Jun 26, 2026
ab5924d
refactor(L1): simplify ProtocolVersions ownership, storage, and acces…
PelleKrab Jul 6, 2026
6cd39d7
refactor(L1): switch ProtocolVersions to numeric upgrade IDs and prox…
PelleKrab Jul 6, 2026
b917183
fix(L1): apply code-review corrections to ProtocolVersions
PelleKrab Jul 6, 2026
c034032
refactor(L1): minimumProtocolVersion, no-arg registerUpgrade, write h…
PelleKrab Jul 6, 2026
1f39756
test: exclude ProtocolVersions from initializer tracking
PelleKrab Jul 6, 2026
871e6d4
feat(L1): deploy ProtocolVersions in standard deployment script
PelleKrab Jul 7, 2026
766f563
refactor(L1): simplify ProtocolVersions schedule seed
PelleKrab Jul 7, 2026
29fff2f
fix(L1): apply ProtocolVersions review nits
PelleKrab Jul 7, 2026
2257727
refactor(L1): reduce ProtocolVersions API surface
PelleKrab Jul 7, 2026
e1ebc49
refactor(L1): rename chainTeam to incidentResponder, combine config, …
PelleKrab Jul 9, 2026
b465d95
refactor(L1): address ProtocolVersions review nits
PelleKrab Jul 9, 2026
21e6cc7
fix(deploy): upgrade ProtocolVersions proxy
PelleKrab Jul 10, 2026
2e348fa
refactor(L1): reorder IProtocolVersions members to match style guide
PelleKrab Jul 10, 2026
90bf7d3
feat(L1): bind aggregate proofs to ProtocolVersions schedule
PelleKrab Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions interfaces/L1/IProtocolVersions.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { ISemver } from "interfaces/universal/ISemver.sol";
import { IProxyAdminOwnedBase } from "interfaces/L1/IProxyAdminOwnedBase.sol";
import { IReinitializableBase } from "interfaces/universal/IReinitializableBase.sol";

/// @title IProtocolVersions
/// @notice Interface for the ProtocolVersions upgrade schedule contract.
interface IProtocolVersions is IProxyAdminOwnedBase, ISemver, IReinitializableBase {
event UpgradeRegistered(uint256 indexed id);
event MinimumProtocolVersionUpdated(uint256 indexed protocolVersion);
event TimestampSet(uint256 indexed id, uint256 timestamp);
event ScheduleIdUpdated(bytes32 indexed newScheduleId);
event IncidentResponderUpdated(address indexed previousIncidentResponder, address indexed newIncidentResponder);
event Initialized(uint8 version);

error ProtocolVersions_UnknownUpgrade(uint256 id);
error ProtocolVersions_InvalidProtocolVersion();
error ProtocolVersions_ActivationAlreadyPassed(uint256 id, uint64 activationTimestamp);
error ProtocolVersions_NotIncidentResponder();
error ProtocolVersions_NotScheduled(uint256 id);
error ProtocolVersions_DelayMustBeLater(uint64 currentTimestamp, uint64 newTimestamp);
error ProtocolVersions_NotInitialized();
error ProtocolVersions_InsufficientNotice(uint64 timestamp);

function initialize(address _incidentResponder) external;
function registerUpgrade(uint64 timestamp, uint256 minProtocolVersion) external returns (uint256);
function setMinimumProtocolVersion(uint256 protocolVersion) external;
function setTimestamp(uint256 id, uint64 timestamp) external;
function setIncidentResponder(address newIncidentResponder) external;
function delayTimestamp(uint256 id, uint64 newTimestamp) external;

function MIN_NOTICE() external view returns (uint64);
function minimumProtocolVersion() external view returns (uint256);
function incidentResponder() external view returns (address);
function scheduleId() external view returns (bytes32);
function scheduleId(uint256 id) external view returns (bytes32);
function getSchedule() external view returns (uint64[] memory);

function __constructor__() external;
}
3 changes: 3 additions & 0 deletions interfaces/L1/proofs/IAggregateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
import { IDelayedWETH } from "./IDelayedWETH.sol";
import { IVerifier } from "./IVerifier.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { Proposal, Hash } from "src/libraries/bridge/Types.sol";
import { Timestamp } from "src/libraries/bridge/LibUDT.sol";

Expand All @@ -23,6 +24,7 @@ interface IAggregateVerifier is IDisputeGame {
function ZK_RANGE_HASH() external view returns (bytes32);
function ZK_AGGREGATE_HASH() external view returns (bytes32);
function CONFIG_HASH() external view returns (bytes32);
function PROTOCOL_VERSIONS() external view returns (IProtocolVersions);
function L2_CHAIN_ID() external view returns (uint256);
function BLOCK_INTERVAL() external view returns (uint256);
function INTERMEDIATE_BLOCK_INTERVAL() external view returns (uint256);
Expand All @@ -35,6 +37,7 @@ interface IAggregateVerifier is IDisputeGame {
function counteredByIntermediateRootIndexPlusOne() external view returns (uint256);
function expectedResolution() external view returns (Timestamp);
function proofCount() external view returns (uint8);
function scheduleId() external view returns (bytes32);

function initializeWithInitData(bytes calldata proof) external payable;
function verifyProposalProof(bytes calldata proofBytes) external;
Expand Down
55 changes: 50 additions & 5 deletions scripts/deploy/SystemDeploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.s
import { IL1ERC721Bridge } from "interfaces/L1/IL1ERC721Bridge.sol";
import { IL1StandardBridge } from "interfaces/L1/IL1StandardBridge.sol";
import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { IAddressManager } from "interfaces/legacy/IAddressManager.sol";
Expand Down Expand Up @@ -107,6 +108,7 @@ contract SystemDeploy is Script {
ISuperchainConfig superchainConfigProxy;
Types.Implementations implementations;
ISystemConfig systemConfigProxy;
IProtocolVersions protocolVersionsProxy;
}

struct UpgradeOutput {
Expand All @@ -127,6 +129,7 @@ contract SystemDeploy is Script {
uint256 l2ChainId;
uint256 multiproofBlockInterval;
uint256 multiproofIntermediateBlockInterval;
IProtocolVersions protocolVersions;
}

struct MultiproofOutput {
Expand Down Expand Up @@ -218,6 +221,7 @@ contract SystemDeploy is Script {
disputeGameFactoryImpl: artifacts.mustGetAddress("DisputeGameFactoryImpl"),
anchorStateRegistryImpl: artifacts.mustGetAddress("AnchorStateRegistryImpl"),
delayedWETHImpl: artifacts.mustGetAddress("DelayedWETHImpl"),
protocolVersionsImpl: artifacts.mustGetAddress("ProtocolVersionsImpl"),
aggregateVerifierImpl: artifacts.getAddress("AggregateVerifier"),
teeProverRegistryImpl: artifacts.getAddress("TEEProverRegistryImpl"),
teeVerifierImpl: artifacts.getAddress("TEEVerifier"),
Expand Down Expand Up @@ -279,7 +283,8 @@ contract SystemDeploy is Script {
opChainProxyAdminOwner: cfg.finalSystemOwner(),
systemConfigOwner: cfg.finalSystemOwner(),
batcher: cfg.batchSenderAddress(),
unsafeBlockSigner: cfg.p2pSequencerAddress()
unsafeBlockSigner: cfg.p2pSequencerAddress(),
incidentResponder: cfg.superchainConfigIncidentResponder()
}),
basefeeScalar: cfg.basefeeScalar(),
blobBasefeeScalar: cfg.blobbasefeeScalar(),
Expand Down Expand Up @@ -336,7 +341,12 @@ contract SystemDeploy is Script {
revert SuperchainConfigNeedsUpgrade();
}

_upgradeOPChain(systemConfigProxy, _input.implementations);
IProtocolVersions protocolVersionsProxy = _input.protocolVersionsProxy;
if (address(protocolVersionsProxy) == address(0) && address(artifacts).code.length != 0) {
protocolVersionsProxy = IProtocolVersions(artifacts.getAddress("ProtocolVersionsProxy"));
}

_upgradeOPChain(systemConfigProxy, _input.implementations, protocolVersionsProxy);
output_.chainUpgraded = true;
}

Expand Down Expand Up @@ -447,6 +457,7 @@ contract SystemDeploy is Script {
output_.delayedWETHImpl = address(_deployDelayedWETHImpl(_input));
output_.disputeGameFactoryImpl = address(_deployDisputeGameFactoryImpl());
output_.anchorStateRegistryImpl = address(_deployAnchorStateRegistryImpl(_input));
output_.protocolVersionsImpl = address(_deployProtocolVersionsImpl());
}

function _deployOPChain(
Expand Down Expand Up @@ -487,6 +498,8 @@ contract SystemDeploy is Script {
output_.anchorStateRegistryProxy =
IAnchorStateRegistry(_deployProxy(_input, output_.opChainProxyAdmin, "AnchorStateRegistry"));
output_.delayedWETHProxy = IDelayedWETH(payable(_deployProxy(_input, output_.opChainProxyAdmin, "DelayedWETH")));
output_.protocolVersionsProxy =
IProtocolVersions(_deployProxy(_input, output_.opChainProxyAdmin, "ProtocolVersions"));

output_.l1StandardBridgeProxy = IL1StandardBridge(
payable(_createDeterministic(
Expand Down Expand Up @@ -619,6 +632,13 @@ contract SystemDeploy is Script {
_impls.anchorStateRegistryImpl,
_encodeAnchorStateRegistryInitializer(_input, _output)
);

_upgradeToAndCall(
_output.opChainProxyAdmin,
address(_output.protocolVersionsProxy),
_impls.protocolVersionsImpl,
abi.encodeCall(IProtocolVersions.initialize, (_input.roles.incidentResponder))
);
}

function _upgradeSuperchainConfigIfNeeded(
Expand All @@ -637,7 +657,13 @@ contract SystemDeploy is Script {
upgraded_ = true;
}

function _upgradeOPChain(ISystemConfig _systemConfigProxy, Types.Implementations memory _impls) internal {
function _upgradeOPChain(
ISystemConfig _systemConfigProxy,
Types.Implementations memory _impls,
IProtocolVersions _protocolVersionsProxy
)
internal
{
IProxyAdmin proxyAdmin = _systemConfigProxy.proxyAdmin();
uint256 l2ChainId = _systemConfigProxy.l2ChainId();

Expand All @@ -662,6 +688,10 @@ contract SystemDeploy is Script {
_upgradeTo(proxyAdmin, opChainAddrs.delayedWETH, _impls.delayedWETHImpl);
}

if (address(_protocolVersionsProxy) != address(0)) {
_upgradeTo(proxyAdmin, address(_protocolVersionsProxy), _impls.protocolVersionsImpl);
}

emit Upgraded(l2ChainId, _systemConfigProxy, msg.sender);
}

Expand Down Expand Up @@ -947,6 +977,16 @@ contract SystemDeploy is Script {
);
}

function _deployProtocolVersionsImpl() internal returns (IProtocolVersions) {
return IProtocolVersions(
DeployUtils.createDeterministic({
_name: "ProtocolVersions",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProtocolVersions.__constructor__, ())),
_salt: DeployUtils.DEFAULT_SALT
})
);
}

function _deployMultiproofContracts(
Types.DeployInput memory _opChainInput,
ImplementationInput memory _input,
Expand Down Expand Up @@ -1009,7 +1049,8 @@ contract SystemDeploy is Script {
multiproofConfigHash: _input.multiproofConfigHash,
l2ChainId: _opChainInput.l2ChainId,
multiproofBlockInterval: _input.multiproofBlockInterval,
multiproofIntermediateBlockInterval: _input.multiproofIntermediateBlockInterval
multiproofIntermediateBlockInterval: _input.multiproofIntermediateBlockInterval,
protocolVersions: _output.protocolVersionsProxy
})
);

Expand Down Expand Up @@ -1038,7 +1079,8 @@ contract SystemDeploy is Script {
_input.multiproofConfigHash,
_input.l2ChainId,
_input.multiproofBlockInterval,
_input.multiproofIntermediateBlockInterval
_input.multiproofIntermediateBlockInterval,
_input.protocolVersions
)
)
);
Expand Down Expand Up @@ -1100,6 +1142,7 @@ contract SystemDeploy is Script {
DeployUtils.assertValidContractAddress(_impls.disputeGameFactoryImpl);
DeployUtils.assertValidContractAddress(_impls.anchorStateRegistryImpl);
DeployUtils.assertValidContractAddress(_impls.delayedWETHImpl);
DeployUtils.assertValidContractAddress(_impls.protocolVersionsImpl);
}

function _implementationsEmpty(Types.Implementations memory _impls) internal pure returns (bool) {
Expand All @@ -1125,6 +1168,7 @@ contract SystemDeploy is Script {
artifacts.save("DisputeGameFactoryProxy", address(chain.disputeGameFactoryProxy));
artifacts.save("DelayedWETHProxy", address(chain.delayedWETHProxy));
artifacts.save("AnchorStateRegistryProxy", address(chain.anchorStateRegistryProxy));
artifacts.save("ProtocolVersionsProxy", address(chain.protocolVersionsProxy));
artifacts.save("OptimismPortalProxy", address(chain.optimismPortalProxy));
artifacts.save("OptimismPortal2Proxy", address(chain.optimismPortalProxy));
_saveIfSet("TEEProverRegistryProxy", address(chain.teeProverRegistryProxy));
Expand All @@ -1151,6 +1195,7 @@ contract SystemDeploy is Script {
artifacts.save("DisputeGameFactoryImpl", _impls.disputeGameFactoryImpl);
artifacts.save("AnchorStateRegistryImpl", _impls.anchorStateRegistryImpl);
artifacts.save("DelayedWETHImpl", _impls.delayedWETHImpl);
artifacts.save("ProtocolVersionsImpl", _impls.protocolVersionsImpl);
_saveIfSet("AggregateVerifier", _impls.aggregateVerifierImpl);
_saveIfSet("TEEProverRegistryImpl", _impls.teeProverRegistryImpl);
_saveIfSet("TEEVerifier", _impls.teeVerifierImpl);
Expand Down
4 changes: 4 additions & 0 deletions scripts/libraries/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { IL1ERC721Bridge } from "interfaces/L1/IL1ERC721Bridge.sol";
import { IL1StandardBridge } from "interfaces/L1/IL1StandardBridge.sol";
import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol";
import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";

import { Proposal } from "src/libraries/bridge/Types.sol";
import { Claim } from "src/libraries/bridge/LibUDT.sol";
Expand All @@ -28,6 +29,7 @@ library Types {
address systemConfigOwner;
address batcher;
address unsafeBlockSigner;
address incidentResponder;
}

/// @notice The full set of inputs to deploy a new OP Stack chain.
Expand Down Expand Up @@ -55,6 +57,7 @@ library Types {
IDisputeGameFactory disputeGameFactoryProxy;
IAnchorStateRegistry anchorStateRegistryProxy;
IDelayedWETH delayedWETHProxy;
IProtocolVersions protocolVersionsProxy;
IVerifier aggregateVerifier;
ITEEProverRegistry teeProverRegistryProxy;
IVerifier teeVerifier;
Expand All @@ -76,6 +79,7 @@ library Types {
address disputeGameFactoryImpl;
address anchorStateRegistryImpl;
address delayedWETHImpl;
address protocolVersionsImpl;
address aggregateVerifierImpl;
address teeProverRegistryImpl;
address teeVerifierImpl;
Expand Down
11 changes: 10 additions & 1 deletion scripts/multiproof/DeployDevBase.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol";

import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol";
import { IVerifier } from "interfaces/L1/proofs/IVerifier.sol";
import { ProtocolVersions } from "src/L1/ProtocolVersions.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { MockVerifier } from "test/mocks/MockVerifier.sol";
import { TEEProverRegistry } from "src/L1/proofs/tee/TEEProverRegistry.sol";
import { TEEVerifier } from "src/L1/proofs/tee/TEEVerifier.sol";
Expand Down Expand Up @@ -104,6 +106,12 @@ abstract contract DeployDevBase is Script {
AggregateVerifier.ZkHashes memory zkHashes =
AggregateVerifier.ZkHashes({ rangeHash: cfg.zkRangeHash(), aggregateHash: cfg.zkAggregationHash() });

Proxy protocolVersionsProxy = new Proxy(msg.sender);
protocolVersionsProxy.upgradeToAndCall(
address(new ProtocolVersions()), abi.encodeCall(IProtocolVersions.initialize, (address(0)))
);
protocolVersionsProxy.changeAdmin(address(0xdead));

aggregateVerifier = address(
new AggregateVerifier(
gameType,
Expand All @@ -116,7 +124,8 @@ abstract contract DeployDevBase is Script {
cfg.multiproofConfigHash(),
cfg.l2ChainId(),
_blockInterval(),
_intermediateBlockInterval()
_intermediateBlockInterval(),
IProtocolVersions(address(protocolVersionsProxy))
)
);

Expand Down
31 changes: 31 additions & 0 deletions snapshots/abi/AggregateVerifier.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
"internalType": "uint256",
"name": "intermediateBlockInterval",
"type": "uint256"
},
{
"internalType": "contract IProtocolVersions",
"name": "protocolVersions",
"type": "address"
}
],
"stateMutability": "nonpayable",
Expand Down Expand Up @@ -215,6 +220,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PROTOCOL_VERSIONS",
"outputs": [
{
"internalType": "contract IProtocolVersions",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "SLOW_FINALIZATION_DELAY",
Expand Down Expand Up @@ -681,6 +699,19 @@
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "scheduleId",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "startingBlockNumber",
Expand Down
Loading
Loading