Skip to content

Commit

Permalink
OPCM: AddressManager and ProxyAdmin assertions. (#12370)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
blmalone authored Oct 8, 2024
1 parent 87d0152 commit a05feb3
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 71 deletions.
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

0 comments on commit a05feb3

Please sign in to comment.