Skip to content

Commit

Permalink
fix: EVM-708 bridge fixes (#703)
Browse files Browse the repository at this point in the history
  • Loading branch information
kelemeno authored Aug 16, 2024
1 parent df1c5c8 commit 7d4b79c
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 32 deletions.
18 changes: 17 additions & 1 deletion l1-contracts/contracts/bridge/L1AssetRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {IL2Bridge} from "./interfaces/IL2Bridge.sol";
import {IL2BridgeLegacy} from "./interfaces/IL2BridgeLegacy.sol";
import {IL1AssetHandler} from "./interfaces/IL1AssetHandler.sol";
import {IL1NativeTokenVault} from "./interfaces/IL1NativeTokenVault.sol";
import {IL1SharedBridgeLegacy} from "./interfaces/IL1SharedBridgeLegacy.sol";

import {IMailbox} from "../state-transition/chain-interfaces/IMailbox.sol";
import {L2Message, TxStatus} from "../common/Messaging.sol";
Expand All @@ -37,7 +38,13 @@ import {IL1AssetDeploymentTracker} from "../bridge/interfaces/IL1AssetDeployment
/// @custom:security-contact security@matterlabs.dev
/// @dev Bridges assets between L1 and ZK chain, supporting both ETH and ERC20 tokens.
/// @dev Designed for use with a proxy for upgradability.
contract L1AssetRouter is IL1AssetRouter, ReentrancyGuard, Ownable2StepUpgradeable, PausableUpgradeable {
contract L1AssetRouter is
IL1AssetRouter,
IL1SharedBridgeLegacy,
ReentrancyGuard,
Ownable2StepUpgradeable,
PausableUpgradeable
{
using SafeERC20 for IERC20;

/// @dev The address of the WETH token on L1.
Expand Down Expand Up @@ -87,6 +94,7 @@ contract L1AssetRouter is IL1AssetRouter, ReentrancyGuard, Ownable2StepUpgradeab
IL1ERC20Bridge public override legacyBridge;

/// @dev A mapping chainId => bridgeProxy. Used to store the bridge proxy's address, and to see if it has been deployed yet.
// slither-disable-next-line uninitialized-state
mapping(uint256 chainId => address l2Bridge) public __DEPRECATED_l2BridgeAddress;

/// @dev A mapping chainId => L2 deposit transaction hash => dataHash
Expand Down Expand Up @@ -213,6 +221,14 @@ contract L1AssetRouter is IL1AssetRouter, ReentrancyGuard, Ownable2StepUpgradeab
chainBalance[_chainId][_token] = 0;
}

/// @notice Legacy function used for migration, do not use!
/// @param _chainId The chain id on which the bridge is deployed.
// slither-disable-next-line uninitialized-state-variables
function l2BridgeAddress(uint256 _chainId) external view returns (address) {
// slither-disable-next-line uninitialized-state-variables
return __DEPRECATED_l2BridgeAddress[_chainId];
}

/// @notice Sets the L1ERC20Bridge contract address.
/// @dev Should be called only once by the owner.
/// @param _legacyBridge The address of the legacy bridge.
Expand Down
10 changes: 10 additions & 0 deletions l1-contracts/contracts/bridge/interfaces/IL1SharedBridgeLegacy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

/// @title L1 Bridge contract interface
/// @author Matter Labs
/// @custom:security-contact security@matterlabs.dev
interface IL1SharedBridgeLegacy {
function l2BridgeAddress(uint256 _chainId) external view returns (address);
}
12 changes: 11 additions & 1 deletion l1-contracts/contracts/bridgehub/Bridgehub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,18 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus
messageRoot = _messageRoot;
}

/// @notice Used for the upgrade to set the baseTokenAssetId previously stored as baseToken.
/// @param _chainId the chainId of the chain.
function setLegacyBaseTokenAssetId(uint256 _chainId) external {
if (baseTokenAssetId[_chainId] == bytes32(0)) {
return;
}
address token = baseToken[_chainId];
require(token != address(0), "BH: token not set");
baseTokenAssetId[_chainId] = DataEncoding.encodeNTVAssetId(block.chainid, token);
}

/// @notice Used to set the legacy chain address for the upgrade.
/// @notice This has to be used after the BH but before the STM is upgraded.
/// @param _chainId The chainId of the legacy chain we are migrating.
function setLegacyChainAddress(uint256 _chainId) external {
address stm = stateTransitionManager[_chainId];
Expand Down
2 changes: 2 additions & 0 deletions l1-contracts/contracts/bridgehub/IBridgehub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,6 @@ interface IBridgehub is IL1AssetHandler {
function setAssetHandlerAddress(bytes32 _additionalData, address _assetAddress) external;

function L1_CHAIN_ID() external view returns (uint256);

function setLegacyBaseTokenAssetId(uint256 _chainId) external;
}
23 changes: 0 additions & 23 deletions l1-contracts/contracts/upgrades/CustomAssetBridging.sol

This file was deleted.

66 changes: 66 additions & 0 deletions l1-contracts/contracts/upgrades/GatewayUpgrade.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import {BaseZkSyncUpgrade, ProposedUpgrade} from "./BaseZkSyncUpgrade.sol";

import {DataEncoding} from "../common/libraries/DataEncoding.sol";

import {Diamond} from "../state-transition/libraries/Diamond.sol";
import {PriorityQueue} from "../state-transition/libraries/PriorityQueue.sol";
import {PriorityTree} from "../state-transition/libraries/PriorityTree.sol";

import {IGatewayUpgrade} from "./IGatewayUpgrade.sol";
import {IL1SharedBridgeLegacy} from "../bridge/interfaces/IL1SharedBridgeLegacy.sol";

import {IBridgehub} from "../bridgehub/IBridgehub.sol";

/// @author Matter Labs
/// @custom:security-contact security@matterlabs.dev
/// @notice This upgrade will be used to migrate Era to be part of the hyperchain ecosystem contracts.
contract GatewayUpgrade is BaseZkSyncUpgrade, Initializable {
using PriorityQueue for PriorityQueue.Queue;
using PriorityTree for PriorityTree.Tree;

address public immutable THIS_ADDRESS;

constructor() {
THIS_ADDRESS = address(this);
}

/// @notice The main function that will be called by the upgrade proxy.
/// @param _proposedUpgrade The upgrade to be executed.
function upgrade(ProposedUpgrade calldata _proposedUpgrade) public override returns (bytes32) {
(bytes memory l2TxDataStart, bytes memory l2TxDataFinish) = abi.decode(
_proposedUpgrade.postUpgradeCalldata,
(bytes, bytes)
);

s.baseTokenAssetId = DataEncoding.encodeNTVAssetId(block.chainid, s.baseToken);
s.priorityTree.setup(s.priorityQueue.getTotalPriorityTxs());
IBridgehub(s.bridgehub).setLegacyBaseTokenAssetId(s.chainId);
ProposedUpgrade memory proposedUpgrade = _proposedUpgrade;
address l2LegacyBridge = IL1SharedBridgeLegacy(s.baseTokenBridge).l2BridgeAddress(s.chainId);
proposedUpgrade.l2ProtocolUpgradeTx.data = bytes.concat(
l2TxDataStart,
bytes32(uint256(uint160(l2LegacyBridge))),
l2TxDataFinish
);
// slither-disable-next-line controlled-delegatecall
(bool success, ) = THIS_ADDRESS.delegatecall(
abi.encodeWithSelector(IGatewayUpgrade.upgradeExternal.selector, proposedUpgrade)
);
// solhint-disable-next-line gas-custom-errors
require(success, "GatewayUpgrade: upgrade failed");
return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE;
}

/// @notice The function that will be called from this same contract, we need an external call to be able to modify _proposedUpgrade (memory/calldata).
function upgradeExternal(ProposedUpgrade calldata _proposedUpgrade) external {
// solhint-disable-next-line gas-custom-errors
require(msg.sender == address(this), "GatewayUpgrade: upgradeExternal");
super.upgrade(_proposedUpgrade);
}
}
9 changes: 9 additions & 0 deletions l1-contracts/contracts/upgrades/IGatewayUpgrade.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

import {ProposedUpgrade} from "./BaseZkSyncUpgrade.sol";

interface IGatewayUpgrade {
function upgradeExternal(ProposedUpgrade calldata _upgrade) external returns (bytes32);
}
17 changes: 14 additions & 3 deletions l2-contracts/contracts/bridge/L2NativeTokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,20 @@ contract L2NativeTokenVault is IL2NativeTokenVault, Ownable2StepUpgradeable {
// Make sure that a NativeTokenVault sent the message
revert AssetIdMismatch(expectedAssetId, _assetId);
}
address deployedToken = _deployL2Token(originToken, erc20Data);
if (deployedToken != expectedToken) {
revert AddressMismatch(expectedToken, deployedToken);
address l1LegacyToken;
if (address(L2_LEGACY_SHARED_BRIDGE) != address(0)) {
l1LegacyToken = L2_LEGACY_SHARED_BRIDGE.l1TokenAddress(expectedToken);
}
if (l1LegacyToken != address(0)) {
/// token is a legacy token, no need to deploy
if (l1LegacyToken != originToken) {
revert AddressMismatch(originToken, l1LegacyToken);
}
} else {
address deployedToken = _deployL2Token(originToken, erc20Data);
if (deployedToken != expectedToken) {
revert AddressMismatch(expectedToken, deployedToken);
}
}
tokenAddress[_assetId] = expectedToken;
token = expectedToken;
Expand Down
10 changes: 6 additions & 4 deletions l2-contracts/contracts/bridge/L2StandardERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {ERC1967Upgrade} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgra

import {IL2StandardToken} from "./interfaces/IL2StandardToken.sol";
import {EmptyAddress, Unauthorized, NonSequentialVersion, Unimplemented} from "../L2ContractErrors.sol";
import {L2_NATIVE_TOKEN_VAULT} from "../L2ContractHelper.sol";

/// @author Matter Labs
/// @custom:security-contact security@matterlabs.dev
Expand All @@ -31,14 +32,15 @@ contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken, ERC1967Upg
/// @notice OpenZeppelin token represents `name` and `symbol` as storage variables and `decimals` as constant.
uint8 private decimals_;

/// @notice The l2Bridge now is deprecated, use the L2AssetRouter and L2NativeTokenVault instead.
/// @dev Address of the L2 bridge that is used as trustee who can mint/burn tokens
address public override l2Bridge;

/// @dev Address of the L1 token that can be deposited to mint this L2 token
address public override l1Address;

modifier onlyBridge() {
if (msg.sender != l2Bridge) {
modifier onlyNTV() {
if (msg.sender != address(L2_NATIVE_TOKEN_VAULT)) {
revert Unauthorized();
}
_;
Expand Down Expand Up @@ -151,7 +153,7 @@ contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken, ERC1967Upg
/// @param _to The account that will receive the created tokens.
/// @param _amount The amount that will be created.
/// @notice Should be called by bridge after depositing tokens from L1.
function bridgeMint(address _to, uint256 _amount) external override onlyBridge {
function bridgeMint(address _to, uint256 _amount) external override onlyNTV {
_mint(_to, _amount);
emit BridgeMint(_to, _amount);
}
Expand All @@ -160,7 +162,7 @@ contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken, ERC1967Upg
/// @param _from The account from which tokens will be burned.
/// @param _amount The amount that will be burned.
/// @notice Should be called by bridge before withdrawing tokens to L1.
function bridgeBurn(address _from, uint256 _amount) external override onlyBridge {
function bridgeBurn(address _from, uint256 _amount) external override onlyNTV {
_burn(_from, _amount);
emit BridgeBurn(_from, _amount);
}
Expand Down

0 comments on commit 7d4b79c

Please sign in to comment.