Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60a06040 | 23839876 | 86 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ValidatorTimelock
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 28000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol";
import {AccessControlEnumerablePerChainAddressUpgradeable} from "./AccessControlEnumerablePerChainAddressUpgradeable.sol";
import {LibMap} from "./libraries/LibMap.sol";
import {IZKChain} from "./chain-interfaces/IZKChain.sol";
import {NotAZKChain, TimeNotReached} from "../common/L1ContractErrors.sol";
import {IL1Bridgehub} from "../bridgehub/IL1Bridgehub.sol";
import {IValidatorTimelock} from "./IValidatorTimelock.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice Intermediate smart contract between the validator EOA account and the ZK chains state transition diamond smart contract.
/// @dev The primary purpose of this contract is to provide a trustless means of delaying batch execution without
/// modifying the main zkChain diamond contract. As such, even if this contract is compromised, it will not impact the main
/// contract.
/// @dev ZKsync actively monitors the chain activity and reacts to any suspicious activity by freezing the chain.
/// This allows time for investigation and mitigation before resuming normal operations.
/// @dev The contract overloads all of the 5 methods, that are used in state transition. When the batch is committed,
/// the timestamp is stored for it. Later, when the owner calls the batch execution, the contract checks that batch
/// was committed not earlier than X time ago.
/// @dev Expected to be deployed as a TransparentUpgradeableProxy.
contract ValidatorTimelock is
IValidatorTimelock,
Ownable2StepUpgradeable,
AccessControlEnumerablePerChainAddressUpgradeable
{
using LibMap for LibMap.Uint32Map;
/// @inheritdoc IValidatorTimelock
string public constant override getName = "ValidatorTimelock";
/// @inheritdoc IValidatorTimelock
bytes32 public constant override PRECOMMITTER_ROLE = keccak256("PRECOMMITTER_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override COMMITTER_ROLE = keccak256("COMMITTER_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override REVERTER_ROLE = keccak256("REVERTER_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override PROVER_ROLE = keccak256("PROVER_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override OPTIONAL_PRECOMMITTER_ADMIN_ROLE = keccak256("OPTIONAL_PRECOMMITTER_ADMIN_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override OPTIONAL_COMMITTER_ADMIN_ROLE = keccak256("OPTIONAL_COMMITTER_ADMIN_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override OPTIONAL_REVERTER_ADMIN_ROLE = keccak256("OPTIONAL_REVERTER_ADMIN_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override OPTIONAL_PROVER_ADMIN_ROLE = keccak256("OPTIONAL_PROVER_ADMIN_ROLE");
/// @inheritdoc IValidatorTimelock
bytes32 public constant override OPTIONAL_EXECUTOR_ADMIN_ROLE = keccak256("OPTIONAL_EXECUTOR_ADMIN_ROLE");
/// @inheritdoc IValidatorTimelock
IL1Bridgehub public immutable override BRIDGE_HUB;
/// @dev The mapping of ZK chain address => batch number => timestamp when it was committed.
mapping(address chainAddress => LibMap.Uint32Map batchNumberToTimestampMapping) internal committedBatchTimestamp;
/// @inheritdoc IValidatorTimelock
uint32 public override executionDelay;
constructor(address _bridgehubAddr) {
BRIDGE_HUB = IL1Bridgehub(_bridgehubAddr);
// Disable initialization to prevent Parity hack.
_disableInitializers();
}
/// @inheritdoc IValidatorTimelock
function initialize(address _initialOwner, uint32 _initialExecutionDelay) external initializer {
_transferOwnership(_initialOwner);
executionDelay = _initialExecutionDelay;
}
/// @inheritdoc IValidatorTimelock
function setExecutionDelay(uint32 _executionDelay) external onlyOwner {
executionDelay = _executionDelay;
emit NewExecutionDelay(_executionDelay);
}
/// @inheritdoc IValidatorTimelock
function getCommittedBatchTimestamp(address _chainAddress, uint256 _l2BatchNumber) external view returns (uint256) {
return committedBatchTimestamp[_chainAddress].get(_l2BatchNumber);
}
/// @inheritdoc IValidatorTimelock
function removeValidatorRoles(
address _chainAddress,
address _validator,
ValidatorRotationParams memory params
) public {
if (params.rotatePrecommitterRole) {
revokeRole(_chainAddress, PRECOMMITTER_ROLE, _validator);
}
if (params.rotateCommitterRole) {
revokeRole(_chainAddress, COMMITTER_ROLE, _validator);
}
if (params.rotateReverterRole) {
revokeRole(_chainAddress, REVERTER_ROLE, _validator);
}
if (params.rotateProverRole) {
revokeRole(_chainAddress, PROVER_ROLE, _validator);
}
if (params.rotateExecutorRole) {
revokeRole(_chainAddress, EXECUTOR_ROLE, _validator);
}
}
/// @inheritdoc IValidatorTimelock
function removeValidator(address _chainAddress, address _validator) public {
removeValidatorRoles(
_chainAddress,
_validator,
ValidatorRotationParams({
rotatePrecommitterRole: true,
rotateCommitterRole: true,
rotateReverterRole: true,
rotateProverRole: true,
rotateExecutorRole: true
})
);
}
/// @inheritdoc IValidatorTimelock
function removeValidatorForChainId(uint256 _chainId, address _validator) external {
removeValidator(BRIDGE_HUB.getZKChain(_chainId), _validator);
}
/// @inheritdoc IValidatorTimelock
function addValidatorRoles(
address _chainAddress,
address _validator,
ValidatorRotationParams memory params
) public {
if (params.rotatePrecommitterRole) {
grantRole(_chainAddress, PRECOMMITTER_ROLE, _validator);
}
if (params.rotateCommitterRole) {
grantRole(_chainAddress, COMMITTER_ROLE, _validator);
}
if (params.rotateReverterRole) {
grantRole(_chainAddress, REVERTER_ROLE, _validator);
}
if (params.rotateProverRole) {
grantRole(_chainAddress, PROVER_ROLE, _validator);
}
if (params.rotateExecutorRole) {
grantRole(_chainAddress, EXECUTOR_ROLE, _validator);
}
}
/// @inheritdoc IValidatorTimelock
function addValidator(address _chainAddress, address _validator) public {
addValidatorRoles(
_chainAddress,
_validator,
ValidatorRotationParams({
rotatePrecommitterRole: true,
rotateCommitterRole: true,
rotateReverterRole: true,
rotateProverRole: true,
rotateExecutorRole: true
})
);
}
/// @inheritdoc IValidatorTimelock
function addValidatorForChainId(uint256 _chainId, address _validator) external {
addValidator(BRIDGE_HUB.getZKChain(_chainId), _validator);
}
/// @inheritdoc IValidatorTimelock
function hasRoleForChainId(uint256 _chainId, bytes32 _role, address _address) public view returns (bool) {
return hasRole(BRIDGE_HUB.getZKChain(_chainId), _role, _address);
}
/// @inheritdoc IValidatorTimelock
function precommitSharedBridge(
address _chainAddress,
uint256, // _l2BlockNumber (unused in this specific implementation)
bytes calldata // _l2Block (unused in this specific implementation)
) public onlyRole(_chainAddress, PRECOMMITTER_ROLE) {
_propagateToZKChain(_chainAddress);
}
/// @inheritdoc IValidatorTimelock
function commitBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata // _batchData (unused in this specific implementation)
) external onlyRole(_chainAddress, COMMITTER_ROLE) {
unchecked {
// This contract is only a temporary solution, that hopefully will be disabled until 2106 year, so...
// It is safe to cast.
uint32 timestamp = uint32(block.timestamp);
for (uint256 i = _processBatchFrom; i <= _processBatchTo; ++i) {
committedBatchTimestamp[_chainAddress].set(i, timestamp);
}
}
_propagateToZKChain(_chainAddress);
}
/// @inheritdoc IValidatorTimelock
function revertBatchesSharedBridge(
address _chainAddress,
uint256 /*_newLastBatch*/
) external onlyRole(_chainAddress, REVERTER_ROLE) {
_propagateToZKChain(_chainAddress);
}
/// @inheritdoc IValidatorTimelock
function proveBatchesSharedBridge(
address _chainAddress,
uint256, // _processBatchFrom (unused in this specific implementation)
uint256, // _processBatchTo (unused in this specific implementation)
bytes calldata // _proofData (unused in this specific implementation)
) external onlyRole(_chainAddress, PROVER_ROLE) {
_propagateToZKChain(_chainAddress);
}
/// @inheritdoc IValidatorTimelock
function executeBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata // _batchData (unused in this specific implementation)
) external onlyRole(_chainAddress, EXECUTOR_ROLE) {
uint256 delay = executionDelay; // uint32
unchecked {
for (uint256 i = _processBatchFrom; i <= _processBatchTo; ++i) {
uint256 commitBatchTimestamp = committedBatchTimestamp[_chainAddress].get(i);
// Note: if the `commitBatchTimestamp` is zero, that means either:
// * The batch was committed, but not through this contract.
// * The batch wasn't committed at all, so execution will fail in the ZKsync contract.
// We allow executing such batches.
if (block.timestamp < commitBatchTimestamp + delay) {
revert TimeNotReached(commitBatchTimestamp + delay, block.timestamp);
}
}
}
_propagateToZKChain(_chainAddress);
}
/// @dev Call the zkChain diamond contract with the same calldata as this contract was called.
/// Note: it is called the zkChain diamond contract, not delegatecalled!
function _propagateToZKChain(address _chainAddress) internal {
assembly {
// Copy function signature and arguments from calldata at zero position into memory at pointer position
calldatacopy(0, 0, calldatasize())
// Call method of the ZK chain diamond contract returns 0 on error
let result := call(gas(), _chainAddress, 0, 0, calldatasize(), 0, 0)
// Get the size of the last return data
let size := returndatasize()
// Copy the size length of bytes from return data at zero position to pointer position
returndatacopy(0, 0, size)
// Depending on the result value
switch result
case 0 {
// End execution and revert state changes
revert(0, size)
}
default {
// Return data with length of size at pointers position
return(0, size)
}
}
}
/// @inheritdoc AccessControlEnumerablePerChainAddressUpgradeable
function _getChainAdmin(address _chainAddress) internal view override returns (address) {
// This function is expected to be rarely used and so additional checks could be added here.
// Since all ZK-chain related roles require that the owner of the `DEFAULT_ADMIN_ROLE` sets them,
// ensuring that this role is only available to chains that are part of the ecosystem is enough
// to ensure that this contract only works with such chains.
// Firstly, we check that the chain is indeed a part of the ecosystem
uint256 chainId = IZKChain(_chainAddress).getChainId();
if (IL1Bridgehub(BRIDGE_HUB).getZKChain(chainId) != _chainAddress) {
revert NotAZKChain(_chainAddress);
}
// Now, we can extract the admin
return IZKChain(_chainAddress).getAdmin();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {EnumerableSetUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/utils/structs/EnumerableSetUpgradeable.sol";
import {RoleAccessDenied, DefaultAdminTransferNotAllowed} from "../common/L1ContractErrors.sol";
/// @title Chain‑Address‑Aware Role‑Based Access Control with Enumeration
/// @notice It is an adapted version of OpenZeppelin's `AccessControlEnumerable` that keeps a completely separate
/// role registry per `chainAddress` (i.e. in case of ZK Chains it is their DiamondProxy).
/// This is useful for cross‑chain applications where the same contract state is deployed on multiple networks and a distinct set of operators
/// is required on each of them. Using address instead of chain Id allows to save up gas spent on resolving
/// the address of the `DiamondProxy` from the chainId.
/// @dev This contract purposefully does *not* inherit from OZ's `AccessControlUpgradeable` to
/// avoid global (cross‑chain) role collisions. Instead, every public method explicitly
/// takes a `_chainAddress` argument.
/// @dev Note, that the chains are identified, not by chain id, but by their Diamond Proxy address.
abstract contract AccessControlEnumerablePerChainAddressUpgradeable {
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
/// @notice Emitted when `role` is granted to `account` for a specific `chainAddress`.
/// @param chainAddress The chain address on which the role is granted.
/// @param role The granted role identifier.
/// @param account The account receiving the role.
event RoleGranted(address indexed chainAddress, bytes32 indexed role, address indexed account);
/// @notice Emitted when `role` is revoked from `account` for a specific `chainAddress`.
/// @param chainAddress The chain address on which the role is revoked.
/// @param role The revoked role identifier.
/// @param account The account losing the role.
event RoleRevoked(address indexed chainAddress, bytes32 indexed role, address indexed account);
/// @notice Emitted when the admin role that controls `role` on `chainAddress` changes.
/// @param chainAddress The chain address on which the admin role is changed.
/// @param role The affected role.
/// @param previousAdminRole The role that previously had admin privileges.
/// @param newAdminRole The new admin role.
event RoleAdminChanged(
address indexed chainAddress,
bytes32 indexed role,
bytes32 previousAdminRole,
bytes32 newAdminRole
);
/// @notice The struct representing data about each role.
/// @param members Enumerable set of members for each role.
/// @param adminRole The role that can grant or revoke rights for the role.
struct RoleData {
EnumerableSetUpgradeable.AddressSet members;
bytes32 adminRole; // 0x00 means DEFAULT_ADMIN_ROLE
}
/// @notice Mapping that stores roles for each chainAddress
mapping(address chainAddress => mapping(bytes32 role => RoleData)) private _roles;
/// @notice The default admin role.
/// @notice For each chain, the default admin role at any point of time belongs to
/// and only to the chain admin of the chain, which should be obtained by the `_getChainAdmin` function.
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @notice Ensures that `msg.sender` possesses `_role` on `_chainAddress`.
/// @param _chainAddress The chain address.
/// @param _role The required role.
modifier onlyRole(address _chainAddress, bytes32 _role) {
_checkRole(_chainAddress, _role, msg.sender);
_;
}
/// @notice Returns `true` if `_account` holds `_role` for `_chainAddress`.
/// @param _chainAddress The chain address.
/// @param _role The role identifier.
/// @param _account The account to check.
function hasRole(address _chainAddress, bytes32 _role, address _account) public view returns (bool) {
if (_role == DEFAULT_ADMIN_ROLE) {
return _account == _getChainAdmin(_chainAddress);
}
return _roles[_chainAddress][_role].members.contains(_account);
}
/// @notice Returns the admin role that controls `_role` on `_chainAddress`.
/// @dev If no admin role was explicitly set, `DEFAULT_ADMIN_ROLE` is returned.
function getRoleAdmin(address _chainAddress, bytes32 _role) public view returns (bytes32) {
if (_role == DEFAULT_ADMIN_ROLE) {
return DEFAULT_ADMIN_ROLE;
}
return _roles[_chainAddress][_role].adminRole;
}
/// @notice Returns one of the accounts that have `_role` on `_chainAddress`.
/// @param _chainAddress The chain address.
/// @param _role The role identifier.
/// @param _index A zero‑based index (ordering is not guaranteed).
/// @dev `_index` must be a value between 0 and {getRoleMemberCount}, non-inclusive.
/// @dev Does not work for `DEFAULT_ADMIN_ROLE` since it is implicitly derived as chain admin.
function getRoleMember(address _chainAddress, bytes32 _role, uint256 _index) public view returns (address) {
if (_role == DEFAULT_ADMIN_ROLE && _index == 0) {
return _getChainAdmin(_chainAddress);
}
return _roles[_chainAddress][_role].members.at(_index);
}
/// @notice Returns the number of accounts that have `_role` on `_chainAddress`.
/// @dev Does not work for `DEFAULT_ADMIN_ROLE` since it is implicitly derived as chain admin.
function getRoleMemberCount(address _chainAddress, bytes32 _role) public view returns (uint256) {
if (_role == DEFAULT_ADMIN_ROLE) {
return 1;
}
return _roles[_chainAddress][_role].members.length();
}
/// @notice Grants `_role` on `_chainAddress` to `_account`.
/// @param _chainAddress The chain address.
/// @param _role The role to grant.
/// @param _account The beneficiary account.
function grantRole(
address _chainAddress,
bytes32 _role,
address _account
) public onlyRole(_chainAddress, getRoleAdmin(_chainAddress, _role)) {
if (_role == DEFAULT_ADMIN_ROLE) {
revert DefaultAdminTransferNotAllowed();
}
if (!hasRole(_chainAddress, _role, _account)) {
// slither-disable-next-line unused-return
_roles[_chainAddress][_role].members.add(_account);
emit RoleGranted(_chainAddress, _role, _account);
}
// Silent no‑op if the role was already granted (same semantics as OZ implementation).
}
/// @notice Revokes `_role` on `_chainAddress` from `_account`.
/// @param _chainAddress The chain address.
/// @param _role The role to revoke.
/// @param _account The target account.
function revokeRole(
address _chainAddress,
bytes32 _role,
address _account
) public onlyRole(_chainAddress, getRoleAdmin(_chainAddress, _role)) {
_revokeRole(_chainAddress, _role, _account);
}
/// @notice Renounces `_role` on `_chainAddress` for the calling account.
/// @param _chainAddress The chain address.
/// @param _role The role to renounce.
function renounceRole(address _chainAddress, bytes32 _role) public onlyRole(_chainAddress, _role) {
_revokeRole(_chainAddress, _role, msg.sender);
}
/// @notice Sets a new admin role for `_role` on `_chainAddress`.
/// @param _chainAddress The chain address.
/// @param _role The role being configured.
/// @param _adminRole The role that will act as admin for `_role`.
function setRoleAdmin(
address _chainAddress,
bytes32 _role,
bytes32 _adminRole
) public onlyRole(_chainAddress, getRoleAdmin(_chainAddress, _role)) {
if (_role == DEFAULT_ADMIN_ROLE) {
revert DefaultAdminTransferNotAllowed();
}
bytes32 previousAdminRole = getRoleAdmin(_chainAddress, _role);
_roles[_chainAddress][_role].adminRole = _adminRole;
emit RoleAdminChanged(_chainAddress, _role, previousAdminRole, _adminRole);
}
/// @dev Reverts unless `_account` possesses `_role` on `_chainAddress`.
function _checkRole(address _chainAddress, bytes32 _role, address _account) internal view {
if (!hasRole(_chainAddress, _role, _account)) {
revert RoleAccessDenied(_chainAddress, _role, _account);
}
}
/// @dev Internal implementation of role revocation. Does *not* perform access checks.
function _revokeRole(address _chainAddress, bytes32 _role, address _account) internal {
if (_role == DEFAULT_ADMIN_ROLE) {
revert DefaultAdminTransferNotAllowed();
}
if (hasRole(_chainAddress, _role, _account)) {
// slither-disable-next-line unused-return
_roles[_chainAddress][_role].members.remove(_account);
emit RoleRevoked(_chainAddress, _role, _account);
}
// Silent no‑op if the role was absent (same semantics as OZ implementation).
}
/// @notice Returns the single holder of `DEFAULT_ADMIN_ROLE` on `_chainAddress`.
/// @dev Must be implemented by the inheriting contract (e.g. read from storage or a getter).
function _getChainAdmin(address _chainAddress) internal view virtual returns (address);
/// @dev Reserved storage space to allow for layout changes in future upgrades.
uint256[49] private __gap;
}// 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; /// @notice Library for storage of packed unsigned integers. /// @author Matter Labs /// @dev This library is an adaptation of the corresponding Solady library (https://github.com/vectorized/solady/blob/main/src/utils/LibMap.sol) /// @custom:security-contact [email protected] library LibMap { /// @dev A uint32 map in storage. struct Uint32Map { mapping(uint256 packedIndex => uint256 eightPackedValues) map; } /// @dev Retrieves the uint32 value at a specific index from the Uint32Map. /// @param _map The Uint32Map instance containing the packed uint32 values. /// @param _index The index of the uint32 value to retrieve. /// @return result The uint32 value at the specified index. function get(Uint32Map storage _map, uint256 _index) internal view returns (uint32 result) { unchecked { // Each storage slot can store 256 bits of data. // As uint32 is 32 bits long, 8 uint32s can be packed into one storage slot. // Hence, `_index / 8` is done to find the storage slot that contains the required uint32. uint256 mapValue = _map.map[_index / 8]; // First three bits of the original `_index` denotes the position of the uint32 in that slot. // So, '(_index & 7) * 32' is done to find the bit position of the uint32 in that storage slot. uint256 bitOffset = (_index & 7) * 32; // Shift the bits to the right and retrieve the uint32 value. result = uint32(mapValue >> bitOffset); } } /// @dev Updates the uint32 value at `_index` in `map`. /// @param _map The Uint32Map instance containing the packed uint32 values. /// @param _index The index of the uint32 value to set. /// @param _value The new value at the specified index. function set(Uint32Map storage _map, uint256 _index, uint32 _value) internal { unchecked { // Each storage slot can store 256 bits of data. // As uint32 is 32 bits long, 8 uint32s can be packed into one storage slot. // Hence, `_index / 8` is done to find the storage slot that contains the required uint32. uint256 mapIndex = _index / 8; uint256 mapValue = _map.map[mapIndex]; // First three bits of the original `_index` denotes the position of the uint32 in that slot. // So, '(_index & 7) * 32' is done to find the bit position of the uint32 in that storage slot. uint256 bitOffset = (_index & 7) * 32; // XORing a value A with B, and then with A again, gives the original value B. // We will use this property to update the uint32 value in the slot. // Shift the bits to the right and retrieve the uint32 value. uint32 oldValue = uint32(mapValue >> bitOffset); // Calculate the XOR of the new value and the existing value. uint256 newValueXorOldValue = uint256(oldValue ^ _value); // Finally, we XOR the slot with the XOR of the new value and the existing value, // shifted to its proper position. The XOR operation will effectively replace the old value with the new value. _map.map[mapIndex] = (newValueXorOldValue << bitOffset) ^ mapValue; } } }
// 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;
import {IAdmin} from "./IAdmin.sol";
import {IExecutor} from "./IExecutor.sol";
import {IGetters} from "./IGetters.sol";
import {IMailbox} from "./IMailbox.sol";
import {Diamond} from "../libraries/Diamond.sol";
interface IZKChain is IAdmin, IExecutor, IGetters, IMailbox {
// We need this structure for the server for now
event ProposeTransparentUpgrade(
Diamond.DiamondCutData diamondCut,
uint256 indexed proposalId,
bytes32 proposalSalt
);
}// 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);
// 0x0dfb42bf
error AddressAlreadySet(address addr);
// 0x86bb51b8
error AddressHasNoCode(address);
// 0x1f73225f
error AddressMismatch(address expected, address supplied);
// 0x2a5989a0
error AlreadyPermanentRollup();
// 0x0bfcef28
error AlreadyWhitelisted(address);
// 0x5e85ae73
error AmountMustBeGreaterThanZero();
// 0xfde974f4
error AssetHandlerDoesNotExist(bytes32 assetId);
// 0x64107968
error AssetHandlerNotRegistered(bytes32 assetId);
// 0xfe919e28
error AssetIdAlreadyRegistered();
// 0x1294e9e1
error AssetIdMismatch(bytes32 expected, bytes32 supplied);
// 0x04a0b7e9
error AssetIdNotSupported(bytes32 assetId);
// 0x11832de8
error AssetRouterAllowanceNotZero();
// 0x6ef9a972
error BaseTokenGasPriceDenominatorNotSet();
// 0x55ad3fd3
error BatchHashMismatch(bytes32 expected, bytes32 actual);
// 0x2078a6a0
error BatchNotExecuted(uint256 batchNumber);
// 0xbd4455ff
error BatchNumberMismatch(uint256 expectedBatchNumber, uint256 providedBatchNumber);
// 0x6cf12312
error BridgeHubAlreadyRegistered();
// 0xdb538614
error BridgeMintNotImplemented();
// 0xaa5f6180
error BurningNativeWETHNotSupported();
// 0xccdd18d2
error BytecodeAlreadyPublished(bytes32 bytecodeHash);
// 0x25d8333c
error CallerNotTimerAdmin();
// 0x3331e9c0
error CallNotAllowed(bytes call);
// 0xe85392f9
error CanOnlyProcessOneBatch();
// 0x00c6ead2
error CantExecuteUnprovenBatches();
// 0xe18cb383
error CantRevertExecutedBatch();
// 0x78d2ed02
error ChainAlreadyLive();
// 0x24591d89
error ChainIdAlreadyExists();
// 0x717a1656
error ChainIdCantBeCurrentChain();
// 0xa179f8c9
error ChainIdMismatch();
// 0x23f3c357
error ChainIdNotRegistered(uint256 chainId);
// 0x8f620a06
error ChainIdTooBig();
// 0x8746f42f
error ConstructorsNotSupported();
// 0xec273439
error CTMAlreadyRegistered();
// 0xc630ef3c
error CTMNotRegistered();
// 0x907f8e51
error DeadlineNotYetPassed();
// 0xf2885eb3
error DefaultAdminTransferNotAllowed();
// 0xf7a01e4d
error DelegateCallFailed(bytes returnData);
// 0x0a8ed92c
error DenominatorIsZero();
// 0xb4f54111
error DeployFailed();
// 0x138ee1a3
error DeployingBridgedTokenForNativeToken();
// 0xc7c9660f
error DepositDoesNotExist();
// 0xad2fa98e
error DepositExists();
// 0x0e7ee319
error DiamondAlreadyFrozen();
// 0xa7151b9a
error DiamondNotFrozen();
// 0x7138356f
error EmptyAddress();
// 0x2d4d012f
error EmptyAssetId();
// 0x1c25715b
error EmptyBytes32();
// 0x99d8fec9
error EmptyData();
// 0x95b66fe9
error EmptyDeposit();
// 0x84286507
error EmptyPrecommitData(uint256 batchNumber);
// 0x456f8f7a
error EmptyProofLength();
// 0x627e0872
error ETHDepositNotSupported();
// 0xac4a3f98
error FacetExists(bytes4 selector, address);
// 0xc91cf3b1
error GasPerPubdataMismatch();
// 0x6d4a7df8
error GenesisBatchCommitmentZero();
// 0x7940c83f
error GenesisBatchHashZero();
// 0xb4fc6835
error GenesisIndexStorageZero();
// 0x3a1a8589
error GenesisUpgradeZero();
// 0xd356e6ba
error HashedLogIsDefault();
// 0x0b08d5be
error HashMismatch(bytes32 expected, bytes32 actual);
// 0xd7d93e1f
error IncorrectBatchBounds(
uint256 processFromExpected,
uint256 processToExpected,
uint256 processFromProvided,
uint256 processToProvided
);
// 0xc1b4bc7b
error IncorrectBatchChainId(uint256, uint256);
// 0xdd381a4c
error IncorrectBridgeHubAddress(address bridgehub);
// 0x1929b7de
error IncorrectTokenAddressFromNTV(bytes32 assetId, address tokenAddress);
// 0x826fb11e
error InsufficientChainBalance();
// 0x9bf8b9aa
error InvalidBatchNumber(uint256 provided, uint256 expected);
// 0xd438e1fa
error InvalidBlockRange(uint64 batchNumber, uint64 from, uint64 to);
// 0xcbd9d2e0
error InvalidCaller(address);
// 0x7a47c9a2
error InvalidChainId();
// 0x92daded2
error InvalidDAForPermanentRollup();
// 0x4fbe5dba
error InvalidDelay();
// 0x3f98a77e
error InvalidL2DACommitmentScheme(uint8);
// 0xc1780bd6
error InvalidLogSender(address sender, uint256 logKey);
// 0xa1ec1876
error InvalidMessageRoot(bytes32 expectedMessageRoot, bytes32 providedMessageRoot);
// 0xd08a97e6
error InvalidMockProofLength();
// 0xde4c0b96
error InvalidNTVBurnData();
// 0xd8e9405c
error InvalidNumberOfBlobs(uint256 expected, uint256 numCommitments, uint256 numHashes);
// 0x99f6cc22
error InvalidPackedPrecommitmentLength(uint256 length);
// 0x09bde339
error InvalidProof();
// 0x48c5fa28
error InvalidProofLengthForFinalNode();
// 0x5428eae7
error InvalidProtocolVersion();
// 0x6f1cf752
error InvalidPubdataPricingMode();
// 0x12ba286f
error InvalidSelector(bytes4 func);
// 0xbe7193d4
error InvalidSystemLogsLength();
// 0x5f1aa154
error InvalidUpgradeTxn(UpgradeTxVerifyParam);
// 0xfb5c22e6
error L2TimestampTooBig();
// 0x97e1359e
error L2WithdrawalMessageWrongLength(uint256 messageLen);
// 0x8efef97a
error LegacyBridgeNotSet();
// 0x29963361
error LegacyBridgeUsesNonNativeToken();
// 0xfade089a
error LegacyEncodingUsedForNonL1Token();
// 0x767eed08
error LegacyMethodForNonL1Token();
// 0xe37d2c02
error LengthIsNotDivisibleBy32(uint256 length);
// 0x1b6825bb
error LogAlreadyProcessed(uint8);
// 0x43e266b0
error MalformedBytecode(BytecodeError);
// 0xafbb7a4e
error MerkleIndexOrHeightMismatch();
// 0x9bb54c35
error MerkleIndexOutOfBounds();
// 0xc33e6128
error MerkleNothingToProve();
// 0x8e23ac1a
error MerklePathEmpty();
// 0x09aa9830
error MerklePathLengthMismatch(uint256 pathLength, uint256 expectedLength);
// 0x1c500385
error MerklePathOutOfBounds();
// 0x1b582fcf
error MerkleWrongIndex(uint256 index, uint256 maxNodeNumber);
// 0x485cfcaa
error MerkleWrongLength(uint256 newLeavesLength, uint256 leafNumber);
// 0x3312a450
error MigrationPaused();
// 0x4e98b356
error MigrationsNotPaused();
// 0xfa44b527
error MissingSystemLogs(uint256 expected, uint256 actual);
// 0x1508fb47
error MockVerifierNotSupported();
// 0x4a094431
error MsgValueMismatch(uint256 expectedMsgValue, uint256 providedMsgValue);
// 0xb385a3da
error MsgValueTooLow(uint256 required, uint256 provided);
// 0x8b7e144a
error NewDeadlineExceedsMaxDeadline();
// 0x6eef58d1
error NewDeadlineNotGreaterThanCurrent();
// 0x79cc2d22
error NoCallsProvided();
// 0xce63ce17
error NoCTMForAssetId(bytes32 assetId);
// 0xa6fef710
error NoFunctionsForDiamondCut();
// 0xcab098d8
error NoFundsTransferred();
// 0xb20b58ce
error NoLegacySharedBridge();
// 0xc21b1ab7
error NonEmptyCalldata();
// 0x536ec84b
error NonEmptyMsgValue();
// 0xd018e08e
error NonIncreasingTimestamp();
// 0x0105f9c0
error NonSequentialBatch();
// 0x0ac76f01
error NonSequentialVersion();
// 0x0e0ff4d9
error NonZeroBlobToVerifyZKsyncOS(uint256 index, bytes32 blobLinearHash, bytes32 blobOpeningCommitment);
// 0xfa5cd00f
error NotAllowed(address addr);
// 0x64846fe4
error NotARestriction(address addr);
// 0xb49df1f2
error NotAZKChain(address addr);
// 0xdd7e3621
error NotInitializedReentrancyGuard();
// 0xdf17e316
error NotWhitelisted(address);
// 0xf3ed9dfa
error OnlyEraSupported();
// 0x6c167909
error OnlySelfAllowed();
// 0x1a21feed
error OperationExists();
// 0xeda2fbb1
error OperationMustBePending();
// 0xe1c1ff37
error OperationMustBeReady();
// 0xb926450e
error OriginChainIdNotFound();
// 0x688c63e5
error PrecommitmentMismatch(uint256 batchNumber, bytes32 expected, bytes32 found);
// 0x9b48e060
error PreviousOperationNotExecuted();
// 0xd5a99014
error PriorityOperationsRollingHashMismatch();
// 0x1a4d284a
error PriorityTxPubdataExceedsMaxPubDataPerBatch();
// 0xa461f651
error ProtocolIdMismatch(uint256 expectedProtocolVersion, uint256 providedProtocolId);
// 0x64f94ec2
error ProtocolIdNotGreater();
// 0x959f26fb
error PubdataGreaterThanLimit(uint256 limit, uint256 length);
// 0x63c36549
error QueueIsEmpty();
// 0xab143c06
error Reentrancy();
// 0x667d17de
error RemoveFunctionFacetAddressNotZero(address facet);
// 0xa2d4b16c
error RemoveFunctionFacetAddressZero();
// 0xf6fd7071
error RemovingPermanentRestriction();
// 0x3580370c
error ReplaceFunctionFacetAddressZero();
// 0xf126e113
error RestrictionWasAlreadyPresent(address restriction);
// 0x52e22c98
error RestrictionWasNotPresent(address restriction);
// 0x9a67c1cb
error RevertedBatchNotAfterNewLastBatch();
// 0xfe0aa4f2
error RoleAccessDenied(address chainAddress, bytes32 role, address account);
// 0xd3b6535b
error SelectorsMustAllHaveSameFreezability();
// 0x02181a13
error SettlementLayersMustSettleOnL1();
// 0x856d5b77
error SharedBridgeNotSet();
// 0x7774d2f9
error SharedBridgeValueNotSet(SharedBridgeKey);
// 0xdf3a8fdd
error SlotOccupied();
// 0xcc0f168b
error SystemContractProxyInitialized();
// 0xae43b424
error SystemLogsSizeTooBig();
// 0x08753982
error TimeNotReached(uint256 expectedTimestamp, uint256 actualTimestamp);
// 0x7a4902ad
error TimerAlreadyStarted();
// 0x2d50c33b
error TimestampError();
// 0xa51fa558
error TokenIsLegacy();
// 0x1850b46b
error TokenNotLegacy();
// 0x06439c6b
error TokenNotSupported(address token);
// 0x23830e28
error TokensWithFeesNotSupported();
// 0x8e3ce3cb
error TooHighDeploymentNonce();
// 0x76da24b9
error TooManyFactoryDeps();
// 0xf0b4e88f
error TooMuchGas();
// 0x00c5a6a9
error TransactionNotAllowed();
// 0x4c991078
error TxHashMismatch();
// 0x2e311df8
error TxnBodyGasLimitNotEnoughGas();
// 0xfcb9b2e1
error UnallowedImplementation(bytes32 implementationHash);
// 0x8e4a23d6
error Unauthorized(address caller);
// 0xe52478c7
error UndefinedDiamondCutAction();
// 0x6aa39880
error UnexpectedSystemLog(uint256 logKey);
// 0xc352bb73
error UnknownVerifierType();
// 0xf3dd1b9c
error UnsupportedCommitBatchEncoding(uint8 version);
// 0x084a1449
error UnsupportedEncodingVersion();
// 0x14d2ed8a
error UnsupportedExecuteBatchEncoding(uint8 version);
// 0xf338f830
error UnsupportedProofBatchEncoding(uint8 version);
// 0x1906f346
error UnsupportedUpgradeType();
// 0xf093c2e5
error UpgradeBatchNumberIsNotZero();
// 0x47b3b145
error ValidateTxnNotEnoughGas();
// 0x626ade30
error ValueMismatch(uint256 expected, uint256 actual);
// 0xe1022469
error VerifiedBatchesExceedsCommittedBatches();
// 0xae899454
error WithdrawalAlreadyFinalized();
// 0x750b219c
error WithdrawFailed();
// 0xf20c5c2a
error WrappedBaseTokenAlreadyRegistered();
// 0x15e8e429
error WrongMagicValue(uint256 expectedMagicValue, uint256 providedMagicValue);
// 0xd92e233d
error ZeroAddress();
// 0xc84885d4
error ZeroChainId();
// 0xdb60e600
error ZeroGasPriceL1TxZKsyncOS();
// 0x601b6882
error ZKChainLimitReached();
// 0x646ac57e
error ZKsyncOSNotForceDeployForExistingContract(address);
enum SharedBridgeKey {
PostUpgradeFirstBatch,
LegacyBridgeFirstBatch,
LegacyBridgeLastDepositBatch,
LegacyBridgeLastDepositTxn
}
enum BytecodeError {
Version,
NumberOfWords,
Length,
WordsMustBeOdd
}
enum UpgradeTxVerifyParam {
From,
To,
Paymaster,
Value,
MaxFeePerGas,
MaxPriorityFeePerGas,
Reserved0,
Reserved1,
Reserved2,
Reserved3,
Signature,
PaymasterInput,
ReservedDynamic
}// 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;
import {IBridgehubBase, L2TransactionRequestDirect, L2TransactionRequestTwoBridgesOuter} from "./IBridgehubBase.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @dev Interface for L1-specific Bridgehub functionality
interface IL1Bridgehub is IBridgehubBase {
/// @notice Request L2 transaction directly
function requestL2TransactionDirect(
L2TransactionRequestDirect calldata _request
) external payable returns (bytes32 canonicalTxHash);
/// @notice Request L2 transaction through two bridges
function requestL2TransactionTwoBridges(
L2TransactionRequestTwoBridgesOuter calldata _request
) external payable returns (bytes32 canonicalTxHash);
/// @notice Create new chain
function createNewChain(
uint256 _chainId,
address _chainTypeManager,
bytes32 _baseTokenAssetId,
uint256 _salt,
address _admin,
bytes calldata _initData,
bytes[] calldata _factoryDeps
) external returns (uint256 chainId);
/// @notice Register settlement layer
function registerSettlementLayer(uint256 _newSettlementLayerChainId, bool _isWhitelisted) external;
/// @notice Register already deployed ZK chain
function registerAlreadyDeployedZKChain(uint256 _chainId, address _hyperchain) external;
/// @notice Register legacy chain
function registerLegacyChain(uint256 _chainId) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IL1Bridgehub} from "../bridgehub/IL1Bridgehub.sol";
import {IExecutor} from "./chain-interfaces/IExecutor.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IValidatorTimelock is IExecutor {
/// @notice Struct specifying which validator roles to grant or revoke in a single call.
/// @param rotatePrecommitterRole Whether to rotate the PRECOMMITTER_ROLE.
/// @param rotateCommitterRole Whether to rotate the COMMITTER_ROLE.
/// @param rotateReverterRole Whether to rotate the REVERTER_ROLE.
/// @param rotateProverRole Whether to rotate the PROVER_ROLE.
/// @param rotateExecutorRole Whether to rotate the EXECUTOR_ROLE.
struct ValidatorRotationParams {
bool rotatePrecommitterRole;
bool rotateCommitterRole;
bool rotateReverterRole;
bool rotateProverRole;
bool rotateExecutorRole;
}
/// @notice The delay between committing and executing batches is changed.
event NewExecutionDelay(uint256 _newExecutionDelay);
/// @notice Role hash for addresses allowed to precommit batches on a chain.
function PRECOMMITTER_ROLE() external view returns (bytes32);
/// @notice Role hash for addresses allowed to commit batches on a chain.
function COMMITTER_ROLE() external view returns (bytes32);
/// @notice Role hash for addresses allowed to revert batches on a chain.
function REVERTER_ROLE() external view returns (bytes32);
/// @notice Role hash for addresses allowed to prove batches on a chain.
function PROVER_ROLE() external view returns (bytes32);
/// @notice Role hash for addresses allowed to execute batches on a chain.
function EXECUTOR_ROLE() external view returns (bytes32);
/// @notice Optional admin role hash for managing PRECOMMITTER_ROLE assignments.
/// @dev Note, that it is optional, meaning that by default the admin role is held by the chain admin
function OPTIONAL_PRECOMMITTER_ADMIN_ROLE() external view returns (bytes32);
/// @notice Optional admin role hash for managing COMMITTER_ROLE assignments.
/// @dev Note, that it is optional, meaning that by default the admin role is held by the chain admin
function OPTIONAL_COMMITTER_ADMIN_ROLE() external view returns (bytes32);
/// @notice Optional admin role hash for managing REVERTER_ROLE assignments.
/// @dev Note, that it is optional, meaning that by default the admin role is held by the chain admin
function OPTIONAL_REVERTER_ADMIN_ROLE() external view returns (bytes32);
/// @notice Optional admin role hash for managing PROVER_ROLE assignments.
/// @dev Note, that it is optional, meaning that by default the admin role is held by the chain admin
function OPTIONAL_PROVER_ADMIN_ROLE() external view returns (bytes32);
/// @notice Optional admin role hash for managing EXECUTOR_ROLE assignments.
/// @dev Note, that it is optional, meaning that by default the admin role is held by the chain admin
function OPTIONAL_EXECUTOR_ADMIN_ROLE() external view returns (bytes32);
/// @notice The address of the bridgehub
function BRIDGE_HUB() external view returns (IL1Bridgehub);
/// @dev The delay between committing and executing batches.
function executionDelay() external view returns (uint32);
/// @dev Part of the IBase interface. Not used in this contract.
function getName() external pure returns (string memory);
/// @notice Initializer for the contract.
/// @dev Expected to be delegatecalled in the constructor of the TransparentUpgradeableProxy
/// @param _initialOwner The initial owner of the Validator timelock.
/// @param _initialExecutionDelay The initial execution delay, i.e. minimal time between a batch is committed and executed.
function initialize(address _initialOwner, uint32 _initialExecutionDelay) external;
/// @dev Set the delay between committing and executing batches.
function setExecutionDelay(uint32 _executionDelay) external;
/// @dev Returns the timestamp when `_l2BatchNumber` was committed.
function getCommittedBatchTimestamp(address _chainAddress, uint256 _l2BatchNumber) external view returns (uint256);
/// @notice Revokes the specified validator roles for a given validator on the target chain.
/// @param _chainAddress The address identifier of the ZK chain.
/// @param _validator The address of the validator to update.
/// @param params Flags indicating which roles to revoke.
/// @dev Note that the access control is managed by the inner `revokeRole` functions.
function removeValidatorRoles(
address _chainAddress,
address _validator,
ValidatorRotationParams memory params
) external;
/// @notice Convenience wrapper to revoke all validator roles for a given validator on the target chain.
/// @param _chainAddress The address identifier of the ZK chain.
/// @param _validator The address of the validator to remove.
function removeValidator(address _chainAddress, address _validator) external;
/// @notice Convenience wrapper to revoke all validator roles for a given validator on the target chain.
/// @param _chainId The chain Id of the ZK chain.
/// @param _validator The address of the validator to remove.
function removeValidatorForChainId(uint256 _chainId, address _validator) external;
/// @notice Grants the specified validator roles for a given validator on the target chain.
/// @param _chainAddress The address identifier of the ZK chain.
/// @param _validator The address of the validator to update.
/// @param params Flags indicating which roles to grant.
function addValidatorRoles(
address _chainAddress,
address _validator,
ValidatorRotationParams memory params
) external;
/// @notice Convenience wrapper to grant all validator roles for a given validator on the target chain.
/// @param _chainAddress The address identifier of the ZK chain.
/// @param _validator The address of the validator to add.
function addValidator(address _chainAddress, address _validator) external;
/// @notice Convenience wrapper to grant all validator roles for a given validator on the target chain.
/// @param _chainId The chain Id of the ZK chain.
/// @param _validator The address of the validator to add.
function addValidatorForChainId(uint256 _chainId, address _validator) external;
/// @notice Convenience wrapper to retrieve whether a certain address has a role for a chain.
/// @param _chainId The chain Id of the ZK chain.
/// @param _role The bytes32 ID of the role.
/// @param _address The address that may have the role.
function hasRoleForChainId(uint256 _chainId, bytes32 _role, address _address) external view returns (bool);
// Chain interaction functions
/// @dev Make a call to the zkChain diamond contract with the same calldata.
function precommitSharedBridge(address _chainAddress, uint256 _l2BlockNumber, bytes calldata _l2Block) external;
/// @dev Records the timestamp for all provided committed batches and make
/// a call to the zkChain diamond contract with the same calldata.
function commitBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata _batchData
) external;
/// @dev Make a call to the zkChain diamond contract with the same calldata.
/// Note: If the batch is reverted, it needs to be committed first before the execution.
/// So it's safe to not override the committed batches.
function revertBatchesSharedBridge(address _chainAddress, uint256 _newLastBatch) external;
/// @dev Make a call to the zkChain diamond contract with the same calldata.
/// Note: We don't track the time when batches are proven, since all information about
/// the batch is known on the commit stage and the proved is not finalized (may be reverted).
function proveBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata _proofData
) external;
/// @dev Check that batches were committed at least X time ago and
/// make a call to the zkChain diamond contract with the same calldata.
function executeBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata _batchData
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSetUpgradeable {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// 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;
import {IZKChainBase} from "../chain-interfaces/IZKChainBase.sol";
import {Diamond} from "../libraries/Diamond.sol";
import {FeeParams, PubdataPricingMode} from "../chain-deps/ZKChainStorage.sol";
import {ZKChainCommitment, L2DACommitmentScheme} from "../../common/Config.sol";
/// @title The interface of the Admin Contract that controls access rights for contract management.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IAdmin is IZKChainBase {
/// @notice Starts the transfer of admin rights. Only the current admin can propose a new pending one.
/// @notice New admin can accept admin rights by calling `acceptAdmin` function.
/// @param _newPendingAdmin Address of the new admin
function setPendingAdmin(address _newPendingAdmin) external;
/// @notice Accepts transfer of admin rights. Only pending admin can accept the role.
function acceptAdmin() external;
/// @notice Change validator status (active or not active)
/// @param _validator Validator address
/// @param _active Active flag
function setValidator(address _validator, bool _active) external;
/// @notice Change zk porter availability
/// @param _zkPorterIsAvailable The availability of zk porter shard
function setPorterAvailability(bool _zkPorterIsAvailable) external;
/// @notice Change the max L2 gas limit for L1 -> L2 transactions
/// @param _newPriorityTxMaxGasLimit The maximum number of L2 gas that a user can request for L1 -> L2 transactions
function setPriorityTxMaxGasLimit(uint256 _newPriorityTxMaxGasLimit) external;
/// @notice Change the fee params for L1->L2 transactions
/// @param _newFeeParams The new fee params
function changeFeeParams(FeeParams calldata _newFeeParams) external;
/// @notice Change the token multiplier for L1->L2 transactions
function setTokenMultiplier(uint128 _nominator, uint128 _denominator) external;
/// @notice Change the pubdata pricing mode before the first batch is processed
/// @param _pricingMode The new pubdata pricing mode
function setPubdataPricingMode(PubdataPricingMode _pricingMode) external;
/// @notice Set the transaction filterer
function setTransactionFilterer(address _transactionFilterer) external;
/// @notice Allow EVM emulation on chain
function allowEvmEmulation() external returns (bytes32 canonicalTxHash);
/// @notice Perform the upgrade from the current protocol version with the corresponding upgrade data
/// @param _protocolVersion The current protocol version from which upgrade is executed
/// @param _cutData The diamond cut parameters that is executed in the upgrade
function upgradeChainFromVersion(uint256 _protocolVersion, Diamond.DiamondCutData calldata _cutData) external;
/// @notice Executes a proposed governor upgrade
/// @dev Only the ChainTypeManager contract can execute the upgrade
/// @param _diamondCut The diamond cut parameters to be executed
function executeUpgrade(Diamond.DiamondCutData calldata _diamondCut) external;
/// @notice Instantly pause the functionality of all freezable facets & their selectors
/// @dev Only the governance mechanism may freeze Diamond Proxy
function freezeDiamond() external;
/// @notice Unpause the functionality of all freezable facets & their selectors
/// @dev Only the CTM can unfreeze Diamond Proxy
function unfreezeDiamond() external;
function genesisUpgrade(
address _l1GenesisUpgrade,
address _ctmDeployer,
bytes calldata _forceDeploymentData,
bytes[] calldata _factoryDeps
) external;
/// @notice Returns address of the RollupDAManager of the ZK Chain.
function getRollupDAManager() external view returns (address);
/// @notice Set the L1 DA validator address as well as the L2 DA commitment scheme.
/// @dev While in principle it is possible that updating only one of the values is needed,
/// usually these should work in pair and L1 validator typically expects a specific input from the L2 Validator.
/// That's why we change those together to prevent admins of chains from shooting themselves in the foot.
/// @param _l1DAValidator The address of the L1 DA validator
/// @param _l2DACommitmentScheme The scheme of the L2 DA commitment
function setDAValidatorPair(address _l1DAValidator, L2DACommitmentScheme _l2DACommitmentScheme) external;
/// @notice Makes the chain as permanent rollup.
/// @dev This is a security feature needed for chains that should be
/// trusted to keep their data available even if the chain admin becomes malicious
/// and tries to set the DA validator pair to something which does not publish DA to Ethereum.
/// @dev DANGEROUS: once activated, there is no way back!
function makePermanentRollup() external;
/// @notice Porter availability status changes
event IsPorterAvailableStatusUpdate(bool isPorterAvailable);
/// @notice Validator's status changed
event ValidatorStatusUpdate(address indexed validatorAddress, bool isActive);
/// @notice pendingAdmin is changed
/// @dev Also emitted when new admin is accepted and in this case, `newPendingAdmin` would be zero address
event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin);
/// @notice Admin changed
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
/// @notice Priority transaction max L2 gas limit changed
event NewPriorityTxMaxGasLimit(uint256 oldPriorityTxMaxGasLimit, uint256 newPriorityTxMaxGasLimit);
/// @notice Fee params for L1->L2 transactions changed
event NewFeeParams(FeeParams oldFeeParams, FeeParams newFeeParams);
/// @notice Validium mode status changed
event PubdataPricingModeUpdate(PubdataPricingMode validiumMode);
/// @notice The transaction filterer has been updated
event NewTransactionFilterer(address oldTransactionFilterer, address newTransactionFilterer);
/// @notice BaseToken multiplier for L1->L2 transactions changed
event NewBaseTokenMultiplier(
uint128 oldNominator,
uint128 oldDenominator,
uint128 newNominator,
uint128 newDenominator
);
/// @notice Emitted when an upgrade is executed.
event ExecuteUpgrade(Diamond.DiamondCutData diamondCut);
/// @notice Emitted when the migration to the new settlement layer is complete.
event MigrationComplete();
/// @notice Emitted when the contract is frozen.
event Freeze();
/// @notice Emitted when the contract is unfrozen.
event Unfreeze();
/// @notice The EVM emulator has been enabled
event EnableEvmEmulator();
/// @notice New L2 DA commitment scheme set
event NewL2DACommitmentScheme(
L2DACommitmentScheme indexed oldL2DACommitmentScheme,
L2DACommitmentScheme indexed newL2DACommitmentScheme
);
event NewL1DAValidator(address indexed oldL1DAValidator, address indexed newL1DAValidator);
event BridgeMint(address indexed _account, uint256 _amount);
/// @dev Similar to IL1AssetHandler interface, used to send chains.
function forwardedBridgeBurn(
address _settlementLayer,
address _originalCaller,
bytes calldata _data
) external payable returns (bytes memory _bridgeMintData);
/// @dev Similar to IL1AssetHandler interface, used to claim failed chain transfers.
function forwardedBridgeRecoverFailedTransfer(
uint256 _chainId,
bytes32 _assetInfo,
address _originalCaller,
bytes calldata _chainData
) external payable;
/// @dev Similar to IL1AssetHandler interface, used to receive chains.
function forwardedBridgeMint(bytes calldata _data, bool _contractAlreadyDeployed) external payable;
function prepareChainCommitment() external view returns (ZKChainCommitment memory commitment);
}// 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;
import {IZKChainBase} from "./IZKChainBase.sol";
import {L2DACommitmentScheme} from "../../common/Config.sol";
/// @dev Enum used by L2 System Contracts to differentiate logs.
enum SystemLogKey {
L2_TO_L1_LOGS_TREE_ROOT_KEY,
PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY,
CHAINED_PRIORITY_TXN_HASH_KEY,
NUMBER_OF_LAYER_1_TXS_KEY,
// Note, that it is important that `PREV_BATCH_HASH_KEY` has position
// `4` since it is the same as it was in the previous protocol version and
// it is the only one that is emitted before the system contracts are upgraded.
PREV_BATCH_HASH_KEY,
L2_DA_VALIDATOR_OUTPUT_HASH_KEY,
USED_L2_DA_VALIDATOR_ADDRESS_KEY,
MESSAGE_ROOT_ROLLING_HASH_KEY,
L2_TXS_STATUS_ROLLING_HASH_KEY,
EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY
}
struct LogProcessingOutput {
uint256 numberOfLayer1Txs;
bytes32 chainedPriorityTxsHash;
bytes32 previousBatchHash;
bytes32 pubdataHash;
bytes32 stateDiffHash;
bytes32 l2LogsTreeRoot;
uint256 packedBatchAndL2BlockTimestamp;
bytes32 l2DAValidatorOutputHash;
bytes32 l2TxsStatusRollingHash;
bytes32 dependencyRootsRollingHash;
}
/// @dev Maximal value that SystemLogKey variable can have.
uint256 constant MAX_LOG_KEY = uint256(type(SystemLogKey).max);
/// @dev Offset used to pull Address From Log. Equal to 4 (bytes for shardId, isService and txNumberInBatch)
uint256 constant L2_LOG_ADDRESS_OFFSET = 4;
/// @dev Offset used to pull Key From Log. Equal to 4 (bytes for shardId, isService and txNumberInBatch) + 20 (bytes for address)
uint256 constant L2_LOG_KEY_OFFSET = 24;
/// @dev Offset used to pull Value From Log. Equal to 4 (bytes for shardId, isService and txNumberInBatch) + 20 (bytes for address) + 32 (bytes for key)
uint256 constant L2_LOG_VALUE_OFFSET = 56;
/// @dev Max number of blobs currently supported
uint256 constant MAX_NUMBER_OF_BLOBS = 6;
/// @dev The number of blobs that must be present in the commitment to a batch.
/// It represents the maximal number of blobs that circuits can support and can be larger
/// than the maximal number of blobs supported by the contract (`MAX_NUMBER_OF_BLOBS`).
uint256 constant TOTAL_BLOBS_IN_COMMITMENT = 16;
/// @title The interface of the ZKsync Executor contract capable of processing events emitted in the ZKsync protocol.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IExecutor is IZKChainBase {
/// @notice Rollup batch stored data, this structure used for both: Era VM and ZKsync OS batches, however some fields have different meaning
/// @param batchNumber Rollup batch number
/// @param batchHash Hash of L2 batch, for ZKsync OS batches we'll store here full state commitment
/// @param indexRepeatedStorageChanges The serial number of the shortcut index that's used as a unique identifier for storage keys that were used twice or more. For ZKsync OS not used, always set to 0
/// @param numberOfLayer1Txs Number of priority operations to be processed
/// @param priorityOperationsHash Hash of all priority operations from this batch
/// @param l2LogsTreeRoot Root hash of tree that contains L2 -> L1 messages from this batch
/// @param timestamp Rollup batch timestamp, have the same format as Ethereum batch constant. For ZKsync OS not used, always set to 0
/// @param commitment Verified input for the ZKsync circuit. For ZKsync OS batches we'll store batch output hash here
// solhint-disable-next-line gas-struct-packing
struct StoredBatchInfo {
uint64 batchNumber;
bytes32 batchHash; // For ZKsync OS batches we'll store here full state commitment
uint64 indexRepeatedStorageChanges; // For ZKsync OS not used, always set to 0
uint256 numberOfLayer1Txs;
bytes32 priorityOperationsHash;
bytes32 dependencyRootsRollingHash;
bytes32 l2LogsTreeRoot;
uint256 timestamp; // For ZKsync OS not used, always set to 0
bytes32 commitment; // For ZKsync OS batches we'll store batch output hash here
}
/// @notice Legacy StoredBatchInfo struct
/// @dev dependencyRootsRollingHash is not included in the struct
// solhint-disable-next-line gas-struct-packing
struct LegacyStoredBatchInfo {
uint64 batchNumber;
bytes32 batchHash;
uint64 indexRepeatedStorageChanges;
uint256 numberOfLayer1Txs;
bytes32 priorityOperationsHash;
bytes32 l2LogsTreeRoot;
uint256 timestamp;
bytes32 commitment;
}
/// @notice Data needed to commit new batch
/// @param batchNumber Number of the committed batch
/// @param timestamp Unix timestamp denoting the start of the batch execution
/// @param indexRepeatedStorageChanges The serial number of the shortcut index that's used as a unique identifier for storage keys that were used twice or more
/// @param newStateRoot The state root of the full state tree
/// @param numberOfLayer1Txs Number of priority operations to be processed
/// @param priorityOperationsHash Hash of all priority operations from this batch
/// @param bootloaderHeapInitialContentsHash Hash of the initial contents of the bootloader heap. In practice it serves as the commitment to the transactions in the batch.
/// @param eventsQueueStateHash Hash of the events queue state. In practice it serves as the commitment to the events in the batch.
/// @param systemLogs concatenation of all L2 -> L1 system logs in the batch
/// @param operatorDAInput Packed pubdata commitments/data.
/// @dev pubdataCommitments format: This will always start with a 1 byte pubdataSource flag. Current allowed values are 0 (calldata) or 1 (blobs)
/// kzg: list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes) = 144 bytes
/// calldata: pubdataCommitments.length - 1 - 32 bytes of pubdata
/// and 32 bytes appended to serve as the blob commitment part for the aux output part of the batch commitment
/// @dev For 2 blobs we will be sending 288 bytes of calldata instead of the full amount for pubdata.
/// @dev When using calldata, we only need to send one blob commitment since the max number of bytes in calldata fits in a single blob and we can pull the
/// linear hash from the system logs
struct CommitBatchInfo {
uint64 batchNumber;
uint64 timestamp;
uint64 indexRepeatedStorageChanges;
bytes32 newStateRoot;
uint256 numberOfLayer1Txs;
bytes32 priorityOperationsHash;
bytes32 bootloaderHeapInitialContentsHash;
bytes32 eventsQueueStateHash;
bytes systemLogs;
bytes operatorDAInput;
}
/// @notice Commit batch info for ZKsync OS
/// @param batchNumber Number of the committed batch
/// @param newStateCommitment State commitment of the new state.
/// @dev chain state commitment, this preimage is not opened on l1,
/// it's guaranteed that this commitment commits to any state that needed for execution
/// (state root, block number, bloch hashes)
/// @param numberOfLayer1Txs Number of priority operations to be processed
/// @param priorityOperationsHash Hash of all priority operations from this batch
/// @param l2LogsTreeRoot Root hash of tree that contains L2 -> L1 messages from this batch
/// @param daCommitmentScheme commitment scheme used to generate pubdata commitment for this batch
/// @param daCommitment commitment to the batch pubdata to validate DA in the l1 da validator
// solhint-disable-next-line gas-struct-packing
struct CommitBatchInfoZKsyncOS {
uint64 batchNumber;
bytes32 newStateCommitment;
uint256 numberOfLayer1Txs;
bytes32 priorityOperationsHash;
bytes32 dependencyRootsRollingHash;
bytes32 l2LogsTreeRoot;
L2DACommitmentScheme daCommitmentScheme;
bytes32 daCommitment;
uint64 firstBlockTimestamp;
uint64 firstBlockNumber;
uint64 lastBlockTimestamp;
uint64 lastBlockNumber;
uint256 chainId;
bytes operatorDAInput;
}
/// @notice Container for a list of transaction statuses to precommit.
/// @param txs A packed array of individual transaction status commitments for the batch. Each is expected to be
/// of length 33 and have the following format: <32-byte tx hash, 1-byte status>. where status is either 0 (failed) or 1 (success).
/// @param untrustedLastL2BlockNumberHint The "hint" for what the last L2 block number that these txs represent is.
struct PrecommitInfo {
bytes packedTxsCommitments;
uint256 untrustedLastL2BlockNumberHint;
}
/// @notice Precommits the status of all L2 transactions for the next batch on the shared bridge.
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _batchNumber The sequential batch number to precommit (must equal `s.totalBatchesCommitted + 1`).
/// @param _precommitData ABI‐encoded transaction status list for the precommit.
function precommitSharedBridge(address _chainAddress, uint256 _batchNumber, bytes calldata _precommitData) external;
/// @notice Function called by the operator to commit new batches. It is responsible for:
/// - Verifying the correctness of their timestamps.
/// - Processing their L2->L1 logs.
/// - Storing batch commitments.
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _processFrom The batch number from which the processing starts.
/// @param _processTo The batch number at which the processing ends.
/// @param _commitData The encoded data of the new batches to be committed.
function commitBatchesSharedBridge(
address _chainAddress,
uint256 _processFrom,
uint256 _processTo,
bytes calldata _commitData
) external;
/// @notice Batches commitment verification.
/// @dev Only verifies batch commitments without any other processing.
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _processBatchFrom The batch number from which the verification starts.
/// @param _processBatchTo The batch number at which the verification ends.
/// @param _proofData The encoded data of the new batches to be verified.
function proveBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata _proofData
) external;
/// @notice The function called by the operator to finalize (execute) batches. It is responsible for:
/// - Processing all pending operations (commpleting priority requests).
/// - Finalizing this batch (i.e. allowing to withdraw funds from the system)
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _processFrom The batch number from which the execution starts.
/// @param _processTo The batch number at which the execution ends.
/// @param _executeData The encoded data of the new batches to be executed.
function executeBatchesSharedBridge(
address _chainAddress,
uint256 _processFrom,
uint256 _processTo,
bytes calldata _executeData
) external;
/// @notice Reverts unexecuted batches
/// @param _chainAddress The address of the DiamondProxy of the chain.
/// @param _newLastBatch batch number after which batches should be reverted
/// @dev When the _newLastBatch is equal to the number of committed batches,
/// only the precommitment is erased.
/// NOTE: Doesn't delete the stored data about batches, but only decreases
/// counters that are responsible for the number of batches
function revertBatchesSharedBridge(address _chainAddress, uint256 _newLastBatch) external;
/// @notice Event emitted when a batch is committed
/// @param batchNumber Number of the batch committed
/// @param batchHash Hash of the L2 batch
/// @param commitment Calculated input for the ZKsync circuit
/// @dev It has the name "BlockCommit" and not "BatchCommit" due to backward compatibility considerations
event BlockCommit(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment);
/// @notice Event emitted when batches are verified
/// @param previousLastVerifiedBatch Batch number of the previous last verified batch
/// @param currentLastVerifiedBatch Batch number of the current last verified batch
/// @dev It has the name "BlocksVerification" and not "BatchesVerification" due to backward compatibility considerations
event BlocksVerification(uint256 indexed previousLastVerifiedBatch, uint256 indexed currentLastVerifiedBatch);
/// @notice Event emitted when a batch is executed
/// @param batchNumber Number of the batch executed
/// @param batchHash Hash of the L2 batch
/// @param commitment Verified input for the ZKsync circuit
/// @dev It has the name "BlockExecution" and not "BatchExecution" due to backward compatibility considerations
event BlockExecution(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment);
/// @notice Event emitted when batches are reverted
/// @param totalBatchesCommitted Total number of committed batches after the revert
/// @param totalBatchesVerified Total number of verified batches after the revert
/// @param totalBatchesExecuted Total number of executed batches
/// @dev It has the name "BlocksRevert" and not "BatchesRevert" due to backward compatibility considerations
event BlocksRevert(uint256 totalBatchesCommitted, uint256 totalBatchesVerified, uint256 totalBatchesExecuted);
/// @notice Emitted when a new precommitment is set for a batch.
/// @param batchNumber The batch number for which the precommitment was recorded.
/// @param untrustedLastL2BlockNumberHint The hint to what L2 block number the precommitment should correspond to. Note, that there are no
/// guarantees on its correctness, it is just a way for the server to make external nodes' indexing simpler.
/// @param precommitment The resulting rolling hash of all transaction statuses.
event BatchPrecommitmentSet(
uint256 indexed batchNumber,
uint256 indexed untrustedLastL2BlockNumberHint,
bytes32 precommitment
);
/// @notice Reports the block range for a zksync os batch.
/// @dev IMPORTANT: in this release this range is not trusted and provided by the operator while not being included to the proof.
event ReportCommittedBatchRangeZKsyncOS(
uint64 indexed batchNumber,
uint64 indexed firstBlockNumber,
uint64 indexed lastBlockNumber
);
}// 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;
import {VerifierParams} from "../chain-interfaces/IVerifier.sol";
import {PubdataPricingMode} from "../chain-deps/ZKChainStorage.sol";
import {IZKChainBase} from "./IZKChainBase.sol";
import {L2DACommitmentScheme} from "../../common/Config.sol";
/// @title The interface of the Getters Contract that implements functions for getting contract state from outside the blockchain.
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @dev Most of the methods simply return the values that correspond to the current diamond proxy and possibly
/// not to the ZK Chain as a whole. For example, if the chain is migrated to another settlement layer, the values returned
/// by this facet will correspond to the values stored on this chain and possilbly not the canonical state of the chain.
interface IGetters is IZKChainBase {
/*//////////////////////////////////////////////////////////////
CUSTOM GETTERS
//////////////////////////////////////////////////////////////*/
/// @return The address of the verifier smart contract
function getVerifier() external view returns (address);
/// @return The address of the current admin
function getAdmin() external view returns (address);
/// @return The address of the pending admin
function getPendingAdmin() external view returns (address);
/// @return The address of the bridgehub
function getBridgehub() external view returns (address);
/// @return The address of the state transition
function getChainTypeManager() external view returns (address);
/// @return The chain ID
function getChainId() external view returns (uint256);
/// @return The address of the base token
function getBaseToken() external view returns (address);
/// @return The address of the base token
function getBaseTokenAssetId() external view returns (bytes32);
/// @return The total number of batches that were committed
function getTotalBatchesCommitted() external view returns (uint256);
/// @return The total number of batches that were committed & verified
function getTotalBatchesVerified() external view returns (uint256);
/// @return The total number of batches that were committed & verified & executed
function getTotalBatchesExecuted() external view returns (uint256);
// @return Address of transaction filterer
function getTransactionFilterer() external view returns (address);
/// @return The total number of priority operations that were added to the priority queue, including all processed ones
function getTotalPriorityTxs() external view returns (uint256);
/// @return The start index of the priority tree, i.e. the index of the first priority operation that
/// was included into the priority tree.
function getPriorityTreeStartIndex() external view returns (uint256);
/// @return The root hash of the priority tree
function getPriorityTreeRoot() external view returns (bytes32);
/// @return Whether the priority queue is active, i.e. whether new priority operations are appended to it.
/// Once the chain processes all the transactions that were present in the priority queue, all the L1->L2 related
/// operations will start to get done using the priority tree.
function isPriorityQueueActive() external view returns (bool);
/// @notice The function that returns the first unprocessed priority transaction.
/// @dev Returns zero if and only if no operations were processed from the queue.
/// @dev If all the transactions were processed, it will return the last processed index, so
/// in case exactly *unprocessed* transactions are needed, one should check that getPriorityQueueSize() is greater than 0.
/// @return Index of the oldest priority operation that wasn't processed yet
function getFirstUnprocessedPriorityTx() external view returns (uint256);
/// @return The number of priority operations currently in the queue
function getPriorityQueueSize() external view returns (uint256);
/// @return Whether the address has a validator access
function isValidator(address _address) external view returns (bool);
/// @return merkleRoot Merkle root of the tree with L2 logs for the selected batch
function l2LogsRootHash(uint256 _batchNumber) external view returns (bytes32 merkleRoot);
/// @notice For unfinalized (non executed) batches may change
/// @dev returns zero for non-committed batches
/// @return The hash of committed L2 batch.
function storedBatchHash(uint256 _batchNumber) external view returns (bytes32);
/// @return Bytecode hash of bootloader program.
function getL2BootloaderBytecodeHash() external view returns (bytes32);
/// @return Bytecode hash of default account (bytecode for EOA).
function getL2DefaultAccountBytecodeHash() external view returns (bytes32);
/// @return Bytecode hash of EVM emulator.
function getL2EvmEmulatorBytecodeHash() external view returns (bytes32);
/// @return Verifier parameters.
/// @dev This function is deprecated and will soon be removed.
function getVerifierParams() external view returns (VerifierParams memory);
/// @return Whether the diamond is frozen or not
function isDiamondStorageFrozen() external view returns (bool);
/// @return The current packed protocol version. To access human-readable version, use `getSemverProtocolVersion` function.
function getProtocolVersion() external view returns (uint256);
/// @return The tuple of (major, minor, patch) protocol version.
function getSemverProtocolVersion() external view returns (uint32, uint32, uint32);
/// @return The upgrade system contract transaction hash, 0 if the upgrade is not initialized
function getL2SystemContractsUpgradeTxHash() external view returns (bytes32);
/// @return The L2 batch number in which the upgrade transaction was processed.
/// @dev It is equal to 0 in the following two cases:
/// - No upgrade transaction has ever been processed.
/// - The upgrade transaction has been processed and the batch with such transaction has been
/// executed (i.e. finalized).
function getL2SystemContractsUpgradeBatchNumber() external view returns (uint256);
/// @return The maximum number of L2 gas that a user can request for L1 -> L2 transactions
function getPriorityTxMaxGasLimit() external view returns (uint256);
/// @return Whether a withdrawal has been finalized.
/// @param _l2BatchNumber The L2 batch number within which the withdrawal happened.
/// @param _l2MessageIndex The index of the L2->L1 message denoting the withdrawal.
function isEthWithdrawalFinalized(uint256 _l2BatchNumber, uint256 _l2MessageIndex) external view returns (bool);
/// @return The pubdata pricing mode.
function getPubdataPricingMode() external view returns (PubdataPricingMode);
/// @return the baseTokenGasPriceMultiplierNominator, used to compare the baseTokenPrice to ether for L1->L2 transactions
function baseTokenGasPriceMultiplierNominator() external view returns (uint128);
/// @return the baseTokenGasPriceMultiplierDenominator, used to compare the baseTokenPrice to ether for L1->L2 transactions
function baseTokenGasPriceMultiplierDenominator() external view returns (uint128);
/*//////////////////////////////////////////////////////////////
DIAMOND LOUPE
//////////////////////////////////////////////////////////////*/
/// @notice Faсet structure compatible with the EIP-2535 diamond loupe
/// @param addr The address of the facet contract
/// @param selectors The NON-sorted array with selectors associated with facet
struct Facet {
address addr;
bytes4[] selectors;
}
/// @return result All facet addresses and their function selectors
function facets() external view returns (Facet[] memory);
/// @return NON-sorted array with function selectors supported by a specific facet
function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory);
/// @return facets NON-sorted array of facet addresses supported on diamond
function facetAddresses() external view returns (address[] memory facets);
/// @return facet The facet address associated with a selector. Zero if the selector is not added to the diamond
function facetAddress(bytes4 _selector) external view returns (address facet);
/// @return Whether the selector can be frozen by the admin or always accessible
function isFunctionFreezable(bytes4 _selector) external view returns (bool);
/// @return isFreezable Whether the facet can be frozen by the admin or always accessible
function isFacetFreezable(address _facet) external view returns (bool isFreezable);
/// @return The address of the current settlement layer.
function getSettlementLayer() external view returns (address);
/// @return DA configuration.
function getDAValidatorPair() external view returns (address, L2DACommitmentScheme);
}// 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;
import {IMessageVerification} from "./IMessageVerification.sol";
import {IMailboxImpl} from "./IMailboxImpl.sol";
/// @title The interface of the ZKsync Mailbox contract that provides interfaces for L1 <-> L2 interaction.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IMailbox is IMessageVerification, IMailboxImpl {}// 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;
import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol";
import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol";
import {AddressHasNoCode, DelegateCallFailed, FacetExists, NoFunctionsForDiamondCut, NonEmptyCalldata, RemoveFunctionFacetAddressNotZero, RemoveFunctionFacetAddressZero, ReplaceFunctionFacetAddressZero, SelectorsMustAllHaveSameFreezability, UndefinedDiamondCutAction} from "../../common/L1ContractErrors.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice The helper library for managing the EIP-2535 diamond proxy.
library Diamond {
using UncheckedMath for uint256;
using SafeCast for uint256;
/// @dev Magic value that should be returned by diamond cut initialize contracts.
/// @dev Used to distinguish calls to contracts that were supposed to be used as diamond initializer from other contracts.
bytes32 internal constant DIAMOND_INIT_SUCCESS_RETURN_VALUE =
0x33774e659306e47509050e97cb651e731180a42d458212294d30751925c551a2; // keccak256("diamond.zksync.init") - 1
/// @dev Storage position of `DiamondStorage` structure.
bytes32 private constant DIAMOND_STORAGE_POSITION =
0xc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131b; // keccak256("diamond.standard.diamond.storage") - 1;
event DiamondCut(FacetCut[] facetCuts, address initAddress, bytes initCalldata);
/// @dev Utility struct that contains associated facet & meta information of selector
/// @param facetAddress address of the facet which is connected with selector
/// @param selectorPosition index in `FacetToSelectors.selectors` array, where is selector stored
/// @param isFreezable denotes whether the selector can be frozen.
struct SelectorToFacet {
address facetAddress;
uint16 selectorPosition;
bool isFreezable;
}
/// @dev Utility struct that contains associated selectors & meta information of facet
/// @param selectors list of all selectors that belong to the facet
/// @param facetPosition index in `DiamondStorage.facets` array, where is facet stored
struct FacetToSelectors {
bytes4[] selectors;
uint16 facetPosition;
}
/// @notice The structure that holds all diamond proxy associated parameters
/// @dev According to the EIP-2535 should be stored on a special storage key - `DIAMOND_STORAGE_POSITION`
/// @param selectorToFacet A mapping from the selector to the facet address and its meta information
/// @param facetToSelectors A mapping from facet address to its selectors with meta information
/// @param facets The array of all unique facet addresses that belong to the diamond proxy
/// @param isFrozen Denotes whether the diamond proxy is frozen and all freezable facets are not accessible
struct DiamondStorage {
mapping(bytes4 selector => SelectorToFacet selectorInfo) selectorToFacet;
mapping(address facetAddress => FacetToSelectors facetInfo) facetToSelectors;
address[] facets;
bool isFrozen;
}
/// @dev Parameters for diamond changes that touch one of the facets
/// @param facet The address of facet that's affected by the cut
/// @param action The action that is made on the facet
/// @param isFreezable Denotes whether the facet & all their selectors can be frozen
/// @param selectors An array of unique selectors that belongs to the facet address
// solhint-disable-next-line gas-struct-packing
struct FacetCut {
address facet;
Action action;
bool isFreezable;
bytes4[] selectors;
}
/// @dev Structure of the diamond proxy changes
/// @param facetCuts The set of changes (adding/removing/replacement) of implementation contracts
/// @param initAddress The address that's delegate called after setting up new facet changes
/// @param initCalldata Calldata for the delegate call to `initAddress`
struct DiamondCutData {
FacetCut[] facetCuts;
address initAddress;
bytes initCalldata;
}
/// @dev Type of change over diamond: add/replace/remove facets
enum Action {
Add,
Replace,
Remove
}
/// @return diamondStorage The pointer to the storage where all specific diamond proxy parameters stored
function getDiamondStorage() internal pure returns (DiamondStorage storage diamondStorage) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
diamondStorage.slot := position
}
}
/// @dev Add/replace/remove any number of selectors and optionally execute a function with delegatecall
/// @param _diamondCut Diamond's facet changes and the parameters to optional initialization delegatecall
function diamondCut(DiamondCutData memory _diamondCut) internal {
FacetCut[] memory facetCuts = _diamondCut.facetCuts;
address initAddress = _diamondCut.initAddress;
bytes memory initCalldata = _diamondCut.initCalldata;
uint256 facetCutsLength = facetCuts.length;
for (uint256 i = 0; i < facetCutsLength; i = i.uncheckedInc()) {
Action action = facetCuts[i].action;
address facet = facetCuts[i].facet;
bool isFacetFreezable = facetCuts[i].isFreezable;
bytes4[] memory selectors = facetCuts[i].selectors;
if (selectors.length == 0) {
revert NoFunctionsForDiamondCut();
}
if (action == Action.Add) {
_addFunctions(facet, selectors, isFacetFreezable);
} else if (action == Action.Replace) {
_replaceFunctions(facet, selectors, isFacetFreezable);
} else if (action == Action.Remove) {
_removeFunctions(facet, selectors);
} else {
revert UndefinedDiamondCutAction();
}
}
_initializeDiamondCut(initAddress, initCalldata);
emit DiamondCut(facetCuts, initAddress, initCalldata);
}
/// @dev Add new functions to the diamond proxy
/// NOTE: expect but NOT enforce that `_selectors` is NON-EMPTY array
function _addFunctions(address _facet, bytes4[] memory _selectors, bool _isFacetFreezable) private {
DiamondStorage storage ds = getDiamondStorage();
// Facet with no code cannot be added.
// This check also verifies that the facet does not have zero address, since it is the
// address with which 0x00000000 selector is associated.
if (_facet.code.length == 0) {
revert AddressHasNoCode(_facet);
}
// Add facet to the list of facets if the facet address is new one
_saveFacetIfNew(_facet);
uint256 selectorsLength = _selectors.length;
for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
bytes4 selector = _selectors[i];
SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
if (oldFacet.facetAddress != address(0)) {
revert FacetExists(selector, oldFacet.facetAddress);
}
_addOneFunction(_facet, selector, _isFacetFreezable);
}
}
/// @dev Change associated facets to already known function selectors
/// NOTE: expect but NOT enforce that `_selectors` is NON-EMPTY array
function _replaceFunctions(address _facet, bytes4[] memory _selectors, bool _isFacetFreezable) private {
DiamondStorage storage ds = getDiamondStorage();
// Facet with no code cannot be added.
// This check also verifies that the facet does not have zero address, since it is the
// address with which 0x00000000 selector is associated.
if (_facet.code.length == 0) {
revert AddressHasNoCode(_facet);
}
uint256 selectorsLength = _selectors.length;
for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
bytes4 selector = _selectors[i];
SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
// it is impossible to replace the facet with zero address
if (oldFacet.facetAddress == address(0)) {
revert ReplaceFunctionFacetAddressZero();
}
_removeOneFunction(oldFacet.facetAddress, selector);
// Add facet to the list of facets if the facet address is a new one
_saveFacetIfNew(_facet);
_addOneFunction(_facet, selector, _isFacetFreezable);
}
}
/// @dev Remove association with function and facet
/// NOTE: expect but NOT enforce that `_selectors` is NON-EMPTY array
function _removeFunctions(address _facet, bytes4[] memory _selectors) private {
DiamondStorage storage ds = getDiamondStorage();
// facet address must be zero
if (_facet != address(0)) {
revert RemoveFunctionFacetAddressNotZero(_facet);
}
uint256 selectorsLength = _selectors.length;
for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
bytes4 selector = _selectors[i];
SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
// Can't delete a non-existent facet
if (oldFacet.facetAddress == address(0)) {
revert RemoveFunctionFacetAddressZero();
}
_removeOneFunction(oldFacet.facetAddress, selector);
}
}
/// @dev Add address to the list of known facets if it is not on the list yet
/// NOTE: should be called ONLY before adding a new selector associated with the address
function _saveFacetIfNew(address _facet) private {
DiamondStorage storage ds = getDiamondStorage();
uint256 selectorsLength = ds.facetToSelectors[_facet].selectors.length;
// If there are no selectors associated with facet then save facet as new one
if (selectorsLength == 0) {
ds.facetToSelectors[_facet].facetPosition = ds.facets.length.toUint16();
ds.facets.push(_facet);
}
}
/// @dev Add one function to the already known facet
/// NOTE: It is expected but NOT enforced that:
/// - `_facet` is NON-ZERO address
/// - `_facet` is already stored address in `DiamondStorage.facets`
/// - `_selector` is NOT associated by another facet
function _addOneFunction(address _facet, bytes4 _selector, bool _isSelectorFreezable) private {
DiamondStorage storage ds = getDiamondStorage();
uint16 selectorPosition = (ds.facetToSelectors[_facet].selectors.length).toUint16();
// if selectorPosition is nonzero, it means it is not a new facet
// so the freezability of the first selector must be matched to _isSelectorFreezable
// so all the selectors in a facet will have the same freezability
if (selectorPosition != 0) {
bytes4 selector0 = ds.facetToSelectors[_facet].selectors[0];
if (_isSelectorFreezable != ds.selectorToFacet[selector0].isFreezable) {
revert SelectorsMustAllHaveSameFreezability();
}
}
ds.selectorToFacet[_selector] = SelectorToFacet({
facetAddress: _facet,
selectorPosition: selectorPosition,
isFreezable: _isSelectorFreezable
});
ds.facetToSelectors[_facet].selectors.push(_selector);
}
/// @dev Remove one associated function with facet
/// NOTE: It is expected but NOT enforced that `_facet` is NON-ZERO address
function _removeOneFunction(address _facet, bytes4 _selector) private {
DiamondStorage storage ds = getDiamondStorage();
// Get index of `FacetToSelectors.selectors` of the selector and last element of array
uint256 selectorPosition = ds.selectorToFacet[_selector].selectorPosition;
uint256 lastSelectorPosition = ds.facetToSelectors[_facet].selectors.length - 1;
// If the selector is not at the end of the array then move the last element to the selector position
if (selectorPosition != lastSelectorPosition) {
bytes4 lastSelector = ds.facetToSelectors[_facet].selectors[lastSelectorPosition];
ds.facetToSelectors[_facet].selectors[selectorPosition] = lastSelector;
ds.selectorToFacet[lastSelector].selectorPosition = selectorPosition.toUint16();
}
// Remove last element from the selectors array
ds.facetToSelectors[_facet].selectors.pop();
// Finally, clean up the association with facet
delete ds.selectorToFacet[_selector];
// If there are no selectors for facet then remove the facet from the list of known facets
if (lastSelectorPosition == 0) {
_removeFacet(_facet);
}
}
/// @dev remove facet from the list of known facets
/// NOTE: It is expected but NOT enforced that there are no selectors associated with `_facet`
function _removeFacet(address _facet) private {
DiamondStorage storage ds = getDiamondStorage();
// Get index of `DiamondStorage.facets` of the facet and last element of array
uint256 facetPosition = ds.facetToSelectors[_facet].facetPosition;
uint256 lastFacetPosition = ds.facets.length - 1;
// If the facet is not at the end of the array then move the last element to the facet position
if (facetPosition != lastFacetPosition) {
address lastFacet = ds.facets[lastFacetPosition];
ds.facets[facetPosition] = lastFacet;
ds.facetToSelectors[lastFacet].facetPosition = facetPosition.toUint16();
}
// Remove last element from the facets array
ds.facets.pop();
}
/// @dev Delegates call to the initialization address with provided calldata
/// @dev Used as a final step of diamond cut to execute the logic of the initialization for changed facets
function _initializeDiamondCut(address _init, bytes memory _calldata) private {
if (_init == address(0)) {
// Non-empty calldata for zero address
if (_calldata.length != 0) {
revert NonEmptyCalldata();
}
} else {
// Do not check whether `_init` is a contract since later we check that it returns data.
(bool success, bytes memory data) = _init.delegatecall(_calldata);
if (!success) {
// If the returndata is too small, we still want to produce some meaningful error
if (data.length < 4) {
revert DelegateCallFailed(data);
}
assembly {
revert(add(data, 0x20), mload(data))
}
}
// Check that called contract returns magic value to make sure that contract logic
// supposed to be used as diamond cut initializer.
if (data.length != 32) {
revert DelegateCallFailed(data);
}
if (abi.decode(data, (bytes32)) != DIAMOND_INIT_SUCCESS_RETURN_VALUE) {
revert DelegateCallFailed(data);
}
}
}
}// 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;
import {L2Log, L2Message, TxStatus} from "../common/Messaging.sol";
import {ICTMDeploymentTracker} from "./ICTMDeploymentTracker.sol";
import {IMessageRoot} from "./IMessageRoot.sol";
struct L2TransactionRequestDirect {
uint256 chainId;
uint256 mintValue;
address l2Contract;
uint256 l2Value;
bytes l2Calldata;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
bytes[] factoryDeps;
address refundRecipient;
}
struct L2TransactionRequestTwoBridgesOuter {
uint256 chainId;
uint256 mintValue;
uint256 l2Value;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
address refundRecipient;
address secondBridgeAddress;
uint256 secondBridgeValue;
bytes secondBridgeCalldata;
}
struct L2TransactionRequestTwoBridgesInner {
bytes32 magicValue;
address l2Contract;
bytes l2Calldata;
bytes[] factoryDeps;
bytes32 txDataHash;
}
struct BridgehubMintCTMAssetData {
uint256 chainId;
bytes32 baseTokenAssetId;
bytes ctmData;
bytes chainData;
}
struct BridgehubBurnCTMAssetData {
uint256 chainId;
bytes ctmData;
bytes chainData;
}
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IBridgehubBase {
/// @notice pendingAdmin is changed
/// @dev Also emitted when new admin is accepted and in this case, `newPendingAdmin` would be zero address
event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin);
/// @notice Admin changed
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
/// @notice CTM asset registered
event AssetRegistered(
bytes32 indexed assetInfo,
address indexed _assetAddress,
bytes32 indexed additionalData,
address sender
);
event SettlementLayerRegistered(uint256 indexed chainId, bool indexed isWhitelisted);
event NewChain(uint256 indexed chainId, address chainTypeManager, address indexed chainGovernance);
event ChainTypeManagerAdded(address indexed chainTypeManager);
event ChainTypeManagerRemoved(address indexed chainTypeManager);
event BaseTokenAssetIdRegistered(bytes32 indexed assetId);
/// @notice Starts the transfer of admin rights. Only the current admin or owner can propose a new pending one.
/// @notice New admin can accept admin rights by calling `acceptAdmin` function.
/// @param _newPendingAdmin Address of the new admin
function setPendingAdmin(address _newPendingAdmin) external;
/// @notice Accepts transfer of admin rights. Only pending admin can accept the role.
function acceptAdmin() external;
/// Getters
function chainTypeManagerIsRegistered(address _chainTypeManager) external view returns (bool);
function chainTypeManager(uint256 _chainId) external view returns (address);
function assetIdIsRegistered(bytes32 _baseTokenAssetId) external view returns (bool);
function baseToken(uint256 _chainId) external view returns (address);
function baseTokenAssetId(uint256 _chainId) external view returns (bytes32);
function messageRoot() external view returns (IMessageRoot);
function getZKChain(uint256 _chainId) external view returns (address);
function getAllZKChains() external view returns (address[] memory);
function getAllZKChainChainIDs() external view returns (uint256[] memory);
function migrationPaused() external view returns (bool);
function admin() external view returns (address);
function assetRouter() external view returns (address);
function whitelistedSettlementLayers(uint256 _chainId) external view returns (bool);
function settlementLayer(uint256 _chainId) external view returns (uint256);
function ctmAssetIdFromChainId(uint256 _chainId) external view returns (bytes32);
function ctmAssetIdFromAddress(address _ctmAddress) external view returns (bytes32);
function l1CtmDeployer() external view returns (ICTMDeploymentTracker);
function ctmAssetIdToAddress(bytes32 _assetInfo) external view returns (address);
function chainAssetHandler() external view returns (address);
/// Mailbox forwarder
function proveL2MessageInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view returns (bool);
function proveL2LogInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Log memory _log,
bytes32[] calldata _proof
) external view returns (bool);
function proveL1ToL2TransactionStatus(
uint256 _chainId,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof,
TxStatus _status
) external view returns (bool);
function l2TransactionBaseCost(
uint256 _chainId,
uint256 _gasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256);
/// Registry
function addChainTypeManager(address _chainTypeManager) external;
function removeChainTypeManager(address _chainTypeManager) external;
function addTokenAssetId(bytes32 _baseTokenAssetId) external;
function setChainAssetHandler(address _chainAssetHandler) external;
function setCTMAssetAddress(bytes32 _additionalData, address _assetAddress) external;
function pauseMigration() external;
function unpauseMigration() external;
/// Asset Handler functions
function forwardedBridgeBurnSetSettlementLayer(
uint256 _chainId,
uint256 _newSettlementLayerChainId
) external returns (address zkChain, address ctm);
function forwardedBridgeMint(
bytes32 _assetId,
uint256 _chainId,
bytes32 _baseTokenAssetId
) external returns (address zkChain, address ctm);
function registerNewZKChain(uint256 _chainId, address _zkChain, bool _checkMaxNumberOfZKChains) external;
function forwardedBridgeRecoverFailedTransfer(uint256 _chainId) external returns (address zkChain, address ctm);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// 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; /// @title The interface of the ZKsync contract, responsible for the main ZKsync logic. /// @author Matter Labs /// @custom:security-contact [email protected] interface IZKChainBase { /// @return Returns facet name. function getName() external view returns (string memory); }
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IVerifier, VerifierParams} from "../chain-interfaces/IVerifier.sol";
import {PriorityQueue} from "../../state-transition/libraries/PriorityQueue.sol";
import {PriorityTree} from "../../state-transition/libraries/PriorityTree.sol";
import {L2DACommitmentScheme} from "../../common/Config.sol";
/// @notice Indicates whether an upgrade is initiated and if yes what type
/// @param None Upgrade is NOT initiated
/// @param Transparent Fully transparent upgrade is initiated, upgrade data is publicly known
/// @param Shadow Shadow upgrade is initiated, upgrade data is hidden
enum UpgradeState {
None,
Transparent,
Shadow
}
/// @dev Logically separated part of the storage structure, which is responsible for everything related to proxy
/// upgrades and diamond cuts
/// @param proposedUpgradeHash The hash of the current upgrade proposal, zero if there is no active proposal
/// @param state Indicates whether an upgrade is initiated and if yes what type
/// @param securityCouncil Address which has the permission to approve instant upgrades (expected to be a Gnosis
/// multisig)
/// @param approvedBySecurityCouncil Indicates whether the security council has approved the upgrade
/// @param proposedUpgradeTimestamp The timestamp when the upgrade was proposed, zero if there are no active proposals
/// @param currentProposalId The serial number of proposed upgrades, increments when proposing a new one
struct UpgradeStorage {
bytes32 proposedUpgradeHash;
UpgradeState state;
address securityCouncil;
bool approvedBySecurityCouncil;
uint40 proposedUpgradeTimestamp;
uint40 currentProposalId;
}
/// @notice The struct that describes whether users will be charged for pubdata for L1->L2 transactions.
/// @param Rollup The users are charged for pubdata & it is priced based on the gas price on Ethereum.
/// @param Validium The pubdata is considered free with regard to the L1 gas price.
enum PubdataPricingMode {
Rollup,
Validium
}
/// @notice The fee params for L1->L2 transactions for the network.
/// @param pubdataPricingMode How the users will charged for pubdata in L1->L2 transactions.
/// @param batchOverheadL1Gas The amount of L1 gas required to process the batch (except for the calldata).
/// @param maxPubdataPerBatch The maximal number of pubdata that can be emitted per batch.
/// @param priorityTxMaxPubdata The maximal amount of pubdata a priority transaction is allowed to publish.
/// It can be slightly less than maxPubdataPerBatch in order to have some margin for the bootloader execution.
/// @param minimalL2GasPrice The minimal L2 gas price to be used by L1->L2 transactions. It should represent
/// the price that a single unit of compute costs.
struct FeeParams {
PubdataPricingMode pubdataPricingMode;
uint32 batchOverheadL1Gas;
uint32 maxPubdataPerBatch;
uint32 maxL2GasPerBatch;
uint32 priorityTxMaxPubdata;
uint64 minimalL2GasPrice;
}
/// @dev storing all storage variables for ZK chain diamond facets
/// NOTE: It is used in a proxy, so it is possible to add new variables to the end
/// but NOT to modify already existing variables or change their order.
/// NOTE: variables prefixed with '__DEPRECATED_' are deprecated and shouldn't be used.
/// Their presence is maintained for compatibility and to prevent storage collision.
// solhint-disable-next-line gas-struct-packing
struct ZKChainStorage {
/// @dev Storage of variables needed for deprecated diamond cut facet
uint256[7] __DEPRECATED_diamondCutStorage;
/// @notice Address which will exercise critical changes to the Diamond Proxy (upgrades, freezing & unfreezing). Replaced by CTM
address __DEPRECATED_governor;
/// @notice Address that the governor proposed as one that will replace it
address __DEPRECATED_pendingGovernor;
/// @notice List of permitted validators
mapping(address validatorAddress => bool isValidator) validators;
/// @dev Verifier contract. Used to verify aggregated proof for batches
IVerifier verifier;
/// @notice Total number of executed batches i.e. batches[totalBatchesExecuted] points at the latest executed batch
/// (batch 0 is genesis)
uint256 totalBatchesExecuted;
/// @notice Total number of proved batches i.e. batches[totalBatchesProved] points at the latest proved batch
uint256 totalBatchesVerified;
/// @notice Total number of committed batches i.e. batches[totalBatchesCommitted] points at the latest committed
/// batch
uint256 totalBatchesCommitted;
/// @dev Stored hashed StoredBatch for batch number
mapping(uint256 batchNumber => bytes32 batchHash) storedBatchHashes;
/// @dev Stored root hashes of L2 -> L1 logs
mapping(uint256 batchNumber => bytes32 l2LogsRootHash) l2LogsRootHashes;
/// @dev Container that stores transactions requested from L1
PriorityQueue.Queue __DEPRECATED_priorityQueue;
/// @dev The smart contract that manages the list with permission to call contract functions
address __DEPRECATED_allowList;
VerifierParams __DEPRECATED_verifierParams;
/// @notice Bytecode hash of bootloader program.
/// @dev Used as an input to zkp-circuit.
bytes32 l2BootloaderBytecodeHash;
/// @notice Bytecode hash of default account (bytecode for EOA).
/// @dev Used as an input to zkp-circuit.
bytes32 l2DefaultAccountBytecodeHash;
/// @dev Indicates that the porter may be touched on L2 transactions.
/// @dev Used as an input to zkp-circuit.
bool zkPorterIsAvailable;
/// @dev The maximum number of the L2 gas that a user can request for L1 -> L2 transactions
/// @dev This is the maximum number of L2 gas that is available for the "body" of the transaction, i.e.
/// without overhead for proving the batch.
uint256 priorityTxMaxGasLimit;
/// @dev Storage of variables needed for upgrade facet
UpgradeStorage __DEPRECATED_upgrades;
/// @dev A mapping L2 batch number => message number => flag.
/// @dev The L2 -> L1 log is sent for every withdrawal, so this mapping is serving as
/// a flag to indicate that the message was already processed.
/// @dev Used to indicate that eth withdrawal was already processed
mapping(uint256 l2BatchNumber => mapping(uint256 l2ToL1MessageNumber => bool isFinalized)) isEthWithdrawalFinalized;
/// @dev The most recent withdrawal time and amount reset
uint256 __DEPRECATED_lastWithdrawalLimitReset;
/// @dev The accumulated withdrawn amount during the withdrawal limit window
uint256 __DEPRECATED_withdrawnAmountInWindow;
/// @dev A mapping user address => the total deposited amount by the user
mapping(address => uint256) __DEPRECATED_totalDepositedAmountPerUser;
/// @dev Stores the protocol version. Note, that the protocol version may not only encompass changes to the
/// smart contracts, but also to the node behavior.
uint256 protocolVersion;
/// @dev Hash of the system contract upgrade transaction. If 0, then no upgrade transaction needs to be done.
bytes32 l2SystemContractsUpgradeTxHash;
/// @dev Batch number where the upgrade transaction has happened. If 0, then no upgrade transaction has happened
/// yet.
uint256 l2SystemContractsUpgradeBatchNumber;
/// @dev Address which will exercise non-critical changes to the Diamond Proxy (changing validator set & unfreezing)
address admin;
/// @notice Address that the admin proposed as one that will replace admin role
address pendingAdmin;
/// @dev Fee params used to derive gasPrice for the L1->L2 transactions. For L2 transactions,
/// the bootloader gives enough freedom to the operator.
/// @dev The value is only for the L1 deployment of the ZK Chain, since payment for all the priority transactions is
/// charged at that level.
FeeParams feeParams;
/// @dev Address of the blob versioned hash getter smart contract used for EIP-4844 versioned hashes.
address __DEPRECATED_blobVersionedHashRetriever;
/// @dev The chainId of the chain
uint256 chainId;
/// @dev The address of the bridgehub
address bridgehub;
/// @dev The address of the ChainTypeManager
address chainTypeManager;
/// @dev The address of the baseToken contract. Eth is address(1)
address __DEPRECATED_baseToken;
/// @dev The address of the baseTokenbridge. Eth also uses the shared bridge
address __DEPRECATED_baseTokenBridge;
/// @notice gasPriceMultiplier for each baseToken, so that each L1->L2 transaction pays for its transaction on the destination
/// we multiply by the nominator, and divide by the denominator
uint128 baseTokenGasPriceMultiplierNominator;
uint128 baseTokenGasPriceMultiplierDenominator;
/// @dev The optional address of the contract that has to be used for transaction filtering/whitelisting
address transactionFilterer;
/// @dev The address of the l1DAValidator contract.
/// This contract is responsible for the verification of the correctness of the DA on L1.
address l1DAValidator;
/// @dev The address of the contract on L2 that is responsible for the data availability verification.
/// This contract sends `l2DAValidatorOutputHash` to L1 via L2->L1 system log and it will routed to the `l1DAValidator` contract.
address __DEPRECATED_l2DAValidator;
/// @dev the Asset Id of the baseToken
bytes32 baseTokenAssetId;
/// @dev If this ZKchain settles on this chain, then this is zero. Otherwise it is the address of the ZKchain that is a
/// settlement layer for this ZKchain. (think about it as a 'forwarding' address for the chain that migrated away).
address settlementLayer;
/// @dev Priority tree, the new data structure for priority queue
PriorityTree.Tree priorityTree;
/// @dev Whether the chain is a permanent rollup. Note, that it only enforces the DA validator pair, but
/// it does not enforce any other parameters, e.g. `pubdataPricingMode`
bool isPermanentRollup;
/// @notice Bytecode hash of evm emulator.
/// @dev Used as an input to zkp-circuit.
bytes32 l2EvmEmulatorBytecodeHash;
/// @notice The precommitment for the latest uncommitted batch (i.e. totalBatchesCommitted + 1).
/// @dev Whenever the `totalBatchesCommitted` changes, this variable is reset to `DEFAULT_PRECOMMITMENT_FOR_THE_LAST_BATCH`
/// (the value of the constant can be found in Config.sol).
/// @dev Note, that precommitments are only supported for Era VM.
bytes32 precommitmentForTheLatestBatch;
/// @dev ZKsync OS flag, if `true` state transition is done with ZKsync OS, otherwise Era VM
bool zksyncOS;
/// @dev The scheme of L2 DA commitment. Different L1 validators may use different schemes.
L2DACommitmentScheme l2DACommitmentScheme;
}// 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;
/// @dev `keccak256("")`
bytes32 constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
/// @dev Bytes in raw L2 log
/// @dev Equal to the bytes size of the tuple - (uint8 ShardId, bool isService, uint16 txNumberInBatch, address sender,
/// bytes32 key, bytes32 value)
uint256 constant L2_TO_L1_LOG_SERIALIZE_SIZE = 88;
/// @dev The maximum length of the bytes array with L2 -> L1 logs
uint256 constant MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES = 4 + L2_TO_L1_LOG_SERIALIZE_SIZE * 512;
/// @dev The value of default leaf hash for L2 -> L1 logs Merkle tree
/// @dev An incomplete fixed-size tree is filled with this value to be a full binary tree
/// @dev Actually equal to the `keccak256(new bytes(L2_TO_L1_LOG_SERIALIZE_SIZE))`
bytes32 constant L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH = 0x72abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43ba;
bytes32 constant DEFAULT_L2_LOGS_TREE_ROOT_HASH = bytes32(0);
/// @dev Denotes the type of the ZKsync Era transaction that came from L1.
uint256 constant PRIORITY_OPERATION_L2_TX_TYPE = 255;
/// @dev Denotes the type of the ZKsync Era transaction that is used for system upgrades.
uint256 constant SYSTEM_UPGRADE_L2_TX_TYPE = 254;
/// @dev Denotes the type of the ZKsync OS transaction that came from L1.
uint256 constant ZKSYNC_OS_PRIORITY_OPERATION_L2_TX_TYPE = 127;
/// @dev Denotes the type of the ZKsync OS transaction that is used for system upgrades.
uint256 constant ZKSYNC_OS_SYSTEM_UPGRADE_L2_TX_TYPE = 126;
/// @dev The maximal allowed difference between protocol minor versions in an upgrade. The 100 gap is needed
/// in case a protocol version has been tested on testnet, but then not launched on mainnet, e.g.
/// due to a bug found.
/// We are allowed to jump at most 100 minor versions at a time. The major version is always expected to be 0.
uint256 constant MAX_ALLOWED_MINOR_VERSION_DELTA = 100;
/// @dev The amount of time in seconds the validator has to process the priority transaction
/// NOTE: The constant is set to zero for the Alpha release period
uint256 constant PRIORITY_EXPIRATION = 0 days;
// @dev The chainId of Ethereum Mainnet
uint256 constant MAINNET_CHAIN_ID = 1;
/// @dev Timestamp - seconds since unix epoch. This value will be used on the mainnet.
uint256 constant MAINNET_COMMIT_TIMESTAMP_NOT_OLDER = 3 days;
/// @dev Timestamp - seconds since unix epoch. This value will be used on testnets.
uint256 constant TESTNET_COMMIT_TIMESTAMP_NOT_OLDER = 30 days;
/// @dev Maximum available error between real commit batch timestamp and analog used in the verifier (in seconds)
/// @dev Must be used cause miner's `block.timestamp` value can differ on some small value (as we know - 12 seconds)
uint256 constant COMMIT_TIMESTAMP_APPROXIMATION_DELTA = 1 hours;
/// @dev Shift to apply to verify public input before verifying.
uint256 constant PUBLIC_INPUT_SHIFT = 32;
/// @dev The maximum number of L2 gas that a user can request for an L2 transaction
uint256 constant MAX_GAS_PER_TRANSACTION = 80_000_000;
/// @dev Even though the price for 1 byte of pubdata is 16 L1 gas, we have a slightly increased
/// value.
uint256 constant L1_GAS_PER_PUBDATA_BYTE = 17;
/// @dev The intrinsic cost of the L1->l2 transaction in computational L2 gas
uint256 constant L1_TX_INTRINSIC_L2_GAS = 167_157;
/// @dev The intrinsic cost of the L1->l2 transaction in pubdata
uint256 constant L1_TX_INTRINSIC_PUBDATA = 88;
/// @dev The minimal base price for L1 transaction
uint256 constant L1_TX_MIN_L2_GAS_BASE = 173_484;
/// @dev The number of L2 gas the transaction starts costing more with each 544 bytes of encoding
uint256 constant L1_TX_DELTA_544_ENCODING_BYTES = 1656;
/// @dev The number of L2 gas an L1->L2 transaction gains with each new factory dependency
uint256 constant L1_TX_DELTA_FACTORY_DEPS_L2_GAS = 2473;
/// @dev The number of L2 gas an L1->L2 transaction gains with each new factory dependency
uint256 constant L1_TX_DELTA_FACTORY_DEPS_PUBDATA = 64;
/// @dev The number of pubdata an L1->L2 transaction requires with each new factory dependency
uint256 constant MAX_NEW_FACTORY_DEPS = 64;
/// @dev The L2 gasPricePerPubdata required to be used in bridges.
uint256 constant REQUIRED_L2_GAS_PRICE_PER_PUBDATA = 800;
/// @dev The native price for L1->L2 transactions in ZKsync OS.
uint256 constant ZKSYNC_OS_L1_TX_NATIVE_PRICE = 10;
/// @dev The intrinsic cost of the L1->L2 transaction in computational L2 gas for ZKsync OS.
uint256 constant L1_TX_INTRINSIC_L2_GAS_ZKSYNC_OS = 21000;
/// @dev The cost of calldata byte for the L1->L2 transaction in computational L2 gas for ZKsync OS.
uint256 constant L1_TX_CALLDATA_PRICE_L2_GAS_ZKSYNC_OS = 16;
/// @dev The static part of the L1->l2 transaction native cost for ZKsync OS.
/// It includes intrinsic cost(130_000) and static part of hashing cost(2500).
uint256 constant L1_TX_STATIC_NATIVE_ZKSYNC_OS = 132_500;
/// @dev The encoding cost per keccak256 round(136 bytes) of the L1->l2 transaction in native resource for ZKsync OS.
uint256 constant L1_TX_ENCODING_136_BYTES_COST_NATIVE_ZKSYNC_OS = 17500;
/// @dev The cost of calldata byte for the L1->L2 transaction in native resource for ZKsync OS.
uint256 constant L1_TX_CALLDATA_COST_NATIVE_ZKSYNC_OS = 1;
/// @dev The intrinsic cost of the L1->l2 transaction in pubdata for ZKsync OS
uint256 constant L1_TX_INTRINSIC_PUBDATA_ZSKYNC_OS = 88;
/// @dev The native per gas ratio for upgrade transactions in ZKsync OS.
uint256 constant UPGRADE_TX_NATIVE_PER_GAS = 10_000;
/// @dev The mask which should be applied to the packed batch and L2 block timestamp in order
/// to obtain the L2 block timestamp. Applying this mask is equivalent to calculating modulo 2**128
uint256 constant PACKED_L2_BLOCK_TIMESTAMP_MASK = 0xffffffffffffffffffffffffffffffff;
/// @dev Address of the point evaluation precompile used for EIP-4844 blob verification.
address constant POINT_EVALUATION_PRECOMPILE_ADDR = address(0x0A);
/// @dev The overhead for a transaction slot in L2 gas.
/// It is roughly equal to 80kk/MAX_TRANSACTIONS_IN_BATCH, i.e. how many gas would an L1->L2 transaction
/// need to pay to compensate for the batch being closed.
/// @dev It is expected that the L1 contracts will enforce that the L2 gas price will be high enough to compensate
/// the operator in case the batch is closed because of tx slots filling up.
uint256 constant TX_SLOT_OVERHEAD_L2_GAS = 10000;
/// @dev The overhead for each byte of the bootloader memory that the encoding of the transaction.
/// It is roughly equal to 80kk/BOOTLOADER_MEMORY_FOR_TXS, i.e. how many gas would an L1->L2 transaction
/// need to pay to compensate for the batch being closed.
/// @dev It is expected that the L1 contracts will enforce that the L2 gas price will be high enough to compensate
/// the operator in case the batch is closed because of the memory for transactions being filled up.
uint256 constant MEMORY_OVERHEAD_GAS = 10;
/// @dev The maximum gas limit for a priority transaction in L2.
uint256 constant PRIORITY_TX_MAX_GAS_LIMIT = 72_000_000;
/// @dev the address used to identify eth as the base token for chains.
address constant ETH_TOKEN_ADDRESS = address(1);
/// @dev the value returned in bridgehubDeposit in the TwoBridges function.
bytes32 constant TWO_BRIDGES_MAGIC_VALUE = bytes32(uint256(keccak256("TWO_BRIDGES_MAGIC_VALUE")) - 1);
/// @dev https://eips.ethereum.org/EIPS/eip-1352
address constant BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS = address(uint160(type(uint16).max));
/// @dev the maximum number of supported chains, this is an arbitrary limit.
/// @dev Note, that in case of a malicious Bridgehub admin, the total number of chains
/// can be up to 2 times higher. This may be possible, in case the old ChainTypeManager
/// had `100` chains and these were migrated to the Bridgehub only after `MAX_NUMBER_OF_ZK_CHAINS`
/// were added to the bridgehub via creation of new chains.
uint256 constant MAX_NUMBER_OF_ZK_CHAINS = 100;
/// @dev Used as the `msg.sender` for transactions that relayed via a settlement layer.
address constant SETTLEMENT_LAYER_RELAY_SENDER = address(uint160(0x1111111111111111111111111111111111111111));
/// @dev The metadata version that is supported by the ZK Chains to prove that an L2->L1 log was included in a batch.
uint256 constant SUPPORTED_PROOF_METADATA_VERSION = 1;
/// @dev The virtual address of the L1 settlement layer.
address constant L1_SETTLEMENT_LAYER_VIRTUAL_ADDRESS = address(
uint160(uint256(keccak256("L1_SETTLEMENT_LAYER_VIRTUAL_ADDRESS")) - 1)
);
struct PriorityTreeCommitment {
uint256 nextLeafIndex;
uint256 startIndex;
uint256 unprocessedIndex;
bytes32[] sides;
}
// Info that allows to restore a chain.
struct ZKChainCommitment {
/// @notice Total number of executed batches i.e. batches[totalBatchesExecuted] points at the latest executed batch
/// (batch 0 is genesis)
uint256 totalBatchesExecuted;
/// @notice Total number of proved batches i.e. batches[totalBatchesProved] points at the latest proved batch
uint256 totalBatchesVerified;
/// @notice Total number of committed batches i.e. batches[totalBatchesCommitted] points at the latest committed
/// batch
uint256 totalBatchesCommitted;
/// @notice The hash of the L2 system contracts ugpgrade transaction.
/// @dev It is non zero if the migration happens while the upgrade is not yet finalized.
bytes32 l2SystemContractsUpgradeTxHash;
/// @notice The batch when the system contracts upgrade transaction was executed.
/// @dev It is non-zero if the migration happens while the batch where the upgrade tx was present
/// has not been finalized (executed) yet.
uint256 l2SystemContractsUpgradeBatchNumber;
/// @notice The hashes of the batches that are needed to keep the blockchain working.
/// @dev The length of the array is equal to the `totalBatchesCommitted - totalBatchesExecuted + 1`, i.e. we need
/// to store all the unexecuted batches' hashes + 1 latest executed one.
bytes32[] batchHashes;
/// @notice Commitment to the priority merkle tree.
PriorityTreeCommitment priorityTree;
/// @notice Whether a chain is a permanent rollup.
bool isPermanentRollup;
/// @notice The precommitment to the transactions of the latest batch.
bytes32 precommitmentForTheLatestBatch;
}
/// @dev Used as the `msg.sender` for system service transactions.
address constant SERVICE_TRANSACTION_SENDER = address(uint160(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF));
/// @dev To avoid higher costs the writes, we avoid making the slot zero.
/// This ensures that the cost of writes is always 5k and avoids the 20k initial write from the non-zero value.
bytes32 constant DEFAULT_PRECOMMITMENT_FOR_THE_LAST_BATCH = bytes32(uint256(1));
/// @dev The length of a packed transaction precommitment in bytes. It consists of two parts: 32-byte tx hash and 1-byte status (0 or 1).
uint256 constant PACKED_L2_PRECOMMITMENT_LENGTH = 33;
/// @dev Pubdata commitment scheme used for DA.
/// @param NONE Invalid option.
/// @param EMPTY_NO_DA No DA commitment, used by Validiums.
/// @param PUBDATA_KECCAK256 Keccak of stateDiffHash and keccak(pubdata). Can be used by custom DA solutions.
/// @param BLOBS_AND_PUBDATA_KECCAK256 This commitment includes EIP-4844 blobs data. Used by default RollupL1DAValidator.
/// @param BLOBS_ZKSYNC_OS Keccak of blob versioned hashes filled with pubdata. This commitment scheme is used only for ZKsyncOS.
enum L2DACommitmentScheme {
NONE,
EMPTY_NO_DA,
PUBDATA_KECCAK256,
BLOBS_AND_PUBDATA_KECCAK256,
BLOBS_ZKSYNC_OS
}
/// @dev The L2 data availability commitment scheme that permanent rollups are expected to use.
L2DACommitmentScheme constant ROLLUP_L2_DA_COMMITMENT_SCHEME = L2DACommitmentScheme.BLOBS_AND_PUBDATA_KECCAK256;// 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;
/// @notice Part of the configuration parameters of ZKP circuits
struct VerifierParams {
bytes32 recursionNodeLevelVkHash;
bytes32 recursionLeafLevelVkHash;
bytes32 recursionCircuitsSetVksHash;
}
/// @title The interface of the Verifier contract, responsible for the zero knowledge proof verification.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IVerifier {
/// @dev Verifies a zk-SNARK proof.
/// @return A boolean value indicating whether the zk-SNARK proof is valid.
/// Note: The function may revert execution instead of returning false in some cases.
function verify(uint256[] calldata _publicInputs, uint256[] calldata _proof) external view returns (bool);
/// @notice Calculates a keccak256 hash of the runtime loaded verification keys.
/// @return vkHash The keccak256 hash of the loaded verification keys.
function verificationKeyHash() external view returns (bytes32);
}// 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;
import {L2Log, L2Message} from "../../common/Messaging.sol";
/// @title The interface of the ZKsync MessageVerification contract that can be used to prove L2 message inclusion.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IMessageVerification {
/// @notice Prove that a specific arbitrary-length message was sent in a specific L2 batch/block number.
/// @param _chainId The chain id of the L2 where the message comes from.
/// @param _blockOrBatchNumber The executed L2 batch/block number in which the message appeared.
/// @param _index The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _message Information about the sent message: sender address, the message itself, tx index in the L2 batch where the message was sent.
/// @param _proof Merkle proof for inclusion of L2 log that was sent with the message.
/// @return Boolean specifying whether the proof is valid.
function proveL2MessageInclusionShared(
uint256 _chainId,
uint256 _blockOrBatchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice Prove that a specific L2 log was sent in a specific L2 batch.
/// @param _chainId The chain id of the L2 where the log comes from.
/// @param _blockOrBatchNumber The executed L2 batch/block number in which the log appeared.
/// @param _index The position of the l2log in the L2 logs Merkle tree.
/// @param _log Information about the sent log.
/// @param _proof Merkle proof for inclusion of the L2 log.
/// @return Whether the proof is correct and L2 log is included in batch.
function proveL2LogInclusionShared(
uint256 _chainId,
uint256 _blockOrBatchNumber,
uint256 _index,
L2Log calldata _log,
bytes32[] calldata _proof
) external view returns (bool);
/// @dev Proves that a certain leaf was included as part of the log merkle tree.
/// @dev Warning: this function does not enforce any additional checks on the structure
/// of the leaf. This means that it can accept intermediate nodes of the Merkle tree as a `_leaf` as
/// well as the default "empty" leaves. It is the responsibility of the caller to ensure that the
/// `_leaf` is a hash of a valid leaf.
/// @param _chainId The chain id of the L2 where the leaf comes from.
/// @param _blockOrBatchNumber The batch/block number of the leaf to be proven.
/// @param _leafProofMask The leaf proof mask.
/// @param _leaf The leaf to be proven.
/// @param _proof The proof.
function proveL2LeafInclusionShared(
uint256 _chainId,
uint256 _blockOrBatchNumber,
uint256 _leafProofMask,
bytes32 _leaf,
bytes32[] calldata _proof
) external view returns (bool);
}// 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;
import {IZKChainBase} from "./IZKChainBase.sol";
import {BridgehubL2TransactionRequest, L2CanonicalTransaction, L2Log, L2Message, TxStatus} from "../../common/Messaging.sol";
/// @title The interface of the ZKsync Mailbox contract that provides functions for L1 <-> L2 interaction.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IMailboxImpl is IZKChainBase {
/// @notice Prove that a specific arbitrary-length message was sent in a specific L2 batch number.
/// @param _batchNumber The executed L2 batch number in which the message appeared.
/// @param _index The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _message Information about the sent message: sender address, the message itself, tx index in the L2 batch where the message was sent.
/// @param _proof Merkle proof for inclusion of L2 log that was sent with the message.
/// @return Boolean specifying whether the proof is valid.
function proveL2MessageInclusion(
uint256 _batchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice Prove that a specific L2 log was sent in a specific L2 batch.
/// @param _batchNumber The executed L2 batch number in which the log appeared.
/// @param _index The position of the l2log in the L2 logs Merkle tree.
/// @param _log Information about the sent log.
/// @param _proof Merkle proof for inclusion of the L2 log.
/// @return Whether the proof is correct and L2 log is included in batch.
function proveL2LogInclusion(
uint256 _batchNumber,
uint256 _index,
L2Log calldata _log,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice Prove that the L1 -> L2 transaction was processed with the specified status.
/// @param _l2TxHash The L2 canonical transaction hash.
/// @param _l2BatchNumber The L2 batch number where the transaction was processed.
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent.
/// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction.
/// @param _status The execution status of the L1 -> L2 transaction (true - success & 0 - fail).
/// @return Whether the proof is correct and the transaction was actually executed with provided status.
/// NOTE: It may return `false` for incorrect proof, but it doesn't mean that the L1 -> L2 transaction has an opposite status!
function proveL1ToL2TransactionStatus(
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof,
TxStatus _status
) external view returns (bool);
/// @notice Finalize the withdrawal and release funds.
/// @param _l2BatchNumber The L2 batch number where the withdrawal was processed.
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _l2TxNumberInBatch The L2 transaction number in a batch, in which the log was sent.
/// @param _message The L2 withdraw data, stored in an L2 -> L1 message.
/// @param _merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization.
function finalizeEthWithdrawal(
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external;
/// @notice Request execution of L2 transaction from L1.
/// @param _contractL2 The L2 receiver address.
/// @param _l2Value `msg.value` of L2 transaction.
/// @param _calldata The input of the L2 transaction.
/// @param _l2GasLimit Maximum amount of L2 gas that transaction can consume during execution on L2.
/// @param _l2GasPerPubdataByteLimit The maximum amount L2 gas that the operator may charge the user for single byte of pubdata.
/// @param _factoryDeps An array of L2 bytecodes that will be marked as known on L2.
/// @param _refundRecipient The address on L2 that will receive the refund for the transaction.
/// @dev If the L2 deposit finalization transaction fails, the `_refundRecipient` will receive the `_l2Value`.
/// Please note, the contract may change the refund recipient's address to eliminate sending funds to addresses out of control.
/// - If `_refundRecipient` is a contract on L1, the refund will be sent to the aliased `_refundRecipient`.
/// - If `_refundRecipient` is set to `address(0)` and the sender has NO deployed bytecode on L1, the refund will be sent to the `msg.sender` address.
/// - If `_refundRecipient` is set to `address(0)` and the sender has deployed bytecode on L1, the refund will be sent to the aliased `msg.sender` address.
/// @dev The address aliasing of L1 contracts as refund recipient on L2 is necessary to guarantee that the funds are controllable,
/// since address aliasing to the from address for the L2 tx will be applied if the L1 `msg.sender` is a contract.
/// Without address aliasing for L1 contracts as refund recipients they would not be able to make proper L2 tx requests
/// through the Mailbox to use or withdraw the funds from L2, and the funds would be lost.
/// @return canonicalTxHash The hash of the requested L2 transaction. This hash can be used to follow the transaction status.
function requestL2Transaction(
address _contractL2,
uint256 _l2Value,
bytes calldata _calldata,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit,
bytes[] calldata _factoryDeps,
address _refundRecipient
) external payable returns (bytes32 canonicalTxHash);
/// @notice Request execution of L2 transaction through the Bridgehub.
/// @dev Only accessible from L1, this is getting checked in the Bridgehub.
/// @param _request the request for the L2 transaction.
function bridgehubRequestL2Transaction(
BridgehubL2TransactionRequest calldata _request
) external returns (bytes32 canonicalTxHash);
/// @notice The chain's mailbox receives the tx from the Bridgehub on Gateway.
/// @param _canonicalTxHash the canonical transaction hash.
/// @param _expirationTimestamp the expiration timestamp for the transaction.
function bridgehubRequestL2TransactionOnGateway(bytes32 _canonicalTxHash, uint64 _expirationTimestamp) external;
/// @notice Request execution of service L2 transaction from L1.
/// @dev Used for chain configuration. Can be called only by DiamondProxy itself.
/// @param _contractL2 The L2 receiver address.
/// @param _l2Calldata The input of the L2 transaction.
function requestL2ServiceTransaction(
address _contractL2,
bytes calldata _l2Calldata
) external returns (bytes32 canonicalTxHash);
/// @dev On L1 we have to forward to the Gateway's mailbox which sends to the Bridgehub on the Gateway.
/// @param _chainId the chainId of the chain.
/// @param _canonicalTxHash the canonical transaction hash.
/// @param _expirationTimestamp the expiration timestamp.
function requestL2TransactionToGatewayMailbox(
uint256 _chainId,
bytes32 _canonicalTxHash,
uint64 _expirationTimestamp
) external returns (bytes32 canonicalTxHash);
/// @notice Estimates the cost in Ether of requesting execution of an L2 transaction from L1.
/// @param _gasPrice expected L1 gas price at which the user requests the transaction execution.
/// @param _l2GasLimit Maximum amount of L2 gas that transaction can consume during execution on L2.
/// @param _l2GasPerPubdataByteLimit The maximum amount of L2 gas that the operator may charge the user for a single byte of pubdata.
/// @return The estimated ETH spent on L2 gas for the transaction.
function l2TransactionBaseCost(
uint256 _gasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256);
/// @dev Proves that a certain leaf was included as part of the log merkle tree.
/// @dev Warning: this function does not enforce any additional checks on the structure
/// of the leaf. This means that it can accept intermediate nodes of the Merkle tree as a `_leaf` as
/// well as the default "empty" leaves. It is the responsibility of the caller to ensure that the
/// `_leaf` is a hash of a valid leaf.
/// @param _batchNumber The batch number of the leaf to be proven.
/// @param _leafProofMask The leaf proof mask.
/// @param _leaf The leaf to be proven.
/// @param _proof The proof.
function proveL2LeafInclusion(
uint256 _batchNumber,
uint256 _leafProofMask,
bytes32 _leaf,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice New priority request event. Emitted when a request is placed into the priority queue.
/// @param txId Serial number of the priority operation.
/// @param txHash keccak256 hash of encoded transaction representation.
/// @param expirationTimestamp Timestamp up to which priority request should be processed.
/// @param transaction The whole transaction structure that is requested to be executed on L2.
/// @param factoryDeps An array of bytecodes that were shown in the L1 public data.
/// Will be marked as known bytecodes in L2.
event NewPriorityRequest(
uint256 txId,
bytes32 txHash,
uint64 expirationTimestamp,
L2CanonicalTransaction transaction,
bytes[] factoryDeps
);
/// @notice Indexed new priority request event. Emitted when a request is placed into the priority queue.
/// @dev We define a new event similar to NewPriorityRequest, as modifying it could break existing indexers.
/// The indexed txId and txHash helps to simplify external node implementation for fast finality.
/// @param txId Serial number of the priority operation.
/// @param txHash keccak256 hash of encoded transaction representation.
event NewPriorityRequestId(uint256 indexed txId, bytes32 indexed txHash);
/// @notice New relayed priority request event. It is emitted on a chain that is deployed
/// on top of the gateway when it receives a request relayed via the Bridgehub.
/// @dev IMPORTANT: this event most likely will be removed in the future, so
/// no one should rely on it for indexing purposes.
/// @param txId Serial number of the priority operation.
/// @param txHash keccak256 hash of encoded transaction representation.
/// @param expirationTimestamp Timestamp up to which priority request should be processed.
event NewRelayedPriorityTransaction(uint256 txId, bytes32 txHash, uint64 expirationTimestamp);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// 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; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice The library for unchecked math. */ library UncheckedMath { function uncheckedInc(uint256 _number) internal pure returns (uint256) { unchecked { return _number + 1; } } function uncheckedAdd(uint256 _lhs, uint256 _rhs) internal pure returns (uint256) { unchecked { return _lhs + _rhs; } } }
// 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;
/// @dev The enum that represents the transaction execution status
/// @param Failure The transaction execution failed
/// @param Success The transaction execution succeeded
enum TxStatus {
Failure,
Success
}
/// @dev The log passed from L2
/// @param l2ShardId The shard identifier, 0 - rollup, 1 - porter
/// All other values are not used but are reserved for the future
/// @param isService A boolean flag that is part of the log along with `key`, `value`, and `sender` address.
/// This field is required formally but does not have any special meaning
/// @param txNumberInBatch The L2 transaction number in a Batch, in which the log was sent
/// @param sender The L2 address which sent the log
/// @param key The 32 bytes of information that was sent in the log
/// @param value The 32 bytes of information that was sent in the log
// Both `key` and `value` are arbitrary 32-bytes selected by the log sender
struct L2Log {
uint8 l2ShardId;
bool isService;
uint16 txNumberInBatch;
address sender;
bytes32 key;
bytes32 value;
}
/// @dev An arbitrary length message passed from L2
/// @notice Under the hood it is `L2Log` sent from the special system L2 contract
/// @param txNumberInBatch The L2 transaction number in a Batch, in which the message was sent
/// @param sender The address of the L2 account from which the message was passed
/// @param data An arbitrary length message
struct L2Message {
uint16 txNumberInBatch;
address sender;
bytes data;
}
/// @dev Internal structure that contains the parameters for the writePriorityOp
/// internal function.
/// @param txId The id of the priority transaction.
/// @param l2GasPrice The gas price for the l2 priority operation.
/// @param expirationTimestamp The timestamp by which the priority operation must be processed by the operator.
/// @param request The external calldata request for the priority operation.
struct WritePriorityOpParams {
uint256 txId;
uint256 l2GasPrice;
uint64 expirationTimestamp;
BridgehubL2TransactionRequest request;
}
/// @dev Structure that includes all fields of the L2 transaction
/// @dev The hash of this structure is the "canonical L2 transaction hash" and can
/// be used as a unique identifier of a tx
/// @param txType The tx type number, depending on which the L2 transaction can be
/// interpreted differently
/// @param from The sender's address. `uint256` type for possible address format changes
/// and maintaining backward compatibility
/// @param to The recipient's address. `uint256` type for possible address format changes
/// and maintaining backward compatibility
/// @param gasLimit The L2 gas limit for L2 transaction. Analog to the `gasLimit` on an
/// L1 transactions
/// @param gasPerPubdataByteLimit Maximum number of L2 gas that will cost one byte of pubdata
/// (every piece of data that will be stored on L1 as calldata)
/// @param maxFeePerGas The absolute maximum sender willing to pay per unit of L2 gas to get
/// the transaction included in a Batch. Analog to the EIP-1559 `maxFeePerGas` on an L1 transactions
/// @param maxPriorityFeePerGas The additional fee that is paid directly to the validator
/// to incentivize them to include the transaction in a Batch. Analog to the EIP-1559
/// `maxPriorityFeePerGas` on an L1 transactions
/// @param paymaster The address of the EIP-4337 paymaster, that will pay fees for the
/// transaction. `uint256` type for possible address format changes and maintaining backward compatibility
/// @param nonce The nonce of the transaction. For L1->L2 transactions it is the priority
/// operation Id
/// @param value The value to pass with the transaction
/// @param reserved The fixed-length fields for usage in a future extension of transaction
/// formats
/// @param data The calldata that is transmitted for the transaction call
/// @param signature An abstract set of bytes that are used for transaction authorization
/// @param factoryDeps The set of L2 bytecode hashes whose preimages were shown on L1
/// @param paymasterInput The arbitrary-length data that is used as a calldata to the paymaster pre-call
/// @param reservedDynamic The arbitrary-length field for usage in a future extension of transaction formats
struct L2CanonicalTransaction {
uint256 txType;
uint256 from;
uint256 to;
uint256 gasLimit;
uint256 gasPerPubdataByteLimit;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
uint256 paymaster;
uint256 nonce;
uint256 value;
// In the future, we might want to add some
// new fields to the struct. The `txData` struct
// is to be passed to account and any changes to its structure
// would mean a breaking change to these accounts. To prevent this,
// we should keep some fields as "reserved"
// It is also recommended that their length is fixed, since
// it would allow easier proof integration (in case we will need
// some special circuit for preprocessing transactions)
uint256[4] reserved;
bytes data;
bytes signature;
uint256[] factoryDeps;
bytes paymasterInput;
// Reserved dynamic type for the future use-case. Using it should be avoided,
// But it is still here, just in case we want to enable some additional functionality
bytes reservedDynamic;
}
/// @param sender The sender's address.
/// @param contractAddressL2 The address of the contract on L2 to call.
/// @param valueToMint The amount of base token that should be minted on L2 as the result of this transaction.
/// @param l2Value The msg.value of the L2 transaction.
/// @param l2Calldata The calldata for the L2 transaction.
/// @param l2GasLimit The limit of the L2 gas for the L2 transaction
/// @param l2GasPerPubdataByteLimit The price for a single pubdata byte in L2 gas.
/// @param factoryDeps The array of L2 bytecodes that the tx depends on.
/// @param refundRecipient The recipient of the refund for the transaction on L2. If the transaction fails, then
/// this address will receive the `l2Value`.
// solhint-disable-next-line gas-struct-packing
struct BridgehubL2TransactionRequest {
address sender;
address contractL2;
uint256 mintValue;
uint256 l2Value;
bytes l2Calldata;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
bytes[] factoryDeps;
address refundRecipient;
}
/// @dev The structure that contains the parameters for the message root
/// @param chainId The chain id of the dependency chain
/// @param blockOrBatchNumber The block number or the batch number where the message root was created
/// For proof based interop it is block number. For commit based interop it is batch number.
/// @param sides The sides of the dynamic incremental merkle tree emitted in the L2ToL1Messenger for precommit based interop
/// For proof and commit based interop, the sides contain a single root.
struct InteropRoot {
uint256 chainId;
uint256 blockOrBatchNumber;
// We are double overloading this. The sides of the dynamic incremental merkle tree normally contains the root, as well as the sides of the tree.
// Second overloading: if the length is 1, we are importing a chainBatchRoot/messageRoot instead of sides.
bytes32[] sides;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IBridgehubBase, L2TransactionRequestTwoBridgesInner} from "./IBridgehubBase.sol";
import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol";
import {IL1AssetDeploymentTracker} from "../bridge/interfaces/IL1AssetDeploymentTracker.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface ICTMDeploymentTracker is IL1AssetDeploymentTracker {
function bridgehubDeposit(
uint256 _chainId,
address _originalCaller,
uint256 _l2Value,
bytes calldata _data
) external payable returns (L2TransactionRequestTwoBridgesInner memory request);
function BRIDGE_HUB() external view returns (IBridgehubBase);
function L1_ASSET_ROUTER() external view returns (IAssetRouterBase);
function registerCTMAssetOnL1(address _ctmAddress) external;
function calculateAssetId(address _l1CTM) external view returns (bytes32);
}// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /** * @author Matter Labs * @notice MessageRoot contract is responsible for storing and aggregating the roots of the batches from different chains into the MessageRoot. * @custom:security-contact [email protected] */ interface IMessageRoot { function BRIDGE_HUB() external view returns (address); function addNewChain(uint256 _chainId) external; function historicalRoot(uint256 _blockNumber) external view returns (bytes32); }
// 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;
import {QueueIsEmpty} from "../../common/L1ContractErrors.sol";
/// @notice The structure that contains meta information of the L2 transaction that was requested from L1
/// @dev The weird size of fields was selected specifically to minimize the structure storage size
/// @param canonicalTxHash Hashed L2 transaction data that is needed to process it
/// @param expirationTimestamp Expiration timestamp for this request (must be satisfied before)
/// @param layer2Tip Additional payment to the validator as an incentive to perform the operation
struct PriorityOperation {
bytes32 canonicalTxHash;
uint64 expirationTimestamp;
uint192 layer2Tip;
}
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @dev The library provides the API to interact with the priority queue container
/// @dev Order of processing operations from queue - FIFO (Fist in - first out)
library PriorityQueue {
using PriorityQueue for Queue;
/// @notice Container that stores priority operations
/// @param data The inner mapping that saves priority operation by its index
/// @param head The pointer to the first unprocessed priority operation, equal to the tail if the queue is empty
/// @param tail The pointer to the free slot
struct Queue {
mapping(uint256 priorityOpId => PriorityOperation priorityOp) data;
uint256 tail;
uint256 head;
}
/// @notice Returns zero if and only if no operations were processed from the queue
/// @return Index of the oldest priority operation that wasn't processed yet
function getFirstUnprocessedPriorityTx(Queue storage _queue) internal view returns (uint256) {
return _queue.head;
}
/// @return The total number of priority operations that were added to the priority queue, including all processed ones
function getTotalPriorityTxs(Queue storage _queue) internal view returns (uint256) {
return _queue.tail;
}
/// @return The total number of unprocessed priority operations in a priority queue
function getSize(Queue storage _queue) internal view returns (uint256) {
return uint256(_queue.tail - _queue.head);
}
/// @return Whether the priority queue contains no operations
function isEmpty(Queue storage _queue) internal view returns (bool) {
return _queue.tail == _queue.head;
}
/// @notice Add the priority operation to the end of the priority queue
function pushBack(Queue storage _queue, PriorityOperation memory _operation) internal {
// Save value into the stack to avoid double reading from the storage
uint256 tail = _queue.tail;
_queue.data[tail] = _operation;
_queue.tail = tail + 1;
}
/// @return The first unprocessed priority operation from the queue
function front(Queue storage _queue) internal view returns (PriorityOperation memory) {
// priority queue is empty
if (_queue.isEmpty()) {
revert QueueIsEmpty();
}
return _queue.data[_queue.head];
}
/// @notice Remove the first unprocessed priority operation from the queue
/// @return priorityOperation that was popped from the priority queue
function popFront(Queue storage _queue) internal returns (PriorityOperation memory priorityOperation) {
// priority queue is empty
if (_queue.isEmpty()) {
revert QueueIsEmpty();
}
// Save value into the stack to avoid double reading from the storage
uint256 head = _queue.head;
priorityOperation = _queue.data[head];
delete _queue.data[head];
_queue.head = head + 1;
}
}// 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;
import {DynamicIncrementalMerkle} from "../../common/libraries/DynamicIncrementalMerkle.sol";
import {Merkle} from "../../common/libraries/Merkle.sol";
import {PriorityTreeCommitment} from "../../common/Config.sol";
import {InvalidCommitment, InvalidNextLeafIndex, InvalidStartIndex, InvalidUnprocessedIndex, NotHistoricalRoot} from "../L1StateTransitionErrors.sol";
struct PriorityOpsBatchInfo {
bytes32[] leftPath;
bytes32[] rightPath;
bytes32[] itemHashes;
}
bytes32 constant ZERO_LEAF_HASH = keccak256("");
library PriorityTree {
using PriorityTree for Tree;
using DynamicIncrementalMerkle for DynamicIncrementalMerkle.Bytes32PushTree;
struct Tree {
uint256 startIndex; // priority tree started accepting priority ops from this index
uint256 unprocessedIndex; // relative to `startIndex`
mapping(bytes32 => bool) historicalRoots;
DynamicIncrementalMerkle.Bytes32PushTree tree;
}
/// @notice Returns zero if and only if no operations were processed from the tree
/// @return Index of the oldest priority operation that wasn't processed yet
function getFirstUnprocessedPriorityTx(Tree storage _tree) internal view returns (uint256) {
return _tree.startIndex + _tree.unprocessedIndex;
}
/// @return The total number of priority operations that were added to the priority queue, including all processed ones
function getTotalPriorityTxs(Tree storage _tree) internal view returns (uint256) {
return _tree.startIndex + _tree.tree._nextLeafIndex;
}
/// @return The total number of unprocessed priority operations in a priority queue
function getSize(Tree storage _tree) internal view returns (uint256) {
return _tree.tree._nextLeafIndex - _tree.unprocessedIndex;
}
/// @notice Add the priority operation to the end of the priority queue
function push(Tree storage _tree, bytes32 _hash) internal {
(, bytes32 newRoot) = _tree.tree.push(_hash);
_tree.historicalRoots[newRoot] = true;
}
/// @notice Set up the tree
function setup(Tree storage _tree, uint256 _startIndex) internal {
bytes32 initialRoot = _tree.tree.setup(ZERO_LEAF_HASH);
_tree.historicalRoots[initialRoot] = true;
_tree.startIndex = _startIndex;
}
/// @return Returns the tree root.
function getRoot(Tree storage _tree) internal view returns (bytes32) {
return _tree.tree.root();
}
/// @param _root The root to check.
/// @return Returns true if the root is a historical root.
function isHistoricalRoot(Tree storage _tree, bytes32 _root) internal view returns (bool) {
return _tree.historicalRoots[_root];
}
/// @notice Process the priority operations of a batch.
/// @dev Note, that the function below only checks that a certain segment of items is present in the tree.
/// It does not check that e.g. there are no zero items inside the provided `itemHashes`, so in theory proofs
/// that include non-existing priority operations could be created. This function relies on the fact
/// that the `itemHashes` of `_priorityOpsData` are hashes of valid priority transactions.
/// This fact is ensured by the fact the rolling hash of those is sent to the Executor by the bootloader
/// and so assuming that zero knowledge proofs are correct, so is the structure of the `itemHashes`.
function processBatch(Tree storage _tree, PriorityOpsBatchInfo memory _priorityOpsData) internal {
if (_priorityOpsData.itemHashes.length > 0) {
bytes32 expectedRoot = Merkle.calculateRootPaths(
_priorityOpsData.leftPath,
_priorityOpsData.rightPath,
_tree.unprocessedIndex,
_priorityOpsData.itemHashes
);
if (!_tree.historicalRoots[expectedRoot]) {
revert NotHistoricalRoot(expectedRoot);
}
_tree.unprocessedIndex += _priorityOpsData.itemHashes.length;
}
}
/// @notice Allows to skip a certain number of operations.
/// @param _lastUnprocessed The new expected id of the unprocessed transaction.
/// @dev It is used when the corresponding transactions have been processed by priority queue.
function skipUntil(Tree storage _tree, uint256 _lastUnprocessed) internal {
if (_tree.startIndex > _lastUnprocessed) {
// Nothing to do, return
return;
}
uint256 newUnprocessedIndex = _lastUnprocessed - _tree.startIndex;
if (newUnprocessedIndex <= _tree.unprocessedIndex) {
// These transactions were already processed, skip.
return;
}
_tree.unprocessedIndex = newUnprocessedIndex;
}
/// @notice Initialize a chain from a commitment.
function initFromCommitment(Tree storage _tree, PriorityTreeCommitment memory _commitment) internal {
uint256 height = _commitment.sides.length; // Height, including the root node.
if (height == 0) {
revert InvalidCommitment();
}
_tree.startIndex = _commitment.startIndex;
_tree.unprocessedIndex = _commitment.unprocessedIndex;
_tree.tree._nextLeafIndex = _commitment.nextLeafIndex;
_tree.tree._sides = _commitment.sides;
bytes32 zero = ZERO_LEAF_HASH;
_tree.tree._zeros = new bytes32[](height);
for (uint256 i; i < height; ++i) {
_tree.tree._zeros[i] = zero;
zero = Merkle.efficientHash(zero, zero);
}
_tree.historicalRoots[_tree.tree.root()] = true;
}
/// @notice Reinitialize the tree from a commitment on L1.
function l1Reinit(Tree storage _tree, PriorityTreeCommitment memory _commitment) internal {
if (_tree.startIndex != _commitment.startIndex) {
revert InvalidStartIndex(_tree.startIndex, _commitment.startIndex);
}
if (_tree.unprocessedIndex > _commitment.unprocessedIndex) {
revert InvalidUnprocessedIndex(_tree.unprocessedIndex, _commitment.unprocessedIndex);
}
if (_tree.tree._nextLeafIndex < _commitment.nextLeafIndex) {
revert InvalidNextLeafIndex(_tree.tree._nextLeafIndex, _commitment.nextLeafIndex);
}
_tree.unprocessedIndex = _commitment.unprocessedIndex;
}
/// @notice Reinitialize the tree from a commitment on GW.
function checkGWReinit(Tree storage _tree, PriorityTreeCommitment memory _commitment) internal view {
if (_tree.startIndex != _commitment.startIndex) {
revert InvalidStartIndex(_tree.startIndex, _commitment.startIndex);
}
if (_tree.unprocessedIndex > _commitment.unprocessedIndex) {
revert InvalidUnprocessedIndex(_tree.unprocessedIndex, _commitment.unprocessedIndex);
}
if (_tree.tree._nextLeafIndex > _commitment.nextLeafIndex) {
revert InvalidNextLeafIndex(_tree.tree._nextLeafIndex, _commitment.nextLeafIndex);
}
}
/// @notice Returns the commitment to the priority tree.
function getCommitment(Tree storage _tree) internal view returns (PriorityTreeCommitment memory commitment) {
commitment.nextLeafIndex = _tree.tree._nextLeafIndex;
commitment.startIndex = _tree.startIndex;
commitment.unprocessedIndex = _tree.unprocessedIndex;
commitment.sides = _tree.tree._sides;
}
}// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @dev The encoding version used for legacy txs. bytes1 constant LEGACY_ENCODING_VERSION = 0x00; /// @dev The encoding version used for new txs. bytes1 constant NEW_ENCODING_VERSION = 0x01; /// @dev The encoding version used for txs that set the asset handler on the counterpart contract. bytes1 constant SET_ASSET_HANDLER_COUNTERPART_ENCODING_VERSION = 0x02; /// @title L1 Bridge contract interface /// @author Matter Labs /// @custom:security-contact [email protected] interface IAssetRouterBase { event BridgehubDepositBaseTokenInitiated( uint256 indexed chainId, address indexed from, bytes32 assetId, uint256 amount ); event BridgehubDepositInitiated( uint256 indexed chainId, bytes32 indexed txDataHash, address indexed from, bytes32 assetId, bytes bridgeMintCalldata ); event BridgehubWithdrawalInitiated( uint256 chainId, address indexed sender, bytes32 indexed assetId, bytes32 assetDataHash // Todo: What's the point of emitting hash? ); event AssetDeploymentTrackerRegistered( bytes32 indexed assetId, bytes32 indexed additionalData, address assetDeploymentTracker ); event AssetHandlerRegistered(bytes32 indexed assetId, address indexed _assetHandlerAddress); event DepositFinalizedAssetRouter(uint256 indexed chainId, bytes32 indexed assetId, bytes assetData); function assetHandlerAddress(bytes32 _assetId) external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @author Matter Labs /// @custom:security-contact [email protected] interface IL1AssetDeploymentTracker { function bridgeCheckCounterpartAddress( uint256 _chainId, bytes32 _assetId, address _originalCaller, address _assetHandlerAddressOnCounterpart ) external view; }
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Merkle} from "./Merkle.sol";
import {Arrays} from "@openzeppelin/contracts-v4/utils/Arrays.sol";
/**
* @dev Library for managing https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures.
*
* Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a
* non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not
* stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}.
*
* A tree is defined by the following parameters:
*
* * Depth: The number of levels in the tree, it also defines the maximum number of leaves as 2**depth.
* * Zero value: The value that represents an empty leaf. Used to avoid regular zero values to be part of the tree.
* * Hashing function: A cryptographic hash function used to produce internal nodes.
*
* This is a fork of OpenZeppelin's [`MerkleTree`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/9af280dc4b45ee5bda96ba47ff829b407eaab67e/contracts/utils/structs/MerkleTree.sol)
* library, with the changes to support dynamic tree growth (doubling the size when full).
*/
library DynamicIncrementalMerkle {
/**
* @dev A complete `bytes32` Merkle tree.
*
* The `sides` and `zero` arrays are set to have a length equal to the depth of the tree during setup.
*
* Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
* lead to unexpected behavior.
*
* NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to
* store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or
* {Checkpoints}).
*
* WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree.
*/
struct Bytes32PushTree {
uint256 _nextLeafIndex;
bytes32[] _sides;
bytes32[] _zeros;
}
/**
* @dev Initialize a {Bytes32PushTree} using {Hashes-Keccak256} to hash internal nodes.
* The capacity of the tree (i.e. number of leaves) is set to `2**levels`.
*
* IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing
* empty leaves. It should be a value that is not expected to be part of the tree.
*/
function setup(Bytes32PushTree storage self, bytes32 zero) internal returns (bytes32 initialRoot) {
self._nextLeafIndex = 0;
self._zeros.push(zero);
self._sides.push(bytes32(0));
return bytes32(0);
}
/**
* @dev Resets the tree to a blank state.
* Calling this function on MerkleTree that was already setup and used will reset it to a blank state.
* @param zero The value that represents an empty leaf.
* @return initialRoot The initial root of the tree.
*/
function reset(Bytes32PushTree storage self, bytes32 zero) internal returns (bytes32 initialRoot) {
self._nextLeafIndex = 0;
uint256 length = self._zeros.length;
for (uint256 i = length; 0 < i; --i) {
self._zeros.pop();
}
length = self._sides.length;
for (uint256 i = length; 0 < i; --i) {
self._sides.pop();
}
self._zeros.push(zero);
self._sides.push(bytes32(0));
return bytes32(0);
}
/**
* @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the
* tree, and the resulting root.
*
* Hashing the leaf before calling this function is recommended as a protection against
* second pre-image attacks.
*/
function push(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) {
// Cache read
uint256 levels = self._zeros.length - 1;
// Get leaf index
// solhint-disable-next-line gas-increment-by-one
index = self._nextLeafIndex++;
// Check if tree is full.
if (index == 1 << levels) {
bytes32 zero = self._zeros[levels];
bytes32 newZero = Merkle.efficientHash(zero, zero);
self._zeros.push(newZero);
self._sides.push(bytes32(0));
++levels;
}
// Rebuild branch from leaf to root
uint256 currentIndex = index;
bytes32 currentLevelHash = leaf;
bool updatedSides = false;
for (uint32 i = 0; i < levels; ++i) {
// Reaching the parent node, is currentLevelHash the left child?
bool isLeft = currentIndex % 2 == 0;
// If so, next time we will come from the right, so we need to save it
if (isLeft && !updatedSides) {
Arrays.unsafeAccess(self._sides, i).value = currentLevelHash;
updatedSides = true;
}
// Compute the current node hash by using the hash function
// with either its sibling (side) or the zero value for that level.
currentLevelHash = Merkle.efficientHash(
isLeft ? currentLevelHash : Arrays.unsafeAccess(self._sides, i).value,
isLeft ? Arrays.unsafeAccess(self._zeros, i).value : currentLevelHash
);
// Update node index
currentIndex >>= 1;
}
Arrays.unsafeAccess(self._sides, levels).value = currentLevelHash;
return (index, currentLevelHash);
}
/**
* @dev Tree's root.
*/
function root(Bytes32PushTree storage self) internal view returns (bytes32) {
return Arrays.unsafeAccess(self._sides, self._sides.length - 1).value;
}
/**
* @dev Tree's height (does not include the root node).
*/
function height(Bytes32PushTree storage self) internal view returns (uint256) {
return self._sides.length - 1;
}
}// 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;
import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol";
import {MerkleIndexOrHeightMismatch, MerkleIndexOutOfBounds, MerkleNothingToProve, MerklePathEmpty, MerklePathLengthMismatch, MerklePathOutOfBounds} from "../../common/L1ContractErrors.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
library Merkle {
using UncheckedMath for uint256;
/// @dev Calculate Merkle root by the provided Merkle proof.
/// NOTE: When using this function, check that the _path length is equal to the tree height to prevent shorter/longer paths attack
/// however, for chains settling on GW the proof includes the GW proof, so the path increases. See Mailbox for more details.
/// @param _path Merkle path from the leaf to the root
/// @param _index Leaf index in the tree
/// @param _itemHash Hash of leaf content
/// @return The Merkle root
function calculateRoot(
bytes32[] calldata _path,
uint256 _index,
bytes32 _itemHash
) internal pure returns (bytes32) {
uint256 pathLength = _path.length;
_validatePathLengthForSingleProof(_index, pathLength);
bytes32 currentHash = _itemHash;
for (uint256 i; i < pathLength; i = i.uncheckedInc()) {
currentHash = (_index % 2 == 0)
? efficientHash(currentHash, _path[i])
: efficientHash(_path[i], currentHash);
_index /= 2;
}
return currentHash;
}
/// @dev Calculate Merkle root by the provided Merkle proof.
/// @dev NOTE: When using this function, check that the _path length is appropriate to prevent shorter/longer paths attack
/// @param _path Merkle path from the leaf to the root
/// @param _index Leaf index in the tree.
/// @dev NOTE the tree can be joined. In this case the second tree's leaves indexes increase by the number of leaves in the first tree.
/// @param _itemHash Hash of leaf content
/// @return The Merkle root
function calculateRootMemory(
bytes32[] memory _path,
uint256 _index,
bytes32 _itemHash
) internal pure returns (bytes32) {
uint256 pathLength = _path.length;
_validatePathLengthForSingleProof(_index, pathLength);
bytes32 currentHash = _itemHash;
for (uint256 i; i < pathLength; i = i.uncheckedInc()) {
currentHash = (_index % 2 == 0)
? efficientHash(currentHash, _path[i])
: efficientHash(_path[i], currentHash);
_index /= 2;
}
return currentHash;
}
/// @dev Calculate Merkle root by the provided Merkle proof for a range of elements
/// NOTE: When using this function, check that the _startPath and _endPath lengths are equal to the tree height to prevent shorter/longer paths attack
/// @param _startPath Merkle path from the first element of the range to the root
/// @param _endPath Merkle path from the last element of the range to the root
/// @param _startIndex Index of the first element of the range in the tree
/// @param _itemHashes Hashes of the elements in the range
/// @return The Merkle root
function calculateRootPaths(
bytes32[] memory _startPath,
bytes32[] memory _endPath,
uint256 _startIndex,
bytes32[] memory _itemHashes
) internal pure returns (bytes32) {
uint256 pathLength = _startPath.length;
if (pathLength != _endPath.length) {
revert MerklePathLengthMismatch(pathLength, _endPath.length);
}
if (pathLength >= 256) {
revert MerklePathOutOfBounds();
}
uint256 levelLen = _itemHashes.length;
// Edge case: we want to be able to prove an element in a single-node tree.
if (pathLength == 0 && (_startIndex != 0 || levelLen != 1)) {
revert MerklePathEmpty();
}
if (levelLen == 0) {
revert MerkleNothingToProve();
}
if (_startIndex + levelLen > (1 << pathLength)) {
revert MerkleIndexOrHeightMismatch();
}
bytes32[] memory itemHashes = _itemHashes;
for (uint256 level; level < pathLength; level = level.uncheckedInc()) {
uint256 parity = _startIndex % 2;
// We get an extra element on the next level if on the current level elements either
// start on an odd index (`parity == 1`) or end on an even index (`levelLen % 2 == 1`)
uint256 nextLevelLen = levelLen / 2 + (parity | (levelLen % 2));
for (uint256 i; i < nextLevelLen; i = i.uncheckedInc()) {
bytes32 lhs = (i == 0 && parity == 1) ? _startPath[level] : itemHashes[2 * i - parity];
bytes32 rhs = (i == nextLevelLen - 1 && (levelLen - parity) % 2 == 1)
? _endPath[level]
: itemHashes[2 * i + 1 - parity];
itemHashes[i] = efficientHash(lhs, rhs);
}
levelLen = nextLevelLen;
_startIndex /= 2;
}
return itemHashes[0];
}
/// @dev Keccak hash of the concatenation of two 32-byte words
function efficientHash(bytes32 _lhs, bytes32 _rhs) internal pure returns (bytes32 result) {
assembly {
mstore(0x00, _lhs)
mstore(0x20, _rhs)
result := keccak256(0x00, 0x40)
}
}
function _validatePathLengthForSingleProof(uint256 _index, uint256 _pathLength) private pure {
if (_pathLength >= 256) {
revert MerklePathOutOfBounds();
}
if (_index >= (1 << _pathLength)) {
revert MerkleIndexOutOfBounds();
}
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; // 0xb325f767 error AdminZero(); // 0xca1c3cbc error AlreadyMigrated(); // 0x125d99b0 error BlobHashBlobCommitmentMismatchValue(); // 0xafda12bf error CommitBasedInteropNotSupported(); // 0xc02d3ee3 error ContractNotDeployed(); // 0xdf2c5fa5 error DependencyRootsRollingHashMismatch(bytes32 _expected, bytes32 _actual); // 0xedae13f3 error ExecutedIsNotConsistentWithVerified(uint256 batchesExecuted, uint256 batchesVerified); // 0xc866ff2c error InitialForceDeploymentMismatch(bytes32 forceDeploymentHash, bytes32 initialForceDeploymentHash); // 0xfbd630b8 error InvalidBatchesDataLength(uint256 batchesDataLength, uint256 priorityOpsDataLength); // 0xc06789fa error InvalidCommitment(); // 0xd2531c15 error InvalidL2DAOutputHash(bytes32 l2DAValidatorOutputHash); // 0x30043900 error InvalidNextLeafIndex(uint256 treeNextLeafIndex, uint256 commitmentNextLeafIndex); // 0xfb1a3b59 error InvalidNumberOfBatchHashes(uint256 batchHashesLength, uint256 expected); // 0xbeb96791 error InvalidNumberOfBlobs(uint256 blobsProvided, uint256 maxBlobsSupported); // 0x5513177c error InvalidPubdataHash(bytes32 fullPubdataHash, bytes32 providedPubdataHash); // 0x5717f940 error InvalidPubdataSource(uint8 pubdataSource); // 0x90f67ecf error InvalidStartIndex(uint256 treeStartIndex, uint256 commitmentStartIndex); // 0x0f67bc0a error InvalidUnprocessedIndex(uint256 treeUnprocessedIndex, uint256 commitmentUnprocessedIndex); // 0x2e89f517 error L1DAValidatorAddressIsZero(); // 0x7fbff2dd error L1DAValidatorInvalidSender(address msgSender); // 0xa969e486 error LocalRootIsZero(); // 0xbdaf7d42 error LocalRootMustBeZero(); // 0x9b5f85eb error MessageRootIsZero(); // 0x32fff278 error MismatchL2DACommitmentScheme(uint256 operatorProvidedScheme, uint256 expectedScheme); // 0x2c01a4af error MismatchNumberOfLayer1Txs(uint256 numberOfLayer1Txs, uint256 expectedLength); // 0xf9ba09d6 error NotAllBatchesExecuted(); // 0xf05c64c6 error NotChainAdmin(address prevMsgSender, address admin); // 0x8fd63d21 error NotEraChain(); // 0xa7050bf6 error NotHistoricalRoot(bytes32); // 0x32ddf9a2 error NotHyperchain(); // 0x87470e36 error NotL1(uint256 blockChainId); // 0xd7b2559b error NotMigrated(); // 0xd0266e26 error NotSettlementLayer(); // 0x04e05fd1 error OnlyOneBlobWithCalldataAllowed(); // 0x885ae069 error OperatorDAInputTooSmall(uint256 operatorDAInputLength, uint256 minAllowedLength); // 0x681150be error OutdatedProtocolVersion(uint256 protocolVersion, uint256 currentProtocolVersion); // 0xc59d372c error ProtocolVersionNotUpToDate(uint256 currentProtocolVersion, uint256 protocolVersion); // 0x2dc9747d error PubdataInputTooSmall(uint256 pubdataInputLength, uint256 totalBlobsCommitmentSize); // 0x9044dff9 error PubdataLengthTooBig(uint256 pubdataLength, uint256 totalBlobSizeBytes); // 0x0baf1d48 error UnknownVerifierVersion(); // 0x79274f04 error UnsupportedProofMetadataVersion(uint256 metadataVersion); // 0x52595598 error ValL1DAWrongInputLength(uint256 inputLength, uint256 expectedLength); // 0x712d02d2 error VerifiedIsNotConsistentWithCommitted(uint256 batchesVerified, uint256 batchesCommitted);
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Arrays.sol)
pragma solidity ^0.8.0;
import "./StorageSlot.sol";
import "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using StorageSlot for bytes32;
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* `array` is expected to be sorted in ascending order, and to contain no
* repeated elements.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
if (array.length == 0) {
return 0;
}
uint256 low = 0;
uint256 high = array.length;
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds down (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getUint256Slot();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}{
"remappings": [
"@ensdomains/=node_modules/@ensdomains/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"hardhat/=node_modules/hardhat/",
"murky/=lib/murky/src/",
"foundry-test/=test/foundry/",
"l2-contracts/=../l2-contracts/contracts/",
"@openzeppelin/contracts-v4/=lib/openzeppelin-contracts-v4/contracts/",
"@openzeppelin/contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable-v4/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/",
"openzeppelin-contracts-v4/=lib/openzeppelin-contracts-v4/",
"openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 28000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_bridgehubAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DefaultAdminTransferNotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"NotAZKChain","type":"error"},{"inputs":[{"internalType":"address","name":"chainAddress","type":"address"},{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"RoleAccessDenied","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedTimestamp","type":"uint256"},{"internalType":"uint256","name":"actualTimestamp","type":"uint256"}],"name":"TimeNotReached","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchNumber","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"untrustedLastL2BlockNumberHint","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"precommitment","type":"bytes32"}],"name":"BatchPrecommitmentSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchNumber","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"batchHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"BlockCommit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchNumber","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"batchHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"BlockExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalBatchesCommitted","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBatchesVerified","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBatchesExecuted","type":"uint256"}],"name":"BlocksRevert","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"previousLastVerifiedBatch","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currentLastVerifiedBatch","type":"uint256"}],"name":"BlocksVerification","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newExecutionDelay","type":"uint256"}],"name":"NewExecutionDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"batchNumber","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"firstBlockNumber","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"lastBlockNumber","type":"uint64"}],"name":"ReportCommittedBatchRangeZKsyncOS","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chainAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chainAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chainAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"BRIDGE_HUB","outputs":[{"internalType":"contract IL1Bridgehub","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COMMITTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTIONAL_COMMITTER_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTIONAL_EXECUTOR_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTIONAL_PRECOMMITTER_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTIONAL_PROVER_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTIONAL_REVERTER_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECOMMITTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVERTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"address","name":"_validator","type":"address"}],"name":"addValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_validator","type":"address"}],"name":"addValidatorForChainId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"address","name":"_validator","type":"address"},{"components":[{"internalType":"bool","name":"rotatePrecommitterRole","type":"bool"},{"internalType":"bool","name":"rotateCommitterRole","type":"bool"},{"internalType":"bool","name":"rotateReverterRole","type":"bool"},{"internalType":"bool","name":"rotateProverRole","type":"bool"},{"internalType":"bool","name":"rotateExecutorRole","type":"bool"}],"internalType":"struct IValidatorTimelock.ValidatorRotationParams","name":"params","type":"tuple"}],"name":"addValidatorRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"uint256","name":"_processBatchFrom","type":"uint256"},{"internalType":"uint256","name":"_processBatchTo","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"commitBatchesSharedBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"uint256","name":"_processBatchFrom","type":"uint256"},{"internalType":"uint256","name":"_processBatchTo","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"executeBatchesSharedBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executionDelay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"uint256","name":"_l2BatchNumber","type":"uint256"}],"name":"getCommittedBatchTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_address","type":"address"}],"name":"hasRoleForChainId","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"uint32","name":"_initialExecutionDelay","type":"uint32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"precommitSharedBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"proveBatchesSharedBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"address","name":"_validator","type":"address"}],"name":"removeValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_validator","type":"address"}],"name":"removeValidatorForChainId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"address","name":"_validator","type":"address"},{"components":[{"internalType":"bool","name":"rotatePrecommitterRole","type":"bool"},{"internalType":"bool","name":"rotateCommitterRole","type":"bool"},{"internalType":"bool","name":"rotateReverterRole","type":"bool"},{"internalType":"bool","name":"rotateProverRole","type":"bool"},{"internalType":"bool","name":"rotateExecutorRole","type":"bool"}],"internalType":"struct IValidatorTimelock.ValidatorRotationParams","name":"params","type":"tuple"}],"name":"removeValidatorRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"revertBatchesSharedBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_executionDelay","type":"uint32"}],"name":"setExecutionDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAddress","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"bytes32","name":"_adminRole","type":"bytes32"}],"name":"setRoleAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234801561000f575f5ffd5b5060405161227538038061227583398101604081905261002e91610105565b6001600160a01b038116608052610043610049565b50610132565b5f54610100900460ff16156100b45760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff90811614610103575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f60208284031215610115575f5ffd5b81516001600160a01b038116811461012b575f5ffd5b9392505050565b60805161210f6101665f395f81816104650152818161097501528181610d9401528181610f8801526116a0015261210f5ff3fe608060405234801561000f575f5ffd5b50600436106102cd575f3560e01c80639271e4501161017c578063b1819c2b116100dd578063e30c397811610093578063f34d18681161006e578063f34d18681461075a578063f3c3437d1461076d578063fdb1dc9214610780575f5ffd5b8063e30c397814610702578063f1ede33714610720578063f2fde38b14610747575f5ffd5b8063c5e4c9f9116100c3578063c5e4c9f9146106b5578063c8c55ead146106c8578063dc9a4ef6146106db575f5ffd5b8063b1819c2b1461064d578063b4dba6f914610660575f5ffd5b8063a217fddf11610132578063a86d67c511610118578063a86d67c5146105ec578063adb4477414610613578063ae7164df14610626575f5ffd5b8063a217fddf146105d2578063a556f4a7146105d9575f5ffd5b806396cb4c0d1161016257806396cb4c0d14610585578063a027985814610598578063a085344d146105bf575f5ffd5b80639271e4501461054b578063962242171461055e575f5ffd5b80634e9d7f63116102315780637ca4eff7116101e75780638c63a1a1116101c25780638c63a1a1146105075780638da5cb5b1461051a5780638e80aaf614610538575f5ffd5b80637ca4eff7146104bc5780638673e5db146104cf5780638b257989146104e2575f5ffd5b80635d4edca7116102175780635d4edca714610460578063715018a6146104ac57806379ba5097146104b4575f5ffd5b80634e9d7f63146104265780635a06267e1461044d575f5ffd5b806317d7de7c116102865780632287f07b1161026c5780632287f07b146103c95780632d3e579a146103f05780633290f93a14610413575f5ffd5b806317d7de7c146103595780631a7c3f73146103a2575f5ffd5b80630b6db820116102b65780630b6db820146103205780630db9eb871461033357806316de635614610346575f5ffd5b806307bd0265146102d15780630997ce711461030b575b5f5ffd5b6102f87fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b6040519081526020015b60405180910390f35b61031e610319366004611c08565b610793565b005b61031e61032e366004611c7f565b610864565b61031e610341366004611cd7565b6108a2565b61031e610354366004611d3c565b610942565b6103956040518060400160405280601181526020017f56616c696461746f7254696d656c6f636b00000000000000000000000000000081525081565b6040516103029190611d6a565b6102f87f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a2010681565b6102f87f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb81565b6104036103fe366004611dbd565b6109fd565b6040519015158152602001610302565b61031e610421366004611dbd565b610a84565b6102f87fd596cfca9f98786bbbcc61c1506316fd2ff44c96f6a4771a1e13e2cf7df5531881565b6102f861045b366004611dfc565b610b7d565b6104877f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610302565b61031e610bc5565b61031e610bd8565b61031e6104ca366004611dfc565b610c92565b6104876104dd366004611c08565b610cce565b60ca546104f29063ffffffff1681565b60405163ffffffff9091168152602001610302565b61031e610515366004611dbd565b610d29565b60335473ffffffffffffffffffffffffffffffffffffffff16610487565b610403610546366004611e26565b610d4a565b61031e610559366004611cd7565b610e04565b6102f87f03e138bd3674247b3c2730aba459026fc3de55a6c40e11b30be5d7afdb726d7d81565b61031e610593366004611e51565b610e3a565b6102f87f764da40dc482d3b385909d7a072df3207fef1d443f7a2633f4e7f1c0bb574ee081565b61031e6105cd366004611cd7565b610e72565b6102f85f81565b61031e6105e7366004611d3c565b610f55565b6102f87f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee81565b6102f8610621366004611dfc565b61100c565b6102f87fc77a7447d79c15063f9229278e1e1165208fb21eb078a86552a94a992151cc2881565b61031e61065b366004611e51565b611052565b6102f861066e366004611dfc565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260c9602090815260408083206008850484528252822054600784169091021c63ffffffff169392505050565b61031e6106c3366004611e95565b61108a565b61031e6106d6366004611ed7565b611249565b6102f87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b60655473ffffffffffffffffffffffffffffffffffffffff16610487565b6102f87f5db23a41c9125bb814d45889d5f3f62adb67c27242e6ad726210a337aa8d65b781565b61031e610755366004611fe1565b61134f565b61031e610768366004611ffc565b6113ff565b61031e61077b366004611dfc565b611470565b61031e61078e366004611ed7565b611488565b8261079e8484610b7d565b6107a982823361158e565b836107e0576040517ff2885eb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6107eb8686610b7d565b73ffffffffffffffffffffffffffffffffffffffff87165f8181526097602090815260408083208a8452825291829020600201889055815184815290810188905292935087927f723017596f662d5bad698223ec9b9d90c19cd1ebc637a2ad7ef27b3d9f85f79c910160405180910390a3505050505050565b837f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee61089182823361158e565b61089a866115f6565b505050505050565b847f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a201066108cf82823361158e565b42865b86811161092e5773ffffffffffffffffffffffffffffffffffffffff89165f90815260c960209081526040808320600885048452825290912080546007841690920282811c851863ffffffff16901b90911890556001016108d2565b5050610939876115f6565b50505050505050565b6040517fe680c4c1000000000000000000000000000000000000000000000000000000008152600481018390526109f9907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e680c4c190602401602060405180830381865afa1580156109cf573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f39190612015565b82611052565b5050565b5f82610a4157610a0c84611616565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149050610a7d565b73ffffffffffffffffffffffffffffffffffffffff84165f9081526097602090815260408083208684529091529020610a7a908361180a565b90505b9392505050565b82610a8f8484610b7d565b610a9a82823361158e565b83610ad1576040517ff2885eb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610adc8585856109fd565b610b765773ffffffffffffffffffffffffffffffffffffffff85165f9081526097602090815260408083208784529091529020610b199084611838565b508273ffffffffffffffffffffffffffffffffffffffff16848673ffffffffffffffffffffffffffffffffffffffff167f2739f947da5133134a8e9c6a84d5ed6da396844d81b4a760121c8b9c668bdf9c60405160405180910390a45b5050505050565b5f81610b8a57505f610bbf565b5073ffffffffffffffffffffffffffffffffffffffff82165f9081526097602090815260408083208484529091529020600201545b92915050565b610bcd611859565b610bd65f6118da565b565b606554339073ffffffffffffffffffffffffffffffffffffffff168114610c86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e6572000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610c8f816118da565b50565b817f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb610cbf82823361158e565b610cc8846115f6565b50505050565b5f82158015610cdb575081155b15610cf057610ce984611616565b9050610a7d565b73ffffffffffffffffffffffffffffffffffffffff84165f9081526097602090815260408083208684529091529020610a7a908361190b565b82610d348484610b7d565b610d3f82823361158e565b610b76858585611916565b6040517fe680c4c1000000000000000000000000000000000000000000000000000000008152600481018490525f90610a7a9073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e680c4c190602401602060405180830381865afa158015610dd9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dfd9190612015565b84846109fd565b847f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610e3182823361158e565b610939876115f6565b6040805160a0810182526001808252602082018190529181018290526060810182905260808101919091526109f99083908390611249565b847fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63610e9f82823361158e565b60ca5463ffffffff16865b868111610f415773ffffffffffffffffffffffffffffffffffffffff89165f90815260c96020908152604080832060088504845282529091205463ffffffff600784169092021c16828101421015610f38576040517f087539820000000000000000000000000000000000000000000000000000000081528184016004820152426024820152604401610c7d565b50600101610eaa565b50610f4b886115f6565b5050505050505050565b6040517fe680c4c1000000000000000000000000000000000000000000000000000000008152600481018390526109f9907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e680c4c190602401602060405180830381865afa158015610fe2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110069190612015565b82610e3a565b5f8161101a57506001610bbf565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526097602090815260408083208584529091529020610a7d906119f7565b6040805160a0810182526001808252602082018190529181018290526060810182905260808101919091526109f99083908390611488565b5f54610100900460ff16158080156110a857505f54600160ff909116105b806110c15750303b1580156110c157505f5460ff166001145b61114d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c7d565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156111a9575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6111b2836118da565b60ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff84161790558015611244575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b80511561127b5761127b837f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee84610d29565b8060200151156112b0576112b0837f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a2010684610d29565b8060400151156112e5576112e5837f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb84610d29565b80606001511561131a5761131a837f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f284610d29565b80608001511561124457611244837fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6384610d29565b611357611859565b6065805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556113ba60335473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b611407611859565b60ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040519081527fd32d6d626bb9c7077c559fc3b4e5ce71ef14609d7d216d030ee63dcf2422c2c49060200160405180910390a150565b818161147d82823361158e565b610cc8848433611916565b8051156114ba576114ba837f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee84610a84565b8060200151156114ef576114ef837f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a2010684610a84565b80604001511561152457611524837f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb84610a84565b80606001511561155957611559837f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f284610a84565b80608001511561124457611244837fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6384610a84565b6115998383836109fd565b611244576040517ffe0aa4f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80851660048301526024820184905282166044820152606401610c7d565b365f5f375f5f365f5f855af13d805f5f3e81801561161257815ff35b815ffd5b5f5f8273ffffffffffffffffffffffffffffffffffffffff16633408e4706040518163ffffffff1660e01b8152600401602060405180830381865afa158015611661573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116859190612030565b90508273ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e680c4c1836040518263ffffffff1660e01b81526004016116f991815260200190565b602060405180830381865afa158015611714573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117389190612015565b73ffffffffffffffffffffffffffffffffffffffff161461179d576040517fb49df1f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610c7d565b8273ffffffffffffffffffffffffffffffffffffffff16636e9960c36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7d9190612015565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526001830160205260408120541515610a7d565b5f610a7d8373ffffffffffffffffffffffffffffffffffffffff8416611a00565b60335473ffffffffffffffffffffffffffffffffffffffff163314610bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c7d565b606580547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610c8f81611a4c565b5f610a7d8383611ac2565b8161194d576040517ff2885eb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119588383836109fd565b156112445773ffffffffffffffffffffffffffffffffffffffff83165f90815260976020908152604080832085845290915290206119969082611ae8565b508073ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff167f8fa769283732af9aa4f65d966aceb1295944e96fcdd7031699b47da23286d28560405160405180910390a4505050565b5f610bbf825490565b5f818152600183016020526040812054611a4557508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610bbf565b505f610bbf565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f825f018281548110611ad757611ad7612047565b905f5260205f200154905092915050565b5f610a7d8373ffffffffffffffffffffffffffffffffffffffff84165f8181526001830160205260408120548015611bde575f611b26600183612074565b85549091505f90611b3990600190612074565b9050818114611b98575f865f018281548110611b5757611b57612047565b905f5260205f200154905080875f018481548110611b7757611b77612047565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080611ba957611ba96120ac565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610bbf565b5f915050610bbf565b73ffffffffffffffffffffffffffffffffffffffff81168114610c8f575f5ffd5b5f5f5f60608486031215611c1a575f5ffd5b8335611c2581611be7565b95602085013595506040909401359392505050565b5f5f83601f840112611c4a575f5ffd5b50813567ffffffffffffffff811115611c61575f5ffd5b602083019150836020828501011115611c78575f5ffd5b9250929050565b5f5f5f5f60608587031215611c92575f5ffd5b8435611c9d81611be7565b935060208501359250604085013567ffffffffffffffff811115611cbf575f5ffd5b611ccb87828801611c3a565b95989497509550505050565b5f5f5f5f5f60808688031215611ceb575f5ffd5b8535611cf681611be7565b94506020860135935060408601359250606086013567ffffffffffffffff811115611d1f575f5ffd5b611d2b88828901611c3a565b969995985093965092949392505050565b5f5f60408385031215611d4d575f5ffd5b823591506020830135611d5f81611be7565b809150509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f5f5f60608486031215611dcf575f5ffd5b8335611dda81611be7565b9250602084013591506040840135611df181611be7565b809150509250925092565b5f5f60408385031215611e0d575f5ffd5b8235611e1881611be7565b946020939093013593505050565b5f5f5f60608486031215611e38575f5ffd5b83359250602084013591506040840135611df181611be7565b5f5f60408385031215611e62575f5ffd5b8235611e6d81611be7565b91506020830135611d5f81611be7565b803563ffffffff81168114611e90575f5ffd5b919050565b5f5f60408385031215611ea6575f5ffd5b8235611eb181611be7565b9150611ebf60208401611e7d565b90509250929050565b80358015158114611e90575f5ffd5b5f5f5f83850360e0811215611eea575f5ffd5b8435611ef581611be7565b93506020850135611f0581611be7565b925060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082011215611f36575f5ffd5b5060405160a0810181811067ffffffffffffffff82111715611f7f577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b8060405250611f9060408601611ec8565b8152611f9e60608601611ec8565b6020820152611faf60808601611ec8565b6040820152611fc060a08601611ec8565b6060820152611fd160c08601611ec8565b6080820152809150509250925092565b5f60208284031215611ff1575f5ffd5b8135610a7d81611be7565b5f6020828403121561200c575f5ffd5b610a7d82611e7d565b5f60208284031215612025575f5ffd5b8151610a7d81611be7565b5f60208284031215612040575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b81810381811115610bbf577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212200fd203a97461b241b450279a8003adaab296658ea34145c41334ffdb33efded464736f6c634300081c0033000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb5213
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106102cd575f3560e01c80639271e4501161017c578063b1819c2b116100dd578063e30c397811610093578063f34d18681161006e578063f34d18681461075a578063f3c3437d1461076d578063fdb1dc9214610780575f5ffd5b8063e30c397814610702578063f1ede33714610720578063f2fde38b14610747575f5ffd5b8063c5e4c9f9116100c3578063c5e4c9f9146106b5578063c8c55ead146106c8578063dc9a4ef6146106db575f5ffd5b8063b1819c2b1461064d578063b4dba6f914610660575f5ffd5b8063a217fddf11610132578063a86d67c511610118578063a86d67c5146105ec578063adb4477414610613578063ae7164df14610626575f5ffd5b8063a217fddf146105d2578063a556f4a7146105d9575f5ffd5b806396cb4c0d1161016257806396cb4c0d14610585578063a027985814610598578063a085344d146105bf575f5ffd5b80639271e4501461054b578063962242171461055e575f5ffd5b80634e9d7f63116102315780637ca4eff7116101e75780638c63a1a1116101c25780638c63a1a1146105075780638da5cb5b1461051a5780638e80aaf614610538575f5ffd5b80637ca4eff7146104bc5780638673e5db146104cf5780638b257989146104e2575f5ffd5b80635d4edca7116102175780635d4edca714610460578063715018a6146104ac57806379ba5097146104b4575f5ffd5b80634e9d7f63146104265780635a06267e1461044d575f5ffd5b806317d7de7c116102865780632287f07b1161026c5780632287f07b146103c95780632d3e579a146103f05780633290f93a14610413575f5ffd5b806317d7de7c146103595780631a7c3f73146103a2575f5ffd5b80630b6db820116102b65780630b6db820146103205780630db9eb871461033357806316de635614610346575f5ffd5b806307bd0265146102d15780630997ce711461030b575b5f5ffd5b6102f87fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b6040519081526020015b60405180910390f35b61031e610319366004611c08565b610793565b005b61031e61032e366004611c7f565b610864565b61031e610341366004611cd7565b6108a2565b61031e610354366004611d3c565b610942565b6103956040518060400160405280601181526020017f56616c696461746f7254696d656c6f636b00000000000000000000000000000081525081565b6040516103029190611d6a565b6102f87f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a2010681565b6102f87f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb81565b6104036103fe366004611dbd565b6109fd565b6040519015158152602001610302565b61031e610421366004611dbd565b610a84565b6102f87fd596cfca9f98786bbbcc61c1506316fd2ff44c96f6a4771a1e13e2cf7df5531881565b6102f861045b366004611dfc565b610b7d565b6104877f000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb521381565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610302565b61031e610bc5565b61031e610bd8565b61031e6104ca366004611dfc565b610c92565b6104876104dd366004611c08565b610cce565b60ca546104f29063ffffffff1681565b60405163ffffffff9091168152602001610302565b61031e610515366004611dbd565b610d29565b60335473ffffffffffffffffffffffffffffffffffffffff16610487565b610403610546366004611e26565b610d4a565b61031e610559366004611cd7565b610e04565b6102f87f03e138bd3674247b3c2730aba459026fc3de55a6c40e11b30be5d7afdb726d7d81565b61031e610593366004611e51565b610e3a565b6102f87f764da40dc482d3b385909d7a072df3207fef1d443f7a2633f4e7f1c0bb574ee081565b61031e6105cd366004611cd7565b610e72565b6102f85f81565b61031e6105e7366004611d3c565b610f55565b6102f87f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee81565b6102f8610621366004611dfc565b61100c565b6102f87fc77a7447d79c15063f9229278e1e1165208fb21eb078a86552a94a992151cc2881565b61031e61065b366004611e51565b611052565b6102f861066e366004611dfc565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260c9602090815260408083206008850484528252822054600784169091021c63ffffffff169392505050565b61031e6106c3366004611e95565b61108a565b61031e6106d6366004611ed7565b611249565b6102f87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b60655473ffffffffffffffffffffffffffffffffffffffff16610487565b6102f87f5db23a41c9125bb814d45889d5f3f62adb67c27242e6ad726210a337aa8d65b781565b61031e610755366004611fe1565b61134f565b61031e610768366004611ffc565b6113ff565b61031e61077b366004611dfc565b611470565b61031e61078e366004611ed7565b611488565b8261079e8484610b7d565b6107a982823361158e565b836107e0576040517ff2885eb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6107eb8686610b7d565b73ffffffffffffffffffffffffffffffffffffffff87165f8181526097602090815260408083208a8452825291829020600201889055815184815290810188905292935087927f723017596f662d5bad698223ec9b9d90c19cd1ebc637a2ad7ef27b3d9f85f79c910160405180910390a3505050505050565b837f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee61089182823361158e565b61089a866115f6565b505050505050565b847f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a201066108cf82823361158e565b42865b86811161092e5773ffffffffffffffffffffffffffffffffffffffff89165f90815260c960209081526040808320600885048452825290912080546007841690920282811c851863ffffffff16901b90911890556001016108d2565b5050610939876115f6565b50505050505050565b6040517fe680c4c1000000000000000000000000000000000000000000000000000000008152600481018390526109f9907f000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb521373ffffffffffffffffffffffffffffffffffffffff169063e680c4c190602401602060405180830381865afa1580156109cf573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f39190612015565b82611052565b5050565b5f82610a4157610a0c84611616565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149050610a7d565b73ffffffffffffffffffffffffffffffffffffffff84165f9081526097602090815260408083208684529091529020610a7a908361180a565b90505b9392505050565b82610a8f8484610b7d565b610a9a82823361158e565b83610ad1576040517ff2885eb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610adc8585856109fd565b610b765773ffffffffffffffffffffffffffffffffffffffff85165f9081526097602090815260408083208784529091529020610b199084611838565b508273ffffffffffffffffffffffffffffffffffffffff16848673ffffffffffffffffffffffffffffffffffffffff167f2739f947da5133134a8e9c6a84d5ed6da396844d81b4a760121c8b9c668bdf9c60405160405180910390a45b5050505050565b5f81610b8a57505f610bbf565b5073ffffffffffffffffffffffffffffffffffffffff82165f9081526097602090815260408083208484529091529020600201545b92915050565b610bcd611859565b610bd65f6118da565b565b606554339073ffffffffffffffffffffffffffffffffffffffff168114610c86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e6572000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610c8f816118da565b50565b817f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb610cbf82823361158e565b610cc8846115f6565b50505050565b5f82158015610cdb575081155b15610cf057610ce984611616565b9050610a7d565b73ffffffffffffffffffffffffffffffffffffffff84165f9081526097602090815260408083208684529091529020610a7a908361190b565b82610d348484610b7d565b610d3f82823361158e565b610b76858585611916565b6040517fe680c4c1000000000000000000000000000000000000000000000000000000008152600481018490525f90610a7a9073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb5213169063e680c4c190602401602060405180830381865afa158015610dd9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dfd9190612015565b84846109fd565b847f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610e3182823361158e565b610939876115f6565b6040805160a0810182526001808252602082018190529181018290526060810182905260808101919091526109f99083908390611249565b847fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63610e9f82823361158e565b60ca5463ffffffff16865b868111610f415773ffffffffffffffffffffffffffffffffffffffff89165f90815260c96020908152604080832060088504845282529091205463ffffffff600784169092021c16828101421015610f38576040517f087539820000000000000000000000000000000000000000000000000000000081528184016004820152426024820152604401610c7d565b50600101610eaa565b50610f4b886115f6565b5050505050505050565b6040517fe680c4c1000000000000000000000000000000000000000000000000000000008152600481018390526109f9907f000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb521373ffffffffffffffffffffffffffffffffffffffff169063e680c4c190602401602060405180830381865afa158015610fe2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110069190612015565b82610e3a565b5f8161101a57506001610bbf565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526097602090815260408083208584529091529020610a7d906119f7565b6040805160a0810182526001808252602082018190529181018290526060810182905260808101919091526109f99083908390611488565b5f54610100900460ff16158080156110a857505f54600160ff909116105b806110c15750303b1580156110c157505f5460ff166001145b61114d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c7d565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156111a9575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6111b2836118da565b60ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff84161790558015611244575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b80511561127b5761127b837f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee84610d29565b8060200151156112b0576112b0837f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a2010684610d29565b8060400151156112e5576112e5837f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb84610d29565b80606001511561131a5761131a837f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f284610d29565b80608001511561124457611244837fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6384610d29565b611357611859565b6065805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556113ba60335473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b611407611859565b60ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040519081527fd32d6d626bb9c7077c559fc3b4e5ce71ef14609d7d216d030ee63dcf2422c2c49060200160405180910390a150565b818161147d82823361158e565b610cc8848433611916565b8051156114ba576114ba837f3353dfbbf9a3ed2a5be49cd3bd3a51ee03c3751d409cccac7723c4907332afee84610a84565b8060200151156114ef576114ef837f0b60b5d7f7e737e4561eecda7c6a01e19e626c495c26e6f45e5b255f76a2010684610a84565b80604001511561152457611524837f30085792330f3f9ee2ee216aea0321c55a0909b87c51ee9ab49d05ca4a4c2ecb84610a84565b80606001511561155957611559837f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f284610a84565b80608001511561124457611244837fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6384610a84565b6115998383836109fd565b611244576040517ffe0aa4f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80851660048301526024820184905282166044820152606401610c7d565b365f5f375f5f365f5f855af13d805f5f3e81801561161257815ff35b815ffd5b5f5f8273ffffffffffffffffffffffffffffffffffffffff16633408e4706040518163ffffffff1660e01b8152600401602060405180830381865afa158015611661573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116859190612030565b90508273ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb521373ffffffffffffffffffffffffffffffffffffffff1663e680c4c1836040518263ffffffff1660e01b81526004016116f991815260200190565b602060405180830381865afa158015611714573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117389190612015565b73ffffffffffffffffffffffffffffffffffffffff161461179d576040517fb49df1f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610c7d565b8273ffffffffffffffffffffffffffffffffffffffff16636e9960c36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7d9190612015565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526001830160205260408120541515610a7d565b5f610a7d8373ffffffffffffffffffffffffffffffffffffffff8416611a00565b60335473ffffffffffffffffffffffffffffffffffffffff163314610bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c7d565b606580547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610c8f81611a4c565b5f610a7d8383611ac2565b8161194d576040517ff2885eb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119588383836109fd565b156112445773ffffffffffffffffffffffffffffffffffffffff83165f90815260976020908152604080832085845290915290206119969082611ae8565b508073ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff167f8fa769283732af9aa4f65d966aceb1295944e96fcdd7031699b47da23286d28560405160405180910390a4505050565b5f610bbf825490565b5f818152600183016020526040812054611a4557508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610bbf565b505f610bbf565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f825f018281548110611ad757611ad7612047565b905f5260205f200154905092915050565b5f610a7d8373ffffffffffffffffffffffffffffffffffffffff84165f8181526001830160205260408120548015611bde575f611b26600183612074565b85549091505f90611b3990600190612074565b9050818114611b98575f865f018281548110611b5757611b57612047565b905f5260205f200154905080875f018481548110611b7757611b77612047565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080611ba957611ba96120ac565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610bbf565b5f915050610bbf565b73ffffffffffffffffffffffffffffffffffffffff81168114610c8f575f5ffd5b5f5f5f60608486031215611c1a575f5ffd5b8335611c2581611be7565b95602085013595506040909401359392505050565b5f5f83601f840112611c4a575f5ffd5b50813567ffffffffffffffff811115611c61575f5ffd5b602083019150836020828501011115611c78575f5ffd5b9250929050565b5f5f5f5f60608587031215611c92575f5ffd5b8435611c9d81611be7565b935060208501359250604085013567ffffffffffffffff811115611cbf575f5ffd5b611ccb87828801611c3a565b95989497509550505050565b5f5f5f5f5f60808688031215611ceb575f5ffd5b8535611cf681611be7565b94506020860135935060408601359250606086013567ffffffffffffffff811115611d1f575f5ffd5b611d2b88828901611c3a565b969995985093965092949392505050565b5f5f60408385031215611d4d575f5ffd5b823591506020830135611d5f81611be7565b809150509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f5f5f60608486031215611dcf575f5ffd5b8335611dda81611be7565b9250602084013591506040840135611df181611be7565b809150509250925092565b5f5f60408385031215611e0d575f5ffd5b8235611e1881611be7565b946020939093013593505050565b5f5f5f60608486031215611e38575f5ffd5b83359250602084013591506040840135611df181611be7565b5f5f60408385031215611e62575f5ffd5b8235611e6d81611be7565b91506020830135611d5f81611be7565b803563ffffffff81168114611e90575f5ffd5b919050565b5f5f60408385031215611ea6575f5ffd5b8235611eb181611be7565b9150611ebf60208401611e7d565b90509250929050565b80358015158114611e90575f5ffd5b5f5f5f83850360e0811215611eea575f5ffd5b8435611ef581611be7565b93506020850135611f0581611be7565b925060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082011215611f36575f5ffd5b5060405160a0810181811067ffffffffffffffff82111715611f7f577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b8060405250611f9060408601611ec8565b8152611f9e60608601611ec8565b6020820152611faf60808601611ec8565b6040820152611fc060a08601611ec8565b6060820152611fd160c08601611ec8565b6080820152809150509250925092565b5f60208284031215611ff1575f5ffd5b8135610a7d81611be7565b5f6020828403121561200c575f5ffd5b610a7d82611e7d565b5f60208284031215612025575f5ffd5b8151610a7d81611be7565b5f60208284031215612040575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b81810381811115610bbf577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212200fd203a97461b241b450279a8003adaab296658ea34145c41334ffdb33efded464736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb5213
-----Decoded View---------------
Arg [0] : _bridgehubAddr (address): 0x303a465B659cBB0ab36eE643eA362c509EEb5213
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb5213
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.