Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,22 @@
"name": "IdentityPrecompileCallFailed",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "devFeature",
"type": "bytes32"
}
],
"name": "InvalidDevFeatureAccess",
"type": "error"
},
{
"inputs": [],
"name": "InvalidGameArgsLength",
"type": "error"
},
{
"inputs": [],
"name": "InvalidGameConfigs",
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts-bedrock/snapshots/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
"sourceCodeHash": "0xfca613b5d055ffc4c3cbccb0773ddb9030abedc1aa6508c9e2e7727cc0cd617b"
},
"src/L1/OPContractsManager.sol:OPContractsManager": {
"initCodeHash": "0x0ef3fcb6fee1f73c95a48269bba8c83ee463a6f116f36f8d88edb247f72e8a05",
"sourceCodeHash": "0x16a845ddb5ee469e81f3d817ee9f6d6ff5697ace0bc399bd1e0f26e05546f781"
"initCodeHash": "0x02af0627bee699be308b7d83ceb41655c38ae6856ed3842246917ae696475d64",
"sourceCodeHash": "0x76f8991025c5346053444d50c4c0b63faa1739deebdbad99360fe37ca068ed15"
},
"src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": {
"initCodeHash": "0x2eaa345ba05582c67b40a1eb7ec9d54823aa08468e697e2d6c04bb74cc574abc",
Expand Down
225 changes: 137 additions & 88 deletions packages/contracts-bedrock/src/L1/OPContractsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,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 { ISystemConfig } from "../../interfaces/L1/ISystemConfig.sol";

contract OPContractsManagerContractsContainer {
/// @notice Addresses of the Blueprint contracts.
Expand Down Expand Up @@ -571,111 +572,159 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase {
outputs[i].delayedWETH = gameConfig.delayedWETH;
}

// Determine the contract name and blueprints for the game type.
string memory gameContractName;
address blueprint1;
address blueprint2;
uint256 gameL2ChainId;
// Grab the DisputeGameFactory and AnchorStateRegistry for the chain.
IDisputeGameFactory dgf = getDisputeGameFactory(gameConfig.systemConfig);

// Separate context to avoid stack too deep.
{
// Grab the blueprints once since we'll need it multiple times below.
OPContractsManager.Blueprints memory bps = getBlueprints();
// Grab the existing game implementation from the DisputeGameFactory.
IFaultDisputeGame existingGame =
IFaultDisputeGame(address(getGameImplementation(dgf, gameConfig.disputeGameType)));

// Determine the contract name and blueprints for the game type.
// Super games don't support V2 contracts yet so fallback to the V1 contracts for those game types.
if (
isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)
&& gameConfig.disputeGameType.raw() != GameTypes.SUPER_PERMISSIONED_CANNON.raw()
&& gameConfig.disputeGameType.raw() != GameTypes.SUPER_CANNON.raw()
&& gameConfig.disputeGameType.raw() != GameTypes.SUPER_CANNON_KONA.raw()
) {
if (
gameConfig.disputeGameType.raw() == GameTypes.CANNON.raw()
|| (
isDevFeatureEnabled(DevFeatures.CANNON_KONA)
&& gameConfig.disputeGameType.raw() == GameTypes.CANNON_KONA.raw()
)
) {
gameContractName = "FaultDisputeGame";
blueprint1 = bps.permissionlessDisputeGame1;
blueprint2 = bps.permissionlessDisputeGame2;
gameL2ChainId = l2ChainId;
address impl = implementations().faultDisputeGameV2Impl;
bytes memory gameArgs = abi.encodePacked(
gameConfig.disputeAbsolutePrestate, // 32 bytes
gameConfig.vm, // 20 bytes
address(getAnchorStateRegistry(ISystemConfig(gameConfig.systemConfig))), // 20
// bytes
address(outputs[i].delayedWETH), // 20 bytes
l2ChainId // 32 bytes
);
setDGFImplementation(dgf, gameConfig.disputeGameType, IDisputeGame(impl), gameArgs);
outputs[i].faultDisputeGame = IFaultDisputeGame(impl);
} else if (gameConfig.disputeGameType.raw() == GameTypes.PERMISSIONED_CANNON.raw()) {
gameContractName = "PermissionedDisputeGame";
blueprint1 = bps.permissionedDisputeGame1;
blueprint2 = bps.permissionedDisputeGame2;
gameL2ChainId = l2ChainId;
} else if (
gameConfig.disputeGameType.raw() == GameTypes.SUPER_CANNON.raw()
|| (
isDevFeatureEnabled(DevFeatures.CANNON_KONA)
&& gameConfig.disputeGameType.raw() == GameTypes.SUPER_CANNON_KONA.raw()
)
) {
gameContractName = "SuperFaultDisputeGame";
blueprint1 = bps.superPermissionlessDisputeGame1;
blueprint2 = bps.superPermissionlessDisputeGame2;
gameL2ChainId = 0;
} else if (gameConfig.disputeGameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw()) {
gameContractName = "SuperPermissionedDisputeGame";
blueprint1 = bps.superPermissionedDisputeGame1;
blueprint2 = bps.superPermissionedDisputeGame2;
gameL2ChainId = 0;
address impl = implementations().permissionedDisputeGameV2Impl;
bytes memory gameArgs = abi.encodePacked(
gameConfig.disputeAbsolutePrestate, // 32 bytes
gameConfig.vm, // 20 bytes
address(getAnchorStateRegistry(ISystemConfig(gameConfig.systemConfig))), // 20 bytes
address(outputs[i].delayedWETH), // 20 bytes
l2ChainId, // 32 bytes
getProposer(dgf, IPermissionedDisputeGame(address(existingGame)), gameConfig.disputeGameType), // 20
// bytes
getChallenger(dgf, IPermissionedDisputeGame(address(existingGame)), gameConfig.disputeGameType) // 20
// bytes
);
setDGFImplementation(dgf, gameConfig.disputeGameType, IDisputeGame(impl), gameArgs);
outputs[i].faultDisputeGame = IFaultDisputeGame(payable(impl));
} else {
revert OPContractsManagerGameTypeAdder_UnsupportedGameType();
}
}

// Grab the DisputeGameFactory and AnchorStateRegistry for the chain.
IDisputeGameFactory dgf = getDisputeGameFactory(gameConfig.systemConfig);
} else {
// Determine the contract name and blueprints for the game type.
string memory gameContractName;
address blueprint1;
address blueprint2;
uint256 gameL2ChainId;

// Separate context to avoid stack too deep.
{
// Grab the blueprints once since we'll need it multiple times below.
OPContractsManager.Blueprints memory bps = getBlueprints();

// Determine the contract name and blueprints for the game type.
if (
gameConfig.disputeGameType.raw() == GameTypes.CANNON.raw()
|| (
isDevFeatureEnabled(DevFeatures.CANNON_KONA)
&& gameConfig.disputeGameType.raw() == GameTypes.CANNON_KONA.raw()
)
) {
gameContractName = "FaultDisputeGame";
blueprint1 = bps.permissionlessDisputeGame1;
blueprint2 = bps.permissionlessDisputeGame2;
gameL2ChainId = l2ChainId;
} else if (gameConfig.disputeGameType.raw() == GameTypes.PERMISSIONED_CANNON.raw()) {
gameContractName = "PermissionedDisputeGame";
blueprint1 = bps.permissionedDisputeGame1;
blueprint2 = bps.permissionedDisputeGame2;
gameL2ChainId = l2ChainId;
} else if (
gameConfig.disputeGameType.raw() == GameTypes.SUPER_CANNON.raw()
|| (
isDevFeatureEnabled(DevFeatures.CANNON_KONA)
&& gameConfig.disputeGameType.raw() == GameTypes.SUPER_CANNON_KONA.raw()
)
) {
gameContractName = "SuperFaultDisputeGame";
blueprint1 = bps.superPermissionlessDisputeGame1;
blueprint2 = bps.superPermissionlessDisputeGame2;
gameL2ChainId = 0;
} else if (gameConfig.disputeGameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw()) {
gameContractName = "SuperPermissionedDisputeGame";
blueprint1 = bps.superPermissionedDisputeGame1;
blueprint2 = bps.superPermissionedDisputeGame2;
gameL2ChainId = 0;
} else {
revert OPContractsManagerGameTypeAdder_UnsupportedGameType();
}
}

// Grab the existing game implementation from the DisputeGameFactory.
IFaultDisputeGame existingGame =
IFaultDisputeGame(address(getGameImplementation(dgf, gameConfig.disputeGameType)));
// Encode the constructor data for the game type.
bytes memory constructorData;
if (gameConfig.permissioned) {
constructorData = encodePermissionedFDGConstructor(
IFaultDisputeGame.GameConstructorParams(
gameConfig.disputeGameType,
gameConfig.disputeAbsolutePrestate,
gameConfig.disputeMaxGameDepth,
gameConfig.disputeSplitDepth,
gameConfig.disputeClockExtension,
gameConfig.disputeMaxClockDuration,
gameConfig.vm,
outputs[i].delayedWETH,
getAnchorStateRegistry(gameConfig.systemConfig),
gameL2ChainId
),
getProposerV1(IPermissionedDisputeGame(address(existingGame))),
getChallengerV1(IPermissionedDisputeGame(address(existingGame)))
);
} else {
constructorData = encodePermissionlessFDGConstructor(
IFaultDisputeGame.GameConstructorParams(
gameConfig.disputeGameType,
gameConfig.disputeAbsolutePrestate,
gameConfig.disputeMaxGameDepth,
gameConfig.disputeSplitDepth,
gameConfig.disputeClockExtension,
gameConfig.disputeMaxClockDuration,
gameConfig.vm,
outputs[i].delayedWETH,
getAnchorStateRegistry(gameConfig.systemConfig),
gameL2ChainId
)
);
}

// Encode the constructor data for the game type.
bytes memory constructorData;
if (gameConfig.permissioned) {
constructorData = encodePermissionedFDGConstructor(
IFaultDisputeGame.GameConstructorParams(
gameConfig.disputeGameType,
gameConfig.disputeAbsolutePrestate,
gameConfig.disputeMaxGameDepth,
gameConfig.disputeSplitDepth,
gameConfig.disputeClockExtension,
gameConfig.disputeMaxClockDuration,
gameConfig.vm,
outputs[i].delayedWETH,
getAnchorStateRegistry(gameConfig.systemConfig),
gameL2ChainId
),
getProposerV1(IPermissionedDisputeGame(address(existingGame))),
getChallengerV1(IPermissionedDisputeGame(address(existingGame)))
);
} else {
constructorData = encodePermissionlessFDGConstructor(
IFaultDisputeGame.GameConstructorParams(
gameConfig.disputeGameType,
gameConfig.disputeAbsolutePrestate,
gameConfig.disputeMaxGameDepth,
gameConfig.disputeSplitDepth,
gameConfig.disputeClockExtension,
gameConfig.disputeMaxClockDuration,
gameConfig.vm,
outputs[i].delayedWETH,
getAnchorStateRegistry(gameConfig.systemConfig),
gameL2ChainId
// Deploy the new game type.
outputs[i].faultDisputeGame = IFaultDisputeGame(
Blueprint.deployFrom(
blueprint1,
blueprint2,
computeSalt(l2ChainId, gameConfig.saltMixer, gameContractName),
constructorData
)
);
}

// Deploy the new game type.
outputs[i].faultDisputeGame = IFaultDisputeGame(
Blueprint.deployFrom(
blueprint1,
blueprint2,
computeSalt(l2ChainId, gameConfig.saltMixer, gameContractName),
constructorData
)
);
// As a last step, register the new game type with the DisputeGameFactory. If the game
// type already exists, then its implementation will be overwritten.
setDGFImplementation(
dgf, gameConfig.disputeGameType, IDisputeGame(address(outputs[i].faultDisputeGame))
);
}

// As a last step, register the new game type with the DisputeGameFactory. If the game
// type already exists, then its implementation will be overwritten.
setDGFImplementation(dgf, gameConfig.disputeGameType, IDisputeGame(address(outputs[i].faultDisputeGame)));
dgf.setInitBond(gameConfig.disputeGameType, gameConfig.initialBond);

// Emit event for the newly added game type with the new and old implementations.
Expand Down Expand Up @@ -2089,9 +2138,9 @@ contract OPContractsManager is ISemver {

// -------- Constants and Variables --------

/// @custom:semver 4.4.0
/// @custom:semver 4.5.0
function version() public pure virtual returns (string memory) {
return "4.4.0";
return "4.5.0";
}

OPContractsManagerGameTypeAdder public immutable opcmGameTypeAdder;
Expand Down
Loading