Commit eea9572d authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

ctb: Make implementations deployments deterministic and idempotent (#13717)

* ctb: Make implementations deployments deterministic and idempotent

* code review updates

* cr updates

* imports

* make superchain deployments deterministic

* forgot to add test

* code review updates

* broadcast in dpeloysuperchain

* add forgotten broadcast
parent f0f0643d
...@@ -114,7 +114,7 @@ func CreateL1(logger log.Logger, fa *foundry.ArtifactsFS, srcFS *foundry.SourceM ...@@ -114,7 +114,7 @@ func CreateL1(logger log.Logger, fa *foundry.ArtifactsFS, srcFS *foundry.SourceM
PrevRandao: cfg.L1GenesisBlockMixHash, PrevRandao: cfg.L1GenesisBlockMixHash,
BlobHashes: nil, BlobHashes: nil,
} }
l1Host := script.NewHost(logger.New("role", "l1", "chain", cfg.ChainID), fa, srcFS, l1Context) l1Host := script.NewHost(logger.New("role", "l1", "chain", cfg.ChainID), fa, srcFS, l1Context, script.WithCreate2Deployer())
return l1Host return l1Host
} }
......
...@@ -292,12 +292,8 @@ contract Deploy is Deployer { ...@@ -292,12 +292,8 @@ contract Deploy is Deployer {
dii.set(dii.mipsVersion.selector, Config.useMultithreadedCannon() ? 2 : 1); dii.set(dii.mipsVersion.selector, Config.useMultithreadedCannon() ? 2 : 1);
string memory release = "dev"; string memory release = "dev";
dii.set(dii.l1ContractsRelease.selector, release); dii.set(dii.l1ContractsRelease.selector, release);
dii.set(
dii.standardVersionsToml.selector, string.concat(vm.projectRoot(), "/test/fixtures/standard-versions.toml")
);
dii.set(dii.superchainConfigProxy.selector, artifacts.mustGetAddress("SuperchainConfigProxy")); dii.set(dii.superchainConfigProxy.selector, artifacts.mustGetAddress("SuperchainConfigProxy"));
dii.set(dii.protocolVersionsProxy.selector, artifacts.mustGetAddress("ProtocolVersionsProxy")); dii.set(dii.protocolVersionsProxy.selector, artifacts.mustGetAddress("ProtocolVersionsProxy"));
dii.set(dii.salt.selector, _implSalt());
if (_isInterop) { if (_isInterop) {
di = DeployImplementations(new DeployImplementationsInterop()); di = DeployImplementations(new DeployImplementationsInterop());
......
...@@ -26,15 +26,12 @@ import { OPContractsManagerInterop } from "src/L1/OPContractsManagerInterop.sol" ...@@ -26,15 +26,12 @@ import { OPContractsManagerInterop } from "src/L1/OPContractsManagerInterop.sol"
import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol";
import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol"; import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol";
import { Blueprint } from "src/libraries/Blueprint.sol";
import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
import { Solarray } from "scripts/libraries/Solarray.sol"; import { Solarray } from "scripts/libraries/Solarray.sol";
import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol";
// See DeploySuperchain.s.sol for detailed comments on the script architecture used here. // See DeploySuperchain.s.sol for detailed comments on the script architecture used here.
contract DeployImplementationsInput is BaseDeployIO { contract DeployImplementationsInput is BaseDeployIO {
bytes32 internal _salt;
uint256 internal _withdrawalDelaySeconds; uint256 internal _withdrawalDelaySeconds;
uint256 internal _minProposalSizeBytes; uint256 internal _minProposalSizeBytes;
uint256 internal _challengePeriodSeconds; uint256 internal _challengePeriodSeconds;
...@@ -50,8 +47,6 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -50,8 +47,6 @@ contract DeployImplementationsInput is BaseDeployIO {
ISuperchainConfig internal _superchainConfigProxy; ISuperchainConfig internal _superchainConfigProxy;
IProtocolVersions internal _protocolVersionsProxy; IProtocolVersions internal _protocolVersionsProxy;
string internal _standardVersionsToml;
function set(bytes4 _sel, uint256 _value) public { function set(bytes4 _sel, uint256 _value) public {
require(_value != 0, "DeployImplementationsInput: cannot set zero value"); require(_value != 0, "DeployImplementationsInput: cannot set zero value");
...@@ -76,7 +71,6 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -76,7 +71,6 @@ contract DeployImplementationsInput is BaseDeployIO {
function set(bytes4 _sel, string memory _value) public { function set(bytes4 _sel, string memory _value) public {
require(!LibString.eq(_value, ""), "DeployImplementationsInput: cannot set empty string"); require(!LibString.eq(_value, ""), "DeployImplementationsInput: cannot set empty string");
if (_sel == this.l1ContractsRelease.selector) _l1ContractsRelease = _value; if (_sel == this.l1ContractsRelease.selector) _l1ContractsRelease = _value;
else if (_sel == this.standardVersionsToml.selector) _standardVersionsToml = _value;
else revert("DeployImplementationsInput: unknown selector"); else revert("DeployImplementationsInput: unknown selector");
} }
...@@ -87,16 +81,6 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -87,16 +81,6 @@ contract DeployImplementationsInput is BaseDeployIO {
else revert("DeployImplementationsInput: unknown selector"); else revert("DeployImplementationsInput: unknown selector");
} }
function set(bytes4 _sel, bytes32 _value) public {
if (_sel == this.salt.selector) _salt = _value;
else revert("DeployImplementationsInput: unknown selector");
}
function salt() public view returns (bytes32) {
// TODO check if implementations are deployed based on code+salt and skip deploy if so.
return _salt;
}
function withdrawalDelaySeconds() public view returns (uint256) { function withdrawalDelaySeconds() public view returns (uint256) {
require(_withdrawalDelaySeconds != 0, "DeployImplementationsInput: not set"); require(_withdrawalDelaySeconds != 0, "DeployImplementationsInput: not set");
return _withdrawalDelaySeconds; return _withdrawalDelaySeconds;
...@@ -135,11 +119,6 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -135,11 +119,6 @@ contract DeployImplementationsInput is BaseDeployIO {
return _l1ContractsRelease; return _l1ContractsRelease;
} }
function standardVersionsToml() public view returns (string memory) {
require(!LibString.eq(_standardVersionsToml, ""), "DeployImplementationsInput: not set");
return _standardVersionsToml;
}
function superchainConfigProxy() public view returns (ISuperchainConfig) { function superchainConfigProxy() public view returns (ISuperchainConfig) {
require(address(_superchainConfigProxy) != address(0), "DeployImplementationsInput: not set"); require(address(_superchainConfigProxy) != address(0), "DeployImplementationsInput: not set");
return _superchainConfigProxy; return _superchainConfigProxy;
...@@ -411,20 +390,22 @@ contract DeployImplementationsOutput is BaseDeployIO { ...@@ -411,20 +390,22 @@ contract DeployImplementationsOutput is BaseDeployIO {
} }
contract DeployImplementations is Script { contract DeployImplementations is Script {
bytes32 internal _salt = DeployUtils.DEFAULT_SALT;
// -------- Core Deployment Methods -------- // -------- Core Deployment Methods --------
function run(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public { function run(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public {
// Deploy the implementations. // Deploy the implementations.
deploySystemConfigImpl(_dii, _dio); deploySystemConfigImpl(_dio);
deployL1CrossDomainMessengerImpl(_dii, _dio); deployL1CrossDomainMessengerImpl(_dio);
deployL1ERC721BridgeImpl(_dii, _dio); deployL1ERC721BridgeImpl(_dio);
deployL1StandardBridgeImpl(_dii, _dio); deployL1StandardBridgeImpl(_dio);
deployOptimismMintableERC20FactoryImpl(_dii, _dio); deployOptimismMintableERC20FactoryImpl(_dio);
deployOptimismPortalImpl(_dii, _dio); deployOptimismPortalImpl(_dii, _dio);
deployDelayedWETHImpl(_dii, _dio); deployDelayedWETHImpl(_dii, _dio);
deployPreimageOracleSingleton(_dii, _dio); deployPreimageOracleSingleton(_dii, _dio);
deployMipsSingleton(_dii, _dio); deployMipsSingleton(_dii, _dio);
deployDisputeGameFactoryImpl(_dii, _dio); deployDisputeGameFactoryImpl(_dio);
// Deploy the OP Contracts Manager with the new implementations set. // Deploy the OP Contracts Manager with the new implementations set.
deployOPContractsManager(_dii, _dio); deployOPContractsManager(_dii, _dio);
...@@ -462,8 +443,14 @@ contract DeployImplementations is Script { ...@@ -462,8 +443,14 @@ contract DeployImplementations is Script {
}); });
vm.broadcast(msg.sender); vm.broadcast(msg.sender);
opcm_ = new OPContractsManager( opcm_ = OPContractsManager(
superchainConfigProxy, protocolVersionsProxy, _l1ContractsRelease, _blueprints, implementations DeployUtils.createDeterministic({
_name: "OPContractsManager",
_args: abi.encode(
superchainConfigProxy, protocolVersionsProxy, _l1ContractsRelease, _blueprints, implementations
),
_salt: _salt
})
); );
vm.label(address(opcm_), "OPContractsManager"); vm.label(address(opcm_), "OPContractsManager");
...@@ -478,42 +465,32 @@ contract DeployImplementations is Script { ...@@ -478,42 +465,32 @@ contract DeployImplementations is Script {
virtual virtual
{ {
string memory l1ContractsRelease = _dii.l1ContractsRelease(); string memory l1ContractsRelease = _dii.l1ContractsRelease();
string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "op_contracts_manager";
OPContractsManager opcm;
address existingImplementation = getReleaseAddress(l1ContractsRelease, contractName, stdVerToml); // First we deploy the blueprints for the singletons deployed by OPCM.
if (existingImplementation != address(0)) { // forgefmt: disable-start
opcm = OPContractsManager(existingImplementation); OPContractsManager.Blueprints memory blueprints;
} else { vm.startBroadcast(msg.sender);
// First we deploy the blueprints for the singletons deployed by OPCM. address checkAddress;
// forgefmt: disable-start (blueprints.addressManager, checkAddress) = DeployUtils.createDeterministicBlueprint(vm.getCode("AddressManager"), _salt);
bytes32 salt = _dii.salt(); require(checkAddress == address(0), "OPCM-10");
OPContractsManager.Blueprints memory blueprints; (blueprints.proxy, checkAddress) = DeployUtils.createDeterministicBlueprint(vm.getCode("Proxy"), _salt);
require(checkAddress == address(0), "OPCM-20");
address checkAddress; (blueprints.proxyAdmin, checkAddress) = DeployUtils.createDeterministicBlueprint(vm.getCode("ProxyAdmin"), _salt);
vm.startBroadcast(msg.sender); require(checkAddress == address(0), "OPCM-30");
(blueprints.addressManager, checkAddress) = Blueprint.create(vm.getCode("AddressManager"), salt); (blueprints.l1ChugSplashProxy, checkAddress) = DeployUtils.createDeterministicBlueprint(vm.getCode("L1ChugSplashProxy"), _salt);
require(checkAddress == address(0), "OPCM-10"); require(checkAddress == address(0), "OPCM-40");
(blueprints.proxy, checkAddress) = Blueprint.create(vm.getCode("Proxy"), salt); (blueprints.resolvedDelegateProxy, checkAddress) = DeployUtils.createDeterministicBlueprint(vm.getCode("ResolvedDelegateProxy"), _salt);
require(checkAddress == address(0), "OPCM-20"); require(checkAddress == address(0), "OPCM-50");
(blueprints.proxyAdmin, checkAddress) = Blueprint.create(vm.getCode("ProxyAdmin"), salt); (blueprints.anchorStateRegistry, checkAddress) = DeployUtils.createDeterministicBlueprint(vm.getCode("AnchorStateRegistry"), _salt);
require(checkAddress == address(0), "OPCM-30"); require(checkAddress == address(0), "OPCM-60");
(blueprints.l1ChugSplashProxy, checkAddress) = Blueprint.create(vm.getCode("L1ChugSplashProxy"), salt);
require(checkAddress == address(0), "OPCM-40");
(blueprints.resolvedDelegateProxy, checkAddress) = Blueprint.create(vm.getCode("ResolvedDelegateProxy"), salt);
require(checkAddress == address(0), "OPCM-50");
(blueprints.anchorStateRegistry, checkAddress) = Blueprint.create(vm.getCode("AnchorStateRegistry"), salt);
require(checkAddress == address(0), "OPCM-60");
// The max initcode/runtimecode size is 48KB/24KB. // The max initcode/runtimecode size is 48KB/24KB.
// But for Blueprint, the initcode is stored as runtime code, that's why it's necessary to split into 2 parts. // But for Blueprint, the initcode is stored as runtime code, that's why it's necessary to split into 2 parts.
(blueprints.permissionedDisputeGame1, blueprints.permissionedDisputeGame2) = Blueprint.create(vm.getCode("PermissionedDisputeGame"), salt); (blueprints.permissionedDisputeGame1, blueprints.permissionedDisputeGame2) = DeployUtils.createDeterministicBlueprint(vm.getCode("PermissionedDisputeGame"), _salt);
(blueprints.permissionlessDisputeGame1, blueprints.permissionlessDisputeGame2) = Blueprint.create(vm.getCode("FaultDisputeGame"), salt); (blueprints.permissionlessDisputeGame1, blueprints.permissionlessDisputeGame2) = DeployUtils.createDeterministicBlueprint(vm.getCode("FaultDisputeGame"), _salt);
vm.stopBroadcast(); // forgefmt: disable-end
// forgefmt: disable-end vm.stopBroadcast();
opcm = createOPCMContract(_dii, _dio, blueprints, l1ContractsRelease); OPContractsManager opcm = createOPCMContract(_dii, _dio, blueprints, l1ContractsRelease);
}
vm.label(address(opcm), "OPContractsManager"); vm.label(address(opcm), "OPContractsManager");
_dio.set(_dio.opcm.selector, address(opcm)); _dio.set(_dio.opcm.selector, address(opcm));
...@@ -521,143 +498,67 @@ contract DeployImplementations is Script { ...@@ -521,143 +498,67 @@ contract DeployImplementations is Script {
// --- Core Contracts --- // --- Core Contracts ---
function deploySystemConfigImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual { function deploySystemConfigImpl(DeployImplementationsOutput _dio) public virtual {
string memory release = _dii.l1ContractsRelease(); vm.broadcast(msg.sender);
string memory stdVerToml = _dii.standardVersionsToml(); ISystemConfig impl = ISystemConfig(
// Using snake case for contract name to match the TOML file in superchain-registry. DeployUtils.createDeterministic({
string memory contractName = "system_config"; _name: "SystemConfig",
ISystemConfig impl; _args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfig.__constructor__, ())),
_salt: _salt
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); })
if (existingImplementation != address(0)) { );
impl = ISystemConfig(existingImplementation);
} else {
// Deploy a new implementation for development builds.
vm.broadcast(msg.sender);
impl = ISystemConfig(
DeployUtils.create1({
_name: "SystemConfig",
_args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfig.__constructor__, ()))
})
);
}
vm.label(address(impl), "SystemConfigImpl"); vm.label(address(impl), "SystemConfigImpl");
_dio.set(_dio.systemConfigImpl.selector, address(impl)); _dio.set(_dio.systemConfigImpl.selector, address(impl));
} }
function deployL1CrossDomainMessengerImpl( function deployL1CrossDomainMessengerImpl(DeployImplementationsOutput _dio) public virtual {
DeployImplementationsInput _dii, vm.broadcast(msg.sender);
DeployImplementationsOutput _dio IL1CrossDomainMessenger impl = IL1CrossDomainMessenger(
) DeployUtils.createDeterministic({
public _name: "L1CrossDomainMessenger",
virtual _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1CrossDomainMessenger.__constructor__, ())),
{ _salt: _salt
string memory release = _dii.l1ContractsRelease(); })
string memory stdVerToml = _dii.standardVersionsToml(); );
string memory contractName = "l1_cross_domain_messenger";
IL1CrossDomainMessenger impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = IL1CrossDomainMessenger(existingImplementation);
} else {
vm.broadcast(msg.sender);
impl = IL1CrossDomainMessenger(
DeployUtils.create1({
_name: "L1CrossDomainMessenger",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IL1CrossDomainMessenger.__constructor__, ()))
})
);
}
vm.label(address(impl), "L1CrossDomainMessengerImpl"); vm.label(address(impl), "L1CrossDomainMessengerImpl");
_dio.set(_dio.l1CrossDomainMessengerImpl.selector, address(impl)); _dio.set(_dio.l1CrossDomainMessengerImpl.selector, address(impl));
} }
function deployL1ERC721BridgeImpl( function deployL1ERC721BridgeImpl(DeployImplementationsOutput _dio) public virtual {
DeployImplementationsInput _dii, vm.broadcast(msg.sender);
DeployImplementationsOutput _dio IL1ERC721Bridge impl = IL1ERC721Bridge(
) DeployUtils.createDeterministic({
public _name: "L1ERC721Bridge",
virtual _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1ERC721Bridge.__constructor__, ())),
{ _salt: _salt
string memory release = _dii.l1ContractsRelease(); })
string memory stdVerToml = _dii.standardVersionsToml(); );
string memory contractName = "l1_erc721_bridge";
IL1ERC721Bridge impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = IL1ERC721Bridge(existingImplementation);
} else {
vm.broadcast(msg.sender);
impl = IL1ERC721Bridge(
DeployUtils.create1({
_name: "L1ERC721Bridge",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IL1ERC721Bridge.__constructor__, ()))
})
);
}
vm.label(address(impl), "L1ERC721BridgeImpl"); vm.label(address(impl), "L1ERC721BridgeImpl");
_dio.set(_dio.l1ERC721BridgeImpl.selector, address(impl)); _dio.set(_dio.l1ERC721BridgeImpl.selector, address(impl));
} }
function deployL1StandardBridgeImpl( function deployL1StandardBridgeImpl(DeployImplementationsOutput _dio) public virtual {
DeployImplementationsInput _dii, vm.broadcast(msg.sender);
DeployImplementationsOutput _dio IL1StandardBridge impl = IL1StandardBridge(
) DeployUtils.createDeterministic({
public _name: "L1StandardBridge",
virtual _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1StandardBridge.__constructor__, ())),
{ _salt: _salt
string memory release = _dii.l1ContractsRelease(); })
string memory stdVerToml = _dii.standardVersionsToml(); );
string memory contractName = "l1_standard_bridge";
IL1StandardBridge impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = IL1StandardBridge(payable(existingImplementation));
} else {
vm.broadcast(msg.sender);
impl = IL1StandardBridge(
DeployUtils.create1({
_name: "L1StandardBridge",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IL1StandardBridge.__constructor__, ()))
})
);
}
vm.label(address(impl), "L1StandardBridgeImpl"); vm.label(address(impl), "L1StandardBridgeImpl");
_dio.set(_dio.l1StandardBridgeImpl.selector, address(impl)); _dio.set(_dio.l1StandardBridgeImpl.selector, address(impl));
} }
function deployOptimismMintableERC20FactoryImpl( function deployOptimismMintableERC20FactoryImpl(DeployImplementationsOutput _dio) public virtual {
DeployImplementationsInput _dii, vm.broadcast(msg.sender);
DeployImplementationsOutput _dio IOptimismMintableERC20Factory impl = IOptimismMintableERC20Factory(
) DeployUtils.createDeterministic({
public _name: "OptimismMintableERC20Factory",
virtual _args: DeployUtils.encodeConstructor(abi.encodeCall(IOptimismMintableERC20Factory.__constructor__, ())),
{ _salt: _salt
string memory release = _dii.l1ContractsRelease(); })
string memory stdVerToml = _dii.standardVersionsToml(); );
string memory contractName = "optimism_mintable_erc20_factory";
IOptimismMintableERC20Factory impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = IOptimismMintableERC20Factory(existingImplementation);
} else {
vm.broadcast(msg.sender);
impl = IOptimismMintableERC20Factory(
DeployUtils.create1({
_name: "OptimismMintableERC20Factory",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IOptimismMintableERC20Factory.__constructor__, ()))
})
);
}
vm.label(address(impl), "OptimismMintableERC20FactoryImpl"); vm.label(address(impl), "OptimismMintableERC20FactoryImpl");
_dio.set(_dio.optimismMintableERC20FactoryImpl.selector, address(impl)); _dio.set(_dio.optimismMintableERC20FactoryImpl.selector, address(impl));
} }
...@@ -706,56 +607,34 @@ contract DeployImplementations is Script { ...@@ -706,56 +607,34 @@ contract DeployImplementations is Script {
public public
virtual virtual
{ {
string memory release = _dii.l1ContractsRelease(); uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds();
string memory stdVerToml = _dii.standardVersionsToml(); uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds();
string memory contractName = "optimism_portal"; vm.broadcast(msg.sender);
IOptimismPortal2 impl; IOptimismPortal2 impl = IOptimismPortal2(
DeployUtils.createDeterministic({
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); _name: "OptimismPortal2",
if (existingImplementation != address(0)) { _args: DeployUtils.encodeConstructor(
impl = IOptimismPortal2(payable(existingImplementation)); abi.encodeCall(
} else { IOptimismPortal2.__constructor__, (proofMaturityDelaySeconds, disputeGameFinalityDelaySeconds)
uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds();
uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds();
vm.broadcast(msg.sender);
impl = IOptimismPortal2(
DeployUtils.create1({
_name: "OptimismPortal2",
_args: DeployUtils.encodeConstructor(
abi.encodeCall(
IOptimismPortal2.__constructor__, (proofMaturityDelaySeconds, disputeGameFinalityDelaySeconds)
)
) )
}) ),
); _salt: _salt
} })
);
vm.label(address(impl), "OptimismPortalImpl"); vm.label(address(impl), "OptimismPortalImpl");
_dio.set(_dio.optimismPortalImpl.selector, address(impl)); _dio.set(_dio.optimismPortalImpl.selector, address(impl));
} }
function deployDelayedWETHImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual { function deployDelayedWETHImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual {
string memory release = _dii.l1ContractsRelease(); uint256 withdrawalDelaySeconds = _dii.withdrawalDelaySeconds();
string memory stdVerToml = _dii.standardVersionsToml(); vm.broadcast(msg.sender);
string memory contractName = "delayed_weth"; IDelayedWETH impl = IDelayedWETH(
IDelayedWETH impl; DeployUtils.createDeterministic({
_name: "DelayedWETH",
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); _args: DeployUtils.encodeConstructor(abi.encodeCall(IDelayedWETH.__constructor__, (withdrawalDelaySeconds))),
if (existingImplementation != address(0)) { _salt: _salt
impl = IDelayedWETH(payable(existingImplementation)); })
} else { );
uint256 withdrawalDelaySeconds = _dii.withdrawalDelaySeconds();
vm.broadcast(msg.sender);
impl = IDelayedWETH(
DeployUtils.create1({
_name: "DelayedWETH",
_args: DeployUtils.encodeConstructor(
abi.encodeCall(IDelayedWETH.__constructor__, (withdrawalDelaySeconds))
)
})
);
}
vm.label(address(impl), "DelayedWETHImpl"); vm.label(address(impl), "DelayedWETHImpl");
_dio.set(_dio.delayedWETHImpl.selector, address(impl)); _dio.set(_dio.delayedWETHImpl.selector, address(impl));
} }
...@@ -767,82 +646,46 @@ contract DeployImplementations is Script { ...@@ -767,82 +646,46 @@ contract DeployImplementations is Script {
public public
virtual virtual
{ {
string memory release = _dii.l1ContractsRelease(); uint256 minProposalSizeBytes = _dii.minProposalSizeBytes();
string memory stdVerToml = _dii.standardVersionsToml(); uint256 challengePeriodSeconds = _dii.challengePeriodSeconds();
string memory contractName = "preimage_oracle"; vm.broadcast(msg.sender);
IPreimageOracle singleton; IPreimageOracle singleton = IPreimageOracle(
DeployUtils.createDeterministic({
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); _name: "PreimageOracle",
if (existingImplementation != address(0)) { _args: DeployUtils.encodeConstructor(
singleton = IPreimageOracle(payable(existingImplementation)); abi.encodeCall(IPreimageOracle.__constructor__, (minProposalSizeBytes, challengePeriodSeconds))
} else { ),
uint256 minProposalSizeBytes = _dii.minProposalSizeBytes(); _salt: _salt
uint256 challengePeriodSeconds = _dii.challengePeriodSeconds(); })
vm.broadcast(msg.sender); );
singleton = IPreimageOracle(
DeployUtils.create1({
_name: "PreimageOracle",
_args: DeployUtils.encodeConstructor(
abi.encodeCall(IPreimageOracle.__constructor__, (minProposalSizeBytes, challengePeriodSeconds))
)
})
);
}
vm.label(address(singleton), "PreimageOracleSingleton"); vm.label(address(singleton), "PreimageOracleSingleton");
_dio.set(_dio.preimageOracleSingleton.selector, address(singleton)); _dio.set(_dio.preimageOracleSingleton.selector, address(singleton));
} }
function deployMipsSingleton(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual { function deployMipsSingleton(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual {
string memory release = _dii.l1ContractsRelease(); uint256 mipsVersion = _dii.mipsVersion();
string memory stdVerToml = _dii.standardVersionsToml(); IPreimageOracle preimageOracle = IPreimageOracle(address(_dio.preimageOracleSingleton()));
string memory contractName = "mips"; vm.broadcast(msg.sender);
IMIPS singleton; IMIPS singleton = IMIPS(
DeployUtils.createDeterministic({
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); _name: mipsVersion == 1 ? "MIPS" : "MIPS64",
if (existingImplementation != address(0)) { _args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))),
singleton = IMIPS(payable(existingImplementation)); _salt: _salt
} else { })
uint256 mipsVersion = _dii.mipsVersion(); );
IPreimageOracle preimageOracle = IPreimageOracle(address(_dio.preimageOracleSingleton()));
vm.broadcast(msg.sender);
singleton = IMIPS(
DeployUtils.create1({
_name: mipsVersion == 1 ? "MIPS" : "MIPS64",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle)))
})
);
}
vm.label(address(singleton), "MIPSSingleton"); vm.label(address(singleton), "MIPSSingleton");
_dio.set(_dio.mipsSingleton.selector, address(singleton)); _dio.set(_dio.mipsSingleton.selector, address(singleton));
} }
function deployDisputeGameFactoryImpl( function deployDisputeGameFactoryImpl(DeployImplementationsOutput _dio) public virtual {
DeployImplementationsInput _dii, vm.broadcast(msg.sender);
DeployImplementationsOutput _dio IDisputeGameFactory impl = IDisputeGameFactory(
) DeployUtils.createDeterministic({
public _name: "DisputeGameFactory",
virtual _args: DeployUtils.encodeConstructor(abi.encodeCall(IDisputeGameFactory.__constructor__, ())),
{ _salt: _salt
string memory release = _dii.l1ContractsRelease(); })
string memory stdVerToml = _dii.standardVersionsToml(); );
string memory contractName = "dispute_game_factory";
IDisputeGameFactory impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = IDisputeGameFactory(payable(existingImplementation));
} else {
vm.broadcast(msg.sender);
impl = IDisputeGameFactory(
DeployUtils.create1({
_name: "DisputeGameFactory",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IDisputeGameFactory.__constructor__, ()))
})
);
}
vm.label(address(impl), "DisputeGameFactoryImpl"); vm.label(address(impl), "DisputeGameFactoryImpl");
_dio.set(_dio.disputeGameFactoryImpl.selector, address(impl)); _dio.set(_dio.disputeGameFactoryImpl.selector, address(impl));
} }
...@@ -869,30 +712,6 @@ contract DeployImplementations is Script { ...@@ -869,30 +712,6 @@ contract DeployImplementations is Script {
dii_ = DeployImplementationsInput(DeployUtils.toIOAddress(msg.sender, "optimism.DeployImplementationsInput")); dii_ = DeployImplementationsInput(DeployUtils.toIOAddress(msg.sender, "optimism.DeployImplementationsInput"));
dio_ = DeployImplementationsOutput(DeployUtils.toIOAddress(msg.sender, "optimism.DeployImplementationsOutput")); dio_ = DeployImplementationsOutput(DeployUtils.toIOAddress(msg.sender, "optimism.DeployImplementationsOutput"));
} }
// Zero address is returned if the address is not found in '_standardVersionsToml'.
function getReleaseAddress(
string memory _version,
string memory _contractName,
string memory _standardVersionsToml
)
internal
pure
returns (address addr_)
{
string memory baseKey = string.concat('.releases["', _version, '"].', _contractName);
string memory implAddressKey = string.concat(baseKey, ".implementation_address");
string memory addressKey = string.concat(baseKey, ".address");
try vm.parseTomlAddress(_standardVersionsToml, implAddressKey) returns (address parsedAddr_) {
addr_ = parsedAddr_;
} catch {
try vm.parseTomlAddress(_standardVersionsToml, addressKey) returns (address parsedAddr_) {
addr_ = parsedAddr_;
} catch {
addr_ = address(0);
}
}
}
} }
// Similar to how DeploySuperchain.s.sol contains a lot of comments to thoroughly document the script // Similar to how DeploySuperchain.s.sol contains a lot of comments to thoroughly document the script
...@@ -955,8 +774,14 @@ contract DeployImplementationsInterop is DeployImplementations { ...@@ -955,8 +774,14 @@ contract DeployImplementationsInterop is DeployImplementations {
}); });
vm.broadcast(msg.sender); vm.broadcast(msg.sender);
opcm_ = new OPContractsManagerInterop( opcm_ = OPContractsManagerInterop(
superchainConfigProxy, protocolVersionsProxy, _l1ContractsRelease, _blueprints, implementations DeployUtils.createDeterministic({
_name: "OPContractsManagerInterop",
_args: abi.encode(
superchainConfigProxy, protocolVersionsProxy, _l1ContractsRelease, _blueprints, implementations
),
_salt: _salt
})
); );
vm.label(address(opcm_), "OPContractsManager"); vm.label(address(opcm_), "OPContractsManager");
...@@ -970,61 +795,34 @@ contract DeployImplementationsInterop is DeployImplementations { ...@@ -970,61 +795,34 @@ contract DeployImplementationsInterop is DeployImplementations {
public public
override override
{ {
string memory release = _dii.l1ContractsRelease(); uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds();
string memory stdVerToml = _dii.standardVersionsToml(); uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds();
string memory contractName = "optimism_portal"; vm.broadcast(msg.sender);
IOptimismPortalInterop impl; IOptimismPortalInterop impl = IOptimismPortalInterop(
DeployUtils.createDeterministic({
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); _name: "OptimismPortalInterop",
if (existingImplementation != address(0)) { _args: DeployUtils.encodeConstructor(
impl = IOptimismPortalInterop(payable(existingImplementation)); abi.encodeCall(
} else { IOptimismPortalInterop.__constructor__, (proofMaturityDelaySeconds, disputeGameFinalityDelaySeconds)
uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds();
uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds();
vm.broadcast(msg.sender);
impl = IOptimismPortalInterop(
DeployUtils.create1({
_name: "OptimismPortalInterop",
_args: DeployUtils.encodeConstructor(
abi.encodeCall(
IOptimismPortalInterop.__constructor__,
(proofMaturityDelaySeconds, disputeGameFinalityDelaySeconds)
)
) )
}) ),
); _salt: _salt
} })
);
vm.label(address(impl), "OptimismPortalImpl"); vm.label(address(impl), "OptimismPortalImpl");
_dio.set(_dio.optimismPortalImpl.selector, address(impl)); _dio.set(_dio.optimismPortalImpl.selector, address(impl));
} }
function deploySystemConfigImpl( function deploySystemConfigImpl(DeployImplementationsOutput _dio) public override {
DeployImplementationsInput _dii, vm.broadcast(msg.sender);
DeployImplementationsOutput _dio ISystemConfigInterop impl = ISystemConfigInterop(
) DeployUtils.createDeterministic({
public _name: "SystemConfigInterop",
override _args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfigInterop.__constructor__, ())),
{ _salt: _salt
string memory release = _dii.l1ContractsRelease(); })
string memory stdVerToml = _dii.standardVersionsToml(); );
string memory contractName = "system_config";
ISystemConfigInterop impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = ISystemConfigInterop(existingImplementation);
} else {
vm.broadcast(msg.sender);
impl = ISystemConfigInterop(
DeployUtils.create1({
_name: "SystemConfigInterop",
_args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfigInterop.__constructor__, ()))
})
);
}
vm.label(address(impl), "SystemConfigImpl"); vm.label(address(impl), "SystemConfigImpl");
_dio.set(_dio.systemConfigImpl.selector, address(impl)); _dio.set(_dio.systemConfigImpl.selector, address(impl));
} }
......
...@@ -292,6 +292,8 @@ contract DeploySuperchainOutput is BaseDeployIO { ...@@ -292,6 +292,8 @@ contract DeploySuperchainOutput is BaseDeployIO {
// default sender would be the broadcaster during test, but the broadcaster needs to be the deployer // default sender would be the broadcaster during test, but the broadcaster needs to be the deployer
// since they are set to the initial proxy admin owner. // since they are set to the initial proxy admin owner.
contract DeploySuperchain is Script { contract DeploySuperchain is Script {
bytes32 internal _salt = DeployUtils.DEFAULT_SALT;
// -------- Core Deployment Methods -------- // -------- Core Deployment Methods --------
function run(DeploySuperchainInput _dsi, DeploySuperchainOutput _dso) public { function run(DeploySuperchainInput _dsi, DeploySuperchainOutput _dso) public {
...@@ -342,15 +344,17 @@ contract DeploySuperchain is Script { ...@@ -342,15 +344,17 @@ contract DeploySuperchain is Script {
// Deploy implementation contracts. // Deploy implementation contracts.
vm.startBroadcast(msg.sender); vm.startBroadcast(msg.sender);
ISuperchainConfig superchainConfigImpl = ISuperchainConfig( ISuperchainConfig superchainConfigImpl = ISuperchainConfig(
DeployUtils.create1({ DeployUtils.createDeterministic({
_name: "SuperchainConfig", _name: "SuperchainConfig",
_args: DeployUtils.encodeConstructor(abi.encodeCall(ISuperchainConfig.__constructor__, ())) _args: DeployUtils.encodeConstructor(abi.encodeCall(ISuperchainConfig.__constructor__, ())),
_salt: _salt
}) })
); );
IProtocolVersions protocolVersionsImpl = IProtocolVersions( IProtocolVersions protocolVersionsImpl = IProtocolVersions(
DeployUtils.create1({ DeployUtils.createDeterministic({
_name: "ProtocolVersions", _name: "ProtocolVersions",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProtocolVersions.__constructor__, ())) _args: DeployUtils.encodeConstructor(abi.encodeCall(IProtocolVersions.__constructor__, ())),
_salt: _salt
}) })
); );
vm.stopBroadcast(); vm.stopBroadcast();
......
...@@ -10,6 +10,7 @@ import { Artifacts } from "scripts/Artifacts.s.sol"; ...@@ -10,6 +10,7 @@ import { Artifacts } from "scripts/Artifacts.s.sol";
import { LibString } from "@solady/utils/LibString.sol"; import { LibString } from "@solady/utils/LibString.sol";
import { Bytes } from "src/libraries/Bytes.sol"; import { Bytes } from "src/libraries/Bytes.sol";
import { Constants } from "src/libraries/Constants.sol"; import { Constants } from "src/libraries/Constants.sol";
import { Blueprint } from "src/libraries/Blueprint.sol";
// Interfaces // Interfaces
import { IProxy } from "interfaces/universal/IProxy.sol"; import { IProxy } from "interfaces/universal/IProxy.sol";
...@@ -20,6 +21,8 @@ import { IResolvedDelegateProxy } from "interfaces/legacy/IResolvedDelegateProxy ...@@ -20,6 +21,8 @@ import { IResolvedDelegateProxy } from "interfaces/legacy/IResolvedDelegateProxy
library DeployUtils { library DeployUtils {
Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
bytes32 internal constant DEFAULT_SALT = keccak256("op-stack-contract-impls-salt-v0");
/// @notice Deploys a contract with the given name and arguments via CREATE. /// @notice Deploys a contract with the given name and arguments via CREATE.
/// @param _name Name of the contract to deploy. /// @param _name Name of the contract to deploy.
/// @param _args ABI-encoded constructor arguments. /// @param _args ABI-encoded constructor arguments.
...@@ -97,19 +100,11 @@ library DeployUtils { ...@@ -97,19 +100,11 @@ library DeployUtils {
/// @param _args ABI-encoded constructor arguments. /// @param _args ABI-encoded constructor arguments.
/// @param _salt Salt for the CREATE2 operation. /// @param _salt Salt for the CREATE2 operation.
/// @return addr_ Address of the deployed contract. /// @return addr_ Address of the deployed contract.
function create2(string memory _name, bytes memory _args, bytes32 _salt) internal returns (address payable addr_) { function create2(string memory _name, bytes memory _args, bytes32 _salt) internal returns (address payable) {
bytes memory initCode = abi.encodePacked(vm.getCode(_name), _args); bytes memory initCode = abi.encodePacked(vm.getCode(_name), _args);
address preComputedAddress = vm.computeCreate2Address(_salt, keccak256(initCode)); address preComputedAddress = vm.computeCreate2Address(_salt, keccak256(initCode));
require(preComputedAddress.code.length == 0, "DeployUtils: contract already deployed"); require(preComputedAddress.code.length == 0, "DeployUtils: contract already deployed");
assembly { return create2asm(initCode, _salt);
addr_ := create2(0, add(initCode, 0x20), mload(initCode), _salt)
if iszero(addr_) {
let size := returndatasize()
returndatacopy(0, 0, size)
revert(0, size)
}
}
assertValidContractAddress(addr_);
} }
/// @notice Deploys a contract with the given name via CREATE2. /// @notice Deploys a contract with the given name via CREATE2.
...@@ -120,6 +115,18 @@ library DeployUtils { ...@@ -120,6 +115,18 @@ library DeployUtils {
return create2(_name, hex"", _salt); return create2(_name, hex"", _salt);
} }
function create2asm(bytes memory _initCode, bytes32 _salt) internal returns (address payable addr_) {
assembly {
addr_ := create2(0, add(_initCode, 0x20), mload(_initCode), _salt)
if iszero(addr_) {
let size := returndatasize()
returndatacopy(0, 0, size)
revert(0, size)
}
}
assertValidContractAddress(addr_);
}
/// @notice Deploys a contract with the given name and arguments via CREATE2 and saves the result. /// @notice Deploys a contract with the given name and arguments via CREATE2 and saves the result.
/// @param _save Artifacts contract. /// @param _save Artifacts contract.
/// @param _name Name of the contract to deploy. /// @param _name Name of the contract to deploy.
...@@ -195,6 +202,64 @@ library DeployUtils { ...@@ -195,6 +202,64 @@ library DeployUtils {
return create2AndSave(_save, _name, _name, hex"", _salt); return create2AndSave(_save, _name, _name, hex"", _salt);
} }
/// @notice Deploys a contract with the given name using CREATE2. If the contract is already deployed, this method
/// does nothing.
/// @param _name Name of the contract to deploy.
/// @param _args ABI-encoded constructor arguments.
function createDeterministic(
string memory _name,
bytes memory _args,
bytes32 _salt
)
internal
returns (address payable addr_)
{
bytes memory initCode = abi.encodePacked(vm.getCode(_name), _args);
address preComputedAddress = vm.computeCreate2Address(_salt, keccak256(initCode));
if (preComputedAddress.code.length > 0) {
addr_ = payable(preComputedAddress);
} else {
addr_ = DeployUtils.create2asm(initCode, _salt);
}
}
/// @notice Deploys a blueprint contract with the given name using CREATE2. If the contract is already deployed,
/// this method does nothing.
/// @param _rawBytecode Raw bytecode of the contract the blueprint will deploy.
function createDeterministicBlueprint(
bytes memory _rawBytecode,
bytes32 _salt
)
internal
returns (address newContract1_, address newContract2_)
{
uint32 maxSize = Blueprint.maxInitCodeSize();
if (_rawBytecode.length <= maxSize) {
bytes memory bpBytecode = Blueprint.blueprintDeployerBytecode(_rawBytecode);
newContract1_ = vm.computeCreate2Address(_salt, keccak256(bpBytecode));
if (newContract1_.code.length == 0) {
(address deployedContract) = Blueprint.deploySmallBytecode(bpBytecode, _salt);
require(deployedContract == newContract1_, "DeployUtils: unexpected blueprint address");
}
newContract2_ = address(0);
} else {
bytes memory part1Slice = Bytes.slice(_rawBytecode, 0, maxSize);
bytes memory part2Slice = Bytes.slice(_rawBytecode, maxSize, _rawBytecode.length - maxSize);
bytes memory bp1Bytecode = Blueprint.blueprintDeployerBytecode(part1Slice);
bytes memory bp2Bytecode = Blueprint.blueprintDeployerBytecode(part2Slice);
newContract1_ = vm.computeCreate2Address(_salt, keccak256(bp1Bytecode));
if (newContract1_.code.length == 0) {
address deployedContract = Blueprint.deploySmallBytecode(bp1Bytecode, _salt);
require(deployedContract == newContract1_, "DeployUtils: unexpected part 1 blueprint address");
}
newContract2_ = vm.computeCreate2Address(_salt, keccak256(bp2Bytecode));
if (newContract2_.code.length == 0) {
address deployedContract = Blueprint.deploySmallBytecode(bp2Bytecode, _salt);
require(deployedContract == newContract2_, "DeployUtils: unexpected part 2 blueprint address");
}
}
}
/// @notice Takes a sender and an identifier and returns a deterministic address based on the /// @notice Takes a sender and an identifier and returns a deterministic address based on the
/// two. The result is used to etch the input and output contracts to a deterministic /// two. The result is used to etch the input and output contracts to a deterministic
/// address based on those two values, where the identifier represents the input or /// address based on those two values, where the identifier represents the input or
......
standard_release = "op-contracts/v1.6.0"
[releases]
# Contracts which are
# * unproxied singletons: specify a standard "address"
# * proxied : specify a standard "implementation_address"
# * neither : specify neither a standard "address" nor "implementation_address"
# Fault Proofs https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.6.0
[releases."op-contracts/v1.6.0"]
optimism_portal = { version = "3.10.0", implementation_address = "0xe2F826324b2faf99E513D16D266c3F80aE87832B" }
system_config = { version = "2.2.0", implementation_address = "0xF56D96B2535B932656d3c04Ebf51baBff241D886" }
anchor_state_registry = { version = "2.0.0" }
delayed_weth = { version = "1.1.0", implementation_address = "0x71e966Ae981d1ce531a7b6d23DC0f27B38409087" }
dispute_game_factory = { version = "1.0.0", implementation_address = "0xc641A33cab81C559F2bd4b21EA34C290E2440C2B" }
fault_dispute_game = { version = "1.3.0" }
permissioned_dispute_game = { version = "1.3.0" }
mips = { version = "1.1.0", address = "0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4" }
preimage_oracle = { version = "1.1.2", address = "0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277" }
l1_cross_domain_messenger = { version = "2.3.0", implementation_address = "0xD3494713A5cfaD3F5359379DfA074E2Ac8C6Fd65" }
l1_erc721_bridge = { version = "2.1.0", implementation_address = "0xAE2AF01232a6c4a4d3012C5eC5b1b35059caF10d" }
l1_standard_bridge = { version = "2.1.0", implementation_address = "0x64B5a5Ed26DCb17370Ff4d33a8D503f0fbD06CfF" }
# l2_output_oracle -- This contract not used in fault proofs
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xE01efbeb1089D1d1dB9c6c8b135C934C0734c846" }
# Fault Proofs https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.4.0
[releases."op-contracts/v1.4.0"]
optimism_portal = { version = "3.10.0", implementation_address = "0xe2F826324b2faf99E513D16D266c3F80aE87832B" }
system_config = { version = "2.2.0", implementation_address = "0xF56D96B2535B932656d3c04Ebf51baBff241D886" }
anchor_state_registry = { version = "1.0.0" }
delayed_weth = { version = "1.0.0", implementation_address = "0x97988d5624F1ba266E1da305117BCf20713bee08" }
dispute_game_factory = { version = "1.0.0", implementation_address = "0xc641A33cab81C559F2bd4b21EA34C290E2440C2B" }
fault_dispute_game = { version = "1.2.0" }
permissioned_dispute_game = { version = "1.2.0" }
mips = { version = "1.0.1", address = "0x0f8EdFbDdD3c0256A80AD8C0F2560B1807873C9c" }
preimage_oracle = { version = "1.0.0", address = "0xD326E10B8186e90F4E2adc5c13a2d0C137ee8b34" }
# MCP https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.3.0
[releases."op-contracts/v1.3.0"]
l1_cross_domain_messenger = { version = "2.3.0", implementation_address = "0xD3494713A5cfaD3F5359379DfA074E2Ac8C6Fd65" }
l1_erc721_bridge = { version = "2.1.0", implementation_address = "0xAE2AF01232a6c4a4d3012C5eC5b1b35059caF10d" }
l1_standard_bridge = { version = "2.1.0", implementation_address = "0x64B5a5Ed26DCb17370Ff4d33a8D503f0fbD06CfF" }
l2_output_oracle = { version = "1.8.0", implementation_address = "0xF243BEd163251380e78068d317ae10f26042B292" }
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xE01efbeb1089D1d1dB9c6c8b135C934C0734c846" }
optimism_portal = { version = "2.5.0", implementation_address = "0x2D778797049FE9259d947D1ED8e5442226dFB589" }
system_config = { version = "1.12.0", implementation_address = "0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1" }
...@@ -68,9 +68,6 @@ contract DeployImplementationsInput_Test is Test { ...@@ -68,9 +68,6 @@ contract DeployImplementationsInput_Test is Test {
vm.expectRevert("DeployImplementationsInput: not set"); vm.expectRevert("DeployImplementationsInput: not set");
dii.protocolVersionsProxy(); dii.protocolVersionsProxy();
vm.expectRevert("DeployImplementationsInput: not set");
dii.standardVersionsToml();
} }
} }
...@@ -225,14 +222,10 @@ contract DeployImplementations_Test is Test { ...@@ -225,14 +222,10 @@ contract DeployImplementations_Test is Test {
IProtocolVersions protocolVersionsProxy = IProtocolVersions(makeAddr("protocolVersionsProxy")); IProtocolVersions protocolVersionsProxy = IProtocolVersions(makeAddr("protocolVersionsProxy"));
function setUp() public virtual { function setUp() public virtual {
vm.etch(address(superchainConfigProxy), hex"01");
vm.etch(address(protocolVersionsProxy), hex"01");
deployImplementations = new DeployImplementations(); deployImplementations = new DeployImplementations();
(dii, dio) = deployImplementations.etchIOContracts(); (dii, dio) = deployImplementations.etchIOContracts();
// End users of the DeployImplementations contract will need to set the `standardVersionsToml`.
string memory standardVersionsTomlPath =
string.concat(vm.projectRoot(), "/test/fixtures/standard-versions.toml");
string memory standardVersionsToml = vm.readFile(standardVersionsTomlPath);
dii.set(dii.standardVersionsToml.selector, standardVersionsToml);
} }
// By deploying the `DeployImplementations` contract with this virtual function, we provide a // By deploying the `DeployImplementations` contract with this virtual function, we provide a
...@@ -247,67 +240,73 @@ contract DeployImplementations_Test is Test { ...@@ -247,67 +240,73 @@ contract DeployImplementations_Test is Test {
} }
function test_deployImplementation_succeeds() public { function test_deployImplementation_succeeds() public {
string memory deployContractsRelease = "dev-release"; deployImplementations.deploySystemConfigImpl(dio);
dii.set(dii.l1ContractsRelease.selector, deployContractsRelease);
deployImplementations.deploySystemConfigImpl(dii, dio);
assertTrue(address(0) != address(dio.systemConfigImpl())); assertTrue(address(0) != address(dio.systemConfigImpl()));
} }
function test_reuseImplementation_succeeds() public { function test_reuseImplementation_succeeds() public {
// All hardcoded addresses below are taken from the superchain-registry config:
// https://github.com/ethereum-optimism/superchain-registry/blob/be65d22f8128cf0c4e5b4e1f677daf86843426bf/validation/standard/standard-versions.toml#L11
string memory testRelease = "op-contracts/v1.6.0"; string memory testRelease = "op-contracts/v1.6.0";
dii.set(dii.l1ContractsRelease.selector, testRelease); dii.set(dii.l1ContractsRelease.selector, testRelease);
dii.set(dii.proofMaturityDelaySeconds.selector, 1);
dii.set(dii.disputeGameFinalityDelaySeconds.selector, 1);
dii.set(dii.withdrawalDelaySeconds.selector, 1);
dii.set(dii.minProposalSizeBytes.selector, 1);
dii.set(dii.challengePeriodSeconds.selector, 1);
dii.set(dii.mipsVersion.selector, 1);
dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy));
dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy));
deployImplementations.deploySystemConfigImpl(dii, dio); // Perform the initial deployment.
address srSystemConfigImpl = address(0xF56D96B2535B932656d3c04Ebf51baBff241D886); deployImplementations.deploySystemConfigImpl(dio);
vm.etch(address(srSystemConfigImpl), hex"01"); deployImplementations.deployL1CrossDomainMessengerImpl(dio);
assertEq(srSystemConfigImpl, address(dio.systemConfigImpl())); deployImplementations.deployL1ERC721BridgeImpl(dio);
deployImplementations.deployL1StandardBridgeImpl(dio);
address srL1CrossDomainMessengerImpl = address(0xD3494713A5cfaD3F5359379DfA074E2Ac8C6Fd65); deployImplementations.deployOptimismMintableERC20FactoryImpl(dio);
vm.etch(address(srL1CrossDomainMessengerImpl), hex"01");
deployImplementations.deployL1CrossDomainMessengerImpl(dii, dio);
assertEq(srL1CrossDomainMessengerImpl, address(dio.l1CrossDomainMessengerImpl()));
address srL1ERC721BridgeImpl = address(0xAE2AF01232a6c4a4d3012C5eC5b1b35059caF10d);
vm.etch(address(srL1ERC721BridgeImpl), hex"01");
deployImplementations.deployL1ERC721BridgeImpl(dii, dio);
assertEq(srL1ERC721BridgeImpl, address(dio.l1ERC721BridgeImpl()));
address srL1StandardBridgeImpl = address(0x64B5a5Ed26DCb17370Ff4d33a8D503f0fbD06CfF);
vm.etch(address(srL1StandardBridgeImpl), hex"01");
deployImplementations.deployL1StandardBridgeImpl(dii, dio);
assertEq(srL1StandardBridgeImpl, address(dio.l1StandardBridgeImpl()));
address srOptimismMintableERC20FactoryImpl = address(0xE01efbeb1089D1d1dB9c6c8b135C934C0734c846);
vm.etch(address(srOptimismMintableERC20FactoryImpl), hex"01");
deployImplementations.deployOptimismMintableERC20FactoryImpl(dii, dio);
assertEq(srOptimismMintableERC20FactoryImpl, address(dio.optimismMintableERC20FactoryImpl()));
address srOptimismPortalImpl = address(0xe2F826324b2faf99E513D16D266c3F80aE87832B);
vm.etch(address(srOptimismPortalImpl), hex"01");
deployImplementations.deployOptimismPortalImpl(dii, dio); deployImplementations.deployOptimismPortalImpl(dii, dio);
assertEq(srOptimismPortalImpl, address(dio.optimismPortalImpl()));
address srDelayedWETHImpl = address(0x71e966Ae981d1ce531a7b6d23DC0f27B38409087);
vm.etch(address(srDelayedWETHImpl), hex"01");
deployImplementations.deployDelayedWETHImpl(dii, dio); deployImplementations.deployDelayedWETHImpl(dii, dio);
assertEq(srDelayedWETHImpl, address(dio.delayedWETHImpl()));
address srPreimageOracleSingleton = address(0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277);
vm.etch(address(srPreimageOracleSingleton), hex"01");
deployImplementations.deployPreimageOracleSingleton(dii, dio); deployImplementations.deployPreimageOracleSingleton(dii, dio);
assertEq(srPreimageOracleSingleton, address(dio.preimageOracleSingleton()));
address srMipsSingleton = address(0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4);
vm.etch(address(srMipsSingleton), hex"01");
deployImplementations.deployMipsSingleton(dii, dio); deployImplementations.deployMipsSingleton(dii, dio);
assertEq(srMipsSingleton, address(dio.mipsSingleton())); deployImplementations.deployDisputeGameFactoryImpl(dio);
deployImplementations.deployOPContractsManager(dii, dio);
address srDisputeGameFactoryImpl = address(0xc641A33cab81C559F2bd4b21EA34C290E2440C2B);
vm.etch(address(srDisputeGameFactoryImpl), hex"01"); // Store the original addresses.
deployImplementations.deployDisputeGameFactoryImpl(dii, dio); address systemConfigImpl = address(dio.systemConfigImpl());
assertEq(srDisputeGameFactoryImpl, address(dio.disputeGameFactoryImpl())); address l1CrossDomainMessengerImpl = address(dio.l1CrossDomainMessengerImpl());
address l1ERC721BridgeImpl = address(dio.l1ERC721BridgeImpl());
address l1StandardBridgeImpl = address(dio.l1StandardBridgeImpl());
address optimismMintableERC20FactoryImpl = address(dio.optimismMintableERC20FactoryImpl());
address optimismPortalImpl = address(dio.optimismPortalImpl());
address delayedWETHImpl = address(dio.delayedWETHImpl());
address preimageOracleSingleton = address(dio.preimageOracleSingleton());
address mipsSingleton = address(dio.mipsSingleton());
address disputeGameFactoryImpl = address(dio.disputeGameFactoryImpl());
address opcm = address(dio.opcm());
// Do the deployments again. Thi should be a noop.
deployImplementations.deploySystemConfigImpl(dio);
deployImplementations.deployL1CrossDomainMessengerImpl(dio);
deployImplementations.deployL1ERC721BridgeImpl(dio);
deployImplementations.deployL1StandardBridgeImpl(dio);
deployImplementations.deployOptimismMintableERC20FactoryImpl(dio);
deployImplementations.deployOptimismPortalImpl(dii, dio);
deployImplementations.deployDelayedWETHImpl(dii, dio);
deployImplementations.deployPreimageOracleSingleton(dii, dio);
deployImplementations.deployMipsSingleton(dii, dio);
deployImplementations.deployDisputeGameFactoryImpl(dio);
deployImplementations.deployOPContractsManager(dii, dio);
// Assert that the addresses did not change.
assertEq(systemConfigImpl, address(dio.systemConfigImpl()), "100");
assertEq(l1CrossDomainMessengerImpl, address(dio.l1CrossDomainMessengerImpl()), "200");
assertEq(l1ERC721BridgeImpl, address(dio.l1ERC721BridgeImpl()), "300");
assertEq(l1StandardBridgeImpl, address(dio.l1StandardBridgeImpl()), "400");
assertEq(optimismMintableERC20FactoryImpl, address(dio.optimismMintableERC20FactoryImpl()), "500");
assertEq(optimismPortalImpl, address(dio.optimismPortalImpl()), "600");
assertEq(delayedWETHImpl, address(dio.delayedWETHImpl()), "700");
assertEq(preimageOracleSingleton, address(dio.preimageOracleSingleton()), "800");
assertEq(mipsSingleton, address(dio.mipsSingleton()), "900");
assertEq(disputeGameFactoryImpl, address(dio.disputeGameFactoryImpl()), "1000");
assertEq(opcm, address(dio.opcm()), "1100");
} }
function testFuzz_run_memory_succeeds(bytes32 _seed) public { function testFuzz_run_memory_succeeds(bytes32 _seed) public {
......
...@@ -398,11 +398,6 @@ contract DeployOPChain_TestBase is Test { ...@@ -398,11 +398,6 @@ contract DeployOPChain_TestBase is Test {
dii.set(dii.l1ContractsRelease.selector, release); dii.set(dii.l1ContractsRelease.selector, release);
dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy)); dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy));
dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy)); dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy));
// End users of the DeployImplementations contract will need to set the `standardVersionsToml`.
string memory standardVersionsTomlPath =
string.concat(vm.projectRoot(), "/test/fixtures/standard-versions.toml");
string memory standardVersionsToml = vm.readFile(standardVersionsTomlPath);
dii.set(dii.standardVersionsToml.selector, standardVersionsToml);
deployImplementations.run(dii, dio); deployImplementations.run(dii, dio);
......
...@@ -234,6 +234,15 @@ contract DeploySuperchain_Test is Test { ...@@ -234,6 +234,15 @@ contract DeploySuperchain_Test is Test {
vm.store(address(dsi), bytes32(slot), bytes32(unwrap(defaultRecommendedProtocolVersion))); vm.store(address(dsi), bytes32(slot), bytes32(unwrap(defaultRecommendedProtocolVersion)));
} }
function test_deploySuperchainImplementationContracts_reuseAddresses_succeeds() public {
deploySuperchain.deploySuperchainImplementationContracts(dsi, dso);
address originalConfig = address(dso.superchainConfigImpl());
address originalProtocolVersions = address(dso.protocolVersionsImpl());
deploySuperchain.deploySuperchainImplementationContracts(dsi, dso);
assertEq(address(dso.superchainConfigImpl()), originalConfig, "100");
assertEq(address(dso.protocolVersionsImpl()), originalProtocolVersions, "200");
}
function zeroOutSlotForSelector(bytes4 _selector) internal returns (uint256 slot_) { function zeroOutSlotForSelector(bytes4 _selector) internal returns (uint256 slot_) {
slot_ = stdstore.enable_packed_slots().target(address(dsi)).sig(_selector).find(); slot_ = stdstore.enable_packed_slots().target(address(dsi)).sig(_selector).find();
vm.store(address(dsi), bytes32(slot_), bytes32(0)); vm.store(address(dsi), bytes32(slot_), bytes32(0));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment