Commit a05feb36 authored by Blaine Malone's avatar Blaine Malone Committed by GitHub

OPCM: AddressManager and ProxyAdmin assertions. (#12370)

* OPCM: AddressManager and ProxyAdmin assertions.

* fix: Added logic for proxy types to check implementations.

* fix: touch ups for RDP impl checking.

* fix: fully fledged proxies added to tests because of new assertions.

* fix: removing console2 lib.

* fix: semgrep complaining.

* fix: comment cleanup and logical split to avoid stack too deep error.

* fix: adding comment back in.

* fix: added natspec comments for new DeployUtils functions.

* fix: removed unused imports.
parent 87d0152b
......@@ -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;
}
......
......@@ -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;
}
......@@ -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;
}
......@@ -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;
}
......@@ -366,6 +375,8 @@ contract DeployOPChainOutput is BaseDeployIO {
assertValidOptimismPortal(_doi);
assertValidPermissionedDisputeGame(_doi);
assertValidSystemConfig(_doi);
assertValidAddressManager(_doi);
assertValidOPChainProxyAdmin(_doi);
}
function assertValidPermissionedDisputeGame(DeployOPChainInput _doi) internal {
......@@ -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 });
......@@ -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 });
......@@ -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 });
......@@ -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 {
......
......@@ -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")))));
......@@ -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.
......
......@@ -16,21 +16,15 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
import { IProxyAdmin } from "src/universal/interfaces/IProxyAdmin.sol";
import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol";
import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol";
import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
import { IPermissionedDisputeGame } from "src/dispute/interfaces/IPermissionedDisputeGame.sol";
import { IL1ChugSplashProxy } from "src/legacy/interfaces/IL1ChugSplashProxy.sol";
import { IResolvedDelegateProxy } from "src/legacy/interfaces/IResolvedDelegateProxy.sol";
import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";
import { IProtocolVersions, ProtocolVersion } from "src/L1/interfaces/IProtocolVersions.sol";
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
import { IOptimismPortal2 } from "src/L1/interfaces/IOptimismPortal2.sol";
import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol";
import { IL1CrossDomainMessenger } from "src/L1/interfaces/IL1CrossDomainMessenger.sol";
import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol";
import { IL1StandardBridge } from "src/L1/interfaces/IL1StandardBridge.sol";
import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol";
import { IProxy } from "src/universal/interfaces/IProxy.sol";
import { Claim, Duration, GameType, GameTypes, Hash, OutputRoot } from "src/dispute/lib/Types.sol";
......@@ -55,20 +49,6 @@ contract DeployOPChainInput_Test is Test {
doi = new DeployOPChainInput();
}
function buildOpcmProxy() public returns (IProxy opcmProxy) {
opcmProxy = IProxy(
DeployUtils.create1({
_name: "Proxy",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (address(0))))
})
);
OPContractsManager opcmImpl = OPContractsManager(address(makeAddr("opcmImpl")));
vm.prank(address(0));
opcmProxy.upgradeTo(address(opcmImpl));
vm.etch(address(opcmProxy), address(opcmProxy).code);
vm.etch(address(opcmImpl), hex"01");
}
function test_set_succeeds() public {
doi.set(doi.opChainProxyAdminOwner.selector, opChainProxyAdminOwner);
doi.set(doi.systemConfigOwner.selector, systemConfigOwner);
......@@ -80,7 +60,7 @@ contract DeployOPChainInput_Test is Test {
doi.set(doi.blobBaseFeeScalar.selector, blobBaseFeeScalar);
doi.set(doi.l2ChainId.selector, l2ChainId);
(IProxy opcmProxy) = buildOpcmProxy();
(IProxy opcmProxy) = DeployUtils.buildERC1967ProxyWithImpl("opcmProxy");
doi.set(doi.opcmProxy.selector, address(opcmProxy));
// Compare the default inputs to the getter methods.
......@@ -131,27 +111,13 @@ contract DeployOPChainInput_Test is Test {
contract DeployOPChainOutput_Test is Test {
DeployOPChainOutput doo;
// Define default outputs to set.
// We set these in storage because doing it locally in test_set_succeeds results in stack too deep.
IProxyAdmin opChainProxyAdmin = IProxyAdmin(makeAddr("optimismPortal2Impl"));
IAddressManager addressManager = IAddressManager(makeAddr("delayedWETHImpl"));
IL1ERC721Bridge l1ERC721BridgeProxy = IL1ERC721Bridge(makeAddr("l1ERC721BridgeProxy"));
ISystemConfig systemConfigProxy = ISystemConfig(makeAddr("systemConfigProxy"));
IOptimismMintableERC20Factory optimismMintableERC20FactoryProxy =
IOptimismMintableERC20Factory(makeAddr("optimismMintableERC20FactoryProxy"));
IL1StandardBridge l1StandardBridgeProxy = IL1StandardBridge(payable(makeAddr("l1StandardBridgeProxy")));
IL1CrossDomainMessenger l1CrossDomainMessengerProxy =
IL1CrossDomainMessenger(makeAddr("l1CrossDomainMessengerProxy"));
IOptimismPortal2 optimismPortalProxy = IOptimismPortal2(payable(makeAddr("optimismPortalProxy")));
IDisputeGameFactory disputeGameFactoryProxy = IDisputeGameFactory(makeAddr("disputeGameFactoryProxy"));
IAnchorStateRegistry anchorStateRegistryProxy = IAnchorStateRegistry(makeAddr("anchorStateRegistryProxy"));
// We set the non proxy contracts in storage because doing it locally in 'test_set_succeeds' function results in
// stack too deep.
IAddressManager addressManager = DeployUtils.buildAddressManager();
IProxyAdmin opChainProxyAdmin = IProxyAdmin(makeAddr("opChainProxyAdmin"));
IAnchorStateRegistry anchorStateRegistryImpl = IAnchorStateRegistry(makeAddr("anchorStateRegistryImpl"));
IFaultDisputeGame faultDisputeGame = IFaultDisputeGame(makeAddr("faultDisputeGame"));
IPermissionedDisputeGame permissionedDisputeGame = IPermissionedDisputeGame(makeAddr("permissionedDisputeGame"));
IDelayedWETH delayedWETHPermissionedGameProxy = IDelayedWETH(payable(makeAddr("delayedWETHPermissionedGameProxy")));
// TODO: Eventually switch from Permissioned to Permissionless.
// DelayedWETH delayedWETHPermissionlessGameProxy =
// DelayedWETH(payable(makeAddr("delayedWETHPermissionlessGameProxy")));
function setUp() public {
doo = new DeployOPChainOutput();
......@@ -159,21 +125,24 @@ contract DeployOPChainOutput_Test is Test {
function test_set_succeeds() public {
vm.etch(address(opChainProxyAdmin), hex"01");
vm.etch(address(addressManager), hex"01");
vm.etch(address(l1ERC721BridgeProxy), hex"01");
vm.etch(address(systemConfigProxy), hex"01");
vm.etch(address(optimismMintableERC20FactoryProxy), hex"01");
vm.etch(address(l1StandardBridgeProxy), hex"01");
vm.etch(address(l1CrossDomainMessengerProxy), hex"01");
vm.etch(address(optimismPortalProxy), hex"01");
vm.etch(address(disputeGameFactoryProxy), hex"01");
vm.etch(address(anchorStateRegistryProxy), hex"01");
(IProxy l1ERC721BridgeProxy) = DeployUtils.buildERC1967ProxyWithImpl("l1ERC721BridgeProxy");
(IProxy systemConfigProxy) = DeployUtils.buildERC1967ProxyWithImpl("systemConfigProxy");
(IProxy optimismMintableERC20FactoryProxy) =
DeployUtils.buildERC1967ProxyWithImpl("optimismMintableERC20FactoryProxy");
(IL1ChugSplashProxy l1StandardBridgeProxy) = DeployUtils.buildL1ChugSplashProxyWithImpl("l1StandardBridgeProxy");
(IResolvedDelegateProxy l1CrossDomainMessengerProxy) =
DeployUtils.buildResolvedDelegateProxyWithImpl(addressManager, "OVM_L1CrossDomainMessenger");
(IProxy optimismPortalProxy) = DeployUtils.buildERC1967ProxyWithImpl("optimismPortalProxy");
(IProxy disputeGameFactoryProxy) = DeployUtils.buildERC1967ProxyWithImpl("disputeGameFactoryProxy");
(IProxy anchorStateRegistryProxy) = DeployUtils.buildERC1967ProxyWithImpl("anchorStateRegistryProxy");
vm.etch(address(anchorStateRegistryImpl), hex"01");
vm.etch(address(faultDisputeGame), hex"01");
vm.etch(address(permissionedDisputeGame), hex"01");
vm.etch(address(delayedWETHPermissionedGameProxy), hex"01");
// TODO: Eventually switch from Permissioned to Permissionless.
// vm.etch(address(delayedWETHPermissionlessGameProxy), hex"01");
// (IProxy delayedWETHPermissionlessGameProxy) =
// DeployUtils.buildERC1967ProxyWithImpl("delayedWETHPermissionlessGameProxy");
(IProxy delayedWETHPermissionedGameProxy) =
DeployUtils.buildERC1967ProxyWithImpl("delayedWETHPermissionedGameProxy");
doo.set(doo.opChainProxyAdmin.selector, address(opChainProxyAdmin));
doo.set(doo.addressManager.selector, address(addressManager));
......@@ -558,9 +527,9 @@ contract DeployOPChain_Test is DeployOPChain_TestBase {
assertEq(doo.permissionedDisputeGame().splitDepth(), 30, "3400");
assertEq(doo.permissionedDisputeGame().maxGameDepth(), 73, "3500");
// Most architecture assertions are handled within the OP Contracts Manager itself and therefore
// we only assert on the things that are not visible onchain.
// TODO add these assertions: AddressManager, Proxy, ProxyAdmin, etc.
assertEq(address(doo.opChainProxyAdmin().addressManager().owner()), address(doo.opChainProxyAdmin()), "3600");
assertEq(address(doo.opChainProxyAdmin().addressManager()), address(doo.addressManager()), "3700");
assertEq(address(doo.opChainProxyAdmin().owner()), opChainProxyAdminOwner, "3800");
}
}
......
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