Skip to content

Commit

Permalink
Merge branch 'dev' into deniallugo-chain-registrator
Browse files Browse the repository at this point in the history
  • Loading branch information
Deniallugo committed Nov 25, 2024
2 parents 8ceaa5b + d1d4391 commit 2953478
Show file tree
Hide file tree
Showing 66 changed files with 2,894 additions and 1,878 deletions.
36 changes: 35 additions & 1 deletion .github/workflows/system-contracts-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: nightly-2023-04-17
toolchain: nightly-2024-08-01

- name: Restore artifacts cache
uses: actions/cache/restore@v3
Expand Down Expand Up @@ -143,3 +143,37 @@ jobs:
- name: Print output logs of era_test_node
if: always()
run: cat era_test_node.log

check-hashes:
needs: [build]
runs-on: ubuntu-latest

steps:
- name: Checkout the repository
uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.18.0
cache: yarn

- name: Install dependencies
run: yarn

- name: Restore artifacts cache
uses: actions/cache/restore@v3
with:
fail-on-cache-miss: true
key: artifacts-system-${{ github.sha }}
path: |
system-contracts/zkout
system-contracts/cache-forge
system-contracts/bootloader/build
system-contracts/artifacts-zk
system-contracts/cache-zk
system-contracts/typechain
system-contracts/contracts-preprocessed
- name: Check hashes
run: yarn sc calculate-hashes:check
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ l1-contracts/script-config/*
l1-contracts/script-out/*
!l1-contracts/script-out/.gitkeep
*.timestamp
l1-contracts/test/foundry/l1/integration/deploy-scripts/script-out/*
l1-contracts/zkout/*
2 changes: 2 additions & 0 deletions .solhintignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ l1-contracts/lib
l1-contracts/node_modules
l1-contracts/contracts/dev-contracts
l1-contracts/test
l1-contracts/deploy-scripts

# l1-contracts-foundry
l1-contracts-foundry/cache
Expand All @@ -16,6 +17,7 @@ l1-contracts-foundry/lib
# l2-contracts
l2-contracts/cache-zk
l2-contracts/node_modules
l2-contracts/contracts/dev-contracts

# system-contracts
system-contracts/contracts/openzeppelin
Expand Down
22 changes: 16 additions & 6 deletions l1-contracts/contracts/bridge/L1SharedBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {ETH_TOKEN_ADDRESS, TWO_BRIDGES_MAGIC_VALUE} from "../common/Config.sol";
import {IBridgehub, L2TransactionRequestTwoBridgesInner, L2TransactionRequestDirect} from "../bridgehub/IBridgehub.sol";
import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol";
import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "../common/L2ContractAddresses.sol";
import {Unauthorized, ZeroAddress, SharedBridgeValueAlreadySet, SharedBridgeKey, NoFundsTransferred, ZeroBalance, ValueMismatch, TokensWithFeesNotSupported, NonEmptyMsgValue, L2BridgeNotSet, TokenNotSupported, DepositIncorrectAmount, EmptyDeposit, DepositExists, AddressAlreadyUsed, InvalidProof, DepositDoesNotExist, InsufficientChainBalance, SharedBridgeValueNotSet, WithdrawalAlreadyFinalized, WithdrawFailed, L2WithdrawalMessageWrongLength, InvalidSelector, SharedBridgeBalanceMismatch, SharedBridgeValueNotSet} from "../common/L1ContractErrors.sol";
import {Unauthorized, ZeroAddress, SharedBridgeValueAlreadySet, SharedBridgeKey, NoFundsTransferred, ZeroBalance, ValueMismatch, TokensWithFeesNotSupported, NonEmptyMsgValue, L2BridgeNotSet, TokenNotSupported, DepositIncorrectAmount, EmptyDeposit, DepositExists, AddressAlreadyUsed, InvalidProof, DepositDoesNotExist, InsufficientChainBalance, SharedBridgeValueNotSet, WithdrawalAlreadyFinalized, WithdrawFailed, L2WithdrawalMessageWrongLength, InvalidSelector, SharedBridgeBalanceMismatch, SharedBridgeValueNotSet, NotPendingAdmin, L2BridgeAlreadySet} from "../common/L1ContractErrors.sol";

/// @author Matter Labs
/// @custom:security-contact [email protected]
Expand Down Expand Up @@ -130,7 +130,9 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade

/// @notice Checks that the message sender is either the owner or admin.
modifier onlyOwnerOrAdmin() {
require(msg.sender == owner() || msg.sender == admin, "ShB not owner or admin");
if (msg.sender != owner() && msg.sender != admin) {
revert Unauthorized(msg.sender);
}
_;
}

Expand Down Expand Up @@ -174,7 +176,9 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade
/// @notice Accepts transfer of admin rights. Only pending admin can accept the role.
function acceptAdmin() external {
address currentPendingAdmin = pendingAdmin;
require(msg.sender == currentPendingAdmin, "ShB not pending admin"); // Only proposed by current admin address can claim the admin rights
if (msg.sender != currentPendingAdmin) {
revert NotPendingAdmin();
}

address previousAdmin = admin;
admin = currentPendingAdmin;
Expand Down Expand Up @@ -276,8 +280,12 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade
/// @param _chainId The chain ID for which the l2Bridge address is being initialized.
/// @param _l2BridgeAddress The address of the L2 bridge contract.
function initializeChainGovernance(uint256 _chainId, address _l2BridgeAddress) external onlyOwnerOrAdmin {
require(l2BridgeAddress[_chainId] == address(0), "ShB: l2 bridge already set");
require(_l2BridgeAddress != address(0), "ShB: l2 bridge 0");
if (l2BridgeAddress[_chainId] != address(0)) {
revert L2BridgeAlreadySet(_chainId);
}
if (_l2BridgeAddress == address(0)) {
revert ZeroAddress();
}
l2BridgeAddress[_chainId] = _l2BridgeAddress;
}

Expand All @@ -287,7 +295,9 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade
/// @param _chainId The chain ID for which the l2Bridge address is being initialized.
/// @param _l2BridgeAddress The address of the L2 bridge contract.
function reinitializeChainGovernance(uint256 _chainId, address _l2BridgeAddress) external onlyOwner {
require(l2BridgeAddress[_chainId] != address(0), "ShB: l2 bridge not yet set");
if (l2BridgeAddress[_chainId] == address(0)) {
revert L2BridgeNotSet(_chainId);
}
l2BridgeAddress[_chainId] = _l2BridgeAddress;
}

Expand Down
26 changes: 26 additions & 0 deletions l1-contracts/contracts/common/L1ContractErrors.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

// 0x5ecf2d7a
error AccessToFallbackDenied(address target, address invoker);
// 0x3995f750
error AccessToFunctionDenied(address target, bytes4 selector, address invoker);
// 0x6c167909
error OnlySelfAllowed();
// 0x52e22c98
error RestrictionWasNotPresent(address restriction);
// 0xf126e113
error RestrictionWasAlreadyPresent(address restriction);
// 0x3331e9c0
error CallNotAllowed(bytes call);
// 0x59e1b0d2
error ChainZeroAddress();
// 0xff4bbdf1
error NotAHyperchain(address chainAddress);
// 0xa3decdf3
error NotAnAdmin(address expected, address actual);
// 0xf6fd7071
error RemovingPermanentRestriction();
// 0xfcb9b2e1
error UnallowedImplementation(bytes32 implementationHash);
// 0x1ff9d522
error AddressAlreadyUsed(address addr);
// 0x86bb51b8
Expand Down Expand Up @@ -115,6 +137,8 @@ error InvalidValue();
error L2BridgeNotDeployed(uint256 chainId);
// 0xff8811ff
error L2BridgeNotSet(uint256 chainId);
// 0x685577fa
error L2BridgeAlreadySet(uint256 chainId);
// 0xcb5e4247
error L2BytecodeHashMismatch(bytes32 expected, bytes32 provided);
// 0xfb5c22e6
Expand Down Expand Up @@ -171,6 +195,8 @@ error NonZeroAddress(address);
error NotEnoughGas();
// 0xdd7e3621
error NotInitializedReentrancyGuard();
// 0x058d9a1b
error NotPendingAdmin();
// 0xf3ed9dfa
error OnlyEraSupported();
// 0x1a21feed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity 0.8.24;

import {IGovernance} from "../../governance/IGovernance.sol";
import {Call} from "../../governance/Common.sol";

contract ReenterGovernance {
// add this to be excluded from coverage report
Expand All @@ -12,7 +13,7 @@ contract ReenterGovernance {

// Store call, predecessor and salt separately,
// because Operation struct can't be stored on storage.
IGovernance.Call call;
Call call;
bytes32 predecessor;
bytes32 salt;

Expand Down Expand Up @@ -45,7 +46,7 @@ contract ReenterGovernance {
fallback() external payable {
if (!alreadyReentered) {
alreadyReentered = true;
IGovernance.Call[] memory calls = new IGovernance.Call[](1);
Call[] memory calls = new Call[](1);
calls[0] = call;
IGovernance.Operation memory op = IGovernance.Operation({
calls: calls,
Expand Down
13 changes: 13 additions & 0 deletions l1-contracts/contracts/governance/Common.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

/// @dev Represents a call to be made during multicall.
/// @param target The address to which the call will be made.
/// @param value The amount of Ether (in wei) to be sent along with the call.
/// @param data The calldata to be executed on the `target` address.
struct Call {
address target;
uint256 value;
bytes data;
}
1 change: 1 addition & 0 deletions l1-contracts/contracts/governance/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.24;

import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol";
import {IGovernance} from "./IGovernance.sol";
import {Call} from "./Common.sol";
import {ZeroAddress, Unauthorized, OperationMustBeReady, OperationMustBePending, OperationExists, InvalidDelay, PreviousOperationNotExecuted} from "../common/L1ContractErrors.sol";

/// @author Matter Labs
Expand Down
12 changes: 2 additions & 10 deletions l1-contracts/contracts/governance/IGovernance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version.
pragma solidity ^0.8.21;

import {Call} from "./Common.sol";

/// @title Governance contract interface
/// @author Matter Labs
/// @custom:security-contact [email protected]
Expand All @@ -18,16 +20,6 @@ interface IGovernance {
Done
}

/// @dev Represents a call to be made during an operation.
/// @param target The address to which the call will be made.
/// @param value The amount of Ether (in wei) to be sent along with the call.
/// @param data The calldata to be executed on the `target` address.
struct Call {
address target;
uint256 value;
bytes data;
}

/// @dev Defines the structure of an operation that Governance executes.
/// @param calls An array of `Call` structs, each representing a call to be made during the operation.
/// @param predecessor The hash of the predecessor operation, that should be executed before this operation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ contract GettersFacet is ZkSyncHyperchainBase, IGetters, ILegacyGetters {
return s.bridgehub;
}

/// @inheritdoc IGetters
function getChainId() external view returns (uint256) {
return s.chainId;
}

/// @inheritdoc IGetters
function getStateTransitionManager() external view returns (address) {
return s.stateTransitionManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ interface IGetters is IZkSyncHyperchainBase {
/// @return The address of the base token
function getBaseToken() external view returns (address);

/// @return The chain id of the ZK Chain.
function getChainId() external view returns (uint256);

/// @return The address of the base token bridge
function getBaseTokenBridge() external view returns (address);

Expand Down
11 changes: 9 additions & 2 deletions l1-contracts/deploy-scripts/DeployL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,17 @@ contract DeployL1Script is Script {
}

function deployChainAdmin() internal {
bytes memory bytecode = abi.encodePacked(
bytes memory accessControlRestrictionBytecode = abi.encodePacked(
type(ChainAdmin).creationCode,
abi.encode(config.ownerAddress, address(0))
abi.encode(uint256(0), config.ownerAddress)
);

address accessControlRestriction = deployViaCreate2(accessControlRestrictionBytecode);
console.log("Access control restriction deployed at:", accessControlRestriction);
address[] memory restrictions = new address[](1);
restrictions[0] = accessControlRestriction;

bytes memory bytecode = abi.encodePacked(type(ChainAdmin).creationCode, abi.encode(restrictions));
address contractAddress = deployViaCreate2(bytecode);
console.log("ChainAdmin deployed at:", contractAddress);
addresses.chainAdmin = contractAddress;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol";
import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol";
import {IStateTransitionManager} from "contracts/state-transition/IStateTransitionManager.sol";
import {IGovernance} from "contracts/governance/IGovernance.sol";
import {IChainAdmin} from "contracts/governance/IChainAdmin.sol";
import {Call} from "contracts/governance/Common.sol";
import {Utils} from "./Utils.sol";

/**
Expand Down Expand Up @@ -106,24 +108,24 @@ contract PrepareZKChainRegistrationCalldataScript is Script {

checkBaseTokenAddress();

IGovernance.Call[] memory calls;
Call[] memory calls;
uint256 cnt = 0;
if (!IBridgehub(ecosystem.bridgehub).tokenIsRegistered(config.baseToken)) {
calls = new IGovernance.Call[](2);
calls = new Call[](2);
console.log("Adding a call to register base token on the bridgehub");
IGovernance.Call memory baseTokenRegistrationCall = prepareRegisterBaseTokenCall();
Call memory baseTokenRegistrationCall = prepareRegisterBaseTokenCall();
calls[cnt] = baseTokenRegistrationCall;
++cnt;
} else {
calls = new IGovernance.Call[](1);
calls = new Call[](1);
}

IGovernance.Call memory registerChainCall = prepareRegisterHyperchainCall();
Call memory registerChainCall = prepareRegisterHyperchainCall();
calls[cnt] = registerChainCall;
++cnt;

address l2SharedBridgeProxy = computeL2BridgeAddress();
IGovernance.Call memory initChainCall = prepareInitializeChainGovernanceCall(l2SharedBridgeProxy);
Call memory initChainCall = prepareInitializeChainGovernanceCall(l2SharedBridgeProxy);

scheduleTransparentCalldata(calls, initChainCall);
}
Expand Down Expand Up @@ -178,12 +180,12 @@ contract PrepareZKChainRegistrationCalldataScript is Script {
console.log("Using base token address:", config.baseToken);
}

function prepareRegisterBaseTokenCall() internal view returns (IGovernance.Call memory) {
function prepareRegisterBaseTokenCall() internal view returns (Call memory) {
Bridgehub bridgehub = Bridgehub(ecosystem.bridgehub);

bytes memory data = abi.encodeCall(bridgehub.addToken, (config.baseToken));

return IGovernance.Call({target: ecosystem.bridgehub, value: 0, data: data});
return Call({target: ecosystem.bridgehub, value: 0, data: data});
}

// @dev Computes the address of the L2 bridge and the L2 bridge proxy
Expand Down Expand Up @@ -267,7 +269,7 @@ contract PrepareZKChainRegistrationCalldataScript is Script {
return proxyContractAddress;
}

function prepareRegisterHyperchainCall() internal view returns (IGovernance.Call memory) {
function prepareRegisterHyperchainCall() internal view returns (Call memory) {
Bridgehub bridgehub = Bridgehub(ecosystem.bridgehub);

bytes memory data = abi.encodeCall(
Expand All @@ -282,26 +284,21 @@ contract PrepareZKChainRegistrationCalldataScript is Script {
)
);

return IGovernance.Call({target: ecosystem.bridgehub, value: 0, data: data});
return Call({target: ecosystem.bridgehub, value: 0, data: data});
}

function prepareInitializeChainGovernanceCall(
address l2SharedBridgeProxy
) internal view returns (IGovernance.Call memory) {
function prepareInitializeChainGovernanceCall(address l2SharedBridgeProxy) internal view returns (Call memory) {
L1SharedBridge bridge = L1SharedBridge(ecosystem.l1SharedBridgeProxy);

bytes memory data = abi.encodeCall(bridge.initializeChainGovernance, (config.chainId, l2SharedBridgeProxy));

return IGovernance.Call({target: ecosystem.l1SharedBridgeProxy, value: 0, data: data});
return Call({target: ecosystem.l1SharedBridgeProxy, value: 0, data: data});
}

// @dev Prepares a call to schedule a transparent operation on the governance contract
// `calls` is an array of calls that will be executed in the first stage (add a token to BH, create a new chain)
// `initChainGovCall` is a call that will be executed in the second stage (register the L2 bridge on the L1 shared bridge)
function scheduleTransparentCalldata(
IGovernance.Call[] memory calls,
IGovernance.Call memory initChainGovCall
) internal {
function scheduleTransparentCalldata(Call[] memory calls, Call memory initChainGovCall) internal {
IGovernance governance = IGovernance(ecosystem.governance);

IGovernance.Operation memory operation = IGovernance.Operation({
Expand All @@ -313,7 +310,7 @@ contract PrepareZKChainRegistrationCalldataScript is Script {
bytes memory scheduleCalldata = abi.encodeCall(governance.scheduleTransparent, (operation, 0));
bytes memory executeCalldata = abi.encodeCall(governance.execute, (operation));

IGovernance.Call[] memory initChainGovArray = new IGovernance.Call[](1);
Call[] memory initChainGovArray = new Call[](1);
initChainGovArray[0] = initChainGovCall;

IGovernance.Operation memory operation2 = IGovernance.Operation({
Expand Down
Loading

0 comments on commit 2953478

Please sign in to comment.