Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
08fa065
feat: add permissionless deploy input fields
lumoswiz Jun 26, 2026
5971a9e
feat: consume permissionless deploy inputs
lumoswiz Jun 26, 2026
486bd89
feat: allow permissionless games at initial deploy
lumoswiz Jun 26, 2026
de2b2ea
fix: validate permissionless deploy config
lumoswiz Jun 29, 2026
5f28ec0
Merge branch 'develop' into feat/pcd-permissionless-opchain-deploy
lumoswiz Jun 29, 2026
20302ca
test: use nonzero cannon prestate in validator fixtures
lumoswiz Jun 29, 2026
950a781
refactor: centralize initial deploy game selection
lumoswiz Jun 29, 2026
896d1d3
test: fix fork tests for current permissionless game config
lumoswiz Jun 29, 2026
7185407
refactor: reduce DeployOPChain permissionless prestate input
lumoswiz Jul 1, 2026
ab659c4
refactor: enable selected initial permissionless game only
lumoswiz Jul 1, 2026
5fa4936
refactor: keep OPCM initial-game validation structural
lumoswiz Jul 1, 2026
2b173db
test: update remaining selected-game fixtures and comments
lumoswiz Jul 1, 2026
c940d5f
chore: refresh OPContractsManagerV2 semver lock
lumoswiz Jul 1, 2026
852e907
chore: remove stale DeployOPChain anchor helper
lumoswiz Jul 1, 2026
0b4e292
chore: document initial deploy game selection
lumoswiz Jul 2, 2026
b661b20
refactor: extract boolean flags for rest of games
0xiamflux Jul 7, 2026
d9c1e68
chore: add clarifying comment on prestate validity
0xiamflux Jul 7, 2026
f8e4932
refactor: extract _isSuperRootEnabled to internal function
0xiamflux Jul 7, 2026
13f4d5c
refactor: move out placeholder to constants file
0xiamflux Jul 7, 2026
5f17dce
refactor: removes _isPermissionlessDeploy
0xiamflux Jul 7, 2026
cb675ca
refactor: simplify config checks for initial deployments
0xiamflux Jul 7, 2026
732e97e
chore: lint fix
0xiamflux Jul 7, 2026
319b506
refactor: extracts game config creation to internal function
0xiamflux Jul 8, 2026
d63c21a
refactor: remove if/else branching in ChainAssertions
0xiamflux Jul 8, 2026
4a7221f
Merge branch 'develop' into feat/pcd-permissionless-opchain-deploy
0xiamflux Jul 8, 2026
f363d19
chore: just pr
0xiamflux Jul 8, 2026
8ee953b
test: fix stale legacy cannon leftovers from develop merge
lumoswiz Jul 8, 2026
828f6d3
refactor: restrict permissionless initial deploy selection to CANNON_…
lumoswiz Jul 8, 2026
d7c5bd1
feat: reject legacy CANNON at initial deployment in OPCMv2
lumoswiz Jul 8, 2026
1b4265b
test: address permissionless deploy review nits
lumoswiz Jul 8, 2026
924bfa1
Merge branch 'develop' into feat/pcd-permissionless-opchain-deploy
0xiamflux Jul 8, 2026
f977197
fix: register permissioned fallback for permissionless deploys
lumoswiz Jul 9, 2026
cf9e65a
Merge remote-tracking branch 'origin/develop' into feat/pcd-permissio…
lumoswiz Jul 9, 2026
69d5b69
Merge remote-tracking branch 'origin/develop' into feat/pcd-permissio…
lumoswiz Jul 9, 2026
48e9b64
test: unify permissionless game init bond helper in DisputeGames
lumoswiz Jul 9, 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
1 change: 1 addition & 0 deletions op-chain-ops/interopgen/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ func DeployL2ToL1(l1Host *script.Host, superCfg *SuperchainConfig, superDeployme
GasLimit: cfg.GasLimit,
DisputeGameType: cfg.DisputeGameType,
DisputeAbsolutePrestate: cfg.DisputeAbsolutePrestate,
StartingAnchorRoot: opcm.DefaultStartingAnchorRoot.Root,
DisputeMaxGameDepth: new(big.Int).SetUint64(cfg.DisputeMaxGameDepth),
DisputeSplitDepth: new(big.Int).SetUint64(cfg.DisputeSplitDepth),
DisputeClockExtension: cfg.DisputeClockExtension,
Expand Down
1 change: 1 addition & 0 deletions op-deployer/pkg/deployer/opcm/opchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type DeployOPChainInput struct {

DisputeGameType uint32
DisputeAbsolutePrestate common.Hash
StartingAnchorRoot common.Hash
DisputeMaxGameDepth *big.Int
DisputeSplitDepth *big.Int
DisputeClockExtension uint64
Expand Down
2 changes: 2 additions & 0 deletions op-deployer/pkg/deployer/pipeline/opchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ func makeDCI(intent *state.Intent, thisIntent *state.ChainIntent, chainID common
return opcm.DeployOPChainInput{}, fmt.Errorf("OPCM implementation is not deployed")
}

// TODO(#20912): Populate StartingAnchorRoot and DisputeAbsolutePrestate from pipeline state for permissionless deploys.
return opcm.DeployOPChainInput{
OpChainProxyAdminOwner: thisIntent.Roles.L1ProxyAdminOwner,
SystemConfigOwner: thisIntent.Roles.SystemConfigOwner,
Expand All @@ -149,6 +150,7 @@ func makeDCI(intent *state.Intent, thisIntent *state.ChainIntent, chainID common
GasLimit: thisIntent.GasLimit,
DisputeGameType: proofParams.DisputeGameType,
DisputeAbsolutePrestate: proofParams.DisputeAbsolutePrestate,
StartingAnchorRoot: opcm.DefaultStartingAnchorRoot.Root,
DisputeMaxGameDepth: new(big.Int).SetUint64(proofParams.DisputeMaxGameDepth),
DisputeSplitDepth: new(big.Int).SetUint64(proofParams.DisputeSplitDepth),
DisputeClockExtension: proofParams.DisputeClockExtension, // 3 hours (input in seconds)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ src_validation = [
"test/dispute/lib/LibGameId.t.sol", # Tests library utilities
"test/libraries/DeployUtils.t.sol", # Tests library utilities - no direct src counterpart
"test/setup/DeployVariations.t.sol", # Tests deployment variations
"test/setup/DisputeGames.t.sol", # Tests a test-only library (test/setup/DisputeGames.sol)
"test/setup/PastNUTBundles.t.sol", # Tests a test-only library (test/setup/PastNUTBundles.sol)
"test/universal/BenchmarkTest.t.sol", # Performance benchmarking tests
"test/universal/ExtendedPause.t.sol", # Tests extended functionality
Expand Down
26 changes: 14 additions & 12 deletions packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
import { Constants } from "src/libraries/Constants.sol";
import { Types } from "scripts/libraries/Types.sol";
import { Blueprint } from "src/libraries/Blueprint.sol";
import { GameType, GameTypes } from "src/dispute/lib/Types.sol";
import { Hash } from "src/dispute/lib/Types.sol";
import { GameType, Hash, Proposal } from "src/dispute/lib/Types.sol";
// Interfaces
import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol";
import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol";
Expand Down Expand Up @@ -402,7 +401,14 @@ library ChainAssertions {
);
}

function checkAnchorStateRegistryProxy(IAnchorStateRegistry _anchorStateRegistryProxy, bool _isProxy) internal {
function checkAnchorStateRegistryProxy(
IAnchorStateRegistry _anchorStateRegistryProxy,
bool _isProxy,
GameType _expectedRespectedGameType,
Hash _expectedRoot
)
internal
{
DeployUtils.assertValidContractAddress(address(_anchorStateRegistryProxy));
if (_isProxy) {
DeployUtils.assertERC1967ImplementationSet(address(_anchorStateRegistryProxy));
Expand All @@ -416,15 +422,11 @@ library ChainAssertions {
});

// The below check cannot be done in the standard validator because the assertion only applies at deploy time.
(Hash actualRoot,) = _anchorStateRegistryProxy.anchors(GameTypes.PERMISSIONED_CANNON);
if (_isProxy) {
require(
Hash.unwrap(actualRoot) == 0xdead000000000000000000000000000000000000000000000000000000000000,
"ANCHORP-40"
);
} else {
require(Hash.unwrap(actualRoot) == bytes32(0), "ANCHORP-40");
}
Proposal memory actualRoot = _anchorStateRegistryProxy.getStartingAnchorRoot();

require(_anchorStateRegistryProxy.respectedGameType().raw() == _expectedRespectedGameType.raw(), "ANCHORP-30");
require(actualRoot.root.raw() == _expectedRoot.raw(), "ANCHORP-40");
require(actualRoot.l2SequenceNumber == 0, "ANCHORP-50");
}

/// @notice Asserts that the ZKDisputeGame implementation is setup correctly.
Expand Down
4 changes: 3 additions & 1 deletion packages/contracts-bedrock/scripts/deploy/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,9 @@ contract Deploy is Deployer {
_mips: IMIPS64(address(dio.mipsSingleton))
});
ChainAssertions.checkSystemConfigImpls(impls);
ChainAssertions.checkAnchorStateRegistryProxy(IAnchorStateRegistry(impls.AnchorStateRegistry), false);
ChainAssertions.checkAnchorStateRegistryProxy(
IAnchorStateRegistry(impls.AnchorStateRegistry), false, GameType.wrap(0), Hash.wrap(bytes32(0))
);
}

/// @notice Deploy all of the OP Chain specific contracts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGam
import { ISuperPermissionedDisputeGame } from "interfaces/dispute/ISuperPermissionedDisputeGame.sol";
import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol";
import { IZKDisputeGame } from "interfaces/dispute/zk/IZKDisputeGame.sol";
import { Duration, GameType, GameTypes } from "src/dispute/lib/Types.sol";
import { Duration, GameType, GameTypes, Hash } from "src/dispute/lib/Types.sol";
import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol";
import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol";
import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol";
Expand Down Expand Up @@ -804,6 +804,8 @@ contract DeployImplementations is Script {
});
ChainAssertions.checkETHLockboxImpl(_output.ethLockboxImpl, _output.optimismPortalImpl);
ChainAssertions.checkSystemConfigImpls(impls);
ChainAssertions.checkAnchorStateRegistryProxy(IAnchorStateRegistry(impls.AnchorStateRegistry), false);
ChainAssertions.checkAnchorStateRegistryProxy(
IAnchorStateRegistry(impls.AnchorStateRegistry), false, GameType.wrap(0), Hash.wrap(bytes32(0))
);
}
}
155 changes: 101 additions & 54 deletions packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Constants as ScriptConstants } from "scripts/libraries/Constants.sol";
import { Types } from "scripts/libraries/Types.sol";

import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol";
import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol";
import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol";
import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol";
Expand All @@ -27,7 +28,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 { GameType, GameTypes } from "src/dispute/lib/Types.sol";
import { GameType, GameTypes, Proposal } from "src/dispute/lib/Types.sol";
import { DevFeatures } from "src/libraries/DevFeatures.sol";

contract DeployOPChain is Script {
Expand Down Expand Up @@ -76,7 +77,7 @@ contract DeployOPChain is Script {
require(address(_input.opcm).code.length > 0, "DeployOPChain: OPCM address has no code");

IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_input.opcm);
isSuperRoot = DevFeatures.isDevFeatureEnabled(opcmV2.devFeatureBitmap(), DevFeatures.SUPER_ROOT_GAMES_MIGRATION);
isSuperRoot = _isSuperRootEnabled(opcmV2);
IOPContractsManagerV2.FullConfig memory config = _toOPCMV2DeployInput(_input);

vm.broadcast(msg.sender);
Expand Down Expand Up @@ -112,11 +113,12 @@ contract DeployOPChain is Script {
view
returns (IOPContractsManagerV2.FullConfig memory config_)
{
// Only PERMISSIONED_CANNON is allowed for initial deployment since no prestate exists for permissionless games.
require(
_input.disputeGameType.raw() == GameTypes.PERMISSIONED_CANNON.raw(),
"DeployOPChain: only PERMISSIONED_CANNON game type is supported for initial deployment"
);
(bool permissionless, GameType respectedGameType) =
_initialDeployGameSelection(_input.disputeGameType, isSuperRoot);
bool enableCannonKona = permissionless && _input.disputeGameType.raw() == GameTypes.CANNON_KONA.raw();
// Non-super-root deploys always register PERMISSIONED_CANNON. In CANNON_KONA mode,
// the ASR respects CANNON_KONA first but the guardian can switch to PERMISSIONED_CANNON.
bool enablePermissionedCannon = !isSuperRoot;

// Shared permissioned game config for legacy permissioned games.
IOPContractsManagerUtils.PermissionedDisputeGameConfig memory pdgConfig = IOPContractsManagerUtils
Expand All @@ -133,36 +135,26 @@ contract DeployOPChain is Script {
IOPContractsManagerUtils.DisputeGameConfig[] memory disputeGameConfigs =
new IOPContractsManagerUtils.DisputeGameConfig[](6);

// Config 0: CANNON (disabled for initial deployment — no prestate exists)
// Config 0: legacy CANNON slot, disabled after U19 and kept to satisfy OPCMV2's 6-config shape.
disputeGameConfigs[0] = IOPContractsManagerUtils.DisputeGameConfig({
enabled: false,
initBond: 0,
gameType: GameTypes.CANNON,
gameArgs: bytes("")
});

// Config 1: PERMISSIONED_CANNON — enabled only in non-super-root mode.
disputeGameConfigs[1] = isSuperRoot
? IOPContractsManagerUtils.DisputeGameConfig({
enabled: false,
initBond: 0,
gameType: GameTypes.PERMISSIONED_CANNON,
gameArgs: bytes("")
})
: IOPContractsManagerUtils.DisputeGameConfig({
enabled: true,
initBond: DEFAULT_INIT_BOND,
gameType: GameTypes.PERMISSIONED_CANNON,
gameArgs: abi.encode(pdgConfig)
});

// Config 2: CANNON_KONA (disabled for initial deployment — no prestate exists)
disputeGameConfigs[2] = IOPContractsManagerUtils.DisputeGameConfig({
enabled: false,
initBond: 0,
gameType: GameTypes.CANNON_KONA,
gameArgs: bytes("")
});
// Config 1: PERMISSIONED_CANNON
disputeGameConfigs[1] =
_createGameConfig(enablePermissionedCannon, GameTypes.PERMISSIONED_CANNON, abi.encode(pdgConfig));

// Config 2: CANNON_KONA
disputeGameConfigs[2] = _createGameConfig(
enableCannonKona,
GameTypes.CANNON_KONA,
abi.encode(
IOPContractsManagerUtils.FaultDisputeGameConfig({ absolutePrestate: _input.disputeAbsolutePrestate })
)
);

// Config 3: SUPER_PERMISSIONED — enabled only in super-root mode.
disputeGameConfigs[3] = isSuperRoot
Expand Down Expand Up @@ -202,8 +194,8 @@ contract DeployOPChain is Script {
systemConfigOwner: _input.systemConfigOwner,
unsafeBlockSigner: _input.unsafeBlockSigner,
batcher: _input.batcher,
startingAnchorRoot: ScriptConstants.DEFAULT_OUTPUT_ROOT(),
startingRespectedGameType: isSuperRoot ? GameTypes.SUPER_PERMISSIONED : GameTypes.PERMISSIONED_CANNON,
startingAnchorRoot: Proposal({ root: _input.startingAnchorRoot, l2SequenceNumber: 0 }),
startingRespectedGameType: respectedGameType,
basefeeScalar: _input.basefeeScalar,
blobBasefeeScalar: _input.blobBaseFeeScalar,
gasLimit: _input.gasLimit,
Expand Down Expand Up @@ -281,6 +273,64 @@ contract DeployOPChain is Script {
require(cfg_.maxResourceLimit > 0, "DeployOPChain: gasLimit too small for any deposit budget");
}

/// @notice Returns the permissionless mode and respected game type for an initial deployment.
Comment thread
lumoswiz marked this conversation as resolved.
/// @dev Permissionless deploys respect the requested game type before the permissioned/super-root default.
function _initialDeployGameSelection(
GameType _disputeGameType,
bool _isSuperRoot
)
internal
pure
returns (bool permissionless_, GameType respectedGameType_)
{
permissionless_ = _disputeGameType.raw() == GameTypes.CANNON_KONA.raw();

// PERMISSIONED_CANNON is the only **permissioned** type supported for an initial deploy.
require(
permissionless_ || _disputeGameType.raw() == GameTypes.PERMISSIONED_CANNON.raw(),
"DeployOPChain: unsupported dispute game type"
);

// Super roots don't support permissionless games and they deploy with SUPER_PERMISSIONED instead.
require(
!(_isSuperRoot && permissionless_), "DeployOPChain: permissionless game type not supported with super roots"
);

respectedGameType_ = permissionless_
? _disputeGameType
: (_isSuperRoot ? GameTypes.SUPER_PERMISSIONED : GameTypes.PERMISSIONED_CANNON);
}

/// @notice Returns whether the given OPCM has the SUPER_ROOT_GAMES_MIGRATION dev feature enabled.
/// @param _opcm The OPCM to check.
/// @return Whether SUPER_ROOT_GAMES_MIGRATION is enabled.
function _isSuperRootEnabled(IOPContractsManagerV2 _opcm) internal view returns (bool) {
return DevFeatures.isDevFeatureEnabled(_opcm.devFeatureBitmap(), DevFeatures.SUPER_ROOT_GAMES_MIGRATION);
}

/// @notice Returns a DisputeGameConfig with the appropriate values based on the parameters passed in.
/// If the game is enabled the configuration is filled with the default init bond and the game
/// arguments passed as parameter otherwise 0 is used for the bond and empty bytes for the arguments.
/// @param _enabled Whether the dispute game is enabled or not
/// @param _gameType The type of this dispute game
/// @param _enabledArgs The arguments for the dispute game config
function _createGameConfig(
bool _enabled,
GameType _gameType,
bytes memory _enabledArgs
)
internal
pure
returns (IOPContractsManagerUtils.DisputeGameConfig memory)
{
return IOPContractsManagerUtils.DisputeGameConfig({
enabled: _enabled,
initBond: _enabled ? DEFAULT_INIT_BOND : 0,
gameType: _gameType,
gameArgs: _enabled ? _enabledArgs : bytes("")
});
}

// -------- Validations --------

/// @notice Checks if the input is valid.
Expand All @@ -302,11 +352,21 @@ contract DeployOPChain is Script {

require(_i.opcm != address(0), "DeployOPChainInput: opcm not set");
DeployUtils.assertValidContractAddress(_i.opcm);
bool superRoot = _isSuperRootEnabled(IOPContractsManagerV2(_i.opcm));
(bool permissionless,) = _initialDeployGameSelection(_i.disputeGameType, superRoot);

require(_i.disputeMaxGameDepth != 0, "DeployOPChainInput: disputeMaxGameDepth not set");
require(_i.disputeSplitDepth != 0, "DeployOPChainInput: disputeSplitDepth not set");
require(_i.disputeMaxClockDuration.raw() != 0, "DeployOPChainInput: disputeMaxClockDuration not set");
require(_i.disputeAbsolutePrestate.raw() != bytes32(0), "DeployOPChainInput: disputeAbsolutePrestate not set");
require(_i.startingAnchorRoot.raw() != bytes32(0), "DeployOPChainInput: startingAnchorRoot not set");

if (permissionless) {
require(
_i.startingAnchorRoot.raw() != ScriptConstants.DEFAULT_OUTPUT_ROOT().root.raw(),
"DeployOPChainInput: permissionless startingAnchorRoot cannot be placeholder"
);
}
}

/// @notice Checks if the output is valid.
Expand Down Expand Up @@ -358,15 +418,18 @@ contract DeployOPChain is Script {

// Check dispute games and get superchain config
IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_i.opcm);
address expectedPDGImpl = isSuperRoot
? opcmV2.implementations().superPermissionedDisputeGameImpl
: opcmV2.implementations().permissionedDisputeGameImpl;
IOPContractsManagerContainer.Implementations memory implementations = opcmV2.implementations();

GameType permGameType = isSuperRoot ? GameTypes.SUPER_PERMISSIONED : GameTypes.PERMISSIONED_CANNON;
(bool permissionless, GameType respectedGameType) = _initialDeployGameSelection(_i.disputeGameType, isSuperRoot);
address expectedDGImpl = permissionless
? implementations.faultDisputeGameImpl
: (isSuperRoot ? implementations.superPermissionedDisputeGameImpl : implementations.permissionedDisputeGameImpl);
ChainAssertions.checkDisputeGameFactory(
_o.disputeGameFactoryProxy, _i.opChainProxyAdminOwner, expectedPDGImpl, true, permGameType
_o.disputeGameFactoryProxy, _i.opChainProxyAdminOwner, expectedDGImpl, true, respectedGameType
);
ChainAssertions.checkAnchorStateRegistryProxy(
_o.anchorStateRegistryProxy, true, respectedGameType, _i.startingAnchorRoot
);
ChainAssertions.checkAnchorStateRegistryProxy(_o.anchorStateRegistryProxy, true);
ChainAssertions.checkL1CrossDomainMessenger(_o.l1CrossDomainMessengerProxy, vm, true);
ChainAssertions.checkOptimismPortal2({
_contracts: proxies,
Expand Down Expand Up @@ -469,20 +532,4 @@ contract DeployOPChain is Script {
"OPCPA-120"
);
}

/// @notice Returns the starting anchor root for the permissioned game.
function startingAnchorRoot() public pure returns (bytes memory) {
// WARNING: For now always hardcode the starting permissioned game anchor root to 0xdead,
// and we do not set anything for the permissioned game. This is because we currently only
// support deploying straight to permissioned games, and the starting root does not
// matter for that, as long as it is non-zero, since no games will be played. We do not
// deploy the permissionless game (and therefore do not set a starting root for it here)
// because updating to the permissionless game will require updating its starting
// anchor root and deploy a new permissioned dispute game contract anyway.
//
// You can `console.logBytes(abi.encode(ScriptConstants.DEFAULT_OUTPUT_ROOT()))` to get the bytes that
// are hardcoded into `op-chain-ops/deployer/opcm/opchain.go`

return abi.encode(ScriptConstants.DEFAULT_OUTPUT_ROOT());
}
}
Loading
Loading