Skip to content

Commit

Permalink
Use L1Factory's address as part of salt calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
gvladika committed Jul 5, 2023
1 parent 2ddc38a commit 2e51766
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 182 deletions.
94 changes: 59 additions & 35 deletions contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,48 @@ import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";

error L2AtomicTokenBridgeFactory_AlreadyInitialized();

contract L2AtomicTokenBridgeFactory {
address public proxyAdmin;
L2GatewayRouter public router;
L2ERC20Gateway public standardGateway;
L2CustomGateway public customGateway;

function deployL2Contracts(
bytes memory routerCreationCode,
bytes memory standardGatewayCreationCode,
bytes memory customGatewayCreationCode,
address l1Router,
address l1StandardGateway,
address l1CustomGateway,
address l2StandardGatewayExpectedAddress
address l2StandardGatewayExpectedAddress,
address proxyAdminOwner
) external {
if (address(router) != address(0)) revert L2AtomicTokenBridgeFactory_AlreadyInitialized();
_deployRouter(routerCreationCode, l1Router, l2StandardGatewayExpectedAddress);
_deployStandardGateway(standardGatewayCreationCode, l1StandardGateway);
_deployCustomGateway(customGatewayCreationCode, l1CustomGateway);
// create proxyAdmin which will be used for all contracts
address proxyAdmin = address(new ProxyAdmin{ salt: _getSaltFrom(L2Salts.PROXY_ADMIN) }());

address router = _deployRouter(
routerCreationCode,
l1Router,
l2StandardGatewayExpectedAddress,
proxyAdmin
);
_deployStandardGateway(standardGatewayCreationCode, l1StandardGateway, router, proxyAdmin);
_deployCustomGateway(customGatewayCreationCode, l1CustomGateway, router, proxyAdmin);

// transfer ownership to L1Creator's msg.sender
ProxyAdmin(proxyAdmin).transferOwnership(proxyAdminOwner);
}

function _deployRouter(
bytes memory creationCode,
address l1Router,
address l2StandardGatewayExpectedAddress
) internal {
// first create proxyAdmin which will be used for all contracts
proxyAdmin = address(new ProxyAdmin{ salt: L2Salts.PROXY_ADMIN }());

address l2StandardGatewayExpectedAddress,
address proxyAdmin
) internal returns (address) {
// create logic and proxy
address routerLogicAddress = Create2.deploy(0, L2Salts.ROUTER_LOGIC, creationCode);
router = L2GatewayRouter(
address routerLogicAddress = Create2.deploy(
0,
_getSaltFrom(L2Salts.ROUTER_LOGIC),
creationCode
);
L2GatewayRouter router = L2GatewayRouter(
address(
new TransparentUpgradeableProxy{ salt: L2Salts.ROUTER }(
new TransparentUpgradeableProxy{ salt: _getSaltFrom(L2Salts.ROUTER) }(
routerLogicAddress,
proxyAdmin,
bytes("")
Expand All @@ -56,18 +62,25 @@ contract L2AtomicTokenBridgeFactory {

// init
router.initialize(l1Router, l2StandardGatewayExpectedAddress);

return address(router);
}

function _deployStandardGateway(bytes memory creationCode, address l1StandardGateway) internal {
function _deployStandardGateway(
bytes memory creationCode,
address l1StandardGateway,
address router,
address proxyAdmin
) internal {
// create logic and proxy
address standardGatewayLogicAddress = Create2.deploy(
0,
L2Salts.STANDARD_GATEWAY_LOGIC,
_getSaltFrom(L2Salts.STANDARD_GATEWAY_LOGIC),
creationCode
);
standardGateway = L2ERC20Gateway(
L2ERC20Gateway standardGateway = L2ERC20Gateway(
address(
new TransparentUpgradeableProxy{ salt: L2Salts.STANDARD_GATEWAY }(
new TransparentUpgradeableProxy{ salt: _getSaltFrom(L2Salts.STANDARD_GATEWAY) }(
standardGatewayLogicAddress,
proxyAdmin,
bytes("")
Expand All @@ -76,30 +89,37 @@ contract L2AtomicTokenBridgeFactory {
);

// create beacon
StandardArbERC20 standardArbERC20 = new StandardArbERC20{ salt: L2Salts.STANDARD_ERC20 }();
UpgradeableBeacon beacon = new UpgradeableBeacon{ salt: L2Salts.UPGRADEABLE_BEACON }(
address(standardArbERC20)
);
StandardArbERC20 standardArbERC20 = new StandardArbERC20{
salt: _getSaltFrom(L2Salts.STANDARD_ERC20)
}();
UpgradeableBeacon beacon = new UpgradeableBeacon{
salt: _getSaltFrom(L2Salts.UPGRADEABLE_BEACON)
}(address(standardArbERC20));
BeaconProxyFactory beaconProxyFactory = new BeaconProxyFactory{
salt: L2Salts.BEACON_PROXY_FACTORY
salt: _getSaltFrom(L2Salts.BEACON_PROXY_FACTORY)
}();

// init contracts
beaconProxyFactory.initialize(address(beacon));
standardGateway.initialize(l1StandardGateway, address(router), address(beaconProxyFactory));
standardGateway.initialize(l1StandardGateway, router, address(beaconProxyFactory));
}

function _deployCustomGateway(bytes memory creationCode, address l1CustomGateway) internal {
function _deployCustomGateway(
bytes memory creationCode,
address l1CustomGateway,
address router,
address proxyAdmin
) internal {
address customGatewayLogicAddress = Create2.deploy(
0,
L2Salts.CUSTOM_GATEWAY_LOGIC,
_getSaltFrom(L2Salts.CUSTOM_GATEWAY_LOGIC),
creationCode
);

// create logic and proxy
customGateway = L2CustomGateway(
L2CustomGateway customGateway = L2CustomGateway(
address(
new TransparentUpgradeableProxy{ salt: L2Salts.CUSTOM_GATEWAY }(
new TransparentUpgradeableProxy{ salt: _getSaltFrom(L2Salts.CUSTOM_GATEWAY) }(
customGatewayLogicAddress,
proxyAdmin,
bytes("")
Expand All @@ -108,7 +128,11 @@ contract L2AtomicTokenBridgeFactory {
);

// init
customGateway.initialize(l1CustomGateway, address(router));
customGateway.initialize(l1CustomGateway, router);
}

function _getSaltFrom(bytes32 prefix) internal view returns (bytes32) {
return keccak256(abi.encodePacked(prefix, msg.sender));
}
}

Expand Down
154 changes: 82 additions & 72 deletions contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ contract L1AtomicTokenBridgeCreator is Ownable {
);

expectedL2ProxyAdminAddress = Create2.computeAddress(
L2Salts.PROXY_ADMIN,
_getSaltFrom(L2Salts.PROXY_ADMIN),
keccak256(type(ProxyAdmin).creationCode),
expectedL2FactoryAddress
);

expectedL2BeaconProxyFactoryAddress = Create2.computeAddress(
L2Salts.BEACON_PROXY_FACTORY,
_getSaltFrom(L2Salts.BEACON_PROXY_FACTORY),
keccak256(type(BeaconProxyFactory).creationCode),
expectedL2FactoryAddress
);
Expand Down Expand Up @@ -77,13 +77,13 @@ contract L1AtomicTokenBridgeCreator is Ownable {

function createTokenBridge(
address inbox,
address owner,
uint256 maxSubmissionCostForFactory,
uint256 maxGasForFactory,
uint256 maxSubmissionCostForContracts,
uint256 maxGasForContracts,
uint256 gasPriceBid
) external payable {
address owner = msg.sender;
(address router, address standardGateway, address customGateway) = _deployL1Contracts(
inbox,
owner
Expand Down Expand Up @@ -122,10 +122,13 @@ contract L1AtomicTokenBridgeCreator is Ownable {
owner,
address(standardGateway),
address(0),
_computeExpectedL2RouterAddress(),
computeExpectedL2RouterAddress(),
inbox
);

// transfer ownership to owner
ProxyAdmin(proxyAdmin).transferOwnership(owner);

// emit it
emit OrbitTokenBridgeCreated(
address(router),
Expand All @@ -151,7 +154,7 @@ contract L1AtomicTokenBridgeCreator is Ownable {
);

standardGateway.initialize(
_computeExpectedL2StandardGatewayAddress(),
computeExpectedL2StandardGatewayAddress(),
router,
inbox,
keccak256(type(ClonableBeaconProxy).creationCode),
Expand All @@ -178,7 +181,7 @@ contract L1AtomicTokenBridgeCreator is Ownable {
);

customGateway.initialize(
_computeExpectedL2CustomGatewayAddress(),
computeExpectedL2CustomGatewayAddress(),
address(router),
inbox,
owner
Expand Down Expand Up @@ -218,6 +221,7 @@ contract L1AtomicTokenBridgeCreator is Ownable {
uint256 maxGas,
uint256 gasPriceBid
) internal {
address proxyAdminOwner = msg.sender;
bytes memory data = abi.encodeWithSelector(
L2AtomicTokenBridgeFactory.deployL2Contracts.selector,
_creationCodeFor(l2RouterTemplate.code),
Expand All @@ -226,7 +230,8 @@ contract L1AtomicTokenBridgeCreator is Ownable {
l1Router,
l1StandardGateway,
l1CustomGateway,
_computeExpectedL2StandardGatewayAddress()
computeExpectedL2StandardGatewayAddress(),
proxyAdminOwner
);

IInbox(inbox).createRetryableTicket{ value: maxSubmissionCost + maxGas * gasPriceBid }(
Expand All @@ -241,8 +246,75 @@ contract L1AtomicTokenBridgeCreator is Ownable {
);
}

function computeExpectedL2RouterAddress() public view returns (address) {
address expectedL2RouterLogic = Create2.computeAddress(
_getSaltFrom(L2Salts.ROUTER_LOGIC),
keccak256(_creationCodeFor(l2RouterTemplate.code)),
expectedL2FactoryAddress
);

return
Create2.computeAddress(
_getSaltFrom(L2Salts.ROUTER),
keccak256(
abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(expectedL2RouterLogic, expectedL2ProxyAdminAddress, bytes(""))
)
),
expectedL2FactoryAddress
);
}

function computeExpectedL2StandardGatewayAddress() public view returns (address) {
address expectedL2StandardGatewayLogic = Create2.computeAddress(
_getSaltFrom(L2Salts.STANDARD_GATEWAY_LOGIC),
keccak256(_creationCodeFor(l2StandardGatewayTemplate.code)),
expectedL2FactoryAddress
);
return
Create2.computeAddress(
_getSaltFrom(L2Salts.STANDARD_GATEWAY),
keccak256(
abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(
expectedL2StandardGatewayLogic,
expectedL2ProxyAdminAddress,
bytes("")
)
)
),
expectedL2FactoryAddress
);
}

function computeExpectedL2CustomGatewayAddress() public view returns (address) {
address expectedL2CustomGatewayLogic = Create2.computeAddress(
_getSaltFrom(L2Salts.CUSTOM_GATEWAY_LOGIC),
keccak256(_creationCodeFor(l2CustomGatewayTemplate.code)),
expectedL2FactoryAddress
);

return
Create2.computeAddress(
_getSaltFrom(L2Salts.CUSTOM_GATEWAY),
keccak256(
abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(
expectedL2CustomGatewayLogic,
expectedL2ProxyAdminAddress,
bytes("")
)
)
),
expectedL2FactoryAddress
);
}

/**
* @notice Generate a creation code that results on a contract with `_code` as bytecode
* @notice Generate a creation code that results on a contract with `code` as bytecode
* @param code The returning value of the resulting `creationCode`
* @return creationCode (constructor) for new contract
*/
Expand Down Expand Up @@ -303,70 +375,8 @@ contract L1AtomicTokenBridgeCreator is Ownable {
return address(uint160(uint256(keccak256(data))));
}

function _computeExpectedL2RouterAddress() internal view returns (address) {
address expectedL2RouterLogic = Create2.computeAddress(
L2Salts.ROUTER_LOGIC,
keccak256(_creationCodeFor(l2RouterTemplate.code)),
expectedL2FactoryAddress
);

function _getSaltFrom(bytes32 prefix) internal view returns (bytes32) {
return
Create2.computeAddress(
L2Salts.ROUTER,
keccak256(
abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(expectedL2RouterLogic, expectedL2ProxyAdminAddress, bytes(""))
)
),
expectedL2FactoryAddress
);
}

function _computeExpectedL2StandardGatewayAddress() internal view returns (address) {
address expectedL2StandardGatewayLogic = Create2.computeAddress(
L2Salts.STANDARD_GATEWAY_LOGIC,
keccak256(_creationCodeFor(l2StandardGatewayTemplate.code)),
expectedL2FactoryAddress
);
return
Create2.computeAddress(
L2Salts.STANDARD_GATEWAY,
keccak256(
abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(
expectedL2StandardGatewayLogic,
expectedL2ProxyAdminAddress,
bytes("")
)
)
),
expectedL2FactoryAddress
);
}

function _computeExpectedL2CustomGatewayAddress() internal view returns (address) {
address expectedL2CustomGatewayLogic = Create2.computeAddress(
L2Salts.CUSTOM_GATEWAY_LOGIC,
keccak256(_creationCodeFor(l2CustomGatewayTemplate.code)),
expectedL2FactoryAddress
);

return
Create2.computeAddress(
L2Salts.CUSTOM_GATEWAY,
keccak256(
abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(
expectedL2CustomGatewayLogic,
expectedL2ProxyAdminAddress,
bytes("")
)
)
),
expectedL2FactoryAddress
);
keccak256(abi.encodePacked(prefix, AddressAliasHelper.applyL1ToL2Alias(address(this))));
}
}
Loading

0 comments on commit 2e51766

Please sign in to comment.