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

OPCM: AddressManager and ProxyAdmin assertions. #12370

Merged
merged 10 commits into from
Oct 8, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ contract DeployImplementationsOutput is BaseDeployIO {

function opcmProxy() public returns (OPContractsManager) {
DeployUtils.assertValidContractAddress(address(_opcmProxy));
DeployUtils.assertImplementationSet(address(_opcmProxy));
DeployUtils.assertERC1967ImplementationSet(address(_opcmProxy));
return _opcmProxy;
}

Expand Down
90 changes: 78 additions & 12 deletions packages/contracts-bedrock/scripts/DeployOPChain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ contract DeployOPChainInput is BaseDeployIO {
function opcmProxy() public returns (OPContractsManager) {
require(address(_opcmProxy) != address(0), "DeployOPChainInput: not set");
DeployUtils.assertValidContractAddress(address(_opcmProxy));
DeployUtils.assertImplementationSet(address(_opcmProxy));
DeployUtils.assertERC1967ImplementationSet(address(_opcmProxy));
return _opcmProxy;
}

Expand Down Expand Up @@ -286,43 +286,51 @@ contract DeployOPChainOutput is BaseDeployIO {
return _addressManager;
}

function l1ERC721BridgeProxy() public view returns (IL1ERC721Bridge) {
function l1ERC721BridgeProxy() public returns (IL1ERC721Bridge) {
DeployUtils.assertValidContractAddress(address(_l1ERC721BridgeProxy));
DeployUtils.assertERC1967ImplementationSet(address(_l1ERC721BridgeProxy));
return _l1ERC721BridgeProxy;
}

function systemConfigProxy() public view returns (ISystemConfig) {
function systemConfigProxy() public returns (ISystemConfig) {
DeployUtils.assertValidContractAddress(address(_systemConfigProxy));
DeployUtils.assertERC1967ImplementationSet(address(_systemConfigProxy));
return _systemConfigProxy;
}

function optimismMintableERC20FactoryProxy() public view returns (IOptimismMintableERC20Factory) {
function optimismMintableERC20FactoryProxy() public returns (IOptimismMintableERC20Factory) {
DeployUtils.assertValidContractAddress(address(_optimismMintableERC20FactoryProxy));
DeployUtils.assertERC1967ImplementationSet(address(_optimismMintableERC20FactoryProxy));
return _optimismMintableERC20FactoryProxy;
}

function l1StandardBridgeProxy() public view returns (IL1StandardBridge) {
function l1StandardBridgeProxy() public returns (IL1StandardBridge) {
DeployUtils.assertValidContractAddress(address(_l1StandardBridgeProxy));
DeployUtils.assertL1ChugSplashImplementationSet(address(_l1StandardBridgeProxy));
return _l1StandardBridgeProxy;
}

function l1CrossDomainMessengerProxy() public view returns (IL1CrossDomainMessenger) {
DeployUtils.assertValidContractAddress(address(_l1CrossDomainMessengerProxy));
DeployUtils.assertResolvedDelegateProxyImplementationSet("OVM_L1CrossDomainMessenger", addressManager());
return _l1CrossDomainMessengerProxy;
}

function optimismPortalProxy() public view returns (IOptimismPortal2) {
function optimismPortalProxy() public returns (IOptimismPortal2) {
DeployUtils.assertValidContractAddress(address(_optimismPortalProxy));
DeployUtils.assertERC1967ImplementationSet(address(_optimismPortalProxy));
return _optimismPortalProxy;
}

function disputeGameFactoryProxy() public view returns (IDisputeGameFactory) {
function disputeGameFactoryProxy() public returns (IDisputeGameFactory) {
DeployUtils.assertValidContractAddress(address(_disputeGameFactoryProxy));
DeployUtils.assertERC1967ImplementationSet(address(_disputeGameFactoryProxy));
return _disputeGameFactoryProxy;
}

function anchorStateRegistryProxy() public view returns (IAnchorStateRegistry) {
function anchorStateRegistryProxy() public returns (IAnchorStateRegistry) {
DeployUtils.assertValidContractAddress(address(_anchorStateRegistryProxy));
DeployUtils.assertERC1967ImplementationSet(address(_anchorStateRegistryProxy));
return _anchorStateRegistryProxy;
}

Expand All @@ -341,8 +349,9 @@ contract DeployOPChainOutput is BaseDeployIO {
return _permissionedDisputeGame;
}

function delayedWETHPermissionedGameProxy() public view returns (IDelayedWETH) {
function delayedWETHPermissionedGameProxy() public returns (IDelayedWETH) {
DeployUtils.assertValidContractAddress(address(_delayedWETHPermissionedGameProxy));
DeployUtils.assertERC1967ImplementationSet(address(_delayedWETHPermissionedGameProxy));
return _delayedWETHPermissionedGameProxy;
}

Expand All @@ -366,6 +375,8 @@ contract DeployOPChainOutput is BaseDeployIO {
assertValidOptimismPortal(_doi);
assertValidPermissionedDisputeGame(_doi);
assertValidSystemConfig(_doi);
assertValidAddressManager(_doi);
assertValidOPChainProxyAdmin(_doi);
}

function assertValidPermissionedDisputeGame(DeployOPChainInput _doi) internal {
Expand Down Expand Up @@ -416,7 +427,7 @@ contract DeployOPChainOutput is BaseDeployIO {
require(Hash.unwrap(actualRoot) == expectedRoot, "ANCHORP-40");
}

function assertValidAnchorStateRegistryImpl(DeployOPChainInput) internal view {
function assertValidAnchorStateRegistryImpl(DeployOPChainInput) internal {
IAnchorStateRegistry registry = anchorStateRegistryImpl();

DeployUtils.assertInitialized({ _contractAddress: address(registry), _slot: 0, _offset: 0 });
Expand Down Expand Up @@ -492,7 +503,7 @@ contract DeployOPChainOutput is BaseDeployIO {
require(address(bridge.superchainConfig()) == address(_doi.opcmProxy().superchainConfig()), "L1SB-50");
}

function assertValidOptimismMintableERC20Factory(DeployOPChainInput) internal view {
function assertValidOptimismMintableERC20Factory(DeployOPChainInput) internal {
IOptimismMintableERC20Factory factory = optimismMintableERC20FactoryProxy();

DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 });
Expand Down Expand Up @@ -530,7 +541,7 @@ contract DeployOPChainOutput is BaseDeployIO {
require(vm.load(address(portal), bytes32(uint256(61))) == bytes32(0));
}

function assertValidDisputeGameFactory(DeployOPChainInput _doi) internal view {
function assertValidDisputeGameFactory(DeployOPChainInput _doi) internal {
IDisputeGameFactory factory = disputeGameFactoryProxy();

DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 });
Expand All @@ -551,6 +562,61 @@ contract DeployOPChainOutput is BaseDeployIO {
address admin = proxy.admin();
require(admin == address(opChainProxyAdmin()), "DWETH-20");
}

function assertValidAddressManager(DeployOPChainInput) internal view {
require(addressManager().owner() == address(opChainProxyAdmin()), "AM-10");
}

function assertValidOPChainProxyAdmin(DeployOPChainInput _doi) internal {
IProxyAdmin admin = opChainProxyAdmin();
require(admin.owner() == _doi.opChainProxyAdminOwner(), "OPCPA-10");
require(
admin.getProxyImplementation(address(l1CrossDomainMessengerProxy()))
== DeployUtils.assertResolvedDelegateProxyImplementationSet("OVM_L1CrossDomainMessenger", addressManager()),
"OPCPA-20"
);
require(address(admin.addressManager()) == address(addressManager()), "OPCPA-30");
require(
admin.getProxyImplementation(address(l1StandardBridgeProxy()))
== DeployUtils.assertL1ChugSplashImplementationSet(address(l1StandardBridgeProxy())),
"OPCPA-40"
);
require(
admin.getProxyImplementation(address(l1ERC721BridgeProxy()))
== DeployUtils.assertERC1967ImplementationSet(address(l1ERC721BridgeProxy())),
"OPCPA-50"
);
require(
admin.getProxyImplementation(address(optimismPortalProxy()))
== DeployUtils.assertERC1967ImplementationSet(address(optimismPortalProxy())),
"OPCPA-60"
);
require(
admin.getProxyImplementation(address(systemConfigProxy()))
== DeployUtils.assertERC1967ImplementationSet(address(systemConfigProxy())),
"OPCPA-70"
);
require(
admin.getProxyImplementation(address(optimismMintableERC20FactoryProxy()))
== DeployUtils.assertERC1967ImplementationSet(address(optimismMintableERC20FactoryProxy())),
"OPCPA-80"
);
require(
admin.getProxyImplementation(address(disputeGameFactoryProxy()))
== DeployUtils.assertERC1967ImplementationSet(address(disputeGameFactoryProxy())),
"OPCPA-90"
);
require(
admin.getProxyImplementation(address(delayedWETHPermissionedGameProxy()))
== DeployUtils.assertERC1967ImplementationSet(address(delayedWETHPermissionedGameProxy())),
"OPCPA-100"
);
require(
admin.getProxyImplementation(address(anchorStateRegistryProxy()))
== DeployUtils.assertERC1967ImplementationSet(address(anchorStateRegistryProxy())),
"OPCPA-110"
);
}
}

contract DeployOPChain is Script {
Expand Down
97 changes: 94 additions & 3 deletions packages/contracts-bedrock/scripts/libraries/DeployUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import { Artifacts } from "scripts/Artifacts.s.sol";
// Libraries
import { LibString } from "@solady/utils/LibString.sol";
import { Bytes } from "src/libraries/Bytes.sol";
import { Constants } from "src/libraries/Constants.sol";

// Interfaces
import { IProxy } from "src/universal/interfaces/IProxy.sol";
import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol";
import { IL1ChugSplashProxy, IStaticL1ChugSplashProxy } from "src/legacy/interfaces/IL1ChugSplashProxy.sol";
import { IResolvedDelegateProxy } from "src/legacy/interfaces/IResolvedDelegateProxy.sol";

library DeployUtils {
Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
Expand Down Expand Up @@ -217,12 +221,99 @@ library DeployUtils {

/// @notice Asserts that the given proxy has an implementation set.
/// @param _proxy Proxy to check.
function assertImplementationSet(address _proxy) internal {
function assertERC1967ImplementationSet(address _proxy) internal returns (address implementation_) {
// We prank as the zero address due to the Proxy's `proxyCallIfNotAdmin` modifier.
// Pranking inside this function also means it can no longer be considered `view`.
vm.prank(address(0));
address implementation = IProxy(payable(_proxy)).implementation();
assertValidContractAddress(implementation);
implementation_ = IProxy(payable(_proxy)).implementation();
assertValidContractAddress(implementation_);
}

/// @notice Asserts that the given L1ChugSplashProxy has an implementation set.
/// @param _proxy L1ChugSplashProxy to check.
function assertL1ChugSplashImplementationSet(address _proxy) internal returns (address implementation_) {
vm.prank(address(0));
implementation_ = IStaticL1ChugSplashProxy(_proxy).getImplementation();
assertValidContractAddress(implementation_);
}

/// @notice Asserts that the given ResolvedDelegateProxy has an implementation set.
/// @param _implementationName Name of the implementation contract.
/// @param _addressManager AddressManager contract.
function assertResolvedDelegateProxyImplementationSet(
string memory _implementationName,
IAddressManager _addressManager
)
internal
view
returns (address implementation_)
{
implementation_ = _addressManager.getAddress(_implementationName);
assertValidContractAddress(implementation_);
}

/// @notice Builds an ERC1967 Proxy with a dummy implementation.
/// @param _proxyImplName Name of the implementation contract.
function buildERC1967ProxyWithImpl(string memory _proxyImplName) public returns (IProxy genericProxy_) {
genericProxy_ = IProxy(
create1({
_name: "Proxy",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (address(0))))
})
);
address implementation = address(vm.addr(uint256(keccak256(abi.encodePacked(_proxyImplName)))));
vm.etch(address(implementation), hex"01");
vm.prank(address(0));
genericProxy_.upgradeTo(address(implementation));
vm.etch(address(genericProxy_), address(genericProxy_).code);
}

/// @notice Builds an L1ChugSplashProxy with a dummy implementation.
/// @param _proxyImplName Name of the implementation contract.
function buildL1ChugSplashProxyWithImpl(string memory _proxyImplName) public returns (IL1ChugSplashProxy proxy_) {
proxy_ = IL1ChugSplashProxy(
create1({
_name: "L1ChugSplashProxy",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IL1ChugSplashProxy.__constructor__, (address(0))))
})
);
address implementation = address(vm.addr(uint256(keccak256(abi.encodePacked(_proxyImplName)))));
vm.etch(address(implementation), hex"01");
vm.prank(address(0));
proxy_.setStorage(Constants.PROXY_IMPLEMENTATION_ADDRESS, bytes32(uint256(uint160(implementation))));
}

/// @notice Builds a ResolvedDelegateProxy with a dummy implementation.
/// @param _addressManager AddressManager contract.
/// @param _proxyImplName Name of the implementation contract.
function buildResolvedDelegateProxyWithImpl(
IAddressManager _addressManager,
string memory _proxyImplName
)
public
returns (IResolvedDelegateProxy proxy_)
{
proxy_ = IResolvedDelegateProxy(
create1({
_name: "ResolvedDelegateProxy",
_args: DeployUtils.encodeConstructor(
abi.encodeCall(IResolvedDelegateProxy.__constructor__, (_addressManager, _proxyImplName))
)
})
);
address implementation = address(vm.addr(uint256(keccak256(abi.encodePacked(_proxyImplName)))));
vm.etch(address(implementation), hex"01");
_addressManager.setAddress(_proxyImplName, implementation);
}

/// @notice Builds an AddressManager contract.
function buildAddressManager() public returns (IAddressManager addressManager_) {
addressManager_ = IAddressManager(
create1({
_name: "AddressManager",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IAddressManager.__constructor__, ()))
})
);
}

/// @notice Asserts that the given addresses are valid contract addresses.
Expand Down
Loading