Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions system-contracts/contracts/test-deps/l2-upgrades/Deps.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
// 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;

uint160 constant SYSTEM_CONTRACTS_OFFSET = 0x8000; // 2^15
address constant L2_DEPLOYER_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x06);
address constant L2_FORCE_DEPLOYER_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x07);
address constant L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0b);

address constant GW_ASSET_TRACKER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0f);
address constant L2_ASSET_TRACKER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0e);
address constant L2_ASSET_ROUTER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x03);
address constant L2_BRIDGEHUB_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x02);
address constant L2_CHAIN_ASSET_HANDLER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0a);
address constant L2_DEPLOYER_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x06);
address constant L2_MESSAGE_ROOT_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x05);
address constant L2_NATIVE_TOKEN_VAULT_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x04);
address constant L2_NTV_BEACON_DEPLOYER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0b);
address constant L2_WRAPPED_BASE_TOKEN_IMPL_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x07);


error Unauthorized(address sender);
error AddressHasNoCode(address addr);
error InvalidChainId();
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.28;

/// @notice Interface for contract deployer system hook on ZKsyncOS.
/// @dev Note, that the actual implementation of this interface is implemented in Rust
/// as a system hook.
interface IZKOSContractDeployer {
/// @notice Sets the bytecode details for a contract on ZKsyncOS.
/// @dev This function is used to set the bytecode details for a contract on ZKsyncOS,
/// it is an alternative to the `forceDeployOnAddresses` function from Era.
/// @param _addr The address of the contract.
/// @param _bytecodeHash The hash of the bytecode.
/// @param _bytecodeLength The length of the bytecode.
/// @param _observableBytecodeHash The hash of the observable bytecode.
function setBytecodeDetailsEVM(
address _addr,
bytes32 _bytecodeHash,
uint32 _bytecodeLength,
bytes32 _observableBytecodeHash
) external;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.28;

import {IContractDeployer as IL2ContractDeployer } from "../../interfaces/IContractDeployer.sol";

import {IComplexUpgrader} from "../../interfaces/IComplexUpgrader.sol";

import {L2GenesisForceDeploymentsHelper} from "./L2GenesisForceDeploymentsHelper.sol";

/**
* @author Matter Labs
* @custom:security-contact [email protected]
* @notice Upgrader which should be used to perform complex multistep upgrades on L2. In case some custom logic for an upgrade is needed
* this logic should be deployed into the user space and then this contract will delegatecall to the deployed contract.
*/
contract L2ComplexUpgrader is IComplexUpgrader {
/// @notice Ensures that only the `FORCE_DEPLOYER` can call the function.
/// @dev Note that it is vital to put this modifier at the start of *each* function,
/// since even temporary anauthorized access can be dangerous.
modifier onlyForceDeployer() {
// Note, that it is not
if (msg.sender != L2_FORCE_DEPLOYER_ADDR) {
revert Unauthorized(msg.sender);
}
_;
}

/// @notice Executes an upgrade process by delegating calls to another contract.
/// @dev This function allows only the `FORCE_DEPLOYER` to initiate the upgrade.
/// If the delegate call fails, the function will revert the transaction, returning the error message
/// provided by the delegated contract.
/// @dev Compatible with Era only.
/// @param _forceDeployments the list of initial deployments that should be performed before the upgrade.
/// They would typically, though not necessarily include the deployment of the upgrade implementation itself.
/// @param _delegateTo the address of the contract to which the calls will be delegated
/// @param _calldata the calldata to be delegate called in the `_delegateTo` contract
function forceDeployAndUpgrade(
IL2ContractDeployer.ForceDeployment[] calldata _forceDeployments,
address _delegateTo,
bytes calldata _calldata
) external payable onlyForceDeployer {
IL2ContractDeployer(L2_DEPLOYER_SYSTEM_CONTRACT_ADDR).forceDeployOnAddresses(_forceDeployments);

upgrade(_delegateTo, _calldata);
}

/// @notice Executes an upgrade process by delegating calls to another contract.
/// @dev Similar to `forceDeployAndUpgrade`, but allows for universal force deployments, that
/// work for both ZKsyncOS and Era.
/// @param _forceDeployments the list of initial deployments that should be performed before the upgrade.
/// They would typically, though not necessarily include the deployment of the upgrade implementation itself.
/// @param _delegateTo the address of the contract to which the calls will be delegated
/// @param _calldata the calldata to be delegate called in the `_delegateTo` contract
function forceDeployAndUpgradeUniversal(
UniversalForceDeploymentInfo[] calldata _forceDeployments,
address _delegateTo,
bytes calldata _calldata
) external payable onlyForceDeployer {
// solhint-disable-next-line gas-length-in-loops
for (uint256 i = 0; i < _forceDeployments.length; ++i) {
L2GenesisForceDeploymentsHelper.forceDeployOnAddress(
_forceDeployments[i].isZKsyncOS,
_forceDeployments[i].deployedBytecodeInfo,
_forceDeployments[i].newAddress
);
}

upgrade(_delegateTo, _calldata);
}

/// @notice Executes an upgrade process by delegating calls to another contract.
/// @dev This function allows only the `FORCE_DEPLOYER` to initiate the upgrade.
/// If the delegate call fails, the function will revert the transaction, returning the error message
/// provided by the delegated contract.
/// @param _delegateTo the address of the contract to which the calls will be delegated
/// @param _calldata the calldata to be delegate called in the `_delegateTo` contract
function upgrade(address _delegateTo, bytes calldata _calldata) public payable onlyForceDeployer {
if (_delegateTo.code.length == 0) {
revert AddressHasNoCode(_delegateTo);
}
// slither-disable-next-line controlled-delegatecall
(bool success, bytes memory returnData) = _delegateTo.delegatecall(_calldata);
assembly {
if iszero(success) {
revert(add(returnData, 0x20), mload(returnData))
}
}
}
}
Loading
Loading