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
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@
},
{
"internalType": "address",
"name": "l1BlockAttributesImpl",
"name": "l1BlockImpl",
"type": "address"
},
{
"internalType": "address",
"name": "l1BlockAttributesCGTImpl",
"name": "l1BlockCGTImpl",
"type": "address"
},
{
Expand Down Expand Up @@ -142,6 +142,11 @@
"internalType": "address",
"name": "feeSplitterImpl",
"type": "address"
},
{
"internalType": "address",
"name": "conditionalDeployerImpl",
"type": "address"
}
],
"internalType": "struct L2ContractsManagerTypes.Implementations",
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 @@ -96,8 +96,8 @@
"sourceCodeHash": "0x7e438cbbe9a8248887b8c21f68c811f90a5cae4902cbbf7b0a1f6cd644dc42d9"
},
"src/L2/L2ContractsManager.sol:L2ContractsManager": {
"initCodeHash": "0x5770f8b4f605f5b13b8f499a7d21f90df2aad86b09268dcb517c14fef33e2f76",
"sourceCodeHash": "0x1b45f8de05722ce89d5ae075a5c94fad57e24a433de5761923946abb57dd50ca"
"initCodeHash": "0x2f41a11c7ed9bddbccebe9486243af5bc2693d1d98dfd77afb48f4154280c2e5",
"sourceCodeHash": "0x977efd878ca60d12f5a9348ad9c0502fe9cdae31d5579bd580fc76c3c0992a3a"
},
"src/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger": {
"initCodeHash": "0xe160be403df12709c371c33195d1b9c3b5e9499e902e86bdabc8eed749c3fd61",
Expand Down
19 changes: 11 additions & 8 deletions packages/contracts-bedrock/src/L2/L2ContractsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ contract L2ContractsManager is ISemver {
address internal immutable OPTIMISM_MINTABLE_ERC20_FACTORY_IMPL;
/// @notice L2ERC721Bridge implementation.
address internal immutable L2_ERC721_BRIDGE_IMPL;
/// @notice L1BlockAttributes implementation.
address internal immutable L1_BLOCK_ATTRIBUTES_IMPL;
/// @notice L1BlockAttributes implementation for custom gas token networks.
address internal immutable L1_BLOCK_ATTRIBUTES_CGT_IMPL;
/// @notice L1Block implementation.
address internal immutable L1_BLOCK_IMPL;
/// @notice L1Block implementation for custom gas token networks.
address internal immutable L1_BLOCK_CGT_IMPL;
/// @notice L2ToL1MessagePasser implementation.
address internal immutable L2_TO_L1_MESSAGE_PASSER_IMPL;
/// @notice L2ToL1MessagePasser implementation for custom gas token networks.
Expand Down Expand Up @@ -102,6 +102,8 @@ contract L2ContractsManager is ISemver {
address internal immutable LIQUIDITY_CONTROLLER_IMPL;
/// @notice FeeSplitter implementation.
address internal immutable FEE_SPLITTER_IMPL;
/// @notice CONDITIONAL_DEPLOYER implementation.
address internal immutable CONDITIONAL_DEPLOYER_IMPL;

/// @notice Constructor for the L2ContractsManager contract.
/// @param _implementations The implementation struct containing the new implementation addresses for the L2
Expand All @@ -119,8 +121,8 @@ contract L2ContractsManager is ISemver {
SEQUENCER_FEE_WALLET_IMPL = _implementations.sequencerFeeWalletImpl;
OPTIMISM_MINTABLE_ERC20_FACTORY_IMPL = _implementations.optimismMintableERC20FactoryImpl;
L2_ERC721_BRIDGE_IMPL = _implementations.l2ERC721BridgeImpl;
L1_BLOCK_ATTRIBUTES_IMPL = _implementations.l1BlockAttributesImpl;
L1_BLOCK_ATTRIBUTES_CGT_IMPL = _implementations.l1BlockAttributesCGTImpl;
L1_BLOCK_IMPL = _implementations.l1BlockImpl;
L1_BLOCK_CGT_IMPL = _implementations.l1BlockCGTImpl;
L2_TO_L1_MESSAGE_PASSER_IMPL = _implementations.l2ToL1MessagePasserImpl;
L2_TO_L1_MESSAGE_PASSER_CGT_IMPL = _implementations.l2ToL1MessagePasserCGTImpl;
OPTIMISM_MINTABLE_ERC721_FACTORY_IMPL = _implementations.optimismMintableERC721FactoryImpl;
Expand All @@ -142,6 +144,7 @@ contract L2ContractsManager is ISemver {
NATIVE_ASSET_LIQUIDITY_IMPL = _implementations.nativeAssetLiquidityImpl;
LIQUIDITY_CONTROLLER_IMPL = _implementations.liquidityControllerImpl;
FEE_SPLITTER_IMPL = _implementations.feeSplitterImpl;
CONDITIONAL_DEPLOYER_IMPL = _implementations.conditionalDeployerImpl;
}

/// @notice Executes the upgrade for all predeploys.
Expand Down Expand Up @@ -362,8 +365,7 @@ contract L2ContractsManager is ISemver {
L2ContractsManagerUtils.upgradeTo(Predeploys.GAS_PRICE_ORACLE, GAS_PRICE_ORACLE_IMPL);
// L1BlockAttributes and L2ToL1MessagePasser have different implementations for custom gas token networks.
L2ContractsManagerUtils.upgradeTo(
Predeploys.L1_BLOCK_ATTRIBUTES,
_config.isCustomGasToken ? L1_BLOCK_ATTRIBUTES_CGT_IMPL : L1_BLOCK_ATTRIBUTES_IMPL
Predeploys.L1_BLOCK_ATTRIBUTES, _config.isCustomGasToken ? L1_BLOCK_CGT_IMPL : L1_BLOCK_IMPL
);
L2ContractsManagerUtils.upgradeTo(
Predeploys.L2_TO_L1_MESSAGE_PASSER,
Expand All @@ -390,5 +392,6 @@ contract L2ContractsManager is ISemver {
L2ContractsManagerUtils.upgradeTo(Predeploys.SUPERCHAIN_TOKEN_BRIDGE, SUPERCHAIN_TOKEN_BRIDGE_IMPL);
L2ContractsManagerUtils.upgradeTo(Predeploys.SCHEMA_REGISTRY, SCHEMA_REGISTRY_IMPL);
L2ContractsManagerUtils.upgradeTo(Predeploys.EAS, EAS_IMPL);
L2ContractsManagerUtils.upgradeTo(Predeploys.CONDITIONAL_DEPLOYER, CONDITIONAL_DEPLOYER_IMPL);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ library L2ContractsManagerTypes {
address sequencerFeeWalletImpl;
address optimismMintableERC20FactoryImpl;
address l2ERC721BridgeImpl;
address l1BlockAttributesImpl;
address l1BlockAttributesCGTImpl;
address l1BlockImpl;
address l1BlockCGTImpl;
address l2ToL1MessagePasserImpl;
address l2ToL1MessagePasserCGTImpl;
address optimismMintableERC721FactoryImpl;
Expand All @@ -95,5 +95,6 @@ library L2ContractsManagerTypes {
address nativeAssetLiquidityImpl;
address liquidityControllerImpl;
address feeSplitterImpl;
address conditionalDeployerImpl;
}
}
39 changes: 39 additions & 0 deletions packages/contracts-bedrock/src/libraries/Predeploys.sol
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,43 @@ library Predeploys {

isUpgradeable_ = isPredeployNamespace(_proxy) && !notProxied(_proxy) && implementation.code.length > 0;
}

/// @notice Returns all proxied predeploys that should be upgraded by L2CM.
/// This means that for each of these predeploys, isUpgradeable(predeploy) should return true if running on
/// a network that supports it.
/// @dev IMPORTANT: This is the SOURCE OF TRUTH for upgrade coverage. All proxied predeploys from
/// Predeploys library should be listed here.
/// Excludes: WETH, GOVERNANCE_TOKEN (not proxied), legacy predeploys (not upgraded).
function getUpgradeablePredeploys() internal pure returns (address[] memory predeploys_) {
predeploys_ = new address[](26);
// Core predeploys
predeploys_[0] = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
predeploys_[1] = Predeploys.GAS_PRICE_ORACLE;
predeploys_[2] = Predeploys.L2_STANDARD_BRIDGE;
predeploys_[3] = Predeploys.SEQUENCER_FEE_WALLET;
predeploys_[4] = Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY;
predeploys_[5] = Predeploys.L2_ERC721_BRIDGE;
predeploys_[6] = Predeploys.L1_BLOCK_ATTRIBUTES;
predeploys_[7] = Predeploys.L2_TO_L1_MESSAGE_PASSER;
predeploys_[8] = Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY;
predeploys_[9] = Predeploys.PROXY_ADMIN;
predeploys_[10] = Predeploys.BASE_FEE_VAULT;
predeploys_[11] = Predeploys.L1_FEE_VAULT;
predeploys_[12] = Predeploys.OPERATOR_FEE_VAULT;
predeploys_[13] = Predeploys.SCHEMA_REGISTRY;
predeploys_[14] = Predeploys.EAS;
predeploys_[15] = Predeploys.FEE_SPLITTER;
predeploys_[16] = Predeploys.CONDITIONAL_DEPLOYER;
// Interop predeploys
predeploys_[17] = Predeploys.CROSS_L2_INBOX;
predeploys_[18] = Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER;
predeploys_[19] = Predeploys.SUPERCHAIN_ETH_BRIDGE;
predeploys_[20] = Predeploys.ETH_LIQUIDITY;
predeploys_[21] = Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY;
predeploys_[22] = Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON;
predeploys_[23] = Predeploys.SUPERCHAIN_TOKEN_BRIDGE;
// CGT predeploys (conditionally deployed, but still must be included in the list)
predeploys_[24] = Predeploys.NATIVE_ASSET_LIQUIDITY;
predeploys_[25] = Predeploys.LIQUIDITY_CONTROLLER;
}
}
74 changes: 25 additions & 49 deletions packages/contracts-bedrock/test/L2/L2ContractsManager.t.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

// Libraries
import { Predeploys } from "src/libraries/Predeploys.sol";
import { DevFeatures } from "src/libraries/DevFeatures.sol";
import { L2ContractsManager } from "src/L2/L2ContractsManager.sol";
import { L2ContractsManagerTypes } from "src/libraries/L2ContractsManagerTypes.sol";
import { CommonTest } from "test/setup/CommonTest.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { StorageSetter } from "src/universal/StorageSetter.sol";
import { L2CrossDomainMessenger } from "src/L2/L2CrossDomainMessenger.sol";
import { Types } from "src/libraries/Types.sol";
import { Features } from "src/libraries/Features.sol";

// Interfaces
import { ICrossDomainMessenger } from "interfaces/universal/ICrossDomainMessenger.sol";
import { IStandardBridge } from "interfaces/universal/IStandardBridge.sol";
import { IERC721Bridge } from "interfaces/universal/IERC721Bridge.sol";
Expand All @@ -16,7 +22,9 @@ import { IFeeVault } from "interfaces/L2/IFeeVault.sol";
import { IFeeSplitter } from "interfaces/L2/IFeeSplitter.sol";
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { ILiquidityController } from "interfaces/L2/ILiquidityController.sol";
import { IProxy } from "interfaces/universal/IProxy.sol";

// Contracts
import { GasPriceOracle } from "src/L2/GasPriceOracle.sol";
import { L2StandardBridge } from "src/L2/L2StandardBridge.sol";
import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol";
Expand All @@ -32,9 +40,6 @@ import { ETHLiquidity } from "src/L2/ETHLiquidity.sol";
import { OptimismSuperchainERC20Beacon } from "src/L2/OptimismSuperchainERC20Beacon.sol";
import { NativeAssetLiquidity } from "src/L2/NativeAssetLiquidity.sol";
import { LiquidityController } from "src/L2/LiquidityController.sol";
import { Types } from "src/libraries/Types.sol";
import { Features } from "src/libraries/Features.sol";
import { IProxy } from "interfaces/universal/IProxy.sol";

/// @title L2ContractsManager_FullConfigExposer_Harness
/// @notice Harness contract that exposes internal functions for testing.
Expand All @@ -56,8 +61,8 @@ contract L2ContractsManager_FullConfigExposer_Harness is L2ContractsManager {
sequencerFeeWalletImpl: SEQUENCER_FEE_WALLET_IMPL,
optimismMintableERC20FactoryImpl: OPTIMISM_MINTABLE_ERC20_FACTORY_IMPL,
l2ERC721BridgeImpl: L2_ERC721_BRIDGE_IMPL,
l1BlockAttributesImpl: L1_BLOCK_ATTRIBUTES_IMPL,
l1BlockAttributesCGTImpl: L1_BLOCK_ATTRIBUTES_CGT_IMPL,
l1BlockImpl: L1_BLOCK_IMPL,
l1BlockCGTImpl: L1_BLOCK_CGT_IMPL,
l2ToL1MessagePasserImpl: L2_TO_L1_MESSAGE_PASSER_IMPL,
l2ToL1MessagePasserCGTImpl: L2_TO_L1_MESSAGE_PASSER_CGT_IMPL,
optimismMintableERC721FactoryImpl: OPTIMISM_MINTABLE_ERC721_FACTORY_IMPL,
Expand All @@ -76,7 +81,8 @@ contract L2ContractsManager_FullConfigExposer_Harness is L2ContractsManager {
superchainTokenBridgeImpl: SUPERCHAIN_TOKEN_BRIDGE_IMPL,
nativeAssetLiquidityImpl: NATIVE_ASSET_LIQUIDITY_IMPL,
liquidityControllerImpl: LIQUIDITY_CONTROLLER_IMPL,
feeSplitterImpl: FEE_SPLITTER_IMPL
feeSplitterImpl: FEE_SPLITTER_IMPL,
conditionalDeployerImpl: CONDITIONAL_DEPLOYER_IMPL
});
}
}
Expand All @@ -96,7 +102,8 @@ contract L2ContractsManager_Upgrade_Test is CommonTest {
address sequencerFeeWalletImpl;
address optimismMintableERC20FactoryImpl;
address l2ERC721BridgeImpl;
address l1BlockAttributesImpl;
address l1BlockImpl;
address l1BlockCGTImpl;
address l2ToL1MessagePasserImpl;
address optimismMintableERC721FactoryImpl;
address proxyAdminImpl;
Expand Down Expand Up @@ -124,6 +131,8 @@ contract L2ContractsManager_Upgrade_Test is CommonTest {
super.setUp();
_loadImplementations();
_deployL2CM();

skipIfDevFeatureDisabled(DevFeatures.L2CM);
}

/// @notice Deploys the target implementations for the predeploys.
Expand All @@ -136,8 +145,8 @@ contract L2ContractsManager_Upgrade_Test is CommonTest {
implementations.l2StandardBridgeImpl = address(new L2StandardBridge());
implementations.optimismMintableERC20FactoryImpl = address(new OptimismMintableERC20Factory());
implementations.l2ERC721BridgeImpl = address(new L2ERC721Bridge());
implementations.l1BlockAttributesImpl = address(new L1Block());
implementations.l1BlockAttributesCGTImpl = address(new L1BlockCGT());
implementations.l1BlockImpl = address(new L1Block());
implementations.l1BlockCGTImpl = address(new L1BlockCGT());
implementations.l2ToL1MessagePasserImpl = address(new L2ToL1MessagePasser());
implementations.l2ToL1MessagePasserCGTImpl = address(new L2ToL1MessagePasserCGT());
implementations.optimismMintableERC721FactoryImpl = address(new OptimismMintableERC721Factory(address(0), 0));
Expand All @@ -164,6 +173,7 @@ contract L2ContractsManager_Upgrade_Test is CommonTest {
deployCode("src/L2/OptimismSuperchainERC20Factory.sol:OptimismSuperchainERC20Factory");
implementations.superchainTokenBridgeImpl = deployCode("src/L2/SuperchainTokenBridge.sol:SuperchainTokenBridge");
implementations.feeSplitterImpl = deployCode("src/L2/FeeSplitter.sol:FeeSplitter");
implementations.conditionalDeployerImpl = deployCode("src/L2/ConditionalDeployer.sol:ConditionalDeployer");
}

/// @notice Deploys the L2ContractsManager with the loaded implementations.
Expand Down Expand Up @@ -193,7 +203,8 @@ contract L2ContractsManager_Upgrade_Test is CommonTest {
state_.optimismMintableERC20FactoryImpl =
EIP1967Helper.getImplementation(Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY);
state_.l2ERC721BridgeImpl = EIP1967Helper.getImplementation(Predeploys.L2_ERC721_BRIDGE);
state_.l1BlockAttributesImpl = EIP1967Helper.getImplementation(Predeploys.L1_BLOCK_ATTRIBUTES);
state_.l1BlockImpl = EIP1967Helper.getImplementation(Predeploys.L1_BLOCK_ATTRIBUTES);
state_.l1BlockCGTImpl = EIP1967Helper.getImplementation(Predeploys.L1_BLOCK_ATTRIBUTES);
state_.l2ToL1MessagePasserImpl = EIP1967Helper.getImplementation(Predeploys.L2_TO_L1_MESSAGE_PASSER);
state_.optimismMintableERC721FactoryImpl =
EIP1967Helper.getImplementation(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY);
Expand Down Expand Up @@ -241,7 +252,8 @@ contract L2ContractsManager_Upgrade_Test is CommonTest {
"OptimismMintableERC20Factory impl mismatch"
);
assertEq(_state1.l2ERC721BridgeImpl, _state2.l2ERC721BridgeImpl, "L2ERC721Bridge impl mismatch");
assertEq(_state1.l1BlockAttributesImpl, _state2.l1BlockAttributesImpl, "L1BlockAttributes impl mismatch");
assertEq(_state1.l1BlockImpl, _state2.l1BlockImpl, "L1Block impl mismatch");
assertEq(_state1.l1BlockCGTImpl, _state2.l1BlockCGTImpl, "L1BlockCGT impl mismatch");
assertEq(_state1.l2ToL1MessagePasserImpl, _state2.l2ToL1MessagePasserImpl, "L2ToL1MessagePasser impl mismatch");
assertEq(
_state1.optimismMintableERC721FactoryImpl,
Expand Down Expand Up @@ -611,7 +623,7 @@ contract L2ContractsManager_Upgrade_CGT_Test is L2ContractsManager_Upgrade_Test
address postUpgradeL1BlockImpl = EIP1967Helper.getImplementation(Predeploys.L1_BLOCK_ATTRIBUTES);
assertEq(
postUpgradeL1BlockImpl,
implementations.l1BlockAttributesCGTImpl,
implementations.l1BlockCGTImpl,
"L1Block should use CGT implementation on CGT networks"
);

Expand Down Expand Up @@ -658,42 +670,6 @@ contract L2ContractsManager_Upgrade_CGT_Test is L2ContractsManager_Upgrade_Test
/// @notice Test that verifies all predeploys receive upgrade calls during L2CM upgrade.
/// Uses Predeploys.sol as the source of truth for which predeploys should be upgraded.
contract L2ContractsManager_Upgrade_Coverage_Test is L2ContractsManager_Upgrade_Test {
/// @notice Returns all predeploys from Predeploys.sol that should be upgraded by L2CM.
/// @dev IMPORTANT: This is the SOURCE OF TRUTH for upgrade coverage. All proxied predeploys from
/// Predeploys.sol should be listed here. If a new predeploy is added to Predeploys.sol,
/// it must be added here.
/// Excludes: WETH, GOVERNANCE_TOKEN (not proxied), legacy predeploys (not upgraded).
function _getAllUpgradeablePredeploys() internal pure returns (address[] memory predeploys_) {
predeploys_ = new address[](24);
// Core predeploys
predeploys_[0] = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
predeploys_[1] = Predeploys.GAS_PRICE_ORACLE;
predeploys_[2] = Predeploys.L2_STANDARD_BRIDGE;
predeploys_[3] = Predeploys.SEQUENCER_FEE_WALLET;
predeploys_[4] = Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY;
predeploys_[5] = Predeploys.L2_ERC721_BRIDGE;
predeploys_[6] = Predeploys.L1_BLOCK_ATTRIBUTES;
predeploys_[7] = Predeploys.L2_TO_L1_MESSAGE_PASSER;
predeploys_[8] = Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY;
predeploys_[9] = Predeploys.PROXY_ADMIN;
predeploys_[10] = Predeploys.BASE_FEE_VAULT;
predeploys_[11] = Predeploys.L1_FEE_VAULT;
predeploys_[12] = Predeploys.OPERATOR_FEE_VAULT;
predeploys_[13] = Predeploys.SCHEMA_REGISTRY;
predeploys_[14] = Predeploys.EAS;
predeploys_[15] = Predeploys.FEE_SPLITTER;
// Interop predeploys
predeploys_[16] = Predeploys.CROSS_L2_INBOX;
predeploys_[17] = Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER;
predeploys_[18] = Predeploys.SUPERCHAIN_ETH_BRIDGE;
predeploys_[19] = Predeploys.ETH_LIQUIDITY;
predeploys_[20] = Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY;
predeploys_[21] = Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON;
predeploys_[22] = Predeploys.SUPERCHAIN_TOKEN_BRIDGE;
// CGT predeploys (conditionally deployed, but still must be included in the list)
predeploys_[23] = Predeploys.NATIVE_ASSET_LIQUIDITY;
}

/// @notice Returns CGT-only predeploys that require initialization.
/// @dev These are separate because they're only deployed on CGT networks.
function _getCGTInitializablePredeploys() internal pure returns (address[] memory predeploys_) {
Expand Down Expand Up @@ -724,7 +700,7 @@ contract L2ContractsManager_Upgrade_Coverage_Test is L2ContractsManager_Upgrade_
/// Uses vm.expectCall() to verify that upgradeTo or upgradeToAndCall is called.
/// @dev If L2CM misses a predeploy that exists in Predeploys.sol, this test will fail.
function test_allPredeploysReceiveUpgradeCall_succeeds() public {
address[] memory allPredeploys = _getAllUpgradeablePredeploys();
address[] memory allPredeploys = Predeploys.getUpgradeablePredeploys();

for (uint256 i = 0; i < allPredeploys.length; i++) {
address predeploy = allPredeploys[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ abstract contract OptimismSuperchainERC20_TestInit is Test {
// Deploy the OptimismSuperchainERC20Beacon implementation
address _addr = Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON;
address _impl = Predeploys.predeployToCodeNamespace(_addr);
vm.etch(_impl, vm.getDeployedCode("OptimismSuperchainERC20Beacon.sol:OptimismSuperchainERC20Beacon"));
vm.etch(
_impl,
vm.getDeployedCode(
"forge-artifacts/OptimismSuperchainERC20Beacon.sol/OptimismSuperchainERC20Beacon.json"
)
);

// Deploy the ERC1967Proxy contract at the Predeploy
bytes memory code = vm.getDeployedCode("universal/Proxy.sol:Proxy");
Expand Down