Skip to content

Commit

Permalink
Merge branch 'sync-layer-stable' into sb-use-l2-chain-admin
Browse files Browse the repository at this point in the history
  • Loading branch information
StanislavBreadless committed Nov 20, 2024
2 parents 128ad4f + 5599678 commit e864827
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 14 deletions.
10 changes: 3 additions & 7 deletions l1-contracts/contracts/upgrades/GatewayUpgrade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {GatewayUpgradeFailed} from "./ZkSyncUpgradeErrors.sol";

import {IGatewayUpgrade} from "./IGatewayUpgrade.sol";
import {IL2ContractDeployer} from "../common/interfaces/IL2ContractDeployer.sol";
import {L1GatewayHelper} from "./L1GatewayHelper.sol";
import {L1GatewayBase} from "./L1GatewayBase.sol";

// solhint-disable-next-line gas-struct-packing
struct GatewayUpgradeEncodedInput {
Expand All @@ -29,7 +29,7 @@ struct GatewayUpgradeEncodedInput {
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice This upgrade will be used to migrate Era to be part of the ZK chain ecosystem contracts.
contract GatewayUpgrade is BaseZkSyncUpgrade {
contract GatewayUpgrade is BaseZkSyncUpgrade, L1GatewayBase {
using PriorityQueue for PriorityQueue.Queue;
using PriorityTree for PriorityTree.Tree;

Expand Down Expand Up @@ -61,11 +61,7 @@ contract GatewayUpgrade is BaseZkSyncUpgrade {
bytes memory gatewayUpgradeCalldata = abi.encode(
encodedInput.ctmDeployer,
encodedInput.fixedForceDeploymentsData,
L1GatewayHelper.getZKChainSpecificForceDeploymentsData(
s,
encodedInput.wrappedBaseTokenStore,
s.__DEPRECATED_baseToken
)
getZKChainSpecificForceDeploymentsData(s, encodedInput.wrappedBaseTokenStore, s.__DEPRECATED_baseToken)
);
encodedInput.forceDeployments[encodedInput.l2GatewayUpgradePosition].input = gatewayUpgradeCalldata;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import {ZKChainStorage} from "../state-transition/chain-deps/ZKChainStorage.sol"
import {L2WrappedBaseTokenStore} from "../bridge/L2WrappedBaseTokenStore.sol";
import {IERC20Metadata} from "@openzeppelin/contracts-v4/token/ERC20/extensions/IERC20Metadata.sol";

/// @title L1GatewayHelper
/// @title L1GatewayBase
/// @author Matter Labs
/// @custom:security-contact [email protected]
library L1GatewayHelper {
abstract contract L1GatewayBase {
/// @notice The function to retrieve the chain-specific upgrade data.
/// @param s The pointer to the storage of the chain.
/// @param _wrappedBaseTokenStore The address of the `L2WrappedBaseTokenStore` contract.
Expand Down Expand Up @@ -43,8 +43,18 @@ library L1GatewayHelper {
baseTokenName = string("Ether");
baseTokenSymbol = string("ETH");
} else {
baseTokenName = IERC20Metadata(_baseTokenAddress).name();
baseTokenSymbol = IERC20Metadata(_baseTokenAddress).symbol();
try this.getTokenName(_baseTokenAddress) returns (string memory name) {
baseTokenName = name;
} catch {
baseTokenName = string("Base Token");
}

try this.getTokenSymbol(_baseTokenAddress) returns (string memory symbol) {
baseTokenSymbol = symbol;
} catch {
// "BT" is an acronym for "Base Token"
baseTokenSymbol = string("BT");
}
}

ZKChainSpecificForceDeploymentsData
Expand All @@ -58,4 +68,12 @@ library L1GatewayHelper {
});
return abi.encode(additionalForceDeploymentsData);
}

function getTokenName(address _token) external view returns (string memory) {
return IERC20Metadata(_token).name();
}

function getTokenSymbol(address _token) external view returns (string memory) {
return IERC20Metadata(_token).symbol();
}
}
6 changes: 3 additions & 3 deletions l1-contracts/contracts/upgrades/L1GenesisUpgrade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import {IBridgehub} from "../bridgehub/IBridgehub.sol";

import {VerifierParams} from "../state-transition/chain-interfaces/IVerifier.sol";
import {L2ContractHelper} from "../common/libraries/L2ContractHelper.sol";
import {L1GatewayHelper} from "./L1GatewayHelper.sol";
import {L1GatewayBase} from "./L1GatewayBase.sol";

/// @author Matter Labs
/// @custom:security-contact [email protected]
contract L1GenesisUpgrade is IL1GenesisUpgrade, BaseZkSyncUpgradeGenesis {
contract L1GenesisUpgrade is IL1GenesisUpgrade, BaseZkSyncUpgradeGenesis, L1GatewayBase {
/// @notice The main function that will be called by the Admin facet.
/// @param _l1GenesisUpgrade the address of the l1 genesis upgrade
/// @param _chainId the chain id
Expand All @@ -46,7 +46,7 @@ contract L1GenesisUpgrade is IL1GenesisUpgrade, BaseZkSyncUpgradeGenesis {
{
bytes memory complexUpgraderCalldata;
{
bytes memory additionalForceDeploymentsData = L1GatewayHelper.getZKChainSpecificForceDeploymentsData(
bytes memory additionalForceDeploymentsData = getZKChainSpecificForceDeploymentsData(
s,
address(0),
baseTokenAddress
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "forge-std/Test.sol";
import {L1GatewayBase} from "contracts/upgrades/L1GatewayBase.sol"; // Adjust the import path accordingly
import {ZKChainStorage} from "contracts/state-transition/chain-deps/ZKChainStorage.sol";
import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol";
import {IL1SharedBridgeLegacy} from "contracts/bridge/interfaces/IL1SharedBridgeLegacy.sol";
import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol";
import {ZKChainSpecificForceDeploymentsData} from "contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol";

// Concrete implementation of L1GatewayBase for testing
contract TestL1GatewayBase is L1GatewayBase {
ZKChainStorage s;

// For testing, we need to be able to call the internal function from outside
function requestGetZKChainSpecificForceDeploymentsData(
address _wrappedBaseTokenStore,
address _baseTokenAddress
) external view returns (bytes memory) {
return getZKChainSpecificForceDeploymentsData(s, _wrappedBaseTokenStore, _baseTokenAddress);
}

function setChainId(uint256 _chainId) external {
s.chainId = _chainId;
}

function setBaseTokenAssetId(bytes32 _assetId) external {
s.baseTokenAssetId = _assetId;
}

function setBrideghub(address _bridgehub) external {
s.bridgehub = _bridgehub;
}
}

contract MockERC20TokenWithMetadata {
string private _name;
string private _symbol;

constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}

function name() external view returns (string memory) {
return _name;
}

function symbol() external view returns (string memory) {
return _symbol;
}
}

contract MockERC20TokenWithoutMetadata {}

contract L1GatewayBaseTest is Test {
TestL1GatewayBase testGateway;
// Mocks for dependencies
address bridgehubMock;
address sharedBridgeMock;
// MockL2WrappedBaseTokenStore wrappedBaseTokenStoreMock;

// Addresses
address sharedBridgeAddress;
address legacySharedBridgeAddress;

// Chain ID for testing
uint256 chainId = 123;
bytes32 baseTokenAssetId;

function setUp() public {
baseTokenAssetId = bytes32("baseTokenAssetId");
bridgehubMock = makeAddr("bridgehubMock");
sharedBridgeMock = makeAddr("sharedBridgeMock");
legacySharedBridgeAddress = makeAddr("legacySharedBridgeAddress");

testGateway = new TestL1GatewayBase();

// Initialize ZKChainStorage
testGateway.setChainId(chainId);
testGateway.setBrideghub(bridgehubMock);
// Set base token asset ID
testGateway.setBaseTokenAssetId(baseTokenAssetId);

vm.mockCall(bridgehubMock, abi.encodeCall(IBridgehub.sharedBridge, ()), abi.encode(sharedBridgeMock));
vm.mockCall(
sharedBridgeMock,
abi.encodeCall(IL1SharedBridgeLegacy.l2BridgeAddress, (chainId)),
abi.encode(address(legacySharedBridgeAddress))
);
}

// Test with ETH as the base token
function testWithETH() public {
// No wrapped base token store
address _wrappedBaseTokenStore = address(0);

// Call the function
bytes memory data = testGateway.requestGetZKChainSpecificForceDeploymentsData(
_wrappedBaseTokenStore,
ETH_TOKEN_ADDRESS
);

// Decode the returned data
ZKChainSpecificForceDeploymentsData memory chainData = abi.decode(data, (ZKChainSpecificForceDeploymentsData));

// Check the values
assertEq(chainData.baseTokenAssetId, baseTokenAssetId);
assertEq(chainData.l2LegacySharedBridge, legacySharedBridgeAddress);
assertEq(chainData.predeployedL2WethAddress, address(0));
assertEq(chainData.baseTokenL1Address, ETH_TOKEN_ADDRESS);
assertEq(chainData.baseTokenName, "Ether");
assertEq(chainData.baseTokenSymbol, "ETH");
}

// Test with ERC20 that correctly implements metadata
function testWithERC20TokenWithMetadata() public {
// Deploy a mock ERC20 token that implements name() and symbol()
MockERC20TokenWithMetadata token = new MockERC20TokenWithMetadata("Test Token", "TTK");

// No wrapped base token store
address _wrappedBaseTokenStore = address(0);

// Call the function
bytes memory data = testGateway.requestGetZKChainSpecificForceDeploymentsData(
_wrappedBaseTokenStore,
address(token)
);

// Decode the returned data
ZKChainSpecificForceDeploymentsData memory chainData = abi.decode(data, (ZKChainSpecificForceDeploymentsData));

// Check the values
assertEq(chainData.baseTokenAssetId, baseTokenAssetId);
assertEq(chainData.l2LegacySharedBridge, legacySharedBridgeAddress);
assertEq(chainData.predeployedL2WethAddress, address(0));
assertEq(chainData.baseTokenL1Address, address(token));
assertEq(chainData.baseTokenName, "Test Token");
assertEq(chainData.baseTokenSymbol, "TTK");
}

// Test with ERC20 that does not implement metadata
function testWithERC20TokenWithoutMetadata() public {
// Deploy a mock ERC20 token that does not implement name() and symbol()
MockERC20TokenWithoutMetadata token = new MockERC20TokenWithoutMetadata();

// No wrapped base token store
address _wrappedBaseTokenStore = address(0);

// Call the function
bytes memory data = testGateway.requestGetZKChainSpecificForceDeploymentsData(
_wrappedBaseTokenStore,
address(token)
);

// Decode the returned data
ZKChainSpecificForceDeploymentsData memory chainData = abi.decode(data, (ZKChainSpecificForceDeploymentsData));

// Check the values
assertEq(chainData.baseTokenAssetId, baseTokenAssetId);
assertEq(chainData.l2LegacySharedBridge, legacySharedBridgeAddress);
assertEq(chainData.predeployedL2WethAddress, address(0));
assertEq(chainData.baseTokenL1Address, address(token));
assertEq(chainData.baseTokenName, "Base Token");
assertEq(chainData.baseTokenSymbol, "BT");
}
}

0 comments on commit e864827

Please sign in to comment.