Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OPSM: More assertions #11994

Merged
merged 8 commits into from
Sep 19, 2024
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
175 changes: 173 additions & 2 deletions packages/contracts-bedrock/scripts/DeployImplementations.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { Script } from "forge-std/Script.sol";

import { LibString } from "@solady/utils/LibString.sol";

import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";

import { Constants } from "src/libraries/Constants.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";

import { ProxyAdmin } from "src/universal/ProxyAdmin.sol";
import { Proxy } from "src/universal/Proxy.sol";
import { L1ChugSplashProxy } from "src/legacy/L1ChugSplashProxy.sol";
Expand Down Expand Up @@ -191,7 +197,7 @@ contract DeployImplementationsOutput is BaseDeployIO {
require(false, "DeployImplementationsOutput: not implemented");
}

function checkOutput(DeployImplementationsInput) public {
function checkOutput(DeployImplementationsInput _dii) public {
address[] memory addrs = Solarray.addresses(
address(this.opsmProxy()),
address(this.optimismPortalImpl()),
Expand All @@ -207,7 +213,7 @@ contract DeployImplementationsOutput is BaseDeployIO {
);
DeployUtils.assertValidContractAddresses(addrs);

// TODO Also add the assertions for the implementation contracts from ChainAssertions.sol
assertValidDeploy(_dii);
}

function opsmProxy() public returns (OPStackManager) {
Expand Down Expand Up @@ -265,6 +271,171 @@ contract DeployImplementationsOutput is BaseDeployIO {
DeployUtils.assertValidContractAddress(address(_disputeGameFactoryImpl));
return _disputeGameFactoryImpl;
}

// -------- Deployment Assertions --------
function assertValidDeploy(DeployImplementationsInput _dii) public {
assertValidDelayedWETHImpl(_dii);
assertValidDisputeGameFactoryImpl(_dii);
assertValidL1CrossDomainMessengerImpl(_dii);
assertValidL1ERC721BridgeImpl(_dii);
assertValidL1StandardBridgeImpl(_dii);
assertValidMipsSingleton(_dii);
assertValidOpsmProxy(_dii);
mds1 marked this conversation as resolved.
Show resolved Hide resolved
assertValidOpsmImpl(_dii);
assertValidOptimismMintableERC20FactoryImpl(_dii);
assertValidOptimismPortalImpl(_dii);
assertValidPreimageOracleSingleton(_dii);
assertValidSystemConfigImpl(_dii);
}

function assertValidOpsmProxy(DeployImplementationsInput _dii) internal {
// First we check the proxy as itself.
Proxy proxy = Proxy(payable(address(opsmProxy())));
vm.prank(address(0));
address admin = proxy.admin();
require(admin == address(_dii.superchainProxyAdmin()), "OPSMP-10");

// Then we check the proxy as OPSM.
DeployUtils.assertInitialized({ _contractAddress: address(opsmProxy()), _slot: 0, _offset: 0 });
require(address(opsmProxy().superchainConfig()) == address(_dii.superchainConfigProxy()), "OPSMP-20");
require(address(opsmProxy().protocolVersions()) == address(_dii.protocolVersionsProxy()), "OPSMP-30");
require(LibString.eq(opsmProxy().latestRelease(), _dii.release()), "OPSMP-50"); // Initial release is latest.
}

function assertValidOpsmImpl(DeployImplementationsInput _dii) internal {
Proxy proxy = Proxy(payable(address(opsmProxy())));
vm.prank(address(0));
OPStackManager impl = OPStackManager(proxy.implementation());
DeployUtils.assertInitialized({ _contractAddress: address(impl), _slot: 0, _offset: 0 });
require(address(impl.superchainConfig()) == address(_dii.superchainConfigProxy()), "OPSMI-10");
require(address(impl.protocolVersions()) == address(_dii.protocolVersionsProxy()), "OPSMI-20");
}

function assertValidOptimismPortalImpl(DeployImplementationsInput) internal view {
OptimismPortal2 portal = optimismPortalImpl();

DeployUtils.assertInitialized({ _contractAddress: address(portal), _slot: 0, _offset: 0 });

require(address(portal.disputeGameFactory()) == address(0), "PORTAL-10");
require(address(portal.systemConfig()) == address(0), "PORTAL-20");
require(address(portal.superchainConfig()) == address(0), "PORTAL-30");
require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER, "PORTAL-40");

// This slot is the custom gas token _balance and this check ensures
// that it stays unset for forwards compatibility with custom gas token.
require(vm.load(address(portal), bytes32(uint256(61))) == bytes32(0), "PORTAL-50");
}

function assertValidDelayedWETHImpl(DeployImplementationsInput _dii) internal view {
DelayedWETH delayedWETH = delayedWETHImpl();

DeployUtils.assertInitialized({ _contractAddress: address(delayedWETH), _slot: 0, _offset: 0 });

require(delayedWETH.owner() == address(0), "DW-10");
require(delayedWETH.delay() == _dii.withdrawalDelaySeconds(), "DW-20");
require(delayedWETH.config() == ISuperchainConfig(address(0)), "DW-30");
}

function assertValidPreimageOracleSingleton(DeployImplementationsInput _dii) internal view {
PreimageOracle oracle = preimageOracleSingleton();

require(oracle.minProposalSize() == _dii.minProposalSizeBytes(), "PO-10");
require(oracle.challengePeriod() == _dii.challengePeriodSeconds(), "PO-20");
}

function assertValidMipsSingleton(DeployImplementationsInput) internal view {
MIPS mips = mipsSingleton();

require(address(mips.oracle()) == address(preimageOracleSingleton()), "MIPS-10");
}

function assertValidSystemConfigImpl(DeployImplementationsInput) internal view {
SystemConfig systemConfig = systemConfigImpl();

DeployUtils.assertInitialized({ _contractAddress: address(systemConfig), _slot: 0, _offset: 0 });

require(systemConfig.owner() == address(0xdead), "SYSCON-10");
require(systemConfig.overhead() == 0, "SYSCON-20");
require(systemConfig.scalar() == uint256(0x01) << 248, "SYSCON-30");
require(systemConfig.basefeeScalar() == 0, "SYSCON-40");
require(systemConfig.blobbasefeeScalar() == 0, "SYSCON-50");
require(systemConfig.batcherHash() == bytes32(0), "SYSCON-60");
require(systemConfig.gasLimit() == 1, "SYSCON-70");
require(systemConfig.unsafeBlockSigner() == address(0), "SYSCON-80");

IResourceMetering.ResourceConfig memory resourceConfig = systemConfig.resourceConfig();
require(resourceConfig.maxResourceLimit == 1, "SYSCON-90");
require(resourceConfig.elasticityMultiplier == 1, "SYSCON-100");
require(resourceConfig.baseFeeMaxChangeDenominator == 2, "SYSCON-110");
require(resourceConfig.systemTxMaxGas == 0, "SYSCON-120");
require(resourceConfig.minimumBaseFee == 0, "SYSCON-130");
require(resourceConfig.maximumBaseFee == 0, "SYSCON-140");

require(systemConfig.startBlock() == type(uint256).max, "SYSCON-150");
require(systemConfig.batchInbox() == address(0), "SYSCON-160");
require(systemConfig.l1CrossDomainMessenger() == address(0), "SYSCON-170");
require(systemConfig.l1ERC721Bridge() == address(0), "SYSCON-180");
require(systemConfig.l1StandardBridge() == address(0), "SYSCON-190");
require(systemConfig.disputeGameFactory() == address(0), "SYSCON-200");
require(systemConfig.optimismPortal() == address(0), "SYSCON-210");
require(systemConfig.optimismMintableERC20Factory() == address(0), "SYSCON-220");
}

function assertValidL1CrossDomainMessengerImpl(DeployImplementationsInput) internal view {
L1CrossDomainMessenger messenger = l1CrossDomainMessengerImpl();

DeployUtils.assertInitialized({ _contractAddress: address(messenger), _slot: 0, _offset: 20 });

require(address(messenger.OTHER_MESSENGER()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "L1xDM-10");
require(address(messenger.otherMessenger()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "L1xDM-20");
require(address(messenger.PORTAL()) == address(0), "L1xDM-30");
require(address(messenger.portal()) == address(0), "L1xDM-40");
require(address(messenger.superchainConfig()) == address(0), "L1xDM-50");

bytes32 xdmSenderSlot = vm.load(address(messenger), bytes32(uint256(204)));
require(address(uint160(uint256(xdmSenderSlot))) == Constants.DEFAULT_L2_SENDER, "L1xDM-60");
}

function assertValidL1ERC721BridgeImpl(DeployImplementationsInput) internal view {
L1ERC721Bridge bridge = l1ERC721BridgeImpl();

DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 0, _offset: 0 });

require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "L721B-10");
require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "L721B-20");
require(address(bridge.MESSENGER()) == address(0), "L721B-30");
require(address(bridge.messenger()) == address(0), "L721B-40");
require(address(bridge.superchainConfig()) == address(0), "L721B-50");
}

function assertValidL1StandardBridgeImpl(DeployImplementationsInput) internal view {
L1StandardBridge bridge = l1StandardBridgeImpl();

DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 0, _offset: 0 });

require(address(bridge.MESSENGER()) == address(0), "L1SB-10");
require(address(bridge.messenger()) == address(0), "L1SB-20");
require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_STANDARD_BRIDGE, "L1SB-30");
require(address(bridge.otherBridge()) == Predeploys.L2_STANDARD_BRIDGE, "L1SB-40");
require(address(bridge.superchainConfig()) == address(0), "L1SB-50");
}

function assertValidOptimismMintableERC20FactoryImpl(DeployImplementationsInput) internal view {
OptimismMintableERC20Factory factory = optimismMintableERC20FactoryImpl();

DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 });

require(address(factory.BRIDGE()) == address(0), "MERC20F-10");
require(address(factory.bridge()) == address(0), "MERC20F-20");
}

function assertValidDisputeGameFactoryImpl(DeployImplementationsInput) internal view {
DisputeGameFactory factory = disputeGameFactoryImpl();

DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 });

require(address(factory.owner()) == address(0), "DG-10");
}
}

contract DeployImplementations is Script {
Expand Down
87 changes: 46 additions & 41 deletions packages/contracts-bedrock/scripts/DeployOPChain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -274,16 +274,17 @@ contract DeployOPChainOutput is BaseDeployIO {
return _delayedWETHPermissionlessGameProxy;
}

// -------- Assertions on chain architecture --------
// -------- Deployment Assertions --------

function assertValidDeploy(DeployOPChainInput _doi) internal view {
assertValidSystemConfig(_doi);
assertValidDelayedWETHs(_doi);
assertValidDisputeGameFactory(_doi);
assertValidL1CrossDomainMessenger(_doi);
assertValidL1ERC721Bridge(_doi);
assertValidL1StandardBridge(_doi);
assertValidOptimismMintableERC20Factory(_doi);
assertValidOptimismPortal(_doi);
assertValidDisputeGameFactory(_doi);
assertValidDelayedWETHs(_doi);
assertValidSystemConfig(_doi);
mds1 marked this conversation as resolved.
Show resolved Hide resolved
// TODO Other FP assertions like the dispute games, anchor state registry, etc.
// TODO add initialization assertions
}
Expand All @@ -293,34 +294,38 @@ contract DeployOPChainOutput is BaseDeployIO {

DeployUtils.assertInitialized({ _contractAddress: address(systemConfig), _slot: 0, _offset: 0 });

require(systemConfig.owner() == _doi.systemConfigOwner(), "SC-10");
require(systemConfig.basefeeScalar() == _doi.basefeeScalar(), "SC-20");
require(systemConfig.blobbasefeeScalar() == _doi.blobBaseFeeScalar(), "SC-30");
require(systemConfig.batcherHash() == bytes32(uint256(uint160(_doi.batcher()))), "SC-40");
require(systemConfig.gasLimit() == uint64(30000000), "SC-50"); // TODO allow other gas limits?
require(systemConfig.unsafeBlockSigner() == _doi.unsafeBlockSigner(), "SC-60");
require(systemConfig.scalar() >> 248 == 1, "SC-70");
require(systemConfig.owner() == _doi.systemConfigOwner(), "SYSCON-10");
require(systemConfig.basefeeScalar() == _doi.basefeeScalar(), "SYSCON-20");
require(systemConfig.blobbasefeeScalar() == _doi.blobBaseFeeScalar(), "SYSCON-30");
require(systemConfig.batcherHash() == bytes32(uint256(uint160(_doi.batcher()))), "SYSCON-40");
require(systemConfig.gasLimit() == uint64(30000000), "SYSCON-50"); // TODO allow other gas limits?
require(systemConfig.unsafeBlockSigner() == _doi.unsafeBlockSigner(), "SYSCON-60");
require(systemConfig.scalar() >> 248 == 1, "SYSCON-70");

IResourceMetering.ResourceConfig memory rConfig = Constants.DEFAULT_RESOURCE_CONFIG();
IResourceMetering.ResourceConfig memory outputConfig = systemConfig.resourceConfig();
require(outputConfig.maxResourceLimit == rConfig.maxResourceLimit, "SC-80");
require(outputConfig.elasticityMultiplier == rConfig.elasticityMultiplier, "SC-90");
require(outputConfig.baseFeeMaxChangeDenominator == rConfig.baseFeeMaxChangeDenominator, "SC-100");
require(outputConfig.systemTxMaxGas == rConfig.systemTxMaxGas, "SC-110");
require(outputConfig.minimumBaseFee == rConfig.minimumBaseFee, "SC-120");
require(outputConfig.maximumBaseFee == rConfig.maximumBaseFee, "SC-130");

require(systemConfig.startBlock() == block.number, "SC-140");
require(systemConfig.batchInbox() == _doi.opsmProxy().chainIdToBatchInboxAddress(_doi.l2ChainId()), "SC-150");

require(systemConfig.l1CrossDomainMessenger() == address(l1CrossDomainMessengerProxy()), "SC-160");
require(systemConfig.l1ERC721Bridge() == address(l1ERC721BridgeProxy()), "SC-170");
require(systemConfig.l1StandardBridge() == address(l1StandardBridgeProxy()), "SC-180");
require(systemConfig.disputeGameFactory() == address(disputeGameFactoryProxy()), "SC-190");
require(systemConfig.optimismPortal() == address(optimismPortalProxy()), "SC-200");
require(systemConfig.optimismMintableERC20Factory() == address(optimismMintableERC20FactoryProxy()), "SC-210");
require(outputConfig.maxResourceLimit == rConfig.maxResourceLimit, "SYSCON-80");
require(outputConfig.elasticityMultiplier == rConfig.elasticityMultiplier, "SYSCON-90");
require(outputConfig.baseFeeMaxChangeDenominator == rConfig.baseFeeMaxChangeDenominator, "SYSCON-100");
require(outputConfig.systemTxMaxGas == rConfig.systemTxMaxGas, "SYSCON-110");
require(outputConfig.minimumBaseFee == rConfig.minimumBaseFee, "SYSCON-120");
require(outputConfig.maximumBaseFee == rConfig.maximumBaseFee, "SYSCON-130");

require(systemConfig.startBlock() == block.number, "SYSCON-140");
require(
systemConfig.batchInbox() == _doi.opsmProxy().chainIdToBatchInboxAddress(_doi.l2ChainId()), "SYSCON-150"
);

require(systemConfig.l1CrossDomainMessenger() == address(l1CrossDomainMessengerProxy()), "SYSCON-160");
require(systemConfig.l1ERC721Bridge() == address(l1ERC721BridgeProxy()), "SYSCON-170");
require(systemConfig.l1StandardBridge() == address(l1StandardBridgeProxy()), "SYSCON-180");
require(systemConfig.disputeGameFactory() == address(disputeGameFactoryProxy()), "SYSCON-190");
require(systemConfig.optimismPortal() == address(optimismPortalProxy()), "SYSCON-200");
require(
systemConfig.optimismMintableERC20Factory() == address(optimismMintableERC20FactoryProxy()), "SYSCON-210"
);
(address gasPayingToken,) = systemConfig.gasPayingToken();
require(gasPayingToken == Constants.ETHER, "SC-220");
require(gasPayingToken == Constants.ETHER, "SYSCON-220");
}

function assertValidL1CrossDomainMessenger(DeployOPChainInput _doi) internal view {
Expand Down Expand Up @@ -357,33 +362,33 @@ contract DeployOPChainOutput is BaseDeployIO {

DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 });

require(factory.BRIDGE() == address(l1StandardBridgeProxy()), "OMEF-10");
require(factory.bridge() == address(l1StandardBridgeProxy()), "OMEF-20");
require(factory.BRIDGE() == address(l1StandardBridgeProxy()), "MERC20F-10");
require(factory.bridge() == address(l1StandardBridgeProxy()), "MERC20F-20");
}

function assertValidL1ERC721Bridge(DeployOPChainInput _doi) internal view {
L1ERC721Bridge bridge = l1ERC721BridgeProxy();

DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 0, _offset: 0 });

require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "LEB-10");
require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "LEB-20");
require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "L721B-10");
require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "L721B-20");

require(address(bridge.MESSENGER()) == address(l1CrossDomainMessengerProxy()), "LEB-30");
require(address(bridge.messenger()) == address(l1CrossDomainMessengerProxy()), "LEB-40");
require(address(bridge.superchainConfig()) == address(_doi.opsmProxy().superchainConfig()), "LEB-50");
require(address(bridge.MESSENGER()) == address(l1CrossDomainMessengerProxy()), "L721B-30");
require(address(bridge.messenger()) == address(l1CrossDomainMessengerProxy()), "L721B-40");
require(address(bridge.superchainConfig()) == address(_doi.opsmProxy().superchainConfig()), "L721B-50");
}

function assertValidOptimismPortal(DeployOPChainInput _doi) internal view {
OptimismPortal2 portal = optimismPortalProxy();
ISuperchainConfig superchainConfig = ISuperchainConfig(address(_doi.opsmProxy().superchainConfig()));

require(address(portal.disputeGameFactory()) == address(disputeGameFactoryProxy()), "OP-10");
require(address(portal.systemConfig()) == address(systemConfigProxy()), "OP-20");
require(address(portal.superchainConfig()) == address(superchainConfig), "OP-30");
require(portal.guardian() == superchainConfig.guardian(), "OP-40");
require(portal.paused() == superchainConfig.paused(), "OP-50");
require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER, "OP-60");
require(address(portal.disputeGameFactory()) == address(disputeGameFactoryProxy()), "PORTAL-10");
require(address(portal.systemConfig()) == address(systemConfigProxy()), "PORTAL-20");
require(address(portal.superchainConfig()) == address(superchainConfig), "PORTAL-30");
require(portal.guardian() == superchainConfig.guardian(), "PORTAL-40");
require(portal.paused() == superchainConfig.paused(), "PORTAL-50");
require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER, "PORTAL-60");

// This slot is the custom gas token _balance and this check ensures
// that it stays unset for forwards compatibility with custom gas token.
Expand Down
Loading