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

Add UpgradeExecutor to token bridge creation flow #38

Merged
merged 15 commits into from
Sep 7, 2023
Merged
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
17 changes: 13 additions & 4 deletions .env-sample
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
## Goerli - Deploy L1TokenBridgeCreator
ARB_GOERLI_RPC=""
ARB_GOERLI_DEPLOYER_KEY=""
ORBIT_RPC=""
.env-sample

## Rollup on top of which token bridge will be created
ROLLUP_ADDRESS=""
ROLLUP_OWNER=""
L1_TOKEN_BRIDGE_CREATOR=""

## RPC endpoints
BASECHAIN_RPC=""
ORBIT_RPC=""

## Deployer key used for deploying creator and creating token bridge
BASECHAIN_DEPLOYER_KEY=""
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.gitignore
.env
node_modules
.vscode/

#Hardhat files
cache
Expand Down
120 changes: 84 additions & 36 deletions contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {L2ERC20Gateway} from "./gateway/L2ERC20Gateway.sol";
import {L2CustomGateway} from "./gateway/L2CustomGateway.sol";
import {L2WethGateway} from "./gateway/L2WethGateway.sol";
import {StandardArbERC20} from "./StandardArbERC20.sol";
import {IUpgradeExecutor} from "@offchainlabs/upgrade-executor/src/IUpgradeExecutor.sol";
import {BeaconProxyFactory} from "../libraries/ClonableBeaconProxy.sol";
import {aeWETH} from "../libraries/aeWETH.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
Expand All @@ -32,24 +33,32 @@ contract L2AtomicTokenBridgeFactory {
address l1WethGateway,
address l1Weth,
address l2StandardGatewayCanonicalAddress,
address rollupOwner
address rollupOwner,
yahgwai marked this conversation as resolved.
Show resolved Hide resolved
address aliasedL1UpgradeExecutor
) external {
// create proxyAdmin which will be used for all contracts. Revert if canonical deployment already exists
address proxyAdminAddress = Create2.computeAddress(
_getL2Salt(OrbitSalts.L2_PROXY_ADMIN),
keccak256(type(ProxyAdmin).creationCode),
address(this)
);
if (proxyAdminAddress.code.length > 0) {
revert L2AtomicTokenBridgeFactory_AlreadyExists();
// Create proxyAdmin which will be used for all contracts. Revert if canonical deployment already exists
{
address proxyAdminAddress = Create2.computeAddress(
_getL2Salt(OrbitSalts.L2_PROXY_ADMIN),
keccak256(type(ProxyAdmin).creationCode),
address(this)
);
if (proxyAdminAddress.code.length > 0) {
revert L2AtomicTokenBridgeFactory_AlreadyExists();
}
}
address proxyAdmin =
address(new ProxyAdmin{ salt: _getL2Salt(OrbitSalts.L2_PROXY_ADMIN) }());

// deploy router/gateways
// deploy router/gateways/executor
address upgradeExecutor = _deployUpgradeExecutor(
l2Code.upgradeExecutor, rollupOwner, proxyAdmin, aliasedL1UpgradeExecutor
);
address router =
_deployRouter(l2Code.router, l1Router, l2StandardGatewayCanonicalAddress, proxyAdmin);
_deployStandardGateway(l2Code.standardGateway, l1StandardGateway, router, proxyAdmin);
_deployStandardGateway(
l2Code.standardGateway, l1StandardGateway, router, proxyAdmin, upgradeExecutor
);
_deployCustomGateway(l2Code.customGateway, l1CustomGateway, router, proxyAdmin);

// fee token based creator will provide address(0) as WETH is not used in ERC20-based chains
Expand All @@ -59,8 +68,39 @@ contract L2AtomicTokenBridgeFactory {
);
}

// transfer ownership to rollup's owner
ProxyAdmin(proxyAdmin).transferOwnership(rollupOwner);
// deploy multicall
Create2.deploy(0, _getL2Salt(OrbitSalts.L2_MULTICALL), _creationCodeFor(l2Code.multicall));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use a proxy in case the multicall implementation changes? Or has it been stable for a long time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm good q, not sure if it is worth it. Arb multicall hasn't been changed last 2 year as far as I can see. @gzeoneth what do you think?


// transfer ownership to L2 upgradeExecutor
ProxyAdmin(proxyAdmin).transferOwnership(upgradeExecutor);
}

function _deployUpgradeExecutor(
bytes calldata runtimeCode,
address rollupOwner,
address proxyAdmin,
address aliasedL1UpgradeExecutor
) internal returns (address) {
// canonical L2 upgrade executor with dummy logic
address canonicalUpgradeExecutor = _deploySeedProxy(
proxyAdmin, _getL2Salt(OrbitSalts.L2_EXECUTOR), _getL2Salt(OrbitSalts.L2_EXECUTOR_LOGIC)
);

// create UpgradeExecutor logic and upgrade to it
address upExecutorLogic = Create2.deploy(
0, _getL2Salt(OrbitSalts.L2_EXECUTOR_LOGIC), _creationCodeFor(runtimeCode)
);
ProxyAdmin(proxyAdmin).upgrade(
ITransparentUpgradeableProxy(canonicalUpgradeExecutor), upExecutorLogic
);

// init upgrade executor
address[] memory executors = new address[](2);
executors[0] = rollupOwner;
executors[1] = aliasedL1UpgradeExecutor;
IUpgradeExecutor(canonicalUpgradeExecutor).initialize(canonicalUpgradeExecutor, executors);

return canonicalUpgradeExecutor;
}

function _deployRouter(
Expand Down Expand Up @@ -89,7 +129,8 @@ contract L2AtomicTokenBridgeFactory {
bytes calldata runtimeCode,
address l1StandardGateway,
address router,
address proxyAdmin
address proxyAdmin,
address upgradeExecutor
) internal {
// canonical L2 standard gateway with dummy logic
address canonicalStdGateway = _deploySeedProxy(
Expand Down Expand Up @@ -122,6 +163,9 @@ contract L2AtomicTokenBridgeFactory {
L2ERC20Gateway(canonicalStdGateway).initialize(
l1StandardGateway, router, address(beaconProxyFactory)
);

// make L2 executor the beacon owner
beacon.transferOwnership(upgradeExecutor);
}

function _deployCustomGateway(
Expand Down Expand Up @@ -201,7 +245,7 @@ contract L2AtomicTokenBridgeFactory {
* permissionless. By making msg.sender part of the salt we know exactly which set of contracts is the "canonical" one,
* deployed by L1TokenBridgeRetryableSender via retryable ticket.
*/
function _getL2Salt(bytes32 prefix) internal view returns (bytes32) {
function _getL2Salt(bytes memory prefix) internal view returns (bytes32) {
return keccak256(abi.encodePacked(prefix, msg.sender));
}

Expand Down Expand Up @@ -257,31 +301,35 @@ struct L2RuntimeCode {
bytes customGateway;
bytes wethGateway;
bytes aeWeth;
bytes upgradeExecutor;
bytes multicall;
}

/**
* Collection of salts used in CREATE2 deployment of L2 token bridge contracts.
*/
library OrbitSalts {
bytes32 public constant L1_PROXY_ADMIN = keccak256(bytes("OrbitL1ProxyAdmin"));
bytes32 public constant L1_ROUTER = keccak256(bytes("OrbitL1GatewayRouterProxy"));
bytes32 public constant L1_STANDARD_GATEWAY = keccak256(bytes("OrbitL1StandardGatewayProxy"));
bytes32 public constant L1_CUSTOM_GATEWAY = keccak256(bytes("OrbitL1CustomGatewayProxy"));
bytes32 public constant L1_WETH_GATEWAY = keccak256(bytes("OrbitL1WethGatewayProxy"));

bytes32 public constant L2_PROXY_ADMIN = keccak256(bytes("OrbitL2ProxyAdmin"));
bytes32 public constant L2_ROUTER_LOGIC = keccak256(bytes("OrbitL2GatewayRouterLogic"));
bytes32 public constant L2_ROUTER = keccak256(bytes("OrbitL2GatewayRouterProxy"));
bytes32 public constant L2_STANDARD_GATEWAY_LOGIC =
keccak256(bytes("OrbitL2StandardGatewayLogic"));
bytes32 public constant L2_STANDARD_GATEWAY = keccak256(bytes("OrbitL2StandardGatewayProxy"));
bytes32 public constant L2_CUSTOM_GATEWAY_LOGIC = keccak256(bytes("OrbitL2CustomGatewayLogic"));
bytes32 public constant L2_CUSTOM_GATEWAY = keccak256(bytes("OrbitL2CustomGatewayProxy"));
bytes32 public constant L2_WETH_GATEWAY_LOGIC = keccak256(bytes("OrbitL2WethGatewayLogic"));
bytes32 public constant L2_WETH_GATEWAY = keccak256(bytes("OrbitL2WethGatewayProxy"));
bytes32 public constant L2_WETH_LOGIC = keccak256(bytes("OrbitL2WETH"));
bytes32 public constant L2_WETH = keccak256(bytes("OrbitL2WETHProxy"));
bytes32 public constant L2_STANDARD_ERC20 = keccak256(bytes("OrbitStandardArbERC20"));
bytes32 public constant UPGRADEABLE_BEACON = keccak256(bytes("OrbitUpgradeableBeacon"));
bytes32 public constant BEACON_PROXY_FACTORY = keccak256(bytes("OrbitBeaconProxyFactory"));
bytes public constant L1_PROXY_ADMIN = bytes("OrbitL1ProxyAdmin");
bytes public constant L1_ROUTER = bytes("OrbitL1GatewayRouterProxy");
bytes public constant L1_STANDARD_GATEWAY = bytes("OrbitL1StandardGatewayProxy");
bytes public constant L1_CUSTOM_GATEWAY = bytes("OrbitL1CustomGatewayProxy");
bytes public constant L1_WETH_GATEWAY = bytes("OrbitL1WethGatewayProxy");

bytes public constant L2_PROXY_ADMIN = bytes("OrbitL2ProxyAdmin");
bytes public constant L2_ROUTER_LOGIC = bytes("OrbitL2GatewayRouterLogic");
bytes public constant L2_ROUTER = bytes("OrbitL2GatewayRouterProxy");
bytes public constant L2_STANDARD_GATEWAY_LOGIC = bytes("OrbitL2StandardGatewayLogic");
bytes public constant L2_STANDARD_GATEWAY = bytes("OrbitL2StandardGatewayProxy");
bytes public constant L2_CUSTOM_GATEWAY_LOGIC = bytes("OrbitL2CustomGatewayLogic");
bytes public constant L2_CUSTOM_GATEWAY = bytes("OrbitL2CustomGatewayProxy");
bytes public constant L2_WETH_GATEWAY_LOGIC = bytes("OrbitL2WethGatewayLogic");
bytes public constant L2_WETH_GATEWAY = bytes("OrbitL2WethGatewayProxy");
bytes public constant L2_WETH_LOGIC = bytes("OrbitL2WETH");
bytes public constant L2_WETH = bytes("OrbitL2WETHProxy");
bytes public constant L2_STANDARD_ERC20 = bytes("OrbitStandardArbERC20");
bytes public constant UPGRADEABLE_BEACON = bytes("OrbitUpgradeableBeacon");
bytes public constant BEACON_PROXY_FACTORY = bytes("OrbitBeaconProxyFactory");
bytes public constant L2_EXECUTOR_LOGIC = bytes("OrbitL2UpgradeExecutorLogic");
bytes public constant L2_EXECUTOR = bytes("OrbitL2UpgradeExecutorProxy");
bytes public constant L2_MULTICALL = bytes("OrbitL2Multicall");
}
Loading