Skip to content

Commit

Permalink
rearrange functions to kepp shared bridge storage layout
Browse files Browse the repository at this point in the history
  • Loading branch information
Raid Ateir committed May 17, 2024
1 parent 0b0131f commit 068b47d
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 49 deletions.
45 changes: 21 additions & 24 deletions l2-contracts/contracts/bridge/L2SharedBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

pragma solidity 0.8.20;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
Expand All @@ -26,7 +25,7 @@ import {NATIVE_TOKEN_VAULT_VIRTUAL_ADDRESS} from "../common/Config.sol";
/// @custom:security-contact [email protected]
/// @notice The "default" bridge implementation for the ERC20 tokens. Note, that it does not
/// support any custom token logic, i.e. rebase tokens' functionality is not supported.
contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, OwnableUpgradeable {
contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, Initializable {
/// @dev The address of the L1 bridge counterpart.
address public override l1SharedBridge;

Expand All @@ -37,6 +36,9 @@ contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, OwnableUpgrad
/// @dev Bytecode hash of the proxy for tokens deployed by the bridge.
bytes32 internal l2TokenProxyBytecodeHash;

/// @dev A mapping l2 token address => l1 token address
mapping(address l2TokenAddress => address l1TokenAddress) public override l1TokenAddress;

address private l1LegacyBridge;

/// @dev Chain ID of Era for legacy reasons
Expand Down Expand Up @@ -66,13 +68,16 @@ contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, OwnableUpgrad
address _l1Bridge,
address _l1LegacyBridge,
bytes32 _l2TokenProxyBytecodeHash,
address _aliasedOwner
) external initializer { // Why do we use reinitializer here insted of initializer?
address _aliasedOwner,
IL2StandardDeployer _standardDeployer
) external reinitializer(2) {
require(_l1Bridge != address(0), "bf");
require(_l2TokenProxyBytecodeHash != bytes32(0), "df");
require(_aliasedOwner != address(0), "sf");
require(address(_standardDeployer) != address(0), "cf");

l1SharedBridge = _l1Bridge;
standardDeployer = _standardDeployer;

if (block.chainid != ERA_CHAIN_ID) {
address l2StandardToken = address(new L2StandardERC20{salt: bytes32(0)}());
Expand All @@ -84,8 +89,6 @@ contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, OwnableUpgrad
l1LegacyBridge = _l1LegacyBridge;
// l2StandardToken and l2TokenBeacon are already deployed on ERA, and stored in the proxy
}

__Ownable_init(); // Shall we use 2 step version instead?
}

/// @notice Finalize the deposit and mint funds
Expand Down Expand Up @@ -120,15 +123,9 @@ contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, OwnableUpgrad
function withdraw(bytes32 _assetInfo, bytes calldata _assetData) external override {
address asset = assetAddress[_assetInfo];
bytes memory _bridgeBurnData;

if (asset != address(0)) {
_bridgeBurnData = IL2StandardAsset(asset).bridgeBurn(
L1_CHAIN_ID,
0,
_assetInfo,
msg.sender,
_assetData
);

if (asset != address(0)) {
_bridgeBurnData = IL2StandardAsset(asset).bridgeBurn(L1_CHAIN_ID, 0, _assetInfo, msg.sender, _assetData);
} else {
_bridgeBurnData = IL2StandardAsset(standardDeployer).bridgeBurn(
L1_CHAIN_ID,
Expand All @@ -155,13 +152,6 @@ contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, OwnableUpgrad
return abi.encodePacked(IL1ERC20Bridge.finalizeWithdrawal.selector, _assetInfo, _bridgeBurnData);
}

/// @dev Sets the L1ERC20Bridge contract address. Should be called only once.
function setNativeTokenVault(IL2StandardDeployer _standardDeployer) external onlyOwner {
require(address(standardDeployer) == address(0), "ShB: standard deployer already set");
require(address(_standardDeployer) != address(0), "ShB: standard deployer 0");
standardDeployer = _standardDeployer;
}

/*//////////////////////////////////////////////////////////////
LEGACY FUNCTIONS
//////////////////////////////////////////////////////////////*/
Expand All @@ -181,14 +171,21 @@ contract L2SharedBridge is IL2SharedBridge, IL2SharedBridgeLegacy, OwnableUpgrad
}

function withdraw(address _l1Receiver, address _l2Token, uint256 _amount) external {
if (l1TokenAddress[_l2Token] == address(0)) {
updateL1TokenAddress(_l2Token);
}
bytes32 assetInfo = keccak256(
abi.encode(L1_CHAIN_ID, NATIVE_TOKEN_VAULT_VIRTUAL_ADDRESS, bytes32(uint256(uint160(l1TokenAddress(_l2Token)))))
abi.encode(
L1_CHAIN_ID,
NATIVE_TOKEN_VAULT_VIRTUAL_ADDRESS,
bytes32(uint256(uint160(l1TokenAddress[_l2Token])))
)
);
bytes memory data = abi.encode(_amount, _l1Receiver);
this.withdraw(assetInfo, data);
}

function l1TokenAddress(address _l2Token) public view returns (address) {
function updateL1TokenAddress(address _l2Token) public view returns (address) {
return IL2StandardToken(_l2Token).l1Address();
}

Expand Down
25 changes: 16 additions & 9 deletions l2-contracts/contracts/bridge/L2StandardDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity 0.8.20;

import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";

Expand All @@ -20,7 +20,7 @@ import {SystemContractsCaller} from "../SystemContractsCaller.sol";
/// @custom:security-contact [email protected]
/// @notice The "default" bridge implementation for the ERC20 tokens. Note, that it does not
/// support any custom token logic, i.e. rebase tokens' functionality is not supported.
contract L2StandardDeployer is IL2StandardDeployer, Initializable {
contract L2StandardDeployer is IL2StandardDeployer, Ownable2StepUpgradeable {
IL2SharedBridge public override l2Bridge;

/// @dev Contract that stores the implementation address for token.
Expand All @@ -38,27 +38,27 @@ contract L2StandardDeployer is IL2StandardDeployer, Initializable {
}

/// @notice Initializes the bridge contract for later use. Expected to be used in the proxy.
/// @param _l2Bridge The address of the L1 Bridge contract.
/// @param _owner Address which can set the shared bridge address and upgrade the deployer
/// @param _l2TokenProxyBytecodeHash The bytecode hash of the proxy for tokens deployed by the bridge.
/// @param _aliasedOwner The address of the governor contract.
/// @param _contractsDeployedAlready Ensures beacon proxy for standard ERC20 has not been deployed
function initialize(
IL2SharedBridge _l2Bridge,
address _owner,
bytes32 _l2TokenProxyBytecodeHash,
address _aliasedOwner,
bool contractsDeployedAlready
bool _contractsDeployedAlready
) external reinitializer(2) {
require(address(_l2Bridge) != address(0), "bf");
require(_l2TokenProxyBytecodeHash != bytes32(0), "df");
require(_aliasedOwner != address(0), "sf");

l2Bridge = _l2Bridge;

if (!contractsDeployedAlready) {
if (!_contractsDeployedAlready) {
address l2StandardToken = address(new L2StandardERC20{salt: bytes32(0)}());
l2TokenBeacon = new UpgradeableBeacon{salt: bytes32(0)}(l2StandardToken);
l2TokenProxyBytecodeHash = _l2TokenProxyBytecodeHash;
l2TokenBeacon.transferOwnership(_aliasedOwner);
}

_transferOwnership(_owner);
}

function bridgeMint(uint256 _chainId, bytes32 _assetInfo, bytes calldata _data) external payable override {
Expand Down Expand Up @@ -143,4 +143,11 @@ contract L2StandardDeployer is IL2StandardDeployer, Initializable {
return
L2ContractHelper.computeCreate2Address(address(this), salt, l2TokenProxyBytecodeHash, constructorInputHash);
}

/// @dev Sets the L1ERC20Bridge contract address. Should be called only once.
function setSharedBridge(IL2SharedBridge _sharedBridge) external onlyOwner {
require(address(l2Bridge) == address(0), "SD: shared bridge already set");
require(address(_sharedBridge) != address(0), "SD: shared bridge 0");
l2Bridge = _sharedBridge;
}
}
32 changes: 16 additions & 16 deletions l2-contracts/test/erc20.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,26 @@ describe("ERC20Bridge", function () {
const beaconProxyBytecodeHash = hashBytecode((await deployer.loadArtifact("BeaconProxy")).bytecode);
const erc20BridgeImpl = await deployer.deploy(await deployer.loadArtifact("L2SharedBridge"), [testChainId, 1]);
const erc20StandardDeployerImpl = await deployer.deploy(await deployer.loadArtifact("L2StandardDeployer"));
const standardDeployerInitializeData = erc20StandardDeployerImpl.interface.encodeFunctionData("initialize", [
deployerWallet.address,
beaconProxyBytecodeHash,
governorWallet.address,
contractsDeployedAlready,
]);

const erc20StandardDeployerProxy = await deployer.deploy(
await deployer.loadArtifact("TransparentUpgradeableProxy"),
[erc20StandardDeployerImpl.address, governorWallet.address, standardDeployerInitializeData]
);

contractsDeployedAlready = true;

const bridgeInitializeData = erc20BridgeImpl.interface.encodeFunctionData("initialize", [
unapplyL1ToL2Alias(l1BridgeWallet.address),
ethers.constants.AddressZero,
beaconProxyBytecodeHash,
governorWallet.address,
erc20StandardDeployerProxy.address,
]);

const erc20BridgeProxy = await deployer.deploy(await deployer.loadArtifact("TransparentUpgradeableProxy"), [
Expand All @@ -67,25 +82,10 @@ describe("ERC20Bridge", function () {
bridgeInitializeData,
]);

const standardDeployerInitializeData = erc20StandardDeployerImpl.interface.encodeFunctionData("initialize", [
erc20BridgeProxy.address,
beaconProxyBytecodeHash,
governorWallet.address,
contractsDeployedAlready,
]);

contractsDeployedAlready = true;

const erc20StandardDeployerProxy = await deployer.deploy(await deployer.loadArtifact("TransparentUpgradeableProxy"), [
erc20StandardDeployerImpl.address,
governorWallet.address,
standardDeployerInitializeData,
]);

erc20Bridge = L2SharedBridgeFactory.connect(erc20BridgeProxy.address, deployerWallet);
erc20StandardDeployer = L2StandardDeployerFactory.connect(erc20StandardDeployerProxy.address, deployerWallet);

await erc20Bridge.setNativeTokenVault(erc20StandardDeployerProxy.address);
await erc20StandardDeployer.setSharedBridge(erc20BridgeProxy.address);
});

it("Should finalize deposit ERC20 deposit", async function () {
Expand Down

0 comments on commit 068b47d

Please sign in to comment.