Skip to content
Merged
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
72 changes: 38 additions & 34 deletions contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@
MasterVaultFactory masterVaultFactory;
}

struct CreateTokenBridgeArgs {
address inbox;
address rollupOwner;
uint256 maxGasForContracts;
uint256 gasPriceBid;
bool isYieldBearingBridge;
}

// use separate mapping to allow appending to the struct in the future
// and workaround some stack too deep issues
mapping(address => L1DeploymentAddresses) public inboxToL1Deployment;
Expand Down Expand Up @@ -193,11 +201,7 @@
* fully deployed and initialized before sending tokens to the bridge. Otherwise tokens might be permanently lost.
*/
function createTokenBridge(
address inbox,
address rollupOwner,
uint256 maxGasForContracts,
uint256 gasPriceBid,
bool isYieldBearingBridge
CreateTokenBridgeArgs calldata args
) external payable {
// templates have to be in place
if (address(l1Templates.routerTemplate) == address(0)) {
Expand All @@ -206,10 +210,10 @@

// Check that the rollupOwner account has EXECUTOR role
// on the upgrade executor which is the owner of the rollup
address upgradeExecutor = IInbox(inbox).bridge().rollup().owner();
address upgradeExecutor = IInbox(args.inbox).bridge().rollup().owner();
if (
!IAccessControlUpgradeable(upgradeExecutor).hasRole(
UpgradeExecutor(upgradeExecutor).EXECUTOR_ROLE(), rollupOwner
UpgradeExecutor(upgradeExecutor).EXECUTOR_ROLE(), args.rollupOwner
)
) {
revert L1AtomicTokenBridgeCreator_RollupOwnershipMisconfig();
Expand All @@ -219,22 +223,22 @@
// this is useful to recover from expired or out-of-order retryables
// in case of resend, we assume L1 contracts already exist and we just need to deploy L2 contracts
// deployment mappings should not be updated in case of resend
bool isResend = (inboxToL1Deployment[inbox].router != address(0));
bool isResend = (inboxToL1Deployment[args.inbox].router != address(0));

address feeToken = _getFeeToken(inbox);
address feeToken = _getFeeToken(args.inbox);

// store L2 addresses before deployments
L1DeploymentAddresses memory l1Deployment;
L2DeploymentAddresses memory l2Deployment;

// if resend, we use the existing l1 deployment
if (isResend) {
l1Deployment = inboxToL1Deployment[inbox];
l1Deployment = inboxToL1Deployment[args.inbox];
}

{
// store L2 addresses which are proxies
uint256 chainId = IRollupCore(address(IInbox(inbox).bridge().rollup())).chainId();
uint256 chainId = IRollupCore(address(IInbox(args.inbox).bridge().rollup())).chainId();
l2Deployment.router = _getProxyAddress(OrbitSalts.L2_ROUTER, chainId);
l2Deployment.standardGateway = _getProxyAddress(OrbitSalts.L2_STANDARD_GATEWAY, chainId);
l2Deployment.customGateway = _getProxyAddress(OrbitSalts.L2_CUSTOM_GATEWAY, chainId);
Expand All @@ -252,17 +256,17 @@

// deploy L1 side of token bridge
// get existing proxy admin and upgrade executor
address proxyAdmin = IInboxProxyAdmin(inbox).getProxyAdmin();
address proxyAdmin = IInboxProxyAdmin(args.inbox).getProxyAdmin();
if (proxyAdmin == address(0)) {
revert L1AtomicTokenBridgeCreator_ProxyAdminNotFound();
}

// if resend, we assume L1 contracts already exist
if (!isResend) {
if (isYieldBearingBridge) {
if (args.isYieldBearingBridge) {
// deploy master vault factory
l1Deployment.masterVaultFactory = _deployProxyWithSalt(
_getL1Salt(OrbitSalts.MASTER_VAULT_FACTORY, inbox),
_getL1Salt(OrbitSalts.MASTER_VAULT_FACTORY, args.inbox),
address(l1Templates.masterVaultFactory),
proxyAdmin
);
Expand All @@ -274,7 +278,7 @@
? address(l1Templates.feeTokenBasedRouterTemplate)
: address(l1Templates.routerTemplate);
l1Deployment.router = _deployProxyWithSalt(
_getL1Salt(OrbitSalts.L1_ROUTER, inbox), routerTemplate, proxyAdmin
_getL1Salt(OrbitSalts.L1_ROUTER, args.inbox), routerTemplate, proxyAdmin
);
}

Expand All @@ -286,14 +290,14 @@

L1ERC20Gateway standardGateway = L1ERC20Gateway(
_deployProxyWithSalt(
_getL1Salt(OrbitSalts.L1_STANDARD_GATEWAY, inbox), template, proxyAdmin
_getL1Salt(OrbitSalts.L1_STANDARD_GATEWAY, args.inbox), template, proxyAdmin
)
);

standardGateway.initialize(
l2Deployment.standardGateway,
l1Deployment.router,
inbox,
args.inbox,
keccak256(type(ClonableBeaconProxy).creationCode),
l2Deployment.beaconProxyFactory,
l1Deployment.masterVaultFactory
Expand All @@ -310,12 +314,12 @@

L1CustomGateway customGateway = L1CustomGateway(
_deployProxyWithSalt(
_getL1Salt(OrbitSalts.L1_CUSTOM_GATEWAY, inbox), template, proxyAdmin
_getL1Salt(OrbitSalts.L1_CUSTOM_GATEWAY, args.inbox), template, proxyAdmin
)
);

customGateway.initialize(
l2Deployment.customGateway, l1Deployment.router, inbox, upgradeExecutor, l1Deployment.masterVaultFactory
l2Deployment.customGateway, l1Deployment.router, args.inbox, upgradeExecutor, l1Deployment.masterVaultFactory
);

l1Deployment.customGateway = address(customGateway);
Expand All @@ -326,15 +330,15 @@
L1WethGateway wethGateway = L1WethGateway(
payable(
_deployProxyWithSalt(
_getL1Salt(OrbitSalts.L1_WETH_GATEWAY, inbox),
_getL1Salt(OrbitSalts.L1_WETH_GATEWAY, args.inbox),
address(l1Templates.wethGatewayTemplate),
proxyAdmin
)
)
);

wethGateway.initialize(
l2Deployment.wethGateway, l1Deployment.router, inbox, l1Weth, l2Deployment.weth
l2Deployment.wethGateway, l1Deployment.router, args.inbox, l1Weth, l2Deployment.weth
);

l1Deployment.wethGateway = address(wethGateway);
Expand All @@ -347,30 +351,30 @@
l1Deployment.standardGateway,
address(0),
l2Deployment.router,
inbox
args.inbox
);
}

// deploy factory and then L2 contracts through L2 factory, using 2 retryables calls
// we do not care if it is a resend or not, if the L2 deployment already exists it will simply fail on L2
_deployL2Factory(inbox, gasPriceBid, feeToken);
_deployL2Factory(args.inbox, args.gasPriceBid, feeToken);

RetryableParams memory retryableParams = RetryableParams(
inbox,
args.inbox,
canonicalL2FactoryAddress,
msg.sender,
msg.sender,
maxGasForContracts,
gasPriceBid,
args.maxGasForContracts,
args.gasPriceBid,
0
);

if (feeToken != address(0)) {
// transfer fee tokens to inbox to pay for 2nd retryable
retryableParams.feeTokenTotalFeeAmount =
_getScaledAmount(feeToken, maxGasForContracts * gasPriceBid);
_getScaledAmount(feeToken, args.maxGasForContracts * args.gasPriceBid);
IERC20(feeToken).safeTransferFrom(
msg.sender, inbox, retryableParams.feeTokenTotalFeeAmount
msg.sender, args.inbox, retryableParams.feeTokenTotalFeeAmount
);
}

Expand All @@ -385,9 +389,9 @@
);

// alias rollup owner if it is a contract
address l2RollupOwner = rollupOwner.code.length == 0
? rollupOwner
: AddressAliasHelper.applyL1ToL2Alias(rollupOwner);
address l2RollupOwner = args.rollupOwner.code.length == 0
? args.rollupOwner
: AddressAliasHelper.applyL1ToL2Alias(args.rollupOwner);

// sweep the balance to send the retryable and refund the difference
// it is known that any eth previously in this contract can be extracted
Expand All @@ -404,10 +408,10 @@
// deployment mappings should not be updated in case of resend
if (!isResend) {
emit OrbitTokenBridgeCreated(
inbox, rollupOwner, l1Deployment, l2Deployment, proxyAdmin, upgradeExecutor
args.inbox, args.rollupOwner, l1Deployment, l2Deployment, proxyAdmin, upgradeExecutor
);
inboxToL1Deployment[inbox] = l1Deployment;
inboxToL2Deployment[inbox] = l2Deployment;
inboxToL1Deployment[args.inbox] = l1Deployment;
inboxToL2Deployment[args.inbox] = l2Deployment;
}
}

Expand Down
Loading