Skip to content

Commit

Permalink
Resolve h06 (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
StanislavBreadless authored Dec 2, 2024
1 parent a71a049 commit 2bcd5de
Show file tree
Hide file tree
Showing 13 changed files with 256 additions and 14 deletions.
11 changes: 8 additions & 3 deletions l1-contracts/contracts/bridge/asset-router/AssetRouterBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ abstract contract AssetRouterBase is IAssetRouterBase, Ownable2StepUpgradeable,
if (!senderIsNTV && msg.sender != assetDeploymentTracker[assetId]) {
revert Unauthorized(msg.sender);
}
assetHandlerAddress[assetId] = _assetHandlerAddress;
_setAssetHandler(assetId, _assetHandlerAddress);
assetDeploymentTracker[assetId] = msg.sender;
emit AssetHandlerRegisteredInitial(assetId, _assetHandlerAddress, _assetRegistrationData, sender);
emit AssetDeploymentTrackerRegistered(assetId, _assetRegistrationData, sender);
}

/*//////////////////////////////////////////////////////////////
Expand All @@ -108,7 +108,7 @@ abstract contract AssetRouterBase is IAssetRouterBase, Ownable2StepUpgradeable,
if (assetHandler != address(0)) {
IAssetHandler(assetHandler).bridgeMint(_chainId, _assetId, _transferData);
} else {
assetHandlerAddress[_assetId] = _nativeTokenVault;
_setAssetHandler(_assetId, _nativeTokenVault);
IAssetHandler(_nativeTokenVault).bridgeMint(_chainId, _assetId, _transferData); // ToDo: Maybe it's better to receive amount and receiver here? transferData may have different encoding
}
}
Expand All @@ -117,6 +117,11 @@ abstract contract AssetRouterBase is IAssetRouterBase, Ownable2StepUpgradeable,
Internal Functions
//////////////////////////////////////////////////////////////*/

function _setAssetHandler(bytes32 _assetId, address _assetHandlerAddress) internal {
assetHandlerAddress[_assetId] = _assetHandlerAddress;
emit AssetHandlerRegistered(_assetId, _assetHandlerAddress);
}

/// @dev send the burn message to the asset
/// @notice Forwards the burn request for specific asset to respective asset handler.
/// @param _chainId The chain ID of the ZK chain to which to deposit.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ interface IAssetRouterBase {
bytes32 assetDataHash // Todo: What's the point of emitting hash?
);

event AssetHandlerRegisteredInitial(
event AssetDeploymentTrackerRegistered(
bytes32 indexed assetId,
address indexed assetHandlerAddress,
bytes32 indexed additionalData,
address assetDeploymentTracker
);
Expand Down
5 changes: 5 additions & 0 deletions l1-contracts/contracts/bridge/asset-router/IL2AssetRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@ interface IL2AssetRouter is IAssetRouterBase {
/// @dev Used to set the assedAddress for a given assetId.
/// @dev Will be used by ZK Gateway
function setAssetHandlerAddress(uint256 _originChainId, bytes32 _assetId, address _assetAddress) external;

/// @notice Function that allows native token vault to register itself as the asset handler for
/// a legacy asset.
/// @param _assetId The assetId of the legacy token.
function setLegacyTokenAssetHandler(bytes32 _assetId) external;
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard {
require(address(_nativeTokenVault) != address(0), "AR: native token vault 0");
nativeTokenVault = _nativeTokenVault;
bytes32 ethAssetId = DataEncoding.encodeNTVAssetId(block.chainid, ETH_TOKEN_ADDRESS);
assetHandlerAddress[ethAssetId] = address(nativeTokenVault);
_setAssetHandler(ethAssetId, address(_nativeTokenVault));
}

/// @notice Sets the L1ERC20Bridge contract address.
Expand Down
20 changes: 17 additions & 3 deletions l1-contracts/contracts/bridge/asset-router/L2AssetRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter {
_;
}

modifier onlyNTV() {
if (msg.sender != L2_NATIVE_TOKEN_VAULT_ADDR) {
revert InvalidCaller(msg.sender);
}
_;
}

/// @dev Disable the initialization to prevent Parity hack.
/// @dev this contract is deployed in the L2GenesisUpgrade, and is meant as direct deployment without a proxy.
/// @param _l1AssetRouter The address of the L1 Bridge contract.
Expand All @@ -83,7 +90,9 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter {
revert EmptyAddress();
}
l1AssetRouter = _l1AssetRouter;
assetHandlerAddress[_baseTokenAssetId] = L2_NATIVE_TOKEN_VAULT_ADDR;

_setAssetHandler(_baseTokenAssetId, L2_NATIVE_TOKEN_VAULT_ADDR);

BASE_TOKEN_ASSET_ID = _baseTokenAssetId;
_disableInitializers();
_transferOwnership(_aliasedOwner);
Expand All @@ -95,8 +104,7 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter {
bytes32 _assetId,
address _assetAddress
) external override onlyAssetRouterCounterpart(_originChainId) {
assetHandlerAddress[_assetId] = _assetAddress;
emit AssetHandlerRegistered(_assetId, _assetAddress);
_setAssetHandler(_assetId, _assetAddress);
}

/// @inheritdoc IAssetRouterBase
Expand All @@ -107,6 +115,12 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter {
_setAssetHandlerAddressThisChain(L2_NATIVE_TOKEN_VAULT_ADDR, _assetRegistrationData, _assetHandlerAddress);
}

function setLegacyTokenAssetHandler(bytes32 _assetId) external override onlyNTV {
// Note, that it is an asset handler, but not asset deployment tracker,
// which is located on L1.
_setAssetHandler(_assetId, L2_NATIVE_TOKEN_VAULT_ADDR);
}

/*//////////////////////////////////////////////////////////////
Receive transaction Functions
//////////////////////////////////////////////////////////////*/
Expand Down
22 changes: 21 additions & 1 deletion l1-contracts/contracts/bridge/ntv/L2NativeTokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ import {NativeTokenVault} from "./NativeTokenVault.sol";

import {IL2SharedBridgeLegacy} from "../interfaces/IL2SharedBridgeLegacy.sol";
import {BridgedStandardERC20} from "../BridgedStandardERC20.sol";
import {IL2AssetRouter} from "../asset-router/IL2AssetRouter.sol";

import {DEPLOYER_SYSTEM_CONTRACT, L2_ASSET_ROUTER_ADDR} from "../../common/L2ContractAddresses.sol";
import {L2ContractHelper, IContractDeployer} from "../../common/libraries/L2ContractHelper.sol";

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

import {EmptyAddress, EmptyBytes32, AddressMismatch, DeployFailed, AssetIdNotSupported} from "../../common/L1ContractErrors.sol";
import {NoLegacySharedBridge, TokenIsLegacy, TokenIsNotLegacy, EmptyAddress, EmptyBytes32, AddressMismatch, DeployFailed, AssetIdNotSupported} from "../../common/L1ContractErrors.sol";

/// @author Matter Labs
/// @custom:security-contact [email protected]
Expand Down Expand Up @@ -85,8 +86,16 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVault {

/// @notice Sets the legacy token asset ID for the given L2 token address.
function setLegacyTokenAssetId(address _l2TokenAddress) public {
if (address(L2_LEGACY_SHARED_BRIDGE) == address(0)) {
revert NoLegacySharedBridge();
}
address l1TokenAddress = L2_LEGACY_SHARED_BRIDGE.l1TokenAddress(_l2TokenAddress);
bytes32 newAssetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, l1TokenAddress);
if (l1TokenAddress == address(0)) {
revert TokenIsNotLegacy();
}

IL2AssetRouter(L2_ASSET_ROUTER_ADDR).setLegacyTokenAssetHandler(newAssetId);
tokenAddress[newAssetId] = _l2TokenAddress;
assetId[_l2TokenAddress] = newAssetId;
originChainId[newAssetId] = L1_CHAIN_ID;
Expand Down Expand Up @@ -244,6 +253,17 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVault {
// on L2s we don't track the balance
}

function _registerToken(address _nativeToken) internal override {
if (
address(L2_LEGACY_SHARED_BRIDGE) != address(0) &&
L2_LEGACY_SHARED_BRIDGE.l1TokenAddress(_nativeToken) != address(0)
) {
// Legacy tokens should be registered via `setLegacyTokenAssetId`.
revert TokenIsLegacy();
}
super._registerToken(_nativeToken);
}

/*//////////////////////////////////////////////////////////////
LEGACY FUNCTIONS
//////////////////////////////////////////////////////////////*/
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/contracts/bridge/ntv/NativeTokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ abstract contract NativeTokenVault is
_registerToken(_nativeToken);
}

function _registerToken(address _nativeToken) internal {
function _registerToken(address _nativeToken) internal virtual {
if (_nativeToken == WETH_TOKEN) {
revert TokenNotSupported(WETH_TOKEN);
}
Expand Down
6 changes: 6 additions & 0 deletions l1-contracts/contracts/common/L1ContractErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,12 @@ error TokenNotLegacy();
error IncorrectTokenAddressFromNTV(bytes32 assetId, address tokenAddress);
// 0x48c5fa28
error InvalidProofLengthForFinalNode();
// 0x7acd7817
error TokenIsNotLegacy();
// 0xa51fa558
error TokenIsLegacy();
// 0xb20b58ce
error NoLegacySharedBridge();

enum SharedBridgeKey {
PostUpgradeFirstBatch,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ contract DummySharedBridge is PausableUpgradeable {
bytes32 assetId = keccak256(abi.encode(uint256(block.chainid), sender, _additionalData));
assetHandlerAddress[assetId] = _assetHandlerAddress;
// assetDeploymentTracker[assetId] = sender;
// emit AssetHandlerRegisteredInitial(assetId, _assetHandlerAddress, _additionalData, sender);
// emit AssetDeploymentTrackerRegistered(assetId, _assetHandlerAddress, _additionalData, sender);
}

// add this to be excluded from coverage report
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

// solhint-disable gas-custom-errors

import {Test} from "forge-std/Test.sol";
import "forge-std/console.sol";

import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol";
import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol";
import {IL2NativeTokenVault} from "contracts/bridge/ntv/IL2NativeTokenVault.sol";

import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol";
import {BeaconProxy} from "@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol";

import {L2_ASSET_ROUTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_BRIDGEHUB_ADDR} from "contracts/common/L2ContractAddresses.sol";
import {ETH_TOKEN_ADDRESS, SETTLEMENT_LAYER_RELAY_SENDER} from "contracts/common/Config.sol";

import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol";
import {BridgehubMintCTMAssetData} from "contracts/bridgehub/IBridgehub.sol";
import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol";
import {IL2AssetRouter} from "contracts/bridge/asset-router/IL2AssetRouter.sol";
import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol";
import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol";
import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol";

import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol";
import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol";
import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol";
import {SystemContractsArgs} from "./_SharedL2ContractL1DeployerUtils.sol";

import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol";
import {L2NativeTokenVaultTestAbstract} from "./L2NativeTokenVaultTestAbstract.t.sol";
import {SharedL2ContractL1DeployerUtils} from "./_SharedL2ContractL1DeployerUtils.sol";

contract L2GatewayL1Test is
Test,
SharedL2ContractL1DeployerUtils,
SharedL2ContractDeployer,
L2NativeTokenVaultTestAbstract
{
function test() internal virtual override(DeployUtils, SharedL2ContractL1DeployerUtils) {}

function initSystemContracts(
SystemContractsArgs memory _args
) internal virtual override(SharedL2ContractDeployer, SharedL2ContractL1DeployerUtils) {
super.initSystemContracts(_args);
}

function deployL2Contracts(
uint256 _l1ChainId
) public virtual override(SharedL2ContractDeployer, SharedL2ContractL1DeployerUtils) {
super.deployL2Contracts(_l1ChainId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

// solhint-disable gas-custom-errors

import {Test} from "forge-std/Test.sol";
import "forge-std/console.sol";

import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol";
import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol";
import {IL2NativeTokenVault} from "contracts/bridge/ntv/IL2NativeTokenVault.sol";

import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol";
import {BeaconProxy} from "@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol";

import {L2_ASSET_ROUTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_BRIDGEHUB_ADDR} from "contracts/common/L2ContractAddresses.sol";
import {ETH_TOKEN_ADDRESS, SETTLEMENT_LAYER_RELAY_SENDER} from "contracts/common/Config.sol";

import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol";
import {BridgehubMintCTMAssetData} from "contracts/bridgehub/IBridgehub.sol";
import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol";
import {IL2AssetRouter} from "contracts/bridge/asset-router/IL2AssetRouter.sol";
import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol";
import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol";
import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol";

import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol";
import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol";
import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol";
import {SystemContractsArgs} from "./_SharedL2ContractL1DeployerUtils.sol";

import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol";
import {TokenIsLegacy, TokenIsNotLegacy, Unauthorized, UnimplementedMessage, BridgeMintNotImplemented} from "contracts/common/L1ContractErrors.sol";

import {IL2SharedBridgeLegacy} from "contracts/bridge/interfaces/IL2SharedBridgeLegacy.sol";
import {L2NativeTokenVault} from "contracts/bridge/ntv/L2NativeTokenVault.sol";

abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeployer {
function test_registerLegacyToken() external {
address l2Token = makeAddr("l2Token");
address l1Token = makeAddr("l1Token");
vm.mockCall(
sharedBridgeLegacy,
abi.encodeCall(IL2SharedBridgeLegacy.l1TokenAddress, (l2Token)),
abi.encode(l1Token)
);
L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).setLegacyTokenAssetId(l2Token);
}

function test_registerLegacyTokenRevertNotLegacy() external {
address l2Token = makeAddr("l2Token");
vm.expectRevert(TokenIsNotLegacy.selector);
L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).setLegacyTokenAssetId(l2Token);
}

function test_registerTokenRevertIsLegacy() external {
address l2Token = makeAddr("l2Token");
address l1Token = makeAddr("l1Token");
vm.mockCall(
sharedBridgeLegacy,
abi.encodeCall(IL2SharedBridgeLegacy.l1TokenAddress, (l2Token)),
abi.encode(l1Token)
);

vm.expectRevert(TokenIsLegacy.selector);
L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).registerToken(l2Token);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ abstract contract SharedL2ContractDeployer is Test, DeployUtils {

bytes internal exampleChainCommitment;

address internal sharedBridgeLegacy;

IChainTypeManager internal chainTypeManager;

function setUp() public {
Expand All @@ -90,7 +92,7 @@ abstract contract SharedL2ContractDeployer is Test, DeployUtils {
beaconProxyBytecodeHash := extcodehash(beaconProxy)
}

address l2SharedBridge = deployL2SharedBridgeLegacy(
sharedBridgeLegacy = deployL2SharedBridgeLegacy(
L1_CHAIN_ID,
ERA_CHAIN_ID,
ownerWallet,
Expand All @@ -105,7 +107,7 @@ abstract contract SharedL2ContractDeployer is Test, DeployUtils {
l1ChainId: L1_CHAIN_ID,
eraChainId: ERA_CHAIN_ID,
l1AssetRouter: l1AssetRouter,
legacySharedBridge: l2SharedBridge,
legacySharedBridge: sharedBridgeLegacy,
l2TokenBeacon: address(beacon),
l2TokenProxyBytecodeHash: beaconProxyBytecodeHash,
aliasedOwner: ownerWallet,
Expand Down
Loading

0 comments on commit 2bcd5de

Please sign in to comment.