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

Refactor resolving proxy to not accept a proxy upfront #34

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
52 changes: 26 additions & 26 deletions bindings/deploy_chain.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/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 contracts/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 contracts/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 contracts/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 contracts/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);
}
}
Loading