Skip to content

Commit

Permalink
Refactor resolving proxy to not accept a proxy upfront
Browse files Browse the repository at this point in the history
  • Loading branch information
mdehoog committed Dec 11, 2024
1 parent a1fdac8 commit 5be4e70
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 116 deletions.
52 changes: 26 additions & 26 deletions bindings/deploy_chain.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion deployments/84532-deploy.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"AnchorStateRegistryProxy": "0x0000000000000000000000000000000000000001",
"CertManager": "0xD42fd50A9A8eE3F127A11AEACD4ADAA67Da7FE3B",
"DelayedWETHProxy": "0x0000000000000000000000000000000000000001",
"DeployChain": "0x8B4dB9468126EA0AA6EC8f1FAEb32173de3A27c7",
"DeployChain": "0x36B138a8cD20b417BFD89Cc0003a55D62B4cFAB5",
"DisputeGameFactoryProxy": "0x0000000000000000000000000000000000000001",
"L1CrossDomainMessenger": "0x50237F4364Dfa91EB16d1DD20ae97b40e430c1fA",
"L1CrossDomainMessengerProxy": "0x05c8428901475fae5341d24DB61529450827E5c6",
Expand Down
116 changes: 70 additions & 46 deletions src/DeployChain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {ResolvingProxyFactory} from "./ResolvingProxyFactory.sol";
import {Portal} from "./Portal.sol";
import {OutputOracle} from "./OutputOracle.sol";
import {SystemConfigOwnable} from "./SystemConfigOwnable.sol";
import {ResolvingProxy} from "./ResolvingProxy.sol";
import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol";
import {ISystemConfig} from "@eth-optimism-bedrock/src/L1/interfaces/ISystemConfig.sol";
import {OptimismPortal} from "@eth-optimism-bedrock/src/L1/OptimismPortal.sol";
Expand All @@ -21,6 +22,10 @@ import {Hashing} from "@eth-optimism-bedrock/src/libraries/Hashing.sol";
import {Types} from "@eth-optimism-bedrock/src/libraries/Types.sol";
import {Constants} from "@eth-optimism-bedrock/src/libraries/Constants.sol";

interface IProxyAdmin {
function getProxyImplementation(address) external view returns (address);
}

contract DeployChain {
struct DeployAddresses {
address l2OutputOracle;
Expand Down Expand Up @@ -100,20 +105,20 @@ contract DeployChain {
}

function deployAddresses(uint256 chainID) external view returns (DeployAddresses memory) {
bytes32 salt = keccak256(abi.encodePacked(chainID));
return DeployAddresses({
l2OutputOracle: proxyAddress(l2OutputOracle, salt),
systemConfig: proxyAddress(systemConfig, salt),
optimismPortal: proxyAddress(optimismPortal, salt),
l1CrossDomainMessenger: proxyAddress(l1CrossDomainMessenger, salt),
l1StandardBridge: proxyAddress(l1StandardBridge, salt),
l1ERC721Bridge: proxyAddress(l1ERC721Bridge, salt),
optimismMintableERC20Factory: proxyAddress(optimismMintableERC20Factory, salt)
l2OutputOracle: proxyAddress(chainID, l2OutputOracle),
systemConfig: proxyAddress(chainID, systemConfig),
optimismPortal: proxyAddress(chainID, optimismPortal),
l1CrossDomainMessenger: proxyAddress(chainID, l1CrossDomainMessenger),
l1StandardBridge: proxyAddress(chainID, l1StandardBridge),
l1ERC721Bridge: proxyAddress(chainID, l1ERC721Bridge),
optimismMintableERC20Factory: proxyAddress(chainID, optimismMintableERC20Factory)
});
}

function proxyAddress(address proxy, bytes32 salt) public view returns (address) {
return ResolvingProxyFactory.proxyAddress(proxy, proxyAdmin, salt);
function proxyAddress(uint256 chainID, address implementation) public view returns (address) {
bytes32 salt = keccak256(abi.encodePacked(chainID, implementation));
return ResolvingProxyFactory.proxyAddress(address(this), salt);
}

function deploy(
Expand Down Expand Up @@ -153,20 +158,20 @@ contract DeployChain {
}

function setupProxies(uint256 chainID) internal returns (DeployAddresses memory) {
bytes32 salt = keccak256(abi.encodePacked(chainID));
return DeployAddresses({
l2OutputOracle: deployProxy(l2OutputOracle, salt),
systemConfig: deployProxy(systemConfig, salt),
optimismPortal: deployProxy(optimismPortal, salt),
l1CrossDomainMessenger: deployProxy(l1CrossDomainMessenger, salt),
l1StandardBridge: deployProxy(l1StandardBridge, salt),
l1ERC721Bridge: deployProxy(l1ERC721Bridge, salt),
optimismMintableERC20Factory: deployProxy(optimismMintableERC20Factory, salt)
l2OutputOracle: deployProxy(chainID, l2OutputOracle),
systemConfig: deployProxy(chainID, systemConfig),
optimismPortal: deployProxy(chainID, optimismPortal),
l1CrossDomainMessenger: deployProxy(chainID, l1CrossDomainMessenger),
l1StandardBridge: deployProxy(chainID, l1StandardBridge),
l1ERC721Bridge: deployProxy(chainID, l1ERC721Bridge),
optimismMintableERC20Factory: deployProxy(chainID, optimismMintableERC20Factory)
});
}

function deployProxy(address proxy, bytes32 salt) public returns (address) {
return ResolvingProxyFactory.setupProxy(proxy, proxyAdmin, salt);
function deployProxy(uint256 chainID, address implementation) public returns (address) {
bytes32 salt = keccak256(abi.encodePacked(chainID, implementation));
return ResolvingProxyFactory.setupProxy(address(this), salt);
}

function calculateHashes(
Expand Down Expand Up @@ -217,47 +222,66 @@ contract DeployChain {
DeployAddresses memory addresses,
bool proofsEnabled
) internal {
OutputOracle(addresses.l2OutputOracle).initialize(
SystemConfigOwnable(addresses.systemConfig), hashes.configHash, hashes.genesisOutputRoot, proofsEnabled
);

Portal(payable(addresses.optimismPortal)).initialize(
_upgradeInitializeAndTransferProxyOwnership(addresses.l2OutputOracle, l2OutputOracle, abi.encodeCall(OutputOracle.initialize, (
SystemConfigOwnable(addresses.systemConfig),
hashes.configHash,
hashes.genesisOutputRoot,
proofsEnabled
)));

_upgradeInitializeAndTransferProxyOwnership(addresses.optimismPortal, optimismPortal, abi.encodeCall(Portal.initialize, (
OutputOracle(addresses.l2OutputOracle),
ISystemConfig(addresses.systemConfig),
ISuperchainConfig(superchainConfig)
);
)));

SystemConfig.Addresses memory systemAddresses = _createSystemAddresses(addresses, gasConfig.gasToken);

SystemConfigOwnable(addresses.systemConfig).initialize({
_basefeeScalar: gasConfig.basefeeScalar,
_blobbasefeeScalar: gasConfig.blobbasefeeScalar,
_batcherHash: bytes32(uint256(uint160(addressConfig.batcher))),
_gasLimit: gasConfig.gasLimit,
_unsafeBlockSigner: addressConfig.unsafeBlockSigner,
_config: Constants.DEFAULT_RESOURCE_CONFIG(),
_batchInbox: batchInbox,
_proposer: addressConfig.proposer,
_addresses: systemAddresses
});

L1CrossDomainMessenger(addresses.l1CrossDomainMessenger).initialize(
_upgradeInitializeAndTransferProxyOwnership(addresses.systemConfig, systemConfig, abi.encodeCall(SystemConfigOwnable.initialize, (
gasConfig.basefeeScalar,
gasConfig.blobbasefeeScalar,
bytes32(uint256(uint160(addressConfig.batcher))),
gasConfig.gasLimit,
addressConfig.unsafeBlockSigner,
Constants.DEFAULT_RESOURCE_CONFIG(),
batchInbox,
addressConfig.proposer,
systemAddresses
)));

_upgradeInitializeAndTransferProxyOwnership(addresses.l1CrossDomainMessenger, l1CrossDomainMessenger, abi.encodeCall(L1CrossDomainMessenger.initialize, (
ISuperchainConfig(superchainConfig),
IOptimismPortal(payable(addresses.optimismPortal)),
ISystemConfig(addresses.systemConfig)
);
)));

L1StandardBridge(payable(addresses.l1StandardBridge)).initialize(
_upgradeInitializeAndTransferProxyOwnership(addresses.l1StandardBridge, l1StandardBridge, abi.encodeCall(L1StandardBridge.initialize, (
ICrossDomainMessenger(addresses.l1CrossDomainMessenger),
ISuperchainConfig(superchainConfig),
ISystemConfig(addresses.systemConfig)
);
)));

L1ERC721Bridge(addresses.l1ERC721Bridge).initialize(
ICrossDomainMessenger(addresses.l1CrossDomainMessenger), ISuperchainConfig(superchainConfig)
);
_upgradeInitializeAndTransferProxyOwnership(addresses.l1ERC721Bridge, l1ERC721Bridge, abi.encodeCall(L1ERC721Bridge.initialize, (
ICrossDomainMessenger(addresses.l1CrossDomainMessenger),
ISuperchainConfig(superchainConfig)
)));

_upgradeInitializeAndTransferProxyOwnership(addresses.optimismMintableERC20Factory, optimismMintableERC20Factory, abi.encodeCall(OptimismMintableERC20Factory.initialize, (
addresses.l1StandardBridge
)));
}

OptimismMintableERC20Factory(addresses.optimismMintableERC20Factory).initialize(addresses.l1StandardBridge);
function _upgradeInitializeAndTransferProxyOwnership(
address _proxy,
address _implementation,
bytes memory _data
) private {
ResolvingProxy proxy = ResolvingProxy(payable(_proxy));
address actual = IProxyAdmin(proxyAdmin).getProxyImplementation(_implementation);
require(actual != address(0), "DeployChain: invalid implementation");
proxy.upgradeToAndCall(actual, _data);
proxy.upgradeTo(_implementation);
proxy.changeAdmin(proxyAdmin);
}

function _createSystemAddresses(DeployAddresses memory addresses, address gasToken)
Expand Down
4 changes: 2 additions & 2 deletions src/ResolvingProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ contract ResolvingProxy {
/// implementation is not possible.
/// @param _admin Address of the initial contract admin. Admin has the ability to access the
/// transparent proxy interface.
constructor(address _implementation, address _admin) {
_setImplementation(_implementation);
constructor(address _admin) {
_setAdmin(_admin);
}

Expand Down Expand Up @@ -145,6 +144,7 @@ contract ResolvingProxy {

function _resolveImplementation() internal view returns (address) {
address proxy = _getImplementation();
require(proxy != address(0));
bytes memory data = abi.encodeCall(IResolver.getProxyImplementation, (proxy));
(bool success, bytes memory returndata) = _getAdmin().staticcall(data);
if (success && returndata.length == 0x20) {
Expand Down
74 changes: 35 additions & 39 deletions src/ResolvingProxyFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,65 +9,61 @@ import {ResolvingProxy} from "./ResolvingProxy.sol";
/// implementation that is more gas efficient to deploy and operate than the solidity
/// ResolvingProxy implementation.
library ResolvingProxyFactory {
function setupProxy(address proxy, address admin, bytes32 salt) internal returns (address instance) {
function setupProxy(address admin, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, shl(0xC0, 0x600661011c565b73))
mstore(add(ptr, 0x8), shl(0x60, proxy))
mstore(add(ptr, 0x1c), shl(0xE8, 0x905573))
mstore(add(ptr, 0x1f), shl(0x60, admin))
mstore(add(ptr, 0x33), 0x905561012280603f5f395ff35f365f600860dd565b8054909180548033143315)
mstore(add(ptr, 0x53), 0x171560545760045f5f375f5160e01c8063f851a4401460a25780635c60da1b14)
mstore(add(ptr, 0x73), 0x609f5780638f2839701460af5780633659cfe61460ac57634f1ef2861460aa57)
mstore(add(ptr, 0x93), 0x5b63204e1c7a60e01b5f52826004525f5f60245f845afa3d5f5f3e3d60201416)
mstore(add(ptr, 0xb3), 0x805f510290158402015f875f89895f375f935af43d5f893d60205260205f523e)
mstore(add(ptr, 0xd3), 0x5f3d890191609d57fd5bf35b50505b505f5260205ff35b5f5b93915b50506020)
mstore(add(ptr, 0xf3), 0x60045f375f518091559160d957903333602060445f375f519560649550506040)
mstore(add(ptr, 0x113), 0x96506054565b5f5ff35b7f360894a13ba1a3210667c828492db98dca3e2076cc)
mstore(add(ptr, 0x133), 0x3735a920a3ca505d382bbc7fb53127684a568b3173ae13b9f8a6016e243e63b6)
mstore(add(ptr, 0x153), shl(0x90, 0xe8ee1178d6a717850b5d61039156))
instance := create2(0, ptr, 0x161, salt)
mstore(ptr, shl(0xC0, 0x600661010e565b73))
mstore(add(ptr, 0x8), shl(0x60, admin))
mstore(add(ptr, 0x1c), 0x90915561012a8060295f395ff35f365f600860e5565b80549091805480331433)
mstore(add(ptr, 0x3c), 0x15171560545760045f5f375f5160e01c8063f851a4401460a75780635c60da1b)
mstore(add(ptr, 0x5c), 0x1460a45780638f2839701460b45780633659cfe61460b157634f1ef2861460af)
mstore(add(ptr, 0x7c), 0x575b63204e1c7a60e01b5f5282801560e2576004525f5f60245f845afa3d5f5f)
mstore(add(ptr, 0x9c), 0x3e3d60201416805f510290158402015f875f89895f375f935af43d5f893d6020)
mstore(add(ptr, 0xbc), 0x5260205f523e5f3d89019160a257fd5bf35b50505b505f5260205ff35b5f5b93)
mstore(add(ptr, 0xdc), 0x915b5050602060045f375f518091559160de57903333602060445f375f519560)
mstore(add(ptr, 0xfc), 0x64955050604096506054565b5f5ff35b5ffd5b7f360894a13ba1a3210667c828)
mstore(add(ptr, 0x11c), 0x492db98dca3e2076cc3735a920a3ca505d382bbc7fb53127684a568b3173ae13)
mstore(add(ptr, 0x13c), shl(0x48, 0xb9f8a6016e243e63b6e8ee1178d6a717850b5d61039156))
instance := create2(0, ptr, 0x153, salt)
}
require(instance != address(0), "Proxy: create2 failed");
}

function proxyAddress(address proxy, address admin, bytes32 salt) internal view returns (address predicted) {
function proxyAddress(address admin, bytes32 salt) internal view returns (address predicted) {
address deployer = address(this);
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, shl(0xC0, 0x600661011c565b73))
mstore(add(ptr, 0x8), shl(0x60, proxy))
mstore(add(ptr, 0x1c), shl(0xE8, 0x905573))
mstore(add(ptr, 0x1f), shl(0x60, admin))
mstore(add(ptr, 0x33), 0x905561012280603f5f395ff35f365f600860dd565b8054909180548033143315)
mstore(add(ptr, 0x53), 0x171560545760045f5f375f5160e01c8063f851a4401460a25780635c60da1b14)
mstore(add(ptr, 0x73), 0x609f5780638f2839701460af5780633659cfe61460ac57634f1ef2861460aa57)
mstore(add(ptr, 0x93), 0x5b63204e1c7a60e01b5f52826004525f5f60245f845afa3d5f5f3e3d60201416)
mstore(add(ptr, 0xb3), 0x805f510290158402015f875f89895f375f935af43d5f893d60205260205f523e)
mstore(add(ptr, 0xd3), 0x5f3d890191609d57fd5bf35b50505b505f5260205ff35b5f5b93915b50506020)
mstore(add(ptr, 0xf3), 0x60045f375f518091559160d957903333602060445f375f519560649550506040)
mstore(add(ptr, 0x113), 0x96506054565b5f5ff35b7f360894a13ba1a3210667c828492db98dca3e2076cc)
mstore(add(ptr, 0x133), 0x3735a920a3ca505d382bbc7fb53127684a568b3173ae13b9f8a6016e243e63b6)
mstore(add(ptr, 0x153), shl(0x88, 0xe8ee1178d6a717850b5d61039156ff))
mstore(add(ptr, 0x162), shl(0x60, deployer))
mstore(add(ptr, 0x176), salt)
mstore(add(ptr, 0x196), keccak256(ptr, 0x161))
predicted := keccak256(add(ptr, 0x161), 0x55)
mstore(ptr, shl(0xC0, 0x600661010e565b73))
mstore(add(ptr, 0x8), shl(0x60, admin))
mstore(add(ptr, 0x1c), 0x90915561012a8060295f395ff35f365f600860e5565b80549091805480331433)
mstore(add(ptr, 0x3c), 0x15171560545760045f5f375f5160e01c8063f851a4401460a75780635c60da1b)
mstore(add(ptr, 0x5c), 0x1460a45780638f2839701460b45780633659cfe61460b157634f1ef2861460af)
mstore(add(ptr, 0x7c), 0x575b63204e1c7a60e01b5f5282801560e2576004525f5f60245f845afa3d5f5f)
mstore(add(ptr, 0x9c), 0x3e3d60201416805f510290158402015f875f89895f375f935af43d5f893d6020)
mstore(add(ptr, 0xbc), 0x5260205f523e5f3d89019160a257fd5bf35b50505b505f5260205ff35b5f5b93)
mstore(add(ptr, 0xdc), 0x915b5050602060045f375f518091559160de57903333602060445f375f519560)
mstore(add(ptr, 0xfc), 0x64955050604096506054565b5f5ff35b5ffd5b7f360894a13ba1a3210667c828)
mstore(add(ptr, 0x11c), 0x492db98dca3e2076cc3735a920a3ca505d382bbc7fb53127684a568b3173ae13)
mstore(add(ptr, 0x13c), shl(0x40, 0xb9f8a6016e243e63b6e8ee1178d6a717850b5d61039156ff))
mstore(add(ptr, 0x154), shl(0x60, deployer))
mstore(add(ptr, 0x168), salt)
mstore(add(ptr, 0x188), keccak256(ptr, 0x153))
predicted := keccak256(add(ptr, 0x153), 0x55)
}
}

function setupExpensiveProxy(address proxy, address admin, bytes32 salt) internal returns (address instance) {
return address(new ResolvingProxy{salt: salt}(proxy, admin));
function setupExpensiveProxy(address admin, bytes32 salt) internal returns (address instance) {
return address(new ResolvingProxy{salt: salt}(admin));
}

function expensiveProxyAddress(address proxy, address admin, bytes32 salt)
function expensiveProxyAddress(address admin, bytes32 salt)
internal
view
returns (address predicted)
{
bytes memory bytecode = abi.encodePacked(type(ResolvingProxy).creationCode, abi.encode(proxy, admin));
bytes memory bytecode = abi.encodePacked(type(ResolvingProxy).creationCode, abi.encode(admin));
bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(bytecode)));
return address(uint160(uint256(hash)));
}
Expand Down
5 changes: 3 additions & 2 deletions test/ResolvingProxyFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ contract ResolvingProxyFactoryTest is Test {
admin = new ProxyAdmin(address(this));
proxy = new Proxy(address(admin));
admin.upgrade(payable(address(proxy)), address(implementation1));
resolvingProxy = ResolvingProxyFactory.setupProxy(address(proxy), address(admin), 0x00);
resolvingProxy = ResolvingProxyFactory.setupProxy(address(admin), 0x00);
admin.upgrade(payable(address(resolvingProxy)), address(proxy));
Implementation1(resolvingProxy).set("world");
}

Expand Down Expand Up @@ -86,7 +87,7 @@ contract ResolvingProxyFactoryTest is Test {
}

function test_proxyAddress() public view {
address predicted = ResolvingProxyFactory.proxyAddress(address(proxy), address(admin), 0x00);
address predicted = ResolvingProxyFactory.proxyAddress(address(admin), 0x00);
assertEq(predicted, resolvingProxy);
}
}

0 comments on commit 5be4e70

Please sign in to comment.