Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -355,6 +355,7 @@ func GenesisL2(l2Host *script.Host, cfg *L2Config, deployment *L2Deployment, mul
GasPayingTokenSymbol: cfg.GasPayingTokenSymbol,
NativeAssetLiquidityAmount: cfg.NativeAssetLiquidityAmount.ToInt(),
LiquidityControllerOwner: cfg.LiquidityControllerOwner,
UseL2CM: false, // TODO(#19102): add support for L2CM
}); err != nil {
return fmt.Errorf("failed L2 genesis: %w", err)
}
Expand Down
3 changes: 3 additions & 0 deletions op-deployer/pkg/deployer/devfeatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ var (

// OPCMV2DevFlag enables the OPContractsManagerV2 contract.
OPCMV2DevFlag = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000010000")

// L2CMDevFlag enables L2CM.
L2CMDevFlag = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000100000")
)

// IsDevFeatureEnabled checks if a specific development feature is enabled in a feature bitmap.
Expand Down
26 changes: 26 additions & 0 deletions op-deployer/pkg/deployer/integration_test/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,32 @@ func TestEndToEndApply(t *testing.T) {
require.Equal(t, amount, account.Balance, "Native asset liquidity predeploy should have the configured balance")
})

t.Run("with L2CM", func(t *testing.T) {
intent, st := shared.NewIntent(t, l1ChainID, dk, l2ChainID1, loc, loc, testCustomGasLimit)

intent.GlobalDeployOverrides = map[string]any{
"devFeatureBitmap": deployer.L2CMDevFlag,
}

require.NoError(t, deployer.ApplyPipeline(ctx, deployer.ApplyPipelineOpts{
DeploymentTarget: deployer.DeploymentTargetLive,
L1RPCUrl: l1RPC,
DeployerPrivateKey: pk,
Intent: intent,
State: st,
Logger: lgr,
StateWriter: pipeline.NoopStateWriter(),
CacheDir: testCacheDir,
}))

// Check that the conditional deployer predeploy is deployed in L2 genesis
conditionalDeployerAddr := common.HexToAddress("0x420000000000000000000000000000000000002C")
l2Genesis := st.Chains[0].Allocs.Data.Accounts
account, exists := l2Genesis[conditionalDeployerAddr]
require.True(t, exists, "Conditional deployer should exist in L2 genesis")
require.NotEmpty(t, account.Code, "Conditional deployer should have code deployed")
})

t.Run("OPCMV2 deployment", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
Expand Down
1 change: 1 addition & 0 deletions op-deployer/pkg/deployer/opcm/l2genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type L2GenesisInput struct {
GasPayingTokenSymbol string
NativeAssetLiquidityAmount *big.Int
LiquidityControllerOwner common.Address
UseL2CM bool
}

type L2GenesisScript script.DeployScriptWithoutOutput[L2GenesisInput]
Expand Down
17 changes: 13 additions & 4 deletions op-deployer/pkg/deployer/pipeline/l2genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum/go-ethereum/common/hexutil"

"github.com/ethereum-optimism/optimism/op-service/jsonutil"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-service/jsonutil"

"github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -85,6 +83,16 @@ func GenerateL2Genesis(pEnv *Env, intent *state.Intent, bundle ArtifactsBundle,

cgt := buildCGTConfig(thisIntent)

// Check if L2CM feature is enabled
var useL2CM bool
if devFeatureBitmap, ok := intent.GlobalDeployOverrides["devFeatureBitmap"].(common.Hash); ok {
// TODO(#19151): Replace this with the L2CMDevFlag constant when we fix import cycles.
l2CMFlag := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000100000")
if isDevFeatureEnabled(devFeatureBitmap, l2CMFlag) {
useL2CM = true
}
}

if err := script.Run(opcm.L2GenesisInput{
L1ChainID: new(big.Int).SetUint64(intent.L1ChainID),
L2ChainID: chainID.Big(),
Expand Down Expand Up @@ -118,6 +126,7 @@ func GenerateL2Genesis(pEnv *Env, intent *state.Intent, bundle ArtifactsBundle,
GasPayingTokenSymbol: cgt.GasPayingTokenSymbol,
NativeAssetLiquidityAmount: cgt.NativeAssetLiquidityAmount,
LiquidityControllerOwner: cgt.LiquidityControllerOwner,
UseL2CM: useL2CM,
}); err != nil {
return fmt.Errorf("failed to call L2Genesis script: %w", err)
}
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
// Select which OPCM to use based on dev feature flag
opcmAddr := st.ImplementationsDeployment.OpcmImpl
if devFeatureBitmap, ok := intent.GlobalDeployOverrides["devFeatureBitmap"].(common.Hash); ok {
// TODO(#19151): Replace this with the OPCMV2DevFlag constant when we fix import cycles.
opcmV2Flag := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000010000")
if isDevFeatureEnabled(devFeatureBitmap, opcmV2Flag) {
opcmAddr = st.ImplementationsDeployment.OpcmV2Impl
Expand Down Expand Up @@ -211,6 +212,7 @@ func shouldDeployOPChain(st *state.State, chainID common.Hash) bool {
return true
}

// TODO(#19151): Remove this function when we fix import cycles.
// isDevFeatureEnabled checks if a specific development feature is enabled in a feature bitmap.
// This mirrors the function in devfeatures.go to avoid import cycles.
func isDevFeatureEnabled(bitmap, flag common.Hash) bool {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @title IConditionalDeployer
/// @notice Interface for the ConditionalDeployer contract.
interface IConditionalDeployer is ISemver {
/// @notice Emitted when an implementation is deployed.
/// @param implementation The address of the deployed implementation.
/// @param salt The salt used for deployment.
event ImplementationDeployed(address indexed implementation, bytes32 salt);

/// @notice Emitted when deployment is skipped because implementation already exists.
/// @param implementation The address of the existing implementation.
event ImplementationExists(address indexed implementation);

/// @notice Error thrown when deployment fails.
/// @param data The data returned from the deployment call.
error ConditionalDeployer_DeploymentFailed(bytes data);

/// @notice Deploys an implementation using CREATE2 if it doesn't already exist.
/// @param _salt The salt to use for CREATE2 deployment.
/// @param _code The initialization code for the contract.
/// @return implementation_ The address of the deployed or existing implementation.
function deploy(bytes32 _salt, bytes memory _code) external returns (address implementation_);

/// @notice Address of the Arachnid's DeterministicDeploymentProxy.
/// @return deterministicDeploymentProxy_ The address of the Arachnid's DeterministicDeploymentProxy.
function deterministicDeploymentProxy() external pure returns (address deterministicDeploymentProxy_);
}
16 changes: 14 additions & 2 deletions packages/contracts-bedrock/scripts/L2Genesis.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ contract L2Genesis is Script {
string gasPayingTokenSymbol;
uint256 nativeAssetLiquidityAmount;
address liquidityControllerOwner;
bool useL2CM;
}

using ForkUtils for Fork;
Expand Down Expand Up @@ -221,8 +222,11 @@ contract L2Genesis is Script {
vm.etch(addr, code);
EIP1967Helper.setAdmin(addr, Predeploys.PROXY_ADMIN);

if (Predeploys.isSupportedPredeploy(addr, _input.fork, _input.deployCrossL2Inbox, _input.useCustomGasToken))
{
if (
Predeploys.isSupportedPredeploy(
addr, _input.fork, _input.deployCrossL2Inbox, _input.useCustomGasToken, _input.useL2CM
)
) {
address implementation = Predeploys.predeployToCodeNamespace(addr);
EIP1967Helper.setImplementation(addr, implementation);
}
Expand Down Expand Up @@ -268,6 +272,9 @@ contract L2Genesis is Script {
setLiquidityController(_input); // 29
setNativeAssetLiquidity(_input); // 2A
}
if (_input.useL2CM) {
setConditionalDeployer(); // 2C
}
}

function setInteropPredeployProxies() internal { }
Expand Down Expand Up @@ -578,6 +585,11 @@ contract L2Genesis is Script {
vm.deal(Predeploys.NATIVE_ASSET_LIQUIDITY, _input.nativeAssetLiquidityAmount);
}

/// @notice This predeploy is following the safety invariant #1.
function setConditionalDeployer() internal {
_setImplementationCode(Predeploys.CONDITIONAL_DEPLOYER);
}

/// @notice Sets all the preinstalls.
function setPreinstalls() internal {
address tmpSetPreinstalls = address(uint160(uint256(keccak256("SetPreinstalls"))));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ contract DeployConfig is Script {
uint256 public faultGameV2ClockExtension;
uint256 public faultGameV2MaxClockDuration;

bool public useL2CM;

bool public useInterop;
bool public useUpgradedFork;
bytes32 public devFeatureBitmap;
Expand Down Expand Up @@ -181,6 +183,8 @@ contract DeployConfig is Script {
daBondSize = _readOr(_json, "$.daBondSize", 1000000000);
daResolverRefundPercentage = _readOr(_json, "$.daResolverRefundPercentage", 0);

useL2CM = _readOr(_json, "$.useL2CM", false);

useInterop = _readOr(_json, "$.useInterop", false);
devFeatureBitmap = bytes32(_readOr(_json, "$.devFeatureBitmap", 0));
useUpgradedFork;
Expand Down Expand Up @@ -317,6 +321,11 @@ contract DeployConfig is Script {
operatorFeeVaultWithdrawalNetwork = _operatorFeeVaultWithdrawalNetwork;
}

/// @notice Allow the `useL2CM` config to be overridden in testing environments
function setUseL2CM(bool _useL2CM) public {
useL2CM = _useL2CM;
}

function latestGenesisFork() internal view returns (Fork) {
if (l2GenesisJovianTimeOffset == 0) {
return Fork.JOVIAN;
Expand Down
5 changes: 5 additions & 0 deletions packages/contracts-bedrock/scripts/libraries/Config.sol
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ library Config {
return vm.envOr("DEV_FEATURE__OPCM_V2", false);
}

/// @notice Returns true if the development feature l2cm is enabled.
function devFeatureL2CM() internal view returns (bool) {
return vm.envOr("DEV_FEATURE__L2CM", false);
}

/// @notice Returns true if the system feature custom_gas_token is enabled.
function sysFeatureCustomGasToken() internal view returns (bool) {
return vm.envOr("SYS_FEATURE__CUSTOM_GAS_TOKEN", false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
[
{
"inputs": [
{
"internalType": "bytes32",
"name": "_salt",
"type": "bytes32"
},
{
"internalType": "bytes",
"name": "_code",
"type": "bytes"
}
],
"name": "deploy",
"outputs": [
{
"internalType": "address",
"name": "implementation_",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "deterministicDeploymentProxy",
"outputs": [
{
"internalType": "address",
"name": "deterministicDeploymentProxy_",
"type": "address"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "implementation",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
}
],
"name": "ImplementationDeployed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "implementation",
"type": "address"
}
],
"name": "ImplementationExists",
"type": "event"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "ConditionalDeployer_DeploymentFailed",
"type": "error"
}
]
4 changes: 4 additions & 0 deletions packages/contracts-bedrock/snapshots/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
"initCodeHash": "0x838bbd7f381e84e21887f72bd1da605bfc4588b3c39aed96cbce67c09335b3ee",
"sourceCodeHash": "0xcb329746df0baddd3dc03c6c88da5d6bdc0f0a96d30e6dc78d0891bb1e935032"
},
"src/L2/ConditionalDeployer.sol:ConditionalDeployer": {
"initCodeHash": "0x580996fd149ac478b9363399eab8ba479ed55a324a215ea8e4841f9e9f033ac5",
"sourceCodeHash": "0x7c83a95f65cfd963af0caf90579e8f8544e3f883a48bc803720ec251c72aeffe"
},
"src/L2/CrossL2Inbox.sol:CrossL2Inbox": {
"initCodeHash": "0x56f868e561c4abe539043f98b16aad9305479e68fd03ece2233249b0c73a24ea",
"sourceCodeHash": "0x7c6d362a69a480a06a079542a7fd2ce48cb1dd80d6b9043fba60218569371349"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Loading