Skip to content

Commit

Permalink
Sync layer stable toolbox (#806)
Browse files Browse the repository at this point in the history
  • Loading branch information
StanislavBreadless committed Sep 20, 2024
1 parent 6b1f483 commit b3c30ae
Show file tree
Hide file tree
Showing 30 changed files with 2,255 additions and 719 deletions.
18 changes: 12 additions & 6 deletions .github/workflows/l1-contracts-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
node-version: 18.18.0
cache: yarn

- name: Use Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Install dependencies
run: yarn

Expand All @@ -39,19 +42,22 @@ jobs:
- name: Build l1 artifacts
run: yarn l1 build

- name: Build da-contracts artifacts
run: yarn da build:foundry

- name: Create cache
uses: actions/cache/save@v3
with:
key: artifacts-l1-${{ github.sha }}
path: |
da-contracts/out
l1-contracts/artifacts
l1-contracts/artifacts-zk
l1-contracts/cache
l1-contracts/typechain
l2-contracts/artifacts-zk
l2-contracts/cache-zk
l2-contracts/typechain
l1-contracts/lib
lint:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -100,14 +106,14 @@ jobs:
fail-on-cache-miss: true
key: artifacts-l1-${{ github.sha }}
path: |
da-contracts/out
l1-contracts/artifacts
l1-contracts/artifacts-zk
l1-contracts/cache
l1-contracts/typechain
l2-contracts/artifacts-zk
l2-contracts/cache-zk
l2-contracts/typechain
l1-contracts/lib
- name: Run tests
working-directory: ./l1-contracts
Expand Down Expand Up @@ -141,14 +147,14 @@ jobs:
fail-on-cache-miss: true
key: artifacts-l1-${{ github.sha }}
path: |
da-contracts/out
l1-contracts/artifacts
l1-contracts/artifacts-zk
l1-contracts/cache
l1-contracts/typechain
l2-contracts/artifacts-zk
l2-contracts/cache-zk
l2-contracts/typechain
l1-contracts/lib
- name: Install foundry zksync
run: |
Expand Down Expand Up @@ -191,14 +197,14 @@ jobs:
fail-on-cache-miss: true
key: artifacts-l1-${{ github.sha }}
path: |
da-contracts/out
l1-contracts/artifacts
l1-contracts/artifacts-zk
l1-contracts/cache
l1-contracts/typechain
l2-contracts/artifacts-zk
l2-contracts/cache-zk
l2-contracts/typechain
l1-contracts/lib
- name: Build L2 contracts
run: yarn l2 build
Expand Down Expand Up @@ -258,14 +264,14 @@ jobs:
fail-on-cache-miss: true
key: artifacts-l1-${{ github.sha }}
path: |
da-contracts/out
l1-contracts/artifacts
l1-contracts/artifacts-zk
l1-contracts/cache
l1-contracts/typechain
l2-contracts/artifacts-zk
l2-contracts/cache-zk
l2-contracts/typechain
l1-contracts/lib
- name: Run coverage
run: FOUNDRY_PROFILE=default yarn test:foundry && FOUNDRY_PROFILE=default yarn coverage:foundry --report summary --report lcov
Expand All @@ -280,7 +286,7 @@ jobs:
- name: Filter directories
run: |
sudo apt update && sudo apt install -y lcov
lcov --remove lcov.info 'test/*' 'contracts/dev-contracts/*' '../lib/forge-std/*' '../lib/murky/*' 'lib/*' '../lib/*' 'lib/' --output-file lcov.info --rc lcov_branch_coverage=1
lcov --remove lcov.info 'test/*' 'contracts/dev-contracts/*' '../lib/forge-std/*' '../lib/murky/*' 'lib/*' '../lib/*' 'lib/' 'deploy-scripts/*' --output-file lcov.info --rc lcov_branch_coverage=1
# This step posts a detailed coverage report as a comment and deletes previous comments on
# each push. The below step is used to fail coverage if the specified coverage threshold is
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/l1-contracts-foundry-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,15 @@ jobs:
- name: Build l2 artifacts
run: yarn l2 build

- name: Build da-contracts artifacts
run: yarn da build:foundry

- name: Create cache
uses: actions/cache/save@v3
with:
key: artifacts-l1-contracts-foudry-${{ github.sha }}
path: |
da-contracts/out
l1-contracts/cache
l1-contracts/out
l1-contracts/artifacts-zk
Expand All @@ -72,6 +76,7 @@ jobs:
fail-on-cache-miss: true
key: artifacts-l1-contracts-foudry-${{ github.sha }}
path: |
da-contracts/out
l1-contracts/cache
l1-contracts/out
l1-contracts/artifacts-zk
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ l1-contracts/test/foundry/l1/integration/deploy-scripts/script-out/*.toml
!l1-contracts/script-out/.gitkeep
*.timestamp
l1-contracts/test/foundry/l1/integration/deploy-scripts/script-out/*
l1-contracts/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-zk-chain-*.toml
l1-contracts/test/foundry/integration/deploy-scripts/script-out/*
l1-contracts/zkout/*
2 changes: 1 addition & 1 deletion da-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
},
"scripts": {
"build": "hardhat compile ",
"build-l1": "harhdat compile",
"build:foundry": "forge build",
"clean": "hardhat clean",
"clean:foundry": "forge clean",
"verify": "hardhat run --network env scripts/verify.ts"
Expand Down
20 changes: 5 additions & 15 deletions l1-contracts/contracts/bridge/L2SharedBridgeLegacy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ import {ZeroAddress, EmptyBytes32, Unauthorized, AmountMustBeGreaterThanZero, De
/// @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 L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable {
/// @dev Contract is expected to be used as proxy implementation.
/// @dev Disable the initialization to prevent Parity hack.
uint256 public immutable ERA_CHAIN_ID;

/// @dev The address of the L1 shared bridge counterpart.
address public override l1SharedBridge;

Expand Down Expand Up @@ -57,19 +53,16 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable {
_;
}

constructor(uint256 _eraChainId) {
ERA_CHAIN_ID = _eraChainId;
constructor() {
_disableInitializers();
}

/// @notice Initializes the bridge contract for later use. Expected to be used in the proxy.
/// @param _l1SharedBridge The address of the L1 Bridge contract.
/// @param _l1Bridge The address of the legacy L1 Bridge contract.
/// @param _l2TokenProxyBytecodeHash The bytecode hash of the proxy for tokens deployed by the bridge.
/// @param _aliasedOwner The address of the governor contract.
function initialize(
address _l1SharedBridge,
address _l1Bridge,
bytes32 _l2TokenProxyBytecodeHash,
address _aliasedOwner
) external reinitializer(2) {
Expand All @@ -87,17 +80,14 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable {

l1SharedBridge = _l1SharedBridge;

if (block.chainid != ERA_CHAIN_ID) {
// The following statement is true only in freshly deployed environments. However,
// for those environments we do not need to deploy this contract at all.
// This check is primarily for local testing purposes.
if (l2TokenProxyBytecodeHash == bytes32(0) && address(l2TokenBeacon) == address(0)) {
address l2StandardToken = address(new BridgedStandardERC20{salt: bytes32(0)}());
l2TokenBeacon = new UpgradeableBeacon{salt: bytes32(0)}(l2StandardToken);
l2TokenProxyBytecodeHash = _l2TokenProxyBytecodeHash;
l2TokenBeacon.transferOwnership(_aliasedOwner);
} else {
if (_l1Bridge == address(0)) {
revert ZeroAddress();
}
l1Bridge = _l1Bridge;
// l2StandardToken and l2TokenBeacon are already deployed on ERA, and stored in the proxy
}
}

Expand Down
8 changes: 4 additions & 4 deletions l1-contracts/contracts/bridgehub/CTMDeploymentTracker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {ReentrancyGuard} from "../common/ReentrancyGuard.sol";
import {TWO_BRIDGES_MAGIC_VALUE} from "../common/Config.sol";
import {L2_BRIDGEHUB_ADDR} from "../common/L2ContractAddresses.sol";

/// @dev The encoding version of the data.
bytes1 constant CTM_DEPLOYMENT_TRACKER_ENCODING_VERSION = 0x01;

/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @dev Contract to be deployed on L1, can link together other contracts based on AssetInfo.
Expand All @@ -25,9 +28,6 @@ contract CTMDeploymentTracker is ICTMDeploymentTracker, ReentrancyGuard, Ownable
/// @dev Bridgehub smart contract that is used to operate with L2 via asynchronous L2 <-> L1 communication.
IAssetRouterBase public immutable override L1_ASSET_ROUTER;

/// @dev The encoding version of the data.
bytes1 internal constant ENCODING_VERSION = 0x01;

/// @notice Checks that the message sender is the bridgehub.
modifier onlyBridgehub() {
// solhint-disable-next-line gas-custom-errors
Expand Down Expand Up @@ -93,7 +93,7 @@ contract CTMDeploymentTracker is ICTMDeploymentTracker, ReentrancyGuard, Ownable

require(_originalCaller == owner(), "CTMDT: not owner");
bytes1 encodingVersion = _data[0];
require(encodingVersion == ENCODING_VERSION, "CTMDT: wrong encoding version");
require(encodingVersion == CTM_DEPLOYMENT_TRACKER_ENCODING_VERSION, "CTMDT: wrong encoding version");
(address _ctmL1Address, address _ctmL2Address) = abi.decode(_data[1:], (address, address));

request = _registerCTMAssetOnL2Bridgehub(_chainId, _ctmL1Address, _ctmL2Address);
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 @@ -197,6 +197,8 @@ interface IBridgehub is IAssetHandler, IL1AssetHandler {

function registerSettlementLayer(uint256 _newSettlementLayerChainId, bool _isWhitelisted) external;

function settlementLayer(uint256 _chainId) external view returns (uint256);

// function finalizeMigrationToGateway(
// uint256 _chainId,
// address _baseToken,
Expand Down
9 changes: 9 additions & 0 deletions l1-contracts/contracts/governance/IChainAdmin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ interface IChainAdmin {
/// @param _restriction The address of the restriction contract.
/// @dev Sometimes restrictions might need to enforce their permanence (e.g. if a chain should be a rollup forever).
function removeRestriction(address _restriction) external;

/// @notice Execute multiple calls as part of contract administration.
/// @param _calls Array of Call structures defining target, value, and data for each call.
/// @param _requireSuccess If true, reverts transaction on any call failure.
/// @dev Intended for batch processing of contract interactions, managing gas efficiency and atomicity of operations.
/// @dev Note, that this function lacks access control. It is expected that the access control is implemented in a separate restriction contract.
/// @dev Even though all the validation from external modules is executed via `staticcall`, the function
/// is marked as `nonReentrant` to prevent reentrancy attacks in case the staticcall restriction is lifted in the future.
function multicall(Call[] calldata _calls, bool _requireSuccess) external payable;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {ITransactionFilterer} from "../state-transition/chain-interfaces/ITransa
import {IBridgehub} from "../bridgehub/IBridgehub.sol";
import {IL2Bridge} from "../bridge/interfaces/IL2Bridge.sol";
import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol";
import {IL2AssetRouter} from "../bridge/asset-router/IL2AssetRouter.sol";

/// @author Matter Labs
/// @custom:security-contact [email protected]
Expand Down Expand Up @@ -82,18 +83,28 @@ contract GatewayTransactionFilterer is ITransactionFilterer, ReentrancyGuard, Ow
) external view returns (bool) {
if (sender == L1_ASSET_ROUTER) {
bytes4 l2TxSelector = bytes4(l2Calldata[:4]);

if (IL2AssetRouter.setAssetHandlerAddress.selector == l2TxSelector) {
(, bytes32 decodedAssetId, ) = abi.decode(l2Calldata[4:], (uint256, bytes32, address));
return _checkSTMAssetId(decodedAssetId);
}

if (
(IAssetRouterBase.finalizeDeposit.selector != l2TxSelector) &&
(IL2Bridge.finalizeDeposit.selector != l2TxSelector)
IAssetRouterBase.finalizeDeposit.selector != l2TxSelector &&
IL2Bridge.finalizeDeposit.selector != l2TxSelector
) {
revert InvalidSelector(l2TxSelector);
}

(, bytes32 decodedAssetId, ) = abi.decode(l2Calldata[4:], (uint256, bytes32, bytes));
address stmAddress = BRIDGE_HUB.ctmAssetIdToAddress(decodedAssetId);
return (stmAddress != address(0));
return _checkSTMAssetId(decodedAssetId);
}

return whitelistedSenders[sender];
}

function _checkSTMAssetId(bytes32 assetId) internal view returns (bool) {
address stmAddress = BRIDGE_HUB.ctmAssetIdToAddress(assetId);
return stmAddress != address(0);
}
}
54 changes: 49 additions & 5 deletions l1-contracts/deploy-scripts/AcceptAdmin.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ import {Script} from "forge-std/Script.sol";

import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol";
import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol";
import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol";
import {ChainAdmin} from "contracts/governance/ChainAdmin.sol";
import {AccessControlRestriction} from "contracts/governance/AccessControlRestriction.sol";
import {IChainAdmin} from "contracts/governance/IChainAdmin.sol";
import {Call} from "contracts/governance/Common.sol";
import {Utils} from "./Utils.sol";
import {stdToml} from "forge-std/StdToml.sol";

bytes32 constant SET_TOKEN_MULTIPLIER_SETTER_ROLE = keccak256("SET_TOKEN_MULTIPLIER_SETTER_ROLE");

contract AcceptAdmin is Script {
using stdToml for string;

Expand Down Expand Up @@ -58,20 +63,59 @@ contract AcceptAdmin is Script {
function chainAdminAcceptAdmin(ChainAdmin chainAdmin, address target) public {
IZKChain adminContract = IZKChain(target);

IChainAdmin.Call[] memory calls = new IChainAdmin.Call[](1);
calls[0] = IChainAdmin.Call({target: target, value: 0, data: abi.encodeCall(adminContract.acceptAdmin, ())});
Call[] memory calls = new Call[](1);
calls[0] = Call({target: target, value: 0, data: abi.encodeCall(adminContract.acceptAdmin, ())});

vm.startBroadcast();
chainAdmin.multicall(calls, true);
vm.stopBroadcast();
}

// This function should be called by the owner to update token multiplier setter role
function chainSetTokenMultiplierSetter(address chainAdmin, address target) public {
IChainAdmin admin = IChainAdmin(chainAdmin);
function chainSetTokenMultiplierSetter(
address accessControlRestriction,
address diamondProxyAddress,
address setter
) public {
AccessControlRestriction restriction = AccessControlRestriction(accessControlRestriction);

if (
restriction.requiredRoles(diamondProxyAddress, IAdmin.setTokenMultiplier.selector) !=
SET_TOKEN_MULTIPLIER_SETTER_ROLE
) {
vm.startBroadcast();
restriction.setRequiredRoleForCall(
diamondProxyAddress,
IAdmin.setTokenMultiplier.selector,
SET_TOKEN_MULTIPLIER_SETTER_ROLE
);
vm.stopBroadcast();
}

if (!restriction.hasRole(SET_TOKEN_MULTIPLIER_SETTER_ROLE, setter)) {
vm.startBroadcast();
restriction.grantRole(SET_TOKEN_MULTIPLIER_SETTER_ROLE, setter);
vm.stopBroadcast();
}
}

function setDAValidatorPair(
ChainAdmin chainAdmin,
address target,
address l1DaValidator,
address l2DaValidator
) public {
IZKChain adminContract = IZKChain(target);

Call[] memory calls = new Call[](1);
calls[0] = Call({
target: target,
value: 0,
data: abi.encodeCall(adminContract.setDAValidatorPair, (l1DaValidator, l2DaValidator))
});

vm.startBroadcast();
admin.setTokenMultiplierSetter(target);
chainAdmin.multicall(calls, true);
vm.stopBroadcast();
}
}
Loading

0 comments on commit b3c30ae

Please sign in to comment.