ETH Price: $2,448.65 (+0.30%)

Transaction Decoder

Block:
21029152 at Oct-23-2024 03:21:35 PM +UTC
Transaction Fee:
0.01193152079350316 ETH $29.22
Gas Used:
278,857 Gas / 42.78723788 Gwei

Emitted Events:

48 DiamondProxy.0x8f2916b2f2d78cc5890ead36c06c0f6d5d112c7e103589947e8e2f0d6eddb763( 0x8f2916b2f2d78cc5890ead36c06c0f6d5d112c7e103589947e8e2f0d6eddb763, 0x0000000000000000000000000000000000000000000000000000000000078718, 0x8c8df87c36a6f1554c777760a108947451c9812e0685ca75db02a843e648a19a, 0x88c5b3a249c9a78593d2b0e0cb4f5e7e968365597d6ac70c03049a61649917fc )

Account State Difference:

  Address   Before After State Difference Code
0x0D3250c3...Ef790ec99
(zkSync Era: Batcher)
60.003867901153108367 Eth
Nonce: 33726
59.991936380359343063 Eth
Nonce: 33727
0.011931520793765304
0x32400084...60a000324
(zkSync Era: Diamond Proxy)
0x5D8ba173...5FDbAd06E
(beaverbuild)
12.426980124841199628 Eth12.429210980841199628 Eth0.002230856

Execution Trace

ValidatorTimelock.commitBatchesSharedBridge( _chainId=324, [{name:batchNumber, type:uint64, order:1, indexed:false, value:493335, valueString:493335}, {name:batchHash, type:bytes32, order:2, indexed:false, value:14BC61DDB25E9172BAF76F429620B052348BD92F203F629B0A387F87661107B8, valueString:14BC61DDB25E9172BAF76F429620B052348BD92F203F629B0A387F87661107B8}, {name:indexRepeatedStorageChanges, type:uint64, order:3, indexed:false, value:364257167, valueString:364257167}, {name:numberOfLayer1Txs, type:uint256, order:4, indexed:false, value:1, valueString:1}, {name:priorityOperationsHash, type:bytes32, order:5, indexed:false, value:888D7428EED4EA7913DFA9D4051DA6E485566130F672FA018D45C272E4E3CA76, valueString:888D7428EED4EA7913DFA9D4051DA6E485566130F672FA018D45C272E4E3CA76}, {name:l2LogsTreeRoot, type:bytes32, order:6, indexed:false, value:770594047373346AF035195B4EF26575FD2CA25309B73BD2E913A239BFE56740, valueString:770594047373346AF035195B4EF26575FD2CA25309B73BD2E913A239BFE56740}, {name:timestamp, type:uint256, order:7, indexed:false, value:1729691634, valueString:1729691634}, {name:commitment, type:bytes32, order:8, indexed:false, value:20A4F5DAA1FD99F6834FDE8A7DCF4ABD56E3298C2B1A9C750D89E45CA7EFB258, valueString:20A4F5DAA1FD99F6834FDE8A7DCF4ABD56E3298C2B1A9C750D89E45CA7EFB258}], _newBatchesData= )
  • TransparentUpgradeableProxy.dead6f7f( )
    • StateTransitionManager.getHyperchain( _chainId=324 ) => ( chainAddress=0x32400084C286CF3E17e7B677ea9583e60a000324 )
    • DiamondProxy.6edd4f12( )
      • ExecutorFacet.commitBatchesSharedBridge( 324, _lastCommittedBatchData=[{name:batchNumber, type:uint64, order:1, indexed:false, value:493335, valueString:493335}, {name:batchHash, type:bytes32, order:2, indexed:false, value:14BC61DDB25E9172BAF76F429620B052348BD92F203F629B0A387F87661107B8, valueString:14BC61DDB25E9172BAF76F429620B052348BD92F203F629B0A387F87661107B8}, {name:indexRepeatedStorageChanges, type:uint64, order:3, indexed:false, value:364257167, valueString:364257167}, {name:numberOfLayer1Txs, type:uint256, order:4, indexed:false, value:1, valueString:1}, {name:priorityOperationsHash, type:bytes32, order:5, indexed:false, value:888D7428EED4EA7913DFA9D4051DA6E485566130F672FA018D45C272E4E3CA76, valueString:888D7428EED4EA7913DFA9D4051DA6E485566130F672FA018D45C272E4E3CA76}, {name:l2LogsTreeRoot, type:bytes32, order:6, indexed:false, value:770594047373346AF035195B4EF26575FD2CA25309B73BD2E913A239BFE56740, valueString:770594047373346AF035195B4EF26575FD2CA25309B73BD2E913A239BFE56740}, {name:timestamp, type:uint256, order:7, indexed:false, value:1729691634, valueString:1729691634}, {name:commitment, type:bytes32, order:8, indexed:false, value:20A4F5DAA1FD99F6834FDE8A7DCF4ABD56E3298C2B1A9C750D89E45CA7EFB258, valueString:20A4F5DAA1FD99F6834FDE8A7DCF4ABD56E3298C2B1A9C750D89E45CA7EFB258}], _newBatchesData= )
        • TransparentUpgradeableProxy.def9d6af( )
          • StateTransitionManager.protocolVersionIsActive( _protocolVersion=103079215106 ) => ( True )
          • 0x000000000000000000000000000000000000000a.011b9b87( )
          • 0x000000000000000000000000000000000000000a.012b752e( )
            File 1 of 5: ValidatorTimelock
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/Context.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 Ownable is Context {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                constructor() {
                    _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);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
            pragma solidity ^0.8.0;
            import "./Ownable.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 Ownable2Step is Ownable {
                address private _pendingOwner;
                event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
                /**
                 * @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);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
            pragma solidity ^0.8.0;
            /**
             * @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 Context {
                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;
                }
            }
            // 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
            pragma solidity 0.8.24;
            /**
             * @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
            pragma solidity 0.8.24;
            /// @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`.
            struct BridgehubL2TransactionRequest {
                address sender;
                address contractL2;
                uint256 mintValue;
                uint256 l2Value;
                bytes l2Calldata;
                uint256 l2GasLimit;
                uint256 l2GasPerPubdataByteLimit;
                bytes[] factoryDeps;
                address refundRecipient;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IVerifier, VerifierParams} from "../chain-interfaces/IVerifier.sol";
            import {PriorityQueue} from "../../state-transition/libraries/PriorityQueue.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 hyperchain 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.
            struct ZkSyncHyperchainStorage {
                /// @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 STM
                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 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.
                FeeParams feeParams;
                /// @dev Address of the blob versioned hash getter smart contract used for EIP-4844 versioned hashes.
                address blobVersionedHashRetriever;
                /// @dev The chainId of the chain
                uint256 chainId;
                /// @dev The address of the bridgehub
                address bridgehub;
                /// @dev The address of the StateTransitionManager
                address stateTransitionManager;
                /// @dev The address of the baseToken contract. Eth is address(1)
                address baseToken;
                /// @dev The address of the baseTokenbridge. Eth also uses the shared bridge
                address 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;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol";
            /// @dev Enum used by L2 System Contracts to differentiate logs.
            enum SystemLogKey {
                L2_TO_L1_LOGS_TREE_ROOT_KEY,
                TOTAL_L2_TO_L1_PUBDATA_KEY,
                STATE_DIFF_HASH_KEY,
                PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY,
                PREV_BATCH_HASH_KEY,
                CHAINED_PRIORITY_TXN_HASH_KEY,
                NUMBER_OF_LAYER_1_TXS_KEY,
                BLOB_ONE_HASH_KEY,
                BLOB_TWO_HASH_KEY,
                BLOB_THREE_HASH_KEY,
                BLOB_FOUR_HASH_KEY,
                BLOB_FIVE_HASH_KEY,
                BLOB_SIX_HASH_KEY,
                EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY
            }
            /// @dev Enum used to determine the source of pubdata. At first we will support calldata and blobs but this can be extended.
            enum PubdataSource {
                Calldata,
                Blob
            }
            struct LogProcessingOutput {
                uint256 numberOfLayer1Txs;
                bytes32 chainedPriorityTxsHash;
                bytes32 previousBatchHash;
                bytes32 pubdataHash;
                bytes32 stateDiffHash;
                bytes32 l2LogsTreeRoot;
                uint256 packedBatchAndL2BlockTimestamp;
                bytes32[] blobHashes;
            }
            /// @dev Total number of bytes in a blob. Blob = 4096 field elements * 31 bytes per field element
            /// @dev EIP-4844 defines it as 131_072 but we use 4096 * 31 within our circuits to always fit within a field element
            /// @dev Our circuits will prove that a EIP-4844 blob and our internal blob are the same.
            uint256 constant BLOB_SIZE_BYTES = 126_976;
            /// @dev Offset used to pull Address From Log. Equal to 4 (bytes for isService)
            uint256 constant L2_LOG_ADDRESS_OFFSET = 4;
            /// @dev Offset used to pull Key From Log. Equal to 4 (bytes for isService) + 20 (bytes for address)
            uint256 constant L2_LOG_KEY_OFFSET = 24;
            /// @dev Offset used to pull Value From Log. Equal to 4 (bytes for isService) + 20 (bytes for address) + 32 (bytes for key)
            uint256 constant L2_LOG_VALUE_OFFSET = 56;
            /// @dev BLS Modulus value defined in EIP-4844 and the magic value returned from a successful call to the
            /// point evaluation precompile
            uint256 constant BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513;
            /// @dev Packed pubdata commitments.
            /// @dev Format: list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes)) = 144 bytes
            uint256 constant PUBDATA_COMMITMENT_SIZE = 144;
            /// @dev Offset in pubdata commitment of blobs for claimed value
            uint256 constant PUBDATA_COMMITMENT_CLAIMED_VALUE_OFFSET = 16;
            /// @dev Offset in pubdata commitment of blobs for kzg commitment
            uint256 constant PUBDATA_COMMITMENT_COMMITMENT_OFFSET = 48;
            /// @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 IZkSyncHyperchainBase {
                /// @notice Rollup batch stored data
                /// @param batchNumber Rollup batch number
                /// @param batchHash Hash of L2 batch
                /// @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 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
                /// @param commitment Verified input for the zkSync circuit
                struct StoredBatchInfo {
                    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 pubdataCommitments 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 pubdataCommitments;
                }
                /// @notice Recursive proof input data (individual commitments are constructed onchain)
                struct ProofInput {
                    uint256[] recursiveAggregationInput;
                    uint256[] serializedProof;
                }
                /// @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 _lastCommittedBatchData Stored data of the last committed batch.
                /// @param _newBatchesData Data of the new batches to be committed.
                function commitBatches(
                    StoredBatchInfo calldata _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external;
                /// @notice same as `commitBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function commitBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo calldata _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external;
                /// @notice Batches commitment verification.
                /// @dev Only verifies batch commitments without any other processing.
                /// @param _prevBatch Stored data of the last committed batch.
                /// @param _committedBatches Stored data of the committed batches.
                /// @param _proof The zero knowledge proof.
                function proveBatches(
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) external;
                /// @notice same as `proveBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function proveBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) 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 _batchesData Data of the batches to be executed.
                function executeBatches(StoredBatchInfo[] calldata _batchesData) external;
                /// @notice same as `executeBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function executeBatchesSharedBridge(uint256 _chainId, StoredBatchInfo[] calldata _batchesData) external;
                /// @notice Reverts unexecuted batches
                /// @param _newLastBatch batch number after which batches should be reverted
                /// NOTE: Doesn't delete the stored data about batches, but only decreases
                /// counters that are responsible for the number of batches
                function revertBatches(uint256 _newLastBatch) external;
                /// @notice same as `revertBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function revertBatchesSharedBridge(uint256 _chainId, 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);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @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,
                    uint256[] calldata _recursiveAggregationInput
                ) 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 pure returns (bytes32);
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.24;
            /// @title The interface of the zkSync contract, responsible for the main zkSync logic.
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            interface IZkSyncHyperchainBase {
                /// @return Returns facet name.
                function getName() external view returns (string memory);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {Diamond} from "./libraries/Diamond.sol";
            import {L2CanonicalTransaction} from "../common/Messaging.sol";
            import {FeeParams} from "./chain-deps/ZkSyncHyperchainStorage.sol";
            /// @notice Struct that holds all data needed for initializing STM Proxy.
            /// @dev We use struct instead of raw parameters in `initialize` function to prevent "Stack too deep" error
            /// @param owner The address who can manage non-critical updates in the contract
            /// @param validatorTimelock The address that serves as consensus, i.e. can submit blocks to be processed
            /// @param chainCreationParams The struct that contains the fields that define how a new chain should be created
            /// @param protocolVersion The initial protocol version on the newly deployed chain
            struct StateTransitionManagerInitializeData {
                address owner;
                address validatorTimelock;
                ChainCreationParams chainCreationParams;
                uint256 protocolVersion;
            }
            /// @notice The struct that contains the fields that define how a new chain should be created
            /// within this STM.
            /// @param genesisUpgrade The address that is used in the diamond cut initialize address on chain creation
            /// @param genesisBatchHash Batch hash of the genesis (initial) batch
            /// @param genesisIndexRepeatedStorageChanges The serial number of the shortcut storage key for the genesis batch
            /// @param genesisBatchCommitment The zk-proof commitment for the genesis batch
            /// @param diamondCut The diamond cut for the first upgrade transaction on the newly deployed chain
            struct ChainCreationParams {
                address genesisUpgrade;
                bytes32 genesisBatchHash;
                uint64 genesisIndexRepeatedStorageChanges;
                bytes32 genesisBatchCommitment;
                Diamond.DiamondCutData diamondCut;
            }
            interface IStateTransitionManager {
                /// @dev Emitted when a new Hyperchain is added
                event NewHyperchain(uint256 indexed _chainId, address indexed _hyperchainContract);
                /// @dev emitted when an chain registers and a SetChainIdUpgrade happens
                event SetChainIdUpgrade(
                    address indexed _hyperchain,
                    L2CanonicalTransaction _l2Transaction,
                    uint256 indexed _protocolVersion
                );
                /// @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 ValidatorTimelock changed
                event NewValidatorTimelock(address indexed oldValidatorTimelock, address indexed newValidatorTimelock);
                /// @notice chain creation parameters changed
                event NewChainCreationParams(
                    address genesisUpgrade,
                    bytes32 genesisBatchHash,
                    uint64 genesisIndexRepeatedStorageChanges,
                    bytes32 genesisBatchCommitment,
                    bytes32 newInitialCutHash
                );
                /// @notice new UpgradeCutHash
                event NewUpgradeCutHash(uint256 indexed protocolVersion, bytes32 indexed upgradeCutHash);
                /// @notice new ProtocolVersion
                event NewProtocolVersion(uint256 indexed oldProtocolVersion, uint256 indexed newProtocolVersion);
                function BRIDGE_HUB() external view returns (address);
                function setPendingAdmin(address _newPendingAdmin) external;
                function acceptAdmin() external;
                function getAllHyperchains() external view returns (address[] memory);
                function getAllHyperchainChainIDs() external view returns (uint256[] memory);
                function getHyperchain(uint256 _chainId) external view returns (address);
                function storedBatchZero() external view returns (bytes32);
                function initialCutHash() external view returns (bytes32);
                function genesisUpgrade() external view returns (address);
                function upgradeCutHash(uint256 _protocolVersion) external view returns (bytes32);
                function protocolVersion() external view returns (uint256);
                function protocolVersionDeadline(uint256 _protocolVersion) external view returns (uint256);
                function protocolVersionIsActive(uint256 _protocolVersion) external view returns (bool);
                function initialize(StateTransitionManagerInitializeData calldata _initializeData) external;
                function setValidatorTimelock(address _validatorTimelock) external;
                function setChainCreationParams(ChainCreationParams calldata _chainCreationParams) external;
                function getChainAdmin(uint256 _chainId) external view returns (address);
                function createNewChain(
                    uint256 _chainId,
                    address _baseToken,
                    address _sharedBridge,
                    address _admin,
                    bytes calldata _diamondCut
                ) external;
                function registerAlreadyDeployedHyperchain(uint256 _chainId, address _hyperchain) external;
                function setNewVersionUpgrade(
                    Diamond.DiamondCutData calldata _cutData,
                    uint256 _oldProtocolVersion,
                    uint256 _oldprotocolVersionDeadline,
                    uint256 _newProtocolVersion
                ) external;
                function setUpgradeDiamondCut(Diamond.DiamondCutData calldata _cutData, uint256 _oldProtocolVersion) external;
                function executeUpgrade(uint256 _chainId, Diamond.DiamondCutData calldata _diamondCut) external;
                function setPriorityTxMaxGasLimit(uint256 _chainId, uint256 _maxGasLimit) external;
                function freezeChain(uint256 _chainId) external;
                function unfreezeChain(uint256 _chainId) external;
                function setTokenMultiplier(uint256 _chainId, uint128 _nominator, uint128 _denominator) external;
                function changeFeeParams(uint256 _chainId, FeeParams calldata _newFeeParams) external;
                function setValidator(uint256 _chainId, address _validator, bool _active) external;
                function setPorterAvailability(uint256 _chainId, bool _zkPorterIsAvailable) external;
                function upgradeChainFromVersion(
                    uint256 _chainId,
                    uint256 _oldProtocolVersion,
                    Diamond.DiamondCutData calldata _diamondCut
                ) external;
                function getSemverProtocolVersion() external view returns (uint32, uint32, uint32);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
            import {UncheckedMath} from "../../common/libraries/UncheckedMath.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
                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;
                        require(selectors.length > 0, "B"); // no functions for diamond cut
                        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("C"); // undefined diamond cut action
                        }
                    }
                    _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.
                    require(_facet.code.length > 0, "G");
                    // 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];
                        require(oldFacet.facetAddress == address(0), "J"); // facet for this selector already exists
                        _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.
                    require(_facet.code.length > 0, "K");
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "L"); // it is impossible to replace the facet with zero address
                        _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();
                    require(_facet == address(0), "a1"); // facet address must be zero
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet
                        _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];
                        require(_isSelectorFreezable == ds.selectorToFacet[selector0].isFreezable, "J1");
                    }
                    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)) {
                        require(_calldata.length == 0, "H"); // Non-empty calldata for zero address
                    } 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("I"); // delegatecall failed
                            }
                            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.
                        require(data.length == 32, "lp");
                        require(abi.decode(data, (bytes32)) == DIAMOND_INIT_SUCCESS_RETURN_VALUE, "lp1");
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @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
            pragma solidity 0.8.24;
            /// @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) {
                    require(!_queue.isEmpty(), "D"); // priority queue is empty
                    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) {
                    require(!_queue.isEmpty(), "s"); // priority queue is empty
                    // 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
            pragma solidity 0.8.24;
            import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
            import {LibMap} from "./libraries/LibMap.sol";
            import {IExecutor} from "./chain-interfaces/IExecutor.sol";
            import {IStateTransitionManager} from "./IStateTransitionManager.sol";
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            /// @notice Intermediate smart contract between the validator EOA account and the hyperchains 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 hyperchain 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 4 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.
            contract ValidatorTimelock is IExecutor, Ownable2Step {
                using LibMap for LibMap.Uint32Map;
                /// @dev Part of the IBase interface. Not used in this contract.
                string public constant override getName = "ValidatorTimelock";
                /// @notice The delay between committing and executing batches is changed.
                event NewExecutionDelay(uint256 _newExecutionDelay);
                /// @notice A new validator has been added.
                event ValidatorAdded(uint256 indexed _chainId, address _addedValidator);
                /// @notice A validator has been removed.
                event ValidatorRemoved(uint256 indexed _chainId, address _removedValidator);
                /// @notice Error for when an address is already a validator.
                error AddressAlreadyValidator(uint256 _chainId);
                /// @notice Error for when an address is not a validator.
                error ValidatorDoesNotExist(uint256 _chainId);
                /// @dev The stateTransitionManager smart contract.
                IStateTransitionManager public stateTransitionManager;
                /// @dev The mapping of L2 chainId => batch number => timestamp when it was committed.
                mapping(uint256 chainId => LibMap.Uint32Map batchNumberToTimestampMapping) internal committedBatchTimestamp;
                /// @dev The address that can commit/revert/validate/execute batches.
                mapping(uint256 _chainId => mapping(address _validator => bool)) public validators;
                /// @dev The delay between committing and executing batches.
                uint32 public executionDelay;
                /// @dev Era's chainID
                uint256 immutable ERA_CHAIN_ID;
                constructor(address _initialOwner, uint32 _executionDelay, uint256 _eraChainId) {
                    _transferOwnership(_initialOwner);
                    executionDelay = _executionDelay;
                    ERA_CHAIN_ID = _eraChainId;
                }
                /// @notice Checks if the caller is the admin of the chain.
                modifier onlyChainAdmin(uint256 _chainId) {
                    require(msg.sender == stateTransitionManager.getChainAdmin(_chainId), "ValidatorTimelock: only chain admin");
                    _;
                }
                /// @notice Checks if the caller is a validator.
                modifier onlyValidator(uint256 _chainId) {
                    require(validators[_chainId][msg.sender], "ValidatorTimelock: only validator");
                    _;
                }
                /// @dev Sets a new state transition manager.
                function setStateTransitionManager(IStateTransitionManager _stateTransitionManager) external onlyOwner {
                    stateTransitionManager = _stateTransitionManager;
                }
                /// @dev Sets an address as a validator.
                function addValidator(uint256 _chainId, address _newValidator) external onlyChainAdmin(_chainId) {
                    if (validators[_chainId][_newValidator]) {
                        revert AddressAlreadyValidator(_chainId);
                    }
                    validators[_chainId][_newValidator] = true;
                    emit ValidatorAdded(_chainId, _newValidator);
                }
                /// @dev Removes an address as a validator.
                function removeValidator(uint256 _chainId, address _validator) external onlyChainAdmin(_chainId) {
                    if (!validators[_chainId][_validator]) {
                        revert ValidatorDoesNotExist(_chainId);
                    }
                    validators[_chainId][_validator] = false;
                    emit ValidatorRemoved(_chainId, _validator);
                }
                /// @dev Set the delay between committing and executing batches.
                function setExecutionDelay(uint32 _executionDelay) external onlyOwner {
                    executionDelay = _executionDelay;
                    emit NewExecutionDelay(_executionDelay);
                }
                /// @dev Returns the timestamp when `_l2BatchNumber` was committed.
                function getCommittedBatchTimestamp(uint256 _chainId, uint256 _l2BatchNumber) external view returns (uint256) {
                    return committedBatchTimestamp[_chainId].get(_l2BatchNumber);
                }
                /// @dev Records the timestamp for all provided committed batches and make
                /// a call to the hyperchain diamond contract with the same calldata.
                function commitBatches(
                    StoredBatchInfo calldata,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external onlyValidator(ERA_CHAIN_ID) {
                    _commitBatchesInner(ERA_CHAIN_ID, _newBatchesData);
                }
                /// @dev Records the timestamp for all provided committed batches and make
                /// a call to the hyperchain diamond contract with the same calldata.
                function commitBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo calldata,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external onlyValidator(_chainId) {
                    _commitBatchesInner(_chainId, _newBatchesData);
                }
                function _commitBatchesInner(uint256 _chainId, CommitBatchInfo[] calldata _newBatchesData) internal {
                    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 = 0; i < _newBatchesData.length; ++i) {
                            committedBatchTimestamp[_chainId].set(_newBatchesData[i].batchNumber, timestamp);
                        }
                    }
                    _propagateToZkSyncHyperchain(_chainId);
                }
                /// @dev Make a call to the hyperchain 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 revertBatches(uint256) external onlyValidator(ERA_CHAIN_ID) {
                    _propagateToZkSyncHyperchain(ERA_CHAIN_ID);
                }
                /// @dev Make a call to the hyperchain 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(uint256 _chainId, uint256) external onlyValidator(_chainId) {
                    _propagateToZkSyncHyperchain(_chainId);
                }
                /// @dev Make a call to the hyperchain 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 proveBatches(
                    StoredBatchInfo calldata,
                    StoredBatchInfo[] calldata,
                    ProofInput calldata
                ) external onlyValidator(ERA_CHAIN_ID) {
                    _propagateToZkSyncHyperchain(ERA_CHAIN_ID);
                }
                /// @dev Make a call to the hyperchain 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(
                    uint256 _chainId,
                    StoredBatchInfo calldata,
                    StoredBatchInfo[] calldata,
                    ProofInput calldata
                ) external onlyValidator(_chainId) {
                    _propagateToZkSyncHyperchain(_chainId);
                }
                /// @dev Check that batches were committed at least X time ago and
                /// make a call to the hyperchain diamond contract with the same calldata.
                function executeBatches(StoredBatchInfo[] calldata _newBatchesData) external onlyValidator(ERA_CHAIN_ID) {
                    _executeBatchesInner(ERA_CHAIN_ID, _newBatchesData);
                }
                /// @dev Check that batches were committed at least X time ago and
                /// make a call to the hyperchain diamond contract with the same calldata.
                function executeBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo[] calldata _newBatchesData
                ) external onlyValidator(_chainId) {
                    _executeBatchesInner(_chainId, _newBatchesData);
                }
                function _executeBatchesInner(uint256 _chainId, StoredBatchInfo[] calldata _newBatchesData) internal {
                    uint256 delay = executionDelay; // uint32
                    unchecked {
                        for (uint256 i = 0; i < _newBatchesData.length; ++i) {
                            uint256 commitBatchTimestamp = committedBatchTimestamp[_chainId].get(_newBatchesData[i].batchNumber);
                            // 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.
                            require(block.timestamp >= commitBatchTimestamp + delay, "5c"); // The delay is not passed
                        }
                    }
                    _propagateToZkSyncHyperchain(_chainId);
                }
                /// @dev Call the hyperchain diamond contract with the same calldata as this contract was called.
                /// Note: it is called the hyperchain diamond contract, not delegatecalled!
                function _propagateToZkSyncHyperchain(uint256 _chainId) internal {
                    address contractAddress = stateTransitionManager.getHyperchain(_chainId);
                    assembly {
                        // Copy function signature and arguments from calldata at zero position into memory at pointer position
                        calldatacopy(0, 0, calldatasize())
                        // Call method of the hyperchain diamond contract returns 0 on error
                        let result := call(gas(), contractAddress, 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)
                        }
                    }
                }
            }
            

            File 2 of 5: DiamondProxy
            // 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);
                }
            }
            pragma solidity ^0.8.0;
            // SPDX-License-Identifier: MIT
            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;
                    }
                }
            }
            pragma solidity ^0.8.0;
            // SPDX-License-Identifier: MIT
            import "./libraries/Diamond.sol";
            /// @title Diamond Proxy Contract (EIP-2535)
            /// @author Matter Labs
            contract DiamondProxy {
                constructor(uint256 _chainId, Diamond.DiamondCutData memory _diamondCut) {
                    // Check that the contract is deployed on the expected chain.
                    // Thus, the contract deployed by the same Create2 factory on the different chain will have different addresses!
                    require(_chainId == block.chainid, "pr");
                    Diamond.diamondCut(_diamondCut);
                }
                /// @dev 1. Find the facet for the function that is called.
                /// @dev 2. Delegate the execution to the found facet via `delegatecall`.
                fallback() external payable {
                    Diamond.DiamondStorage storage diamondStorage = Diamond.getDiamondStorage();
                    // Check whether the data contains a "full" selector or it is empty.
                    // Required because Diamond proxy finds a facet by function signature,
                    // which is not defined for data length in range [1, 3].
                    require(msg.data.length >= 4 || msg.data.length == 0, "Ut");
                    // Get facet from function selector
                    Diamond.SelectorToFacet memory facet = diamondStorage.selectorToFacet[msg.sig];
                    address facetAddress = facet.facetAddress;
                    require(facetAddress != address(0), "F"); // Proxy has no facet for this selector
                    require(!diamondStorage.isFrozen || !facet.isFreezable, "q1"); // Facet is frozen
                    assembly {
                        // The pointer to the free memory slot
                        let ptr := mload(0x40)
                        // Copy function signature and arguments from calldata at zero position into memory at pointer position
                        calldatacopy(ptr, 0, calldatasize())
                        // Delegatecall method of the implementation contract returns 0 on error
                        let result := delegatecall(gas(), facetAddress, ptr, 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(ptr, 0, size)
                        // Depending on the result value
                        switch result
                        case 0 {
                            // End execution and revert state changes
                            revert(ptr, size)
                        }
                        default {
                            // Return data with length of size at pointers position
                            return(ptr, size)
                        }
                    }
                }
            }
            pragma solidity ^0.8.0;
            // SPDX-License-Identifier: MIT
            import "@openzeppelin/contracts/utils/math/SafeCast.sol";
            import "../../common/libraries/UncheckedMath.sol";
            /// @author Matter Labs
            /// @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 constant DIAMOND_INIT_SUCCESS_RETURN_VALUE =
                    0x33774e659306e47509050e97cb651e731180a42d458212294d30751925c551a2; // keccak256("diamond.zksync.init") - 1
                /// @dev Storage position of `DiamondStorage` structure.
                bytes32 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 selector 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 => SelectorToFacet) selectorToFacet;
                    mapping(address => FacetToSelectors) 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
                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;
                        require(selectors.length > 0, "B"); // no functions for diamond cut
                        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("C"); // undefined diamond cut action
                        }
                    }
                    _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();
                    require(_facet != address(0), "G"); // facet with zero address cannot be added
                    // 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];
                        require(oldFacet.facetAddress == address(0), "J"); // facet for this selector already exists
                        _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();
                    require(_facet != address(0), "K"); // cannot replace facet with zero address
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "L"); // it is impossible to replace the facet with zero address
                        _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();
                    require(_facet == address(0), "a1"); // facet address must be zero
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet
                        _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];
                        require(_isSelectorFreezable == ds.selectorToFacet[selector0].isFreezable, "J1");
                    }
                    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)) {
                        require(_calldata.length == 0, "H"); // Non-empty calldata for zero address
                    } 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);
                        require(success, "I"); // delegatecall failed
                        // Check that called contract returns magic value to make sure that contract logic
                        // supposed to be used as diamond cut initializer.
                        require(data.length == 32, "lp");
                        require(abi.decode(data, (bytes32)) == DIAMOND_INIT_SUCCESS_RETURN_VALUE, "lp1");
                    }
                }
            }
            

            File 3 of 5: TransparentUpgradeableProxy
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
             * proxy whose upgrades are fully controlled by the current implementation.
             */
            interface IERC1822Proxiable {
                /**
                 * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                 * address.
                 *
                 * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                 * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                 * function revert if invoked through a proxy.
                 */
                function proxiableUUID() external view returns (bytes32);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev This is the interface that {BeaconProxy} expects of its beacon.
             */
            interface IBeacon {
                /**
                 * @dev Must return an address that can be used as a delegate call target.
                 *
                 * {BeaconProxy} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
            pragma solidity ^0.8.0;
            import "../Proxy.sol";
            import "./ERC1967Upgrade.sol";
            /**
             * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
             * implementation address that can be changed. This address is stored in storage in the location specified by
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
             * implementation behind the proxy.
             */
            contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                /**
                 * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                 *
                 * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                 * function call, and allows initializing the storage of the proxy like a Solidity constructor.
                 */
                constructor(address _logic, bytes memory _data) payable {
                    _upgradeToAndCall(_logic, _data, false);
                }
                /**
                 * @dev Returns the current implementation address.
                 */
                function _implementation() internal view virtual override returns (address impl) {
                    return ERC1967Upgrade._getImplementation();
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.sol";
            import "../../interfaces/draft-IERC1822.sol";
            import "../../utils/Address.sol";
            import "../../utils/StorageSlot.sol";
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             *
             * _Available since v4.1._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                 * validated in the constructor.
                 */
                bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                /**
                 * @dev Returns the current implementation address.
                 */
                function _getImplementation() internal view returns (address) {
                    return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                }
                /**
                 * @dev Stores a new address in the EIP1967 implementation slot.
                 */
                function _setImplementation(address newImplementation) private {
                    require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                    StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                }
                /**
                 * @dev Perform implementation upgrade
                 *
                 * Emits an {Upgraded} event.
                 */
                function _upgradeTo(address newImplementation) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                }
                /**
                 * @dev Perform implementation upgrade with additional setup call.
                 *
                 * Emits an {Upgraded} event.
                 */
                function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                    _upgradeTo(newImplementation);
                    if (data.length > 0 || forceCall) {
                        Address.functionDelegateCall(newImplementation, data);
                    }
                }
                /**
                 * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                 *
                 * Emits an {Upgraded} event.
                 */
                function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
                    // Upgrades from old implementations will perform a rollback test. This test requires the new
                    // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                    // this special case will break upgrade paths from old UUPS implementation to new ones.
                    if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                        _setImplementation(newImplementation);
                    } else {
                        try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                            require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                        } catch {
                            revert("ERC1967Upgrade: new implementation is not UUPS");
                        }
                        _upgradeToAndCall(newImplementation, data, forceCall);
                    }
                }
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                 * validated in the constructor.
                 */
                bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                /**
                 * @dev Returns the current admin.
                 */
                function _getAdmin() internal view returns (address) {
                    return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                }
                /**
                 * @dev Stores a new address in the EIP1967 admin slot.
                 */
                function _setAdmin(address newAdmin) private {
                    require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                    StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                }
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {AdminChanged} event.
                 */
                function _changeAdmin(address newAdmin) internal {
                    emit AdminChanged(_getAdmin(), newAdmin);
                    _setAdmin(newAdmin);
                }
                /**
                 * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                 * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                 */
                bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                /**
                 * @dev Returns the current beacon.
                 */
                function _getBeacon() internal view returns (address) {
                    return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                }
                /**
                 * @dev Stores a new beacon in the EIP1967 beacon slot.
                 */
                function _setBeacon(address newBeacon) private {
                    require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                    require(
                        Address.isContract(IBeacon(newBeacon).implementation()),
                        "ERC1967: beacon implementation is not a contract"
                    );
                    StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                }
                /**
                 * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                 * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                 *
                 * Emits a {BeaconUpgraded} event.
                 */
                function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
                    if (data.length > 0 || forceCall) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
             * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
             * be specified by overriding the virtual {_implementation} function.
             *
             * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
             * different contract through the {_delegate} function.
             *
             * The success and return data of the delegated call will be returned back to the caller of the proxy.
             */
            abstract contract Proxy {
                /**
                 * @dev Delegates the current call to `implementation`.
                 *
                 * This function does not return to its internal call site, it will return directly to the external caller.
                 */
                function _delegate(address implementation) internal virtual {
                    assembly {
                        // Copy msg.data. We take full control of memory in this inline assembly
                        // block because it will not return to Solidity code. We overwrite the
                        // Solidity scratch pad at memory position 0.
                        calldatacopy(0, 0, calldatasize())
                        // Call the implementation.
                        // out and outsize are 0 because we don't know the size yet.
                        let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                        // Copy the returned data.
                        returndatacopy(0, 0, returndatasize())
                        switch result
                        // delegatecall returns 0 on error.
                        case 0 {
                            revert(0, returndatasize())
                        }
                        default {
                            return(0, returndatasize())
                        }
                    }
                }
                /**
                 * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
                 * and {_fallback} should delegate.
                 */
                function _implementation() internal view virtual returns (address);
                /**
                 * @dev Delegates the current call to the address returned by `_implementation()`.
                 *
                 * This function does not return to its internal call site, it will return directly to the external caller.
                 */
                function _fallback() internal virtual {
                    _beforeFallback();
                    _delegate(_implementation());
                }
                /**
                 * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                 * function in the contract matches the call data.
                 */
                fallback() external payable virtual {
                    _fallback();
                }
                /**
                 * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                 * is empty.
                 */
                receive() external payable virtual {
                    _fallback();
                }
                /**
                 * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                 * call, or as part of the Solidity `fallback` or `receive` functions.
                 *
                 * If overridden should call `super._beforeFallback()`.
                 */
                function _beforeFallback() internal virtual {}
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
            pragma solidity ^0.8.0;
            import "../ERC1967/ERC1967Proxy.sol";
            /**
             * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
             * does not implement this interface directly, and some of its functions are implemented by an internal dispatch
             * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
             * include them in the ABI so this interface must be used to interact with it.
             */
            interface ITransparentUpgradeableProxy is IERC1967 {
                function admin() external view returns (address);
                function implementation() external view returns (address);
                function changeAdmin(address) external;
                function upgradeTo(address) external;
                function upgradeToAndCall(address, bytes memory) external payable;
            }
            /**
             * @dev This contract implements a proxy that is upgradeable by an admin.
             *
             * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
             * clashing], which can potentially be used in an attack, this contract uses the
             * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
             * things that go hand in hand:
             *
             * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
             * that call matches one of the admin functions exposed by the proxy itself.
             * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
             * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
             * "admin cannot fallback to proxy target".
             *
             * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
             * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
             * to sudden errors when trying to call a function from the proxy implementation.
             *
             * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
             * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
             *
             * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
             * inherit from that interface, and instead the admin functions are implicitly implemented using a custom dispatch
             * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
             * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
             * implementation.
             *
             * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the compiler
             * will not check that there are no selector conflicts, due to the note above. A selector clash between any new function
             * and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could
             * render the admin operations inaccessible, which could prevent upgradeability. Transparency may also be compromised.
             */
            contract TransparentUpgradeableProxy is ERC1967Proxy {
                /**
                 * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                 * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                 */
                constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                    _changeAdmin(admin_);
                }
                /**
                 * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                 *
                 * CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the
                 * implementation provides a function with the same selector.
                 */
                modifier ifAdmin() {
                    if (msg.sender == _getAdmin()) {
                        _;
                    } else {
                        _fallback();
                    }
                }
                /**
                 * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior
                 */
                function _fallback() internal virtual override {
                    if (msg.sender == _getAdmin()) {
                        bytes memory ret;
                        bytes4 selector = msg.sig;
                        if (selector == ITransparentUpgradeableProxy.upgradeTo.selector) {
                            ret = _dispatchUpgradeTo();
                        } else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
                            ret = _dispatchUpgradeToAndCall();
                        } else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector) {
                            ret = _dispatchChangeAdmin();
                        } else if (selector == ITransparentUpgradeableProxy.admin.selector) {
                            ret = _dispatchAdmin();
                        } else if (selector == ITransparentUpgradeableProxy.implementation.selector) {
                            ret = _dispatchImplementation();
                        } else {
                            revert("TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                        }
                        assembly {
                            return(add(ret, 0x20), mload(ret))
                        }
                    } else {
                        super._fallback();
                    }
                }
                /**
                 * @dev Returns the current admin.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                function _dispatchAdmin() private returns (bytes memory) {
                    _requireZeroValue();
                    address admin = _getAdmin();
                    return abi.encode(admin);
                }
                /**
                 * @dev Returns the current implementation.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                 */
                function _dispatchImplementation() private returns (bytes memory) {
                    _requireZeroValue();
                    address implementation = _implementation();
                    return abi.encode(implementation);
                }
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {AdminChanged} event.
                 */
                function _dispatchChangeAdmin() private returns (bytes memory) {
                    _requireZeroValue();
                    address newAdmin = abi.decode(msg.data[4:], (address));
                    _changeAdmin(newAdmin);
                    return "";
                }
                /**
                 * @dev Upgrade the implementation of the proxy.
                 */
                function _dispatchUpgradeTo() private returns (bytes memory) {
                    _requireZeroValue();
                    address newImplementation = abi.decode(msg.data[4:], (address));
                    _upgradeToAndCall(newImplementation, bytes(""), false);
                    return "";
                }
                /**
                 * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                 * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                 * proxied contract.
                 */
                function _dispatchUpgradeToAndCall() private returns (bytes memory) {
                    (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
                    _upgradeToAndCall(newImplementation, data, true);
                    return "";
                }
                /**
                 * @dev Returns the current admin.
                 *
                 * CAUTION: This function is deprecated. Use {ERC1967Upgrade-_getAdmin} instead.
                 */
                function _admin() internal view virtual returns (address) {
                    return _getAdmin();
                }
                /**
                 * @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to
                 * emulate some proxy functions being non-payable while still allowing value to pass through.
                 */
                function _requireZeroValue() private {
                    require(msg.value == 0);
                }
            }
            // 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 Address {
                /**
                 * @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
            // 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
                    }
                }
            }
            

            File 4 of 5: StateTransitionManager
            // 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
            // 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/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
            // 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/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);
                    }
                }
            }
            // 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
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableMap.sol)
            // This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
            pragma solidity ^0.8.0;
            import "./EnumerableSet.sol";
            /**
             * @dev Library for managing an enumerable variant of Solidity's
             * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
             * type.
             *
             * Maps have the following properties:
             *
             * - Entries are added, removed, and checked for existence in constant time
             * (O(1)).
             * - Entries are enumerated in O(n). No guarantees are made on the ordering.
             *
             * ```solidity
             * contract Example {
             *     // Add the library methods
             *     using EnumerableMap for EnumerableMap.UintToAddressMap;
             *
             *     // Declare a set state variable
             *     EnumerableMap.UintToAddressMap private myMap;
             * }
             * ```
             *
             * The following map types are supported:
             *
             * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
             * - `address -> uint256` (`AddressToUintMap`) since v4.6.0
             * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
             * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
             * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
             *
             * [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 EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
             * array of EnumerableMap.
             * ====
             */
            library EnumerableMap {
                using EnumerableSet for EnumerableSet.Bytes32Set;
                // To implement this library for multiple types with as little code
                // repetition as possible, we write it in terms of a generic Map type with
                // bytes32 keys and values.
                // The Map implementation uses private functions, and user-facing
                // implementations (such as Uint256ToAddressMap) are just wrappers around
                // the underlying Map.
                // This means that we can only create new EnumerableMaps for types that fit
                // in bytes32.
                struct Bytes32ToBytes32Map {
                    // Storage of keys
                    EnumerableSet.Bytes32Set _keys;
                    mapping(bytes32 => bytes32) _values;
                }
                /**
                 * @dev Adds a key-value pair to a map, or updates the value for an existing
                 * key. O(1).
                 *
                 * Returns true if the key was added to the map, that is if it was not
                 * already present.
                 */
                function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
                    map._values[key] = value;
                    return map._keys.add(key);
                }
                /**
                 * @dev Removes a key-value pair from a map. O(1).
                 *
                 * Returns true if the key was removed from the map, that is if it was present.
                 */
                function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
                    delete map._values[key];
                    return map._keys.remove(key);
                }
                /**
                 * @dev Returns true if the key is in the map. O(1).
                 */
                function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
                    return map._keys.contains(key);
                }
                /**
                 * @dev Returns the number of key-value pairs in the map. O(1).
                 */
                function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
                    return map._keys.length();
                }
                /**
                 * @dev Returns the key-value pair stored at position `index` in the map. O(1).
                 *
                 * Note that there are no guarantees on the ordering of entries inside the
                 * array, and it may change when more entries are added or removed.
                 *
                 * Requirements:
                 *
                 * - `index` must be strictly less than {length}.
                 */
                function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
                    bytes32 key = map._keys.at(index);
                    return (key, map._values[key]);
                }
                /**
                 * @dev Tries to returns the value associated with `key`. O(1).
                 * Does not revert if `key` is not in the map.
                 */
                function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
                    bytes32 value = map._values[key];
                    if (value == bytes32(0)) {
                        return (contains(map, key), bytes32(0));
                    } else {
                        return (true, value);
                    }
                }
                /**
                 * @dev Returns the value associated with `key`. O(1).
                 *
                 * Requirements:
                 *
                 * - `key` must be in the map.
                 */
                function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
                    bytes32 value = map._values[key];
                    require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
                    return value;
                }
                /**
                 * @dev Same as {get}, with a custom error message when `key` is not in the map.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryGet}.
                 */
                function get(
                    Bytes32ToBytes32Map storage map,
                    bytes32 key,
                    string memory errorMessage
                ) internal view returns (bytes32) {
                    bytes32 value = map._values[key];
                    require(value != 0 || contains(map, key), errorMessage);
                    return value;
                }
                /**
                 * @dev Return the an array containing all the keys
                 *
                 * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
                 */
                function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
                    return map._keys.values();
                }
                // UintToUintMap
                struct UintToUintMap {
                    Bytes32ToBytes32Map _inner;
                }
                /**
                 * @dev Adds a key-value pair to a map, or updates the value for an existing
                 * key. O(1).
                 *
                 * Returns true if the key was added to the map, that is if it was not
                 * already present.
                 */
                function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
                    return set(map._inner, bytes32(key), bytes32(value));
                }
                /**
                 * @dev Removes a value from a map. O(1).
                 *
                 * Returns true if the key was removed from the map, that is if it was present.
                 */
                function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
                    return remove(map._inner, bytes32(key));
                }
                /**
                 * @dev Returns true if the key is in the map. O(1).
                 */
                function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
                    return contains(map._inner, bytes32(key));
                }
                /**
                 * @dev Returns the number of elements in the map. O(1).
                 */
                function length(UintToUintMap storage map) internal view returns (uint256) {
                    return length(map._inner);
                }
                /**
                 * @dev Returns the element stored at position `index` in the map. 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(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
                    (bytes32 key, bytes32 value) = at(map._inner, index);
                    return (uint256(key), uint256(value));
                }
                /**
                 * @dev Tries to returns the value associated with `key`. O(1).
                 * Does not revert if `key` is not in the map.
                 */
                function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
                    (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
                    return (success, uint256(value));
                }
                /**
                 * @dev Returns the value associated with `key`. O(1).
                 *
                 * Requirements:
                 *
                 * - `key` must be in the map.
                 */
                function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
                    return uint256(get(map._inner, bytes32(key)));
                }
                /**
                 * @dev Same as {get}, with a custom error message when `key` is not in the map.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryGet}.
                 */
                function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) {
                    return uint256(get(map._inner, bytes32(key), errorMessage));
                }
                /**
                 * @dev Return the an array containing all the keys
                 *
                 * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
                 */
                function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
                    bytes32[] memory store = keys(map._inner);
                    uint256[] memory result;
                    /// @solidity memory-safe-assembly
                    assembly {
                        result := store
                    }
                    return result;
                }
                // UintToAddressMap
                struct UintToAddressMap {
                    Bytes32ToBytes32Map _inner;
                }
                /**
                 * @dev Adds a key-value pair to a map, or updates the value for an existing
                 * key. O(1).
                 *
                 * Returns true if the key was added to the map, that is if it was not
                 * already present.
                 */
                function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
                    return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
                }
                /**
                 * @dev Removes a value from a map. O(1).
                 *
                 * Returns true if the key was removed from the map, that is if it was present.
                 */
                function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
                    return remove(map._inner, bytes32(key));
                }
                /**
                 * @dev Returns true if the key is in the map. O(1).
                 */
                function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
                    return contains(map._inner, bytes32(key));
                }
                /**
                 * @dev Returns the number of elements in the map. O(1).
                 */
                function length(UintToAddressMap storage map) internal view returns (uint256) {
                    return length(map._inner);
                }
                /**
                 * @dev Returns the element stored at position `index` in the map. 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(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
                    (bytes32 key, bytes32 value) = at(map._inner, index);
                    return (uint256(key), address(uint160(uint256(value))));
                }
                /**
                 * @dev Tries to returns the value associated with `key`. O(1).
                 * Does not revert if `key` is not in the map.
                 */
                function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
                    (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
                    return (success, address(uint160(uint256(value))));
                }
                /**
                 * @dev Returns the value associated with `key`. O(1).
                 *
                 * Requirements:
                 *
                 * - `key` must be in the map.
                 */
                function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
                    return address(uint160(uint256(get(map._inner, bytes32(key)))));
                }
                /**
                 * @dev Same as {get}, with a custom error message when `key` is not in the map.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryGet}.
                 */
                function get(
                    UintToAddressMap storage map,
                    uint256 key,
                    string memory errorMessage
                ) internal view returns (address) {
                    return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
                }
                /**
                 * @dev Return the an array containing all the keys
                 *
                 * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
                 */
                function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
                    bytes32[] memory store = keys(map._inner);
                    uint256[] memory result;
                    /// @solidity memory-safe-assembly
                    assembly {
                        result := store
                    }
                    return result;
                }
                // AddressToUintMap
                struct AddressToUintMap {
                    Bytes32ToBytes32Map _inner;
                }
                /**
                 * @dev Adds a key-value pair to a map, or updates the value for an existing
                 * key. O(1).
                 *
                 * Returns true if the key was added to the map, that is if it was not
                 * already present.
                 */
                function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
                    return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
                }
                /**
                 * @dev Removes a value from a map. O(1).
                 *
                 * Returns true if the key was removed from the map, that is if it was present.
                 */
                function remove(AddressToUintMap storage map, address key) internal returns (bool) {
                    return remove(map._inner, bytes32(uint256(uint160(key))));
                }
                /**
                 * @dev Returns true if the key is in the map. O(1).
                 */
                function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
                    return contains(map._inner, bytes32(uint256(uint160(key))));
                }
                /**
                 * @dev Returns the number of elements in the map. O(1).
                 */
                function length(AddressToUintMap storage map) internal view returns (uint256) {
                    return length(map._inner);
                }
                /**
                 * @dev Returns the element stored at position `index` in the map. 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(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
                    (bytes32 key, bytes32 value) = at(map._inner, index);
                    return (address(uint160(uint256(key))), uint256(value));
                }
                /**
                 * @dev Tries to returns the value associated with `key`. O(1).
                 * Does not revert if `key` is not in the map.
                 */
                function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
                    (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
                    return (success, uint256(value));
                }
                /**
                 * @dev Returns the value associated with `key`. O(1).
                 *
                 * Requirements:
                 *
                 * - `key` must be in the map.
                 */
                function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
                    return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
                }
                /**
                 * @dev Same as {get}, with a custom error message when `key` is not in the map.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryGet}.
                 */
                function get(
                    AddressToUintMap storage map,
                    address key,
                    string memory errorMessage
                ) internal view returns (uint256) {
                    return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
                }
                /**
                 * @dev Return the an array containing all the keys
                 *
                 * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
                 */
                function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
                    bytes32[] memory store = keys(map._inner);
                    address[] memory result;
                    /// @solidity memory-safe-assembly
                    assembly {
                        result := store
                    }
                    return result;
                }
                // Bytes32ToUintMap
                struct Bytes32ToUintMap {
                    Bytes32ToBytes32Map _inner;
                }
                /**
                 * @dev Adds a key-value pair to a map, or updates the value for an existing
                 * key. O(1).
                 *
                 * Returns true if the key was added to the map, that is if it was not
                 * already present.
                 */
                function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
                    return set(map._inner, key, bytes32(value));
                }
                /**
                 * @dev Removes a value from a map. O(1).
                 *
                 * Returns true if the key was removed from the map, that is if it was present.
                 */
                function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
                    return remove(map._inner, key);
                }
                /**
                 * @dev Returns true if the key is in the map. O(1).
                 */
                function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
                    return contains(map._inner, key);
                }
                /**
                 * @dev Returns the number of elements in the map. O(1).
                 */
                function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
                    return length(map._inner);
                }
                /**
                 * @dev Returns the element stored at position `index` in the map. 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(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
                    (bytes32 key, bytes32 value) = at(map._inner, index);
                    return (key, uint256(value));
                }
                /**
                 * @dev Tries to returns the value associated with `key`. O(1).
                 * Does not revert if `key` is not in the map.
                 */
                function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
                    (bool success, bytes32 value) = tryGet(map._inner, key);
                    return (success, uint256(value));
                }
                /**
                 * @dev Returns the value associated with `key`. O(1).
                 *
                 * Requirements:
                 *
                 * - `key` must be in the map.
                 */
                function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
                    return uint256(get(map._inner, key));
                }
                /**
                 * @dev Same as {get}, with a custom error message when `key` is not in the map.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryGet}.
                 */
                function get(
                    Bytes32ToUintMap storage map,
                    bytes32 key,
                    string memory errorMessage
                ) internal view returns (uint256) {
                    return uint256(get(map._inner, key, errorMessage));
                }
                /**
                 * @dev Return the an array containing all the keys
                 *
                 * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
                 */
                function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
                    bytes32[] memory store = keys(map._inner);
                    bytes32[] memory result;
                    /// @solidity memory-safe-assembly
                    assembly {
                        result := store
                    }
                    return result;
                }
            }
            // 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 EnumerableSet {
                // 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
            pragma solidity 0.8.24;
            /// @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;
            // TODO: change constant to the real root hash of empty Merkle tree (SMA-184)
            bytes32 constant DEFAULT_L2_LOGS_TREE_ROOT_HASH = bytes32(0);
            /// @dev Denotes the type of the zkSync transaction that came from L1.
            uint256 constant PRIORITY_OPERATION_L2_TX_TYPE = 255;
            /// @dev Denotes the type of the zkSync transaction that is used for system upgrades.
            uint256 constant SYSTEM_UPGRADE_L2_TX_TYPE = 254;
            /// @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 Timestamp - seconds since unix epoch.
            uint256 constant COMMIT_TIMESTAMP_NOT_OLDER = 3 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 = 32;
            /// @dev The L2 gasPricePerPubdata required to be used in bridges.
            uint256 constant REQUIRED_L2_GAS_PRICE_PER_PUBDATA = 800;
            /// @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;
            address constant ETH_TOKEN_ADDRESS = address(1);
            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));
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @dev The formal address of the initial program of the system: the bootloader
            address constant L2_BOOTLOADER_ADDRESS = address(0x8001);
            /// @dev The address of the known code storage system contract
            address constant L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR = address(0x8004);
            /// @dev The address of the L2 deployer system contract.
            address constant L2_DEPLOYER_SYSTEM_CONTRACT_ADDR = address(0x8006);
            /// @dev The special reserved L2 address. It is located in the system contracts space but doesn't have deployed
            /// bytecode.
            /// @dev The L2 deployer system contract allows changing bytecodes on any address if the `msg.sender` is this address.
            /// @dev So, whenever the governor wants to redeploy system contracts, it just initiates the L1 upgrade call deployer
            /// system contract
            /// via the L1 -> L2 transaction with `sender == L2_FORCE_DEPLOYER_ADDR`. For more details see the
            /// `diamond-initializers` contracts.
            address constant L2_FORCE_DEPLOYER_ADDR = address(0x8007);
            /// @dev The address of the special smart contract that can send arbitrary length message as an L2 log
            address constant L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR = address(0x8008);
            /// @dev The address of the eth token system contract
            address constant L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR = address(0x800a);
            /// @dev The address of the context system contract
            address constant L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR = address(0x800b);
            /// @dev The address of the pubdata chunk publisher contract
            address constant L2_PUBDATA_CHUNK_PUBLISHER_ADDR = address(0x8011);
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /**
             * @author Matter Labs
             * @custom:security-contact [email protected]
             * @notice Helper library for working with L2 contracts on L1.
             */
            library L2ContractHelper {
                /// @dev The prefix used to create CREATE2 addresses.
                bytes32 private constant CREATE2_PREFIX = keccak256("zksyncCreate2");
                /// @notice Validate the bytecode format and calculate its hash.
                /// @param _bytecode The bytecode to hash.
                /// @return hashedBytecode The 32-byte hash of the bytecode.
                /// Note: The function reverts the execution if the bytecode has non expected format:
                /// - Bytecode bytes length is not a multiple of 32
                /// - Bytecode bytes length is not less than 2^21 bytes (2^16 words)
                /// - Bytecode words length is not odd
                function hashL2Bytecode(bytes memory _bytecode) internal pure returns (bytes32 hashedBytecode) {
                    // Note that the length of the bytecode must be provided in 32-byte words.
                    require(_bytecode.length % 32 == 0, "pq");
                    uint256 bytecodeLenInWords = _bytecode.length / 32;
                    require(bytecodeLenInWords < 2 ** 16, "pp"); // bytecode length must be less than 2^16 words
                    require(bytecodeLenInWords % 2 == 1, "ps"); // bytecode length in words must be odd
                    hashedBytecode = sha256(_bytecode) & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                    // Setting the version of the hash
                    hashedBytecode = (hashedBytecode | bytes32(uint256(1 << 248)));
                    // Setting the length
                    hashedBytecode = hashedBytecode | bytes32(bytecodeLenInWords << 224);
                }
                /// @notice Validates the format of the given bytecode hash.
                /// @dev Due to the specification of the L2 bytecode hash, not every 32 bytes could be a legit bytecode hash.
                /// @dev The function reverts on invalid bytecode hash format.
                /// @param _bytecodeHash The hash of the bytecode to validate.
                function validateBytecodeHash(bytes32 _bytecodeHash) internal pure {
                    uint8 version = uint8(_bytecodeHash[0]);
                    require(version == 1 && _bytecodeHash[1] == bytes1(0), "zf"); // Incorrectly formatted bytecodeHash
                    require(bytecodeLen(_bytecodeHash) % 2 == 1, "uy"); // Code length in words must be odd
                }
                /// @notice Returns the length of the bytecode associated with the given hash.
                /// @param _bytecodeHash The hash of the bytecode.
                /// @return codeLengthInWords The length of the bytecode in words.
                function bytecodeLen(bytes32 _bytecodeHash) internal pure returns (uint256 codeLengthInWords) {
                    codeLengthInWords = uint256(uint8(_bytecodeHash[2])) * 256 + uint256(uint8(_bytecodeHash[3]));
                }
                /// @notice Computes the create2 address for a Layer 2 contract.
                /// @param _sender The address of the sender.
                /// @param _salt The salt value to use in the create2 address computation.
                /// @param _bytecodeHash The contract bytecode hash.
                /// @param _constructorInputHash The hash of the constructor input data.
                /// @return The create2 address of the contract.
                /// NOTE: L2 create2 derivation is different from L1 derivation!
                function computeCreate2Address(
                    address _sender,
                    bytes32 _salt,
                    bytes32 _bytecodeHash,
                    bytes32 _constructorInputHash
                ) internal pure returns (address) {
                    bytes32 senderBytes = bytes32(uint256(uint160(_sender)));
                    bytes32 data = keccak256(
                        // solhint-disable-next-line func-named-parameters
                        bytes.concat(CREATE2_PREFIX, senderBytes, _salt, _bytecodeHash, _constructorInputHash)
                    );
                    return address(uint160(uint256(data)));
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @dev The number of bits dedicated to the "patch" portion of the protocol version.
            /// This also defines the bit starting from which the "minor" part is located.
            uint256 constant SEMVER_MINOR_OFFSET = 32;
            /// @dev The number of bits dedicated to the "patch" and "minor" portions of the protocol version.
            /// This also defines the bit starting from which the "major" part is located.
            /// Note, that currently, only major version of "0" is supported.
            uint256 constant SEMVER_MAJOR_OFFSET = 64;
            /**
             * @author Matter Labs
             * @custom:security-contact [email protected]
             * @notice The library for managing SemVer for the protocol version.
             */
            library SemVer {
                /// @notice Unpacks the SemVer version from a single uint256 into major, minor and patch components.
                /// @param _packedProtocolVersion The packed protocol version.
                /// @return major The major version.
                /// @return minor The minor version.
                /// @return patch The patch version.
                function unpackSemVer(
                    uint96 _packedProtocolVersion
                ) internal pure returns (uint32 major, uint32 minor, uint32 patch) {
                    patch = uint32(_packedProtocolVersion);
                    minor = uint32(_packedProtocolVersion >> SEMVER_MINOR_OFFSET);
                    major = uint32(_packedProtocolVersion >> SEMVER_MAJOR_OFFSET);
                }
                /// @notice Packs the SemVer version from the major, minor and patch components into a single uint96.
                /// @param _major The major version.
                /// @param _minor The minor version.
                /// @param _patch The patch version.
                /// @return packedProtocolVersion The packed protocol version.
                function packSemVer(
                    uint32 _major,
                    uint32 _minor,
                    uint32 _patch
                ) internal pure returns (uint96 packedProtocolVersion) {
                    packedProtocolVersion =
                        uint96(_patch) |
                        (uint96(_minor) << SEMVER_MINOR_OFFSET) |
                        (uint96(_major) << SEMVER_MAJOR_OFFSET);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /**
             * @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
            pragma solidity 0.8.24;
            /// @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`.
            struct BridgehubL2TransactionRequest {
                address sender;
                address contractL2;
                uint256 mintValue;
                uint256 l2Value;
                bytes l2Calldata;
                uint256 l2GasLimit;
                uint256 l2GasPerPubdataByteLimit;
                bytes[] factoryDeps;
                address refundRecipient;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /**
             * @custom:security-contact [email protected]
             * @dev Contract module that helps prevent reentrant calls to a function.
             *
             * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
             * available, which can be applied to functions to make sure there are no nested
             * (reentrant) calls to them.
             *
             * Note that because there is a single `nonReentrant` guard, functions marked as
             * `nonReentrant` may not call one another. This can be worked around by making
             * those functions `private`, and then adding `external` `nonReentrant` entry
             * points to them.
             *
             * TIP: If you would like to learn more about reentrancy and alternative ways
             * to protect against it, check out our blog post
             * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
             *
             * _Since v2.5.0:_ this module is now much more gas efficient, given net gas
             * metering changes introduced in the Istanbul hardfork.
             */
            abstract contract ReentrancyGuard {
                /// @dev Address of lock flag variable.
                /// @dev Flag is placed at random memory location to not interfere with Storage contract.
                // keccak256("ReentrancyGuard") - 1;
                uint256 private constant LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4;
                // solhint-disable-next-line max-line-length
                // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/566a774222707e424896c0c390a84dc3c13bdcb2/contracts/security/ReentrancyGuard.sol
                // The values being non-zero value makes deployment a bit more expensive,
                // but in exchange the refund on every call to nonReentrant will be lower in
                // amount. Since refunds are capped to a percentage of the total
                // transaction's gas, it is best to keep them low in cases like this one, to
                // increase the likelihood of the full refund coming into effect.
                uint256 private constant _NOT_ENTERED = 1;
                uint256 private constant _ENTERED = 2;
                modifier reentrancyGuardInitializer() {
                    _initializeReentrancyGuard();
                    _;
                }
                function _initializeReentrancyGuard() private {
                    uint256 lockSlotOldValue;
                    // Storing an initial non-zero value makes deployment a bit more
                    // expensive but in exchange every call to nonReentrant
                    // will be cheaper.
                    assembly {
                        lockSlotOldValue := sload(LOCK_FLAG_ADDRESS)
                        sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED)
                    }
                    // Check that storage slot for reentrancy guard is empty to rule out possibility of slot conflict
                    require(lockSlotOldValue == 0, "1B");
                }
                /**
                 * @dev Prevents a contract from calling itself, directly or indirectly.
                 * Calling a `nonReentrant` function from another `nonReentrant`
                 * function is not supported. It is possible to prevent this from happening
                 * by making the `nonReentrant` function external, and make it call a
                 * `private` function that does the actual work.
                 */
                modifier nonReentrant() {
                    uint256 _status;
                    assembly {
                        _status := sload(LOCK_FLAG_ADDRESS)
                    }
                    // On the first call to nonReentrant, _notEntered will be true
                    require(_status == _NOT_ENTERED, "r1");
                    // Any calls to nonReentrant after this point will fail
                    assembly {
                        sstore(LOCK_FLAG_ADDRESS, _ENTERED)
                    }
                    _;
                    // By storing the original value once again, a refund is triggered (see
                    // https://eips.ethereum.org/EIPS/eip-2200)
                    assembly {
                        sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {Diamond} from "../libraries/Diamond.sol";
            /// @title Diamond Proxy Contract (EIP-2535)
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            contract DiamondProxy {
                constructor(uint256 _chainId, Diamond.DiamondCutData memory _diamondCut) {
                    // Check that the contract is deployed on the expected chain.
                    // Thus, the contract deployed by the same Create2 factory on the different chain will have different addresses!
                    require(_chainId == block.chainid, "pr");
                    Diamond.diamondCut(_diamondCut);
                }
                /// @dev 1. Find the facet for the function that is called.
                /// @dev 2. Delegate the execution to the found facet via `delegatecall`.
                fallback() external payable {
                    Diamond.DiamondStorage storage diamondStorage = Diamond.getDiamondStorage();
                    // Check whether the data contains a "full" selector or it is empty.
                    // Required because Diamond proxy finds a facet by function signature,
                    // which is not defined for data length in range [1, 3].
                    require(msg.data.length >= 4 || msg.data.length == 0, "Ut");
                    // Get facet from function selector
                    Diamond.SelectorToFacet memory facet = diamondStorage.selectorToFacet[msg.sig];
                    address facetAddress = facet.facetAddress;
                    require(facetAddress != address(0), "F"); // Proxy has no facet for this selector
                    require(!diamondStorage.isFrozen || !facet.isFreezable, "q1"); // Facet is frozen
                    assembly {
                        // The pointer to the free memory slot
                        let ptr := mload(0x40)
                        // Copy function signature and arguments from calldata at zero position into memory at pointer position
                        calldatacopy(ptr, 0, calldatasize())
                        // Delegatecall method of the implementation contract returns 0 on error
                        let result := delegatecall(gas(), facetAddress, ptr, 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(ptr, 0, size)
                        // Depending on the result value
                        switch result
                        case 0 {
                            // End execution and revert state changes
                            revert(ptr, size)
                        }
                        default {
                            // Return data with length of size at pointers position
                            return(ptr, size)
                        }
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {ZkSyncHyperchainStorage} from "../ZkSyncHyperchainStorage.sol";
            import {ReentrancyGuard} from "../../../common/ReentrancyGuard.sol";
            /// @title Base contract containing functions accessible to the other facets.
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            contract ZkSyncHyperchainBase is ReentrancyGuard {
                // slither-disable-next-line uninitialized-state
                ZkSyncHyperchainStorage internal s;
                /// @notice Checks that the message sender is an active admin
                modifier onlyAdmin() {
                    require(msg.sender == s.admin, "Hyperchain: not admin");
                    _;
                }
                /// @notice Checks if validator is active
                modifier onlyValidator() {
                    require(s.validators[msg.sender], "Hyperchain: not validator");
                    _;
                }
                modifier onlyStateTransitionManager() {
                    require(msg.sender == s.stateTransitionManager, "Hyperchain: not state transition manager");
                    _;
                }
                modifier onlyBridgehub() {
                    require(msg.sender == s.bridgehub, "Hyperchain: not bridgehub");
                    _;
                }
                modifier onlyAdminOrStateTransitionManager() {
                    require(
                        msg.sender == s.admin || msg.sender == s.stateTransitionManager,
                        "Hyperchain: Only by admin or state transition manager"
                    );
                    _;
                }
                modifier onlyValidatorOrStateTransitionManager() {
                    require(
                        s.validators[msg.sender] || msg.sender == s.stateTransitionManager,
                        "Hyperchain: Only by validator or state transition manager"
                    );
                    _;
                }
                modifier onlyBaseTokenBridge() {
                    require(msg.sender == s.baseTokenBridge, "Hyperchain: Only base token bridge can call this function");
                    _;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IVerifier, VerifierParams} from "../chain-interfaces/IVerifier.sol";
            import {PriorityQueue} from "../../state-transition/libraries/PriorityQueue.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 hyperchain 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.
            struct ZkSyncHyperchainStorage {
                /// @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 STM
                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 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.
                FeeParams feeParams;
                /// @dev Address of the blob versioned hash getter smart contract used for EIP-4844 versioned hashes.
                address blobVersionedHashRetriever;
                /// @dev The chainId of the chain
                uint256 chainId;
                /// @dev The address of the bridgehub
                address bridgehub;
                /// @dev The address of the StateTransitionManager
                address stateTransitionManager;
                /// @dev The address of the baseToken contract. Eth is address(1)
                address baseToken;
                /// @dev The address of the baseTokenbridge. Eth also uses the shared bridge
                address 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;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IZkSyncHyperchainBase} from "../chain-interfaces/IZkSyncHyperchainBase.sol";
            import {Diamond} from "../libraries/Diamond.sol";
            import {FeeParams, PubdataPricingMode} from "../chain-deps/ZkSyncHyperchainStorage.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 IZkSyncHyperchainBase {
                /// @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 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 current admin 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 Both the admin and the STM can unfreeze Diamond Proxy
                function unfreezeDiamond() 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 ValidiumModeStatusUpdate(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 contract is frozen.
                event Freeze();
                /// @notice Emitted when the contract is unfrozen.
                event Unfreeze();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IVerifier, VerifierParams} from "./IVerifier.sol";
            import {FeeParams} from "../chain-deps/ZkSyncHyperchainStorage.sol";
            /// @param chainId the id of the chain
            /// @param bridgehub the address of the bridgehub contract
            /// @param stateTransitionManager contract's address
            /// @param protocolVersion initial protocol version
            /// @param validatorTimelock address of the validator timelock that delays execution
            /// @param admin address who can manage the contract
            /// @param baseToken address of the base token of the chain
            /// @param baseTokenBridge address of the L1 shared bridge contract
            /// @param storedBatchZero hash of the initial genesis batch
            /// @param verifier address of Verifier contract
            /// @param verifierParams Verifier config parameters that describes the circuit to be verified
            /// @param l2BootloaderBytecodeHash The hash of bootloader L2 bytecode
            /// @param l2DefaultAccountBytecodeHash The hash of default account L2 bytecode
            /// @param priorityTxMaxGasLimit maximum number of the L2 gas that a user can request for L1 -> L2 transactions
            /// @param feeParams Fee parameters to be used for L1->L2 transactions
            /// @param blobVersionedHashRetriever Address of contract used to pull the blob versioned hash for a transaction.
            struct InitializeData {
                uint256 chainId;
                address bridgehub;
                address stateTransitionManager;
                uint256 protocolVersion;
                address admin;
                address validatorTimelock;
                address baseToken;
                address baseTokenBridge;
                bytes32 storedBatchZero;
                IVerifier verifier;
                VerifierParams verifierParams;
                bytes32 l2BootloaderBytecodeHash;
                bytes32 l2DefaultAccountBytecodeHash;
                uint256 priorityTxMaxGasLimit;
                FeeParams feeParams;
                address blobVersionedHashRetriever;
            }
            /// @param verifier address of Verifier contract
            /// @param verifierParams Verifier config parameters that describes the circuit to be verified
            /// @param l2BootloaderBytecodeHash The hash of bootloader L2 bytecode
            /// @param l2DefaultAccountBytecodeHash The hash of default account L2 bytecode
            /// @param priorityTxMaxGasLimit maximum number of the L2 gas that a user can request for L1 -> L2 transactions
            /// @param feeParams Fee parameters to be used for L1->L2 transactions
            /// @param blobVersionedHashRetriever Address of contract used to pull the blob versioned hash for a transaction.
            struct InitializeDataNewChain {
                IVerifier verifier;
                VerifierParams verifierParams;
                bytes32 l2BootloaderBytecodeHash;
                bytes32 l2DefaultAccountBytecodeHash;
                uint256 priorityTxMaxGasLimit;
                FeeParams feeParams;
                address blobVersionedHashRetriever;
            }
            interface IDiamondInit {
                function initialize(InitializeData calldata _initData) external returns (bytes32);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol";
            /// @dev Enum used by L2 System Contracts to differentiate logs.
            enum SystemLogKey {
                L2_TO_L1_LOGS_TREE_ROOT_KEY,
                TOTAL_L2_TO_L1_PUBDATA_KEY,
                STATE_DIFF_HASH_KEY,
                PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY,
                PREV_BATCH_HASH_KEY,
                CHAINED_PRIORITY_TXN_HASH_KEY,
                NUMBER_OF_LAYER_1_TXS_KEY,
                BLOB_ONE_HASH_KEY,
                BLOB_TWO_HASH_KEY,
                BLOB_THREE_HASH_KEY,
                BLOB_FOUR_HASH_KEY,
                BLOB_FIVE_HASH_KEY,
                BLOB_SIX_HASH_KEY,
                EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY
            }
            /// @dev Enum used to determine the source of pubdata. At first we will support calldata and blobs but this can be extended.
            enum PubdataSource {
                Calldata,
                Blob
            }
            struct LogProcessingOutput {
                uint256 numberOfLayer1Txs;
                bytes32 chainedPriorityTxsHash;
                bytes32 previousBatchHash;
                bytes32 pubdataHash;
                bytes32 stateDiffHash;
                bytes32 l2LogsTreeRoot;
                uint256 packedBatchAndL2BlockTimestamp;
                bytes32[] blobHashes;
            }
            /// @dev Total number of bytes in a blob. Blob = 4096 field elements * 31 bytes per field element
            /// @dev EIP-4844 defines it as 131_072 but we use 4096 * 31 within our circuits to always fit within a field element
            /// @dev Our circuits will prove that a EIP-4844 blob and our internal blob are the same.
            uint256 constant BLOB_SIZE_BYTES = 126_976;
            /// @dev Offset used to pull Address From Log. Equal to 4 (bytes for isService)
            uint256 constant L2_LOG_ADDRESS_OFFSET = 4;
            /// @dev Offset used to pull Key From Log. Equal to 4 (bytes for isService) + 20 (bytes for address)
            uint256 constant L2_LOG_KEY_OFFSET = 24;
            /// @dev Offset used to pull Value From Log. Equal to 4 (bytes for isService) + 20 (bytes for address) + 32 (bytes for key)
            uint256 constant L2_LOG_VALUE_OFFSET = 56;
            /// @dev BLS Modulus value defined in EIP-4844 and the magic value returned from a successful call to the
            /// point evaluation precompile
            uint256 constant BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513;
            /// @dev Packed pubdata commitments.
            /// @dev Format: list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes)) = 144 bytes
            uint256 constant PUBDATA_COMMITMENT_SIZE = 144;
            /// @dev Offset in pubdata commitment of blobs for claimed value
            uint256 constant PUBDATA_COMMITMENT_CLAIMED_VALUE_OFFSET = 16;
            /// @dev Offset in pubdata commitment of blobs for kzg commitment
            uint256 constant PUBDATA_COMMITMENT_COMMITMENT_OFFSET = 48;
            /// @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 IZkSyncHyperchainBase {
                /// @notice Rollup batch stored data
                /// @param batchNumber Rollup batch number
                /// @param batchHash Hash of L2 batch
                /// @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 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
                /// @param commitment Verified input for the zkSync circuit
                struct StoredBatchInfo {
                    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 pubdataCommitments 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 pubdataCommitments;
                }
                /// @notice Recursive proof input data (individual commitments are constructed onchain)
                struct ProofInput {
                    uint256[] recursiveAggregationInput;
                    uint256[] serializedProof;
                }
                /// @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 _lastCommittedBatchData Stored data of the last committed batch.
                /// @param _newBatchesData Data of the new batches to be committed.
                function commitBatches(
                    StoredBatchInfo calldata _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external;
                /// @notice same as `commitBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function commitBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo calldata _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external;
                /// @notice Batches commitment verification.
                /// @dev Only verifies batch commitments without any other processing.
                /// @param _prevBatch Stored data of the last committed batch.
                /// @param _committedBatches Stored data of the committed batches.
                /// @param _proof The zero knowledge proof.
                function proveBatches(
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) external;
                /// @notice same as `proveBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function proveBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) 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 _batchesData Data of the batches to be executed.
                function executeBatches(StoredBatchInfo[] calldata _batchesData) external;
                /// @notice same as `executeBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function executeBatchesSharedBridge(uint256 _chainId, StoredBatchInfo[] calldata _batchesData) external;
                /// @notice Reverts unexecuted batches
                /// @param _newLastBatch batch number after which batches should be reverted
                /// NOTE: Doesn't delete the stored data about batches, but only decreases
                /// counters that are responsible for the number of batches
                function revertBatches(uint256 _newLastBatch) external;
                /// @notice same as `revertBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function revertBatchesSharedBridge(uint256 _chainId, 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);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {PriorityOperation} from "../libraries/PriorityQueue.sol";
            import {VerifierParams} from "../chain-interfaces/IVerifier.sol";
            import {PubdataPricingMode} from "../chain-deps/ZkSyncHyperchainStorage.sol";
            import {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.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]
            interface IGetters is IZkSyncHyperchainBase {
                /*//////////////////////////////////////////////////////////////
                                        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 getStateTransitionManager() external view returns (address);
                /// @return The address of the base token
                function getBaseToken() external view returns (address);
                /// @return The address of the base token bridge
                function getBaseTokenBridge() external view returns (address);
                /// @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 The total number of priority operations that were added to the priority queue, including all processed ones
                function getTotalPriorityTxs() external view returns (uint256);
                /// @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 The first unprocessed priority operation from the queue
                function priorityQueueFrontOperation() external view returns (PriorityOperation memory);
                /// @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 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);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol";
            import {L2CanonicalTransaction, L2Log, L2Message, TxStatus, BridgehubL2TransactionRequest} from "../../common/Messaging.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 IZkSyncHyperchainBase {
                /// @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 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 memory _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);
                function bridgehubRequestL2Transaction(
                    BridgehubL2TransactionRequest calldata _request
                ) 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);
                /// @notice transfer Eth to shared bridge as part of migration process
                function transferEthToSharedBridge() external;
                /// @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
                );
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @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,
                    uint256[] calldata _recursiveAggregationInput
                ) 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 pure returns (bytes32);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            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 IZkSyncHyperchain 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: UNLICENSED
            pragma solidity 0.8.24;
            /// @title The interface of the zkSync contract, responsible for the main zkSync logic.
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            interface IZkSyncHyperchainBase {
                /// @return Returns facet name.
                function getName() external view returns (string memory);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {Diamond} from "./libraries/Diamond.sol";
            import {L2CanonicalTransaction} from "../common/Messaging.sol";
            import {FeeParams} from "./chain-deps/ZkSyncHyperchainStorage.sol";
            /// @notice Struct that holds all data needed for initializing STM Proxy.
            /// @dev We use struct instead of raw parameters in `initialize` function to prevent "Stack too deep" error
            /// @param owner The address who can manage non-critical updates in the contract
            /// @param validatorTimelock The address that serves as consensus, i.e. can submit blocks to be processed
            /// @param chainCreationParams The struct that contains the fields that define how a new chain should be created
            /// @param protocolVersion The initial protocol version on the newly deployed chain
            struct StateTransitionManagerInitializeData {
                address owner;
                address validatorTimelock;
                ChainCreationParams chainCreationParams;
                uint256 protocolVersion;
            }
            /// @notice The struct that contains the fields that define how a new chain should be created
            /// within this STM.
            /// @param genesisUpgrade The address that is used in the diamond cut initialize address on chain creation
            /// @param genesisBatchHash Batch hash of the genesis (initial) batch
            /// @param genesisIndexRepeatedStorageChanges The serial number of the shortcut storage key for the genesis batch
            /// @param genesisBatchCommitment The zk-proof commitment for the genesis batch
            /// @param diamondCut The diamond cut for the first upgrade transaction on the newly deployed chain
            struct ChainCreationParams {
                address genesisUpgrade;
                bytes32 genesisBatchHash;
                uint64 genesisIndexRepeatedStorageChanges;
                bytes32 genesisBatchCommitment;
                Diamond.DiamondCutData diamondCut;
            }
            interface IStateTransitionManager {
                /// @dev Emitted when a new Hyperchain is added
                event NewHyperchain(uint256 indexed _chainId, address indexed _hyperchainContract);
                /// @dev emitted when an chain registers and a SetChainIdUpgrade happens
                event SetChainIdUpgrade(
                    address indexed _hyperchain,
                    L2CanonicalTransaction _l2Transaction,
                    uint256 indexed _protocolVersion
                );
                /// @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 ValidatorTimelock changed
                event NewValidatorTimelock(address indexed oldValidatorTimelock, address indexed newValidatorTimelock);
                /// @notice chain creation parameters changed
                event NewChainCreationParams(
                    address genesisUpgrade,
                    bytes32 genesisBatchHash,
                    uint64 genesisIndexRepeatedStorageChanges,
                    bytes32 genesisBatchCommitment,
                    bytes32 newInitialCutHash
                );
                /// @notice New UpgradeCutHash
                event NewUpgradeCutHash(uint256 indexed protocolVersion, bytes32 indexed upgradeCutHash);
                /// @notice New UpgradeCutData
                event NewUpgradeCutData(uint256 indexed protocolVersion, Diamond.DiamondCutData diamondCutData);
                /// @notice New ProtocolVersion
                event NewProtocolVersion(uint256 indexed oldProtocolVersion, uint256 indexed newProtocolVersion);
                function BRIDGE_HUB() external view returns (address);
                function setPendingAdmin(address _newPendingAdmin) external;
                function acceptAdmin() external;
                function getAllHyperchains() external view returns (address[] memory);
                function getAllHyperchainChainIDs() external view returns (uint256[] memory);
                function getHyperchain(uint256 _chainId) external view returns (address);
                function storedBatchZero() external view returns (bytes32);
                function initialCutHash() external view returns (bytes32);
                function genesisUpgrade() external view returns (address);
                function upgradeCutHash(uint256 _protocolVersion) external view returns (bytes32);
                function protocolVersion() external view returns (uint256);
                function protocolVersionDeadline(uint256 _protocolVersion) external view returns (uint256);
                function protocolVersionIsActive(uint256 _protocolVersion) external view returns (bool);
                function initialize(StateTransitionManagerInitializeData calldata _initializeData) external;
                function setValidatorTimelock(address _validatorTimelock) external;
                function setChainCreationParams(ChainCreationParams calldata _chainCreationParams) external;
                function getChainAdmin(uint256 _chainId) external view returns (address);
                function createNewChain(
                    uint256 _chainId,
                    address _baseToken,
                    address _sharedBridge,
                    address _admin,
                    bytes calldata _diamondCut
                ) external;
                function registerAlreadyDeployedHyperchain(uint256 _chainId, address _hyperchain) external;
                function setNewVersionUpgrade(
                    Diamond.DiamondCutData calldata _cutData,
                    uint256 _oldProtocolVersion,
                    uint256 _oldprotocolVersionDeadline,
                    uint256 _newProtocolVersion
                ) external;
                function setUpgradeDiamondCut(Diamond.DiamondCutData calldata _cutData, uint256 _oldProtocolVersion) external;
                function executeUpgrade(uint256 _chainId, Diamond.DiamondCutData calldata _diamondCut) external;
                function setPriorityTxMaxGasLimit(uint256 _chainId, uint256 _maxGasLimit) external;
                function freezeChain(uint256 _chainId) external;
                function unfreezeChain(uint256 _chainId) external;
                function setTokenMultiplier(uint256 _chainId, uint128 _nominator, uint128 _denominator) external;
                function changeFeeParams(uint256 _chainId, FeeParams calldata _newFeeParams) external;
                function setValidator(uint256 _chainId, address _validator, bool _active) external;
                function setPorterAvailability(uint256 _chainId, bool _zkPorterIsAvailable) external;
                function upgradeChainFromVersion(
                    uint256 _chainId,
                    uint256 _oldProtocolVersion,
                    Diamond.DiamondCutData calldata _diamondCut
                ) external;
                function getSemverProtocolVersion() external view returns (uint32, uint32, uint32);
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity ^0.8.0;
            interface ISystemContext {
                function setChainId(uint256 _newChainId) external;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
            import {UncheckedMath} from "../../common/libraries/UncheckedMath.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
                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;
                        require(selectors.length > 0, "B"); // no functions for diamond cut
                        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("C"); // undefined diamond cut action
                        }
                    }
                    _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.
                    require(_facet.code.length > 0, "G");
                    // 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];
                        require(oldFacet.facetAddress == address(0), "J"); // facet for this selector already exists
                        _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.
                    require(_facet.code.length > 0, "K");
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "L"); // it is impossible to replace the facet with zero address
                        _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();
                    require(_facet == address(0), "a1"); // facet address must be zero
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet
                        _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];
                        require(_isSelectorFreezable == ds.selectorToFacet[selector0].isFreezable, "J1");
                    }
                    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)) {
                        require(_calldata.length == 0, "H"); // Non-empty calldata for zero address
                    } 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("I"); // delegatecall failed
                            }
                            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.
                        require(data.length == 32, "lp");
                        require(abi.decode(data, (bytes32)) == DIAMOND_INIT_SUCCESS_RETURN_VALUE, "lp1");
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @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) {
                    require(!_queue.isEmpty(), "D"); // priority queue is empty
                    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) {
                    require(!_queue.isEmpty(), "s"); // priority queue is empty
                    // 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
            pragma solidity 0.8.24;
            import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
            import {L2CanonicalTransaction} from "../../common/Messaging.sol";
            import {TX_SLOT_OVERHEAD_L2_GAS, MEMORY_OVERHEAD_GAS, L1_TX_INTRINSIC_L2_GAS, L1_TX_DELTA_544_ENCODING_BYTES, L1_TX_DELTA_FACTORY_DEPS_L2_GAS, L1_TX_MIN_L2_GAS_BASE, L1_TX_INTRINSIC_PUBDATA, L1_TX_DELTA_FACTORY_DEPS_PUBDATA} from "../../common/Config.sol";
            /// @title zkSync Library for validating L1 -> L2 transactions
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            library TransactionValidator {
                /// @dev Used to validate key properties of an L1->L2 transaction
                /// @param _transaction The transaction to validate
                /// @param _encoded The abi encoded bytes of the transaction
                /// @param _priorityTxMaxGasLimit The max gas limit, generally provided from Storage.sol
                /// @param _priorityTxMaxPubdata The maximal amount of pubdata that a single L1->L2 transaction can emit
                function validateL1ToL2Transaction(
                    L2CanonicalTransaction memory _transaction,
                    bytes memory _encoded,
                    uint256 _priorityTxMaxGasLimit,
                    uint256 _priorityTxMaxPubdata
                ) internal pure {
                    uint256 l2GasForTxBody = getTransactionBodyGasLimit(_transaction.gasLimit, _encoded.length);
                    // Ensuring that the transaction is provable
                    require(l2GasForTxBody <= _priorityTxMaxGasLimit, "ui");
                    // Ensuring that the transaction cannot output more pubdata than is processable
                    require(l2GasForTxBody / _transaction.gasPerPubdataByteLimit <= _priorityTxMaxPubdata, "uk");
                    // Ensuring that the transaction covers the minimal costs for its processing:
                    // hashing its content, publishing the factory dependencies, etc.
                    require(
                        getMinimalPriorityTransactionGasLimit(
                            _encoded.length,
                            _transaction.factoryDeps.length,
                            _transaction.gasPerPubdataByteLimit
                        ) <= l2GasForTxBody,
                        "up"
                    );
                }
                /// @dev Used to validate upgrade transactions
                /// @param _transaction The transaction to validate
                function validateUpgradeTransaction(L2CanonicalTransaction memory _transaction) internal pure {
                    // Restrict from to be within system contract range (0...2^16 - 1)
                    require(_transaction.from <= type(uint16).max, "ua");
                    require(_transaction.to <= type(uint160).max, "ub");
                    require(_transaction.paymaster == 0, "uc");
                    require(_transaction.value == 0, "ud");
                    require(_transaction.maxFeePerGas == 0, "uq");
                    require(_transaction.maxPriorityFeePerGas == 0, "ux");
                    require(_transaction.reserved[0] == 0, "ue");
                    require(_transaction.reserved[1] <= type(uint160).max, "uf");
                    require(_transaction.reserved[2] == 0, "ug");
                    require(_transaction.reserved[3] == 0, "uo");
                    require(_transaction.signature.length == 0, "uh");
                    require(_transaction.paymasterInput.length == 0, "ul1");
                    require(_transaction.reservedDynamic.length == 0, "um");
                }
                /// @dev Calculates the approximate minimum gas limit required for executing a priority transaction.
                /// @param _encodingLength The length of the priority transaction encoding in bytes.
                /// @param _numberOfFactoryDependencies The number of new factory dependencies that will be added.
                /// @param _l2GasPricePerPubdata The L2 gas price for publishing the priority transaction on L2.
                /// @return The minimum gas limit required to execute the priority transaction.
                /// Note: The calculation includes the main cost of the priority transaction, however, in reality, the operator can spend a little more gas on overheads.
                function getMinimalPriorityTransactionGasLimit(
                    uint256 _encodingLength,
                    uint256 _numberOfFactoryDependencies,
                    uint256 _l2GasPricePerPubdata
                ) internal pure returns (uint256) {
                    uint256 costForComputation;
                    {
                        // Adding the intrinsic cost for the transaction, i.e. auxiliary prices which cannot be easily accounted for
                        costForComputation = L1_TX_INTRINSIC_L2_GAS;
                        // Taking into account the hashing costs that depend on the length of the transaction
                        // Note that L1_TX_DELTA_544_ENCODING_BYTES is the delta in the price for every 544 bytes of
                        // the transaction's encoding. It is taken as LCM between 136 and 32 (the length for each keccak256 round
                        // and the size of each new encoding word).
                        costForComputation += Math.ceilDiv(_encodingLength * L1_TX_DELTA_544_ENCODING_BYTES, 544);
                        // Taking into the account the additional costs of providing new factory dependencies
                        costForComputation += _numberOfFactoryDependencies * L1_TX_DELTA_FACTORY_DEPS_L2_GAS;
                        // There is a minimal amount of computational L2 gas that the transaction should cover
                        costForComputation = Math.max(costForComputation, L1_TX_MIN_L2_GAS_BASE);
                    }
                    uint256 costForPubdata = 0;
                    {
                        // Adding the intrinsic cost for the transaction, i.e. auxiliary prices which cannot be easily accounted for
                        costForPubdata = L1_TX_INTRINSIC_PUBDATA * _l2GasPricePerPubdata;
                        // Taking into the account the additional costs of providing new factory dependencies
                        costForPubdata += _numberOfFactoryDependencies * L1_TX_DELTA_FACTORY_DEPS_PUBDATA * _l2GasPricePerPubdata;
                    }
                    return costForComputation + costForPubdata;
                }
                /// @notice Based on the full L2 gas limit (that includes the batch overhead) and other
                /// properties of the transaction, returns the l2GasLimit for the body of the transaction (the actual execution).
                /// @param _totalGasLimit The L2 gas limit that includes both the overhead for processing the batch
                /// and the L2 gas needed to process the transaction itself (i.e. the actual l2GasLimit that will be used for the transaction).
                /// @param _encodingLength The length of the ABI-encoding of the transaction.
                function getTransactionBodyGasLimit(
                    uint256 _totalGasLimit,
                    uint256 _encodingLength
                ) internal pure returns (uint256 txBodyGasLimit) {
                    uint256 overhead = getOverheadForTransaction(_encodingLength);
                    require(_totalGasLimit >= overhead, "my"); // provided gas limit doesn't cover transaction overhead
                    unchecked {
                        // We enforce the fact that `_totalGasLimit >= overhead` explicitly above.
                        txBodyGasLimit = _totalGasLimit - overhead;
                    }
                }
                /// @notice Based on the total L2 gas limit and several other parameters of the transaction
                /// returns the part of the L2 gas that will be spent on the batch's overhead.
                /// @dev The details of how this function works can be checked in the documentation
                /// of the fee model of zkSync. The appropriate comments are also present
                /// in the Rust implementation description of function `get_maximal_allowed_overhead`.
                /// @param _encodingLength The length of the binary encoding of the transaction in bytes
                function getOverheadForTransaction(
                    uint256 _encodingLength
                ) internal pure returns (uint256 batchOverheadForTransaction) {
                    // The overhead from taking up the transaction's slot
                    batchOverheadForTransaction = TX_SLOT_OVERHEAD_L2_GAS;
                    // The overhead for occupying the bootloader memory can be derived from encoded_len
                    uint256 overheadForLength = MEMORY_OVERHEAD_GAS * _encodingLength;
                    batchOverheadForTransaction = Math.max(batchOverheadForTransaction, overheadForLength);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
            import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
            import {Diamond} from "./libraries/Diamond.sol";
            import {DiamondProxy} from "./chain-deps/DiamondProxy.sol";
            import {IAdmin} from "./chain-interfaces/IAdmin.sol";
            import {IDefaultUpgrade} from "../upgrades/IDefaultUpgrade.sol";
            import {IDiamondInit} from "./chain-interfaces/IDiamondInit.sol";
            import {IExecutor} from "./chain-interfaces/IExecutor.sol";
            import {IStateTransitionManager, StateTransitionManagerInitializeData, ChainCreationParams} from "./IStateTransitionManager.sol";
            import {ISystemContext} from "./l2-deps/ISystemContext.sol";
            import {IZkSyncHyperchain} from "./chain-interfaces/IZkSyncHyperchain.sol";
            import {FeeParams} from "./chain-deps/ZkSyncHyperchainStorage.sol";
            import {L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_FORCE_DEPLOYER_ADDR} from "../common/L2ContractAddresses.sol";
            import {L2CanonicalTransaction} from "../common/Messaging.sol";
            import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
            import {ProposedUpgrade} from "../upgrades/BaseZkSyncUpgrade.sol";
            import {ReentrancyGuard} from "../common/ReentrancyGuard.sol";
            import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA, L2_TO_L1_LOG_SERIALIZE_SIZE, DEFAULT_L2_LOGS_TREE_ROOT_HASH, EMPTY_STRING_KECCAK, SYSTEM_UPGRADE_L2_TX_TYPE, PRIORITY_TX_MAX_GAS_LIMIT} from "../common/Config.sol";
            import {VerifierParams} from "./chain-interfaces/IVerifier.sol";
            import {SemVer} from "../common/libraries/SemVer.sol";
            /// @title State Transition Manager contract
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Ownable2StepUpgradeable {
                using EnumerableMap for EnumerableMap.UintToAddressMap;
                /// @notice Address of the bridgehub
                address public immutable BRIDGE_HUB;
                /// @notice The total number of hyperchains can be created/connected to this STM.
                /// This is the temporary security measure.
                uint256 public immutable MAX_NUMBER_OF_HYPERCHAINS;
                /// @notice The map from chainId => hyperchain contract
                EnumerableMap.UintToAddressMap internal hyperchainMap;
                /// @dev The batch zero hash, calculated at initialization
                bytes32 public storedBatchZero;
                /// @dev The stored cutData for diamond cut
                bytes32 public initialCutHash;
                /// @dev The genesisUpgrade contract address, used to setChainId
                address public genesisUpgrade;
                /// @dev The current packed protocolVersion. To access human-readable version, use `getSemverProtocolVersion` function.
                uint256 public protocolVersion;
                /// @dev The timestamp when protocolVersion can be last used
                mapping(uint256 _protocolVersion => uint256) public protocolVersionDeadline;
                /// @dev The validatorTimelock contract address, used to setChainId
                address public validatorTimelock;
                /// @dev The stored cutData for upgrade diamond cut. protocolVersion => cutHash
                mapping(uint256 protocolVersion => bytes32 cutHash) public upgradeCutHash;
                /// @dev The address used to manage non critical updates
                address public admin;
                /// @dev The address to accept the admin role
                address private pendingAdmin;
                /// @dev Contract is expected to be used as proxy implementation.
                /// @dev Initialize the implementation to prevent Parity hack.
                constructor(address _bridgehub, uint256 _maxNumberOfHyperchains) reentrancyGuardInitializer {
                    BRIDGE_HUB = _bridgehub;
                    MAX_NUMBER_OF_HYPERCHAINS = _maxNumberOfHyperchains;
                    // While this does not provide a protection in the production, it is needed for local testing
                    // Length of the L2Log encoding should not be equal to the length of other L2Logs' tree nodes preimages
                    assert(L2_TO_L1_LOG_SERIALIZE_SIZE != 2 * 32);
                }
                /// @notice only the bridgehub can call
                modifier onlyBridgehub() {
                    require(msg.sender == BRIDGE_HUB, "STM: only bridgehub");
                    _;
                }
                /// @notice the admin can call, for non-critical updates
                modifier onlyOwnerOrAdmin() {
                    require(msg.sender == admin || msg.sender == owner(), "STM: not owner or admin");
                    _;
                }
                /// @return The tuple of (major, minor, patch) protocol version.
                function getSemverProtocolVersion() external view returns (uint32, uint32, uint32) {
                    // slither-disable-next-line unused-return
                    return SemVer.unpackSemVer(SafeCast.toUint96(protocolVersion));
                }
                /// @notice Returns all the registered hyperchain addresses
                function getAllHyperchains() public view override returns (address[] memory chainAddresses) {
                    uint256[] memory keys = hyperchainMap.keys();
                    chainAddresses = new address[](keys.length);
                    for (uint256 i = 0; i < keys.length; i++) {
                        chainAddresses[i] = hyperchainMap.get(keys[i]);
                    }
                }
                /// @notice Returns all the registered hyperchain chainIDs
                function getAllHyperchainChainIDs() public view override returns (uint256[] memory) {
                    return hyperchainMap.keys();
                }
                /// @notice Returns the address of the hyperchain with the corresponding chainID
                function getHyperchain(uint256 _chainId) public view override returns (address chainAddress) {
                    // slither-disable-next-line unused-return
                    (, chainAddress) = hyperchainMap.tryGet(_chainId);
                }
                /// @notice Returns the address of the hyperchain admin with the corresponding chainID
                function getChainAdmin(uint256 _chainId) external view override returns (address) {
                    return IZkSyncHyperchain(hyperchainMap.get(_chainId)).getAdmin();
                }
                /// @dev initialize
                function initialize(
                    StateTransitionManagerInitializeData calldata _initializeData
                ) external reentrancyGuardInitializer {
                    require(_initializeData.owner != address(0), "STM: owner zero");
                    _transferOwnership(_initializeData.owner);
                    protocolVersion = _initializeData.protocolVersion;
                    protocolVersionDeadline[_initializeData.protocolVersion] = type(uint256).max;
                    validatorTimelock = _initializeData.validatorTimelock;
                    _setChainCreationParams(_initializeData.chainCreationParams);
                }
                /// @notice Updates the parameters with which a new chain is created
                /// @param _chainCreationParams The new chain creation parameters
                function _setChainCreationParams(ChainCreationParams calldata _chainCreationParams) internal {
                    require(_chainCreationParams.genesisUpgrade != address(0), "STM: genesisUpgrade zero");
                    require(_chainCreationParams.genesisBatchHash != bytes32(0), "STM: genesisBatchHash zero");
                    require(
                        _chainCreationParams.genesisIndexRepeatedStorageChanges != uint64(0),
                        "STM: genesisIndexRepeatedStorageChanges zero"
                    );
                    require(_chainCreationParams.genesisBatchCommitment != bytes32(0), "STM: genesisBatchCommitment zero");
                    genesisUpgrade = _chainCreationParams.genesisUpgrade;
                    // We need to initialize the state hash because it is used in the commitment of the next batch
                    IExecutor.StoredBatchInfo memory batchZero = IExecutor.StoredBatchInfo({
                        batchNumber: 0,
                        batchHash: _chainCreationParams.genesisBatchHash,
                        indexRepeatedStorageChanges: _chainCreationParams.genesisIndexRepeatedStorageChanges,
                        numberOfLayer1Txs: 0,
                        priorityOperationsHash: EMPTY_STRING_KECCAK,
                        l2LogsTreeRoot: DEFAULT_L2_LOGS_TREE_ROOT_HASH,
                        timestamp: 0,
                        commitment: _chainCreationParams.genesisBatchCommitment
                    });
                    storedBatchZero = keccak256(abi.encode(batchZero));
                    bytes32 newInitialCutHash = keccak256(abi.encode(_chainCreationParams.diamondCut));
                    initialCutHash = newInitialCutHash;
                    emit NewChainCreationParams({
                        genesisUpgrade: _chainCreationParams.genesisUpgrade,
                        genesisBatchHash: _chainCreationParams.genesisBatchHash,
                        genesisIndexRepeatedStorageChanges: _chainCreationParams.genesisIndexRepeatedStorageChanges,
                        genesisBatchCommitment: _chainCreationParams.genesisBatchCommitment,
                        newInitialCutHash: newInitialCutHash
                    });
                }
                /// @notice Updates the parameters with which a new chain is created
                /// @param _chainCreationParams The new chain creation parameters
                function setChainCreationParams(ChainCreationParams calldata _chainCreationParams) external onlyOwner {
                    _setChainCreationParams(_chainCreationParams);
                }
                /// @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
                /// @dev Please note, if the owner wants to enforce the admin change it must execute both `setPendingAdmin` and
                /// `acceptAdmin` atomically. Otherwise `admin` can set different pending admin and so fail to accept the admin rights.
                function setPendingAdmin(address _newPendingAdmin) external onlyOwnerOrAdmin {
                    // Save previous value into the stack to put it into the event later
                    address oldPendingAdmin = pendingAdmin;
                    // Change pending admin
                    pendingAdmin = _newPendingAdmin;
                    emit NewPendingAdmin(oldPendingAdmin, _newPendingAdmin);
                }
                /// @notice Accepts transfer of admin rights. Only pending admin can accept the role.
                function acceptAdmin() external {
                    address currentPendingAdmin = pendingAdmin;
                    require(msg.sender == currentPendingAdmin, "n42"); // Only proposed by current admin address can claim the admin rights
                    address previousAdmin = admin;
                    admin = currentPendingAdmin;
                    delete pendingAdmin;
                    emit NewPendingAdmin(currentPendingAdmin, address(0));
                    emit NewAdmin(previousAdmin, currentPendingAdmin);
                }
                /// @dev set validatorTimelock. Cannot do it during initialization, as validatorTimelock is deployed after STM
                function setValidatorTimelock(address _validatorTimelock) external onlyOwnerOrAdmin {
                    address oldValidatorTimelock = validatorTimelock;
                    validatorTimelock = _validatorTimelock;
                    emit NewValidatorTimelock(oldValidatorTimelock, _validatorTimelock);
                }
                /// @dev set New Version with upgrade from old version
                function setNewVersionUpgrade(
                    Diamond.DiamondCutData calldata _cutData,
                    uint256 _oldProtocolVersion,
                    uint256 _oldProtocolVersionDeadline,
                    uint256 _newProtocolVersion
                ) external onlyOwner {
                    bytes32 newCutHash = keccak256(abi.encode(_cutData));
                    uint256 previousProtocolVersion = protocolVersion;
                    upgradeCutHash[_oldProtocolVersion] = newCutHash;
                    protocolVersionDeadline[_oldProtocolVersion] = _oldProtocolVersionDeadline;
                    protocolVersionDeadline[_newProtocolVersion] = type(uint256).max;
                    protocolVersion = _newProtocolVersion;
                    emit NewProtocolVersion(previousProtocolVersion, _newProtocolVersion);
                    emit NewUpgradeCutHash(_oldProtocolVersion, newCutHash);
                    emit NewUpgradeCutData(_newProtocolVersion, _cutData);
                }
                /// @dev check that the protocolVersion is active
                function protocolVersionIsActive(uint256 _protocolVersion) external view override returns (bool) {
                    return block.timestamp <= protocolVersionDeadline[_protocolVersion];
                }
                /// @dev set the protocol version timestamp
                function setProtocolVersionDeadline(uint256 _protocolVersion, uint256 _timestamp) external onlyOwner {
                    protocolVersionDeadline[_protocolVersion] = _timestamp;
                }
                /// @dev set upgrade for some protocolVersion
                function setUpgradeDiamondCut(
                    Diamond.DiamondCutData calldata _cutData,
                    uint256 _oldProtocolVersion
                ) external onlyOwner {
                    bytes32 newCutHash = keccak256(abi.encode(_cutData));
                    upgradeCutHash[_oldProtocolVersion] = newCutHash;
                    emit NewUpgradeCutHash(_oldProtocolVersion, newCutHash);
                }
                /// @dev freezes the specified chain
                function freezeChain(uint256 _chainId) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).freezeDiamond();
                }
                /// @dev freezes the specified chain
                function unfreezeChain(uint256 _chainId) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).unfreezeDiamond();
                }
                /// @dev reverts batches on the specified chain
                function revertBatches(uint256 _chainId, uint256 _newLastBatch) external onlyOwnerOrAdmin {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).revertBatches(_newLastBatch);
                }
                /// @dev execute predefined upgrade
                function upgradeChainFromVersion(
                    uint256 _chainId,
                    uint256 _oldProtocolVersion,
                    Diamond.DiamondCutData calldata _diamondCut
                ) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).upgradeChainFromVersion(_oldProtocolVersion, _diamondCut);
                }
                /// @dev executes upgrade on chain
                function executeUpgrade(uint256 _chainId, Diamond.DiamondCutData calldata _diamondCut) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).executeUpgrade(_diamondCut);
                }
                /// @dev setPriorityTxMaxGasLimit for the specified chain
                function setPriorityTxMaxGasLimit(uint256 _chainId, uint256 _maxGasLimit) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).setPriorityTxMaxGasLimit(_maxGasLimit);
                }
                /// @dev setTokenMultiplier for the specified chain
                function setTokenMultiplier(uint256 _chainId, uint128 _nominator, uint128 _denominator) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).setTokenMultiplier(_nominator, _denominator);
                }
                /// @dev changeFeeParams for the specified chain
                function changeFeeParams(uint256 _chainId, FeeParams calldata _newFeeParams) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).changeFeeParams(_newFeeParams);
                }
                /// @dev setValidator for the specified chain
                function setValidator(uint256 _chainId, address _validator, bool _active) external onlyOwnerOrAdmin {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).setValidator(_validator, _active);
                }
                /// @dev setPorterAvailability for the specified chain
                function setPorterAvailability(uint256 _chainId, bool _zkPorterIsAvailable) external onlyOwner {
                    IZkSyncHyperchain(hyperchainMap.get(_chainId)).setPorterAvailability(_zkPorterIsAvailable);
                }
                /// registration
                /// @dev we have to set the chainId at genesis, as blockhashzero is the same for all chains with the same chainId
                function _setChainIdUpgrade(uint256 _chainId, address _chainContract) internal {
                    bytes memory systemContextCalldata = abi.encodeCall(ISystemContext.setChainId, (_chainId));
                    uint256[] memory uintEmptyArray;
                    bytes[] memory bytesEmptyArray;
                    uint256 cachedProtocolVersion = protocolVersion;
                    // slither-disable-next-line unused-return
                    (, uint32 minorVersion, ) = SemVer.unpackSemVer(SafeCast.toUint96(cachedProtocolVersion));
                    L2CanonicalTransaction memory l2ProtocolUpgradeTx = L2CanonicalTransaction({
                        txType: SYSTEM_UPGRADE_L2_TX_TYPE,
                        from: uint256(uint160(L2_FORCE_DEPLOYER_ADDR)),
                        to: uint256(uint160(L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR)),
                        gasLimit: PRIORITY_TX_MAX_GAS_LIMIT,
                        gasPerPubdataByteLimit: REQUIRED_L2_GAS_PRICE_PER_PUBDATA,
                        maxFeePerGas: uint256(0),
                        maxPriorityFeePerGas: uint256(0),
                        paymaster: uint256(0),
                        // Note, that the `minor` of the protocol version is used as "nonce" for system upgrade transactions
                        nonce: uint256(minorVersion),
                        value: 0,
                        reserved: [uint256(0), 0, 0, 0],
                        data: systemContextCalldata,
                        signature: new bytes(0),
                        factoryDeps: uintEmptyArray,
                        paymasterInput: new bytes(0),
                        reservedDynamic: new bytes(0)
                    });
                    ProposedUpgrade memory proposedUpgrade = ProposedUpgrade({
                        l2ProtocolUpgradeTx: l2ProtocolUpgradeTx,
                        factoryDeps: bytesEmptyArray,
                        bootloaderHash: bytes32(0),
                        defaultAccountHash: bytes32(0),
                        verifier: address(0),
                        verifierParams: VerifierParams({
                            recursionNodeLevelVkHash: bytes32(0),
                            recursionLeafLevelVkHash: bytes32(0),
                            recursionCircuitsSetVksHash: bytes32(0)
                        }),
                        l1ContractsUpgradeCalldata: new bytes(0),
                        postUpgradeCalldata: new bytes(0),
                        upgradeTimestamp: 0,
                        newProtocolVersion: cachedProtocolVersion
                    });
                    Diamond.FacetCut[] memory emptyArray;
                    Diamond.DiamondCutData memory cutData = Diamond.DiamondCutData({
                        facetCuts: emptyArray,
                        initAddress: genesisUpgrade,
                        initCalldata: abi.encodeCall(IDefaultUpgrade.upgrade, (proposedUpgrade))
                    });
                    IAdmin(_chainContract).executeUpgrade(cutData);
                    emit SetChainIdUpgrade(_chainContract, l2ProtocolUpgradeTx, cachedProtocolVersion);
                }
                /// @dev used to register already deployed hyperchain contracts
                /// @param _chainId the chain's id
                /// @param _hyperchain the chain's contract address
                function registerAlreadyDeployedHyperchain(uint256 _chainId, address _hyperchain) external onlyOwner {
                    require(_hyperchain != address(0), "STM: hyperchain zero");
                    _registerNewHyperchain(_chainId, _hyperchain);
                }
                /// @notice called by Bridgehub when a chain registers
                /// @param _chainId the chain's id
                /// @param _baseToken the base token address used to pay for gas fees
                /// @param _sharedBridge the shared bridge address, used as base token bridge
                /// @param _admin the chain's admin address
                /// @param _diamondCut the diamond cut data that initializes the chains Diamond Proxy
                function createNewChain(
                    uint256 _chainId,
                    address _baseToken,
                    address _sharedBridge,
                    address _admin,
                    bytes calldata _diamondCut
                ) external onlyBridgehub {
                    if (getHyperchain(_chainId) != address(0)) {
                        // Hyperchain already registered
                        return;
                    }
                    // check not registered
                    Diamond.DiamondCutData memory diamondCut = abi.decode(_diamondCut, (Diamond.DiamondCutData));
                    // check input
                    bytes32 cutHashInput = keccak256(_diamondCut);
                    require(cutHashInput == initialCutHash, "STM: initial cutHash mismatch");
                    // construct init data
                    bytes memory initData;
                    /// all together 4+9*32=292 bytes
                    // solhint-disable-next-line func-named-parameters
                    initData = bytes.concat(
                        IDiamondInit.initialize.selector,
                        bytes32(_chainId),
                        bytes32(uint256(uint160(BRIDGE_HUB))),
                        bytes32(uint256(uint160(address(this)))),
                        bytes32(uint256(protocolVersion)),
                        bytes32(uint256(uint160(_admin))),
                        bytes32(uint256(uint160(validatorTimelock))),
                        bytes32(uint256(uint160(_baseToken))),
                        bytes32(uint256(uint160(_sharedBridge))),
                        bytes32(storedBatchZero),
                        diamondCut.initCalldata
                    );
                    diamondCut.initCalldata = initData;
                    // deploy hyperchainContract
                    // slither-disable-next-line reentrancy-no-eth
                    DiamondProxy hyperchainContract = new DiamondProxy{salt: bytes32(0)}(block.chainid, diamondCut);
                    // save data
                    address hyperchainAddress = address(hyperchainContract);
                    _registerNewHyperchain(_chainId, hyperchainAddress);
                    // set chainId in VM
                    _setChainIdUpgrade(_chainId, hyperchainAddress);
                }
                /// @dev This internal function is used to register a new hyperchain in the system.
                function _registerNewHyperchain(uint256 _chainId, address _hyperchain) internal {
                    // slither-disable-next-line unused-return
                    hyperchainMap.set(_chainId, _hyperchain);
                    require(hyperchainMap.length() <= MAX_NUMBER_OF_HYPERCHAINS, "STM: Hyperchain limit reached");
                    emit NewHyperchain(_chainId, _hyperchain);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
            import {ZkSyncHyperchainBase} from "../state-transition/chain-deps/facets/ZkSyncHyperchainBase.sol";
            import {VerifierParams} from "../state-transition/chain-interfaces/IVerifier.sol";
            import {IVerifier} from "../state-transition/chain-interfaces/IVerifier.sol";
            import {L2ContractHelper} from "../common/libraries/L2ContractHelper.sol";
            import {TransactionValidator} from "../state-transition/libraries/TransactionValidator.sol";
            import {MAX_NEW_FACTORY_DEPS, SYSTEM_UPGRADE_L2_TX_TYPE, MAX_ALLOWED_MINOR_VERSION_DELTA} from "../common/Config.sol";
            import {L2CanonicalTransaction} from "../common/Messaging.sol";
            import {SemVer} from "../common/libraries/SemVer.sol";
            /// @notice The struct that represents the upgrade proposal.
            /// @param l2ProtocolUpgradeTx The system upgrade transaction.
            /// @param factoryDeps The list of factory deps for the l2ProtocolUpgradeTx.
            /// @param bootloaderHash The hash of the new bootloader bytecode. If zero, it will not be updated.
            /// @param defaultAccountHash The hash of the new default account bytecode. If zero, it will not be updated.
            /// @param verifier The address of the new verifier. If zero, the verifier will not be updated.
            /// @param verifierParams The new verifier params. If all of its fields are 0, the params will not be updated.
            /// @param l1ContractsUpgradeCalldata Custom calldata for L1 contracts upgrade, it may be interpreted differently
            /// in each upgrade. Usually empty.
            /// @param postUpgradeCalldata Custom calldata for post upgrade hook, it may be interpreted differently in each
            /// upgrade. Usually empty.
            /// @param upgradeTimestamp The timestamp after which the upgrade can be executed.
            /// @param newProtocolVersion The new version number for the protocol after this upgrade. Should be greater than
            /// the previous protocol version.
            struct ProposedUpgrade {
                L2CanonicalTransaction l2ProtocolUpgradeTx;
                bytes[] factoryDeps;
                bytes32 bootloaderHash;
                bytes32 defaultAccountHash;
                address verifier;
                VerifierParams verifierParams;
                bytes l1ContractsUpgradeCalldata;
                bytes postUpgradeCalldata;
                uint256 upgradeTimestamp;
                uint256 newProtocolVersion;
            }
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            /// @notice Interface to which all the upgrade implementations should adhere
            abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase {
                /// @notice Changes the protocol version
                event NewProtocolVersion(uint256 indexed previousProtocolVersion, uint256 indexed newProtocolVersion);
                /// @notice Сhanges to the bytecode that is used in L2 as a bootloader (start program)
                event NewL2BootloaderBytecodeHash(bytes32 indexed previousBytecodeHash, bytes32 indexed newBytecodeHash);
                /// @notice Сhanges to the bytecode that is used in L2 as a default account
                event NewL2DefaultAccountBytecodeHash(bytes32 indexed previousBytecodeHash, bytes32 indexed newBytecodeHash);
                /// @notice Verifier address changed
                event NewVerifier(address indexed oldVerifier, address indexed newVerifier);
                /// @notice Verifier parameters changed
                event NewVerifierParams(VerifierParams oldVerifierParams, VerifierParams newVerifierParams);
                /// @notice Notifies about complete upgrade
                event UpgradeComplete(uint256 indexed newProtocolVersion, bytes32 indexed l2UpgradeTxHash, ProposedUpgrade upgrade);
                /// @notice The main function that will be provided by the upgrade proxy
                /// @dev This is a virtual function and should be overridden by custom upgrade implementations.
                /// @param _proposedUpgrade The upgrade to be executed.
                /// @return txHash The hash of the L2 system contract upgrade transaction.
                function upgrade(ProposedUpgrade calldata _proposedUpgrade) public virtual returns (bytes32 txHash) {
                    // Note that due to commitment delay, the timestamp of the L2 upgrade batch may be earlier than the timestamp
                    // of the L1 block at which the upgrade occurred. This means that using timestamp as a signifier of "upgraded"
                    // on the L2 side would be inaccurate. The effects of this "back-dating" of L2 upgrade batches will be reduced
                    // as the permitted delay window is reduced in the future.
                    require(block.timestamp >= _proposedUpgrade.upgradeTimestamp, "Upgrade is not ready yet");
                    (uint32 newMinorVersion, bool isPatchOnly) = _setNewProtocolVersion(_proposedUpgrade.newProtocolVersion);
                    _upgradeL1Contract(_proposedUpgrade.l1ContractsUpgradeCalldata);
                    _upgradeVerifier(_proposedUpgrade.verifier, _proposedUpgrade.verifierParams);
                    _setBaseSystemContracts(_proposedUpgrade.bootloaderHash, _proposedUpgrade.defaultAccountHash, isPatchOnly);
                    txHash = _setL2SystemContractUpgrade(
                        _proposedUpgrade.l2ProtocolUpgradeTx,
                        _proposedUpgrade.factoryDeps,
                        newMinorVersion,
                        isPatchOnly
                    );
                    _postUpgrade(_proposedUpgrade.postUpgradeCalldata);
                    emit UpgradeComplete(_proposedUpgrade.newProtocolVersion, txHash, _proposedUpgrade);
                }
                /// @notice Change default account bytecode hash, that is used on L2
                /// @param _l2DefaultAccountBytecodeHash The hash of default account L2 bytecode
                /// @param _patchOnly Whether only the patch part of the protocol version semver has changed
                function _setL2DefaultAccountBytecodeHash(bytes32 _l2DefaultAccountBytecodeHash, bool _patchOnly) private {
                    if (_l2DefaultAccountBytecodeHash == bytes32(0)) {
                        return;
                    }
                    require(!_patchOnly, "Patch only upgrade can not set new default account");
                    L2ContractHelper.validateBytecodeHash(_l2DefaultAccountBytecodeHash);
                    // Save previous value into the stack to put it into the event later
                    bytes32 previousDefaultAccountBytecodeHash = s.l2DefaultAccountBytecodeHash;
                    // Change the default account bytecode hash
                    s.l2DefaultAccountBytecodeHash = _l2DefaultAccountBytecodeHash;
                    emit NewL2DefaultAccountBytecodeHash(previousDefaultAccountBytecodeHash, _l2DefaultAccountBytecodeHash);
                }
                /// @notice Change bootloader bytecode hash, that is used on L2
                /// @param _l2BootloaderBytecodeHash The hash of bootloader L2 bytecode
                /// @param _patchOnly Whether only the patch part of the protocol version semver has changed
                function _setL2BootloaderBytecodeHash(bytes32 _l2BootloaderBytecodeHash, bool _patchOnly) private {
                    if (_l2BootloaderBytecodeHash == bytes32(0)) {
                        return;
                    }
                    require(!_patchOnly, "Patch only upgrade can not set new bootloader");
                    L2ContractHelper.validateBytecodeHash(_l2BootloaderBytecodeHash);
                    // Save previous value into the stack to put it into the event later
                    bytes32 previousBootloaderBytecodeHash = s.l2BootloaderBytecodeHash;
                    // Change the bootloader bytecode hash
                    s.l2BootloaderBytecodeHash = _l2BootloaderBytecodeHash;
                    emit NewL2BootloaderBytecodeHash(previousBootloaderBytecodeHash, _l2BootloaderBytecodeHash);
                }
                /// @notice Change the address of the verifier smart contract
                /// @param _newVerifier Verifier smart contract address
                function _setVerifier(IVerifier _newVerifier) private {
                    // An upgrade to the verifier must be done carefully to ensure there aren't batches in the committed state
                    // during the transition. If verifier is upgraded, it will immediately be used to prove all committed batches.
                    // Batches committed expecting the old verifier will fail. Ensure all committed batches are finalized before the
                    // verifier is upgraded.
                    if (_newVerifier == IVerifier(address(0))) {
                        return;
                    }
                    IVerifier oldVerifier = s.verifier;
                    s.verifier = _newVerifier;
                    emit NewVerifier(address(oldVerifier), address(_newVerifier));
                }
                /// @notice Change the verifier parameters
                /// @param _newVerifierParams New parameters for the verifier
                function _setVerifierParams(VerifierParams calldata _newVerifierParams) private {
                    // An upgrade to the verifier params must be done carefully to ensure there aren't batches in the committed state
                    // during the transition. If verifier is upgraded, it will immediately be used to prove all committed batches.
                    // Batches committed expecting the old verifier params will fail. Ensure all committed batches are finalized before the
                    // verifier is upgraded.
                    if (
                        _newVerifierParams.recursionNodeLevelVkHash == bytes32(0) &&
                        _newVerifierParams.recursionLeafLevelVkHash == bytes32(0) &&
                        _newVerifierParams.recursionCircuitsSetVksHash == bytes32(0)
                    ) {
                        return;
                    }
                    VerifierParams memory oldVerifierParams = s.__DEPRECATED_verifierParams;
                    s.__DEPRECATED_verifierParams = _newVerifierParams;
                    emit NewVerifierParams(oldVerifierParams, _newVerifierParams);
                }
                /// @notice Updates the verifier and the verifier params
                /// @param _newVerifier The address of the new verifier. If 0, the verifier will not be updated.
                /// @param _verifierParams The new verifier params. If all of the fields are 0, the params will not be updated.
                function _upgradeVerifier(address _newVerifier, VerifierParams calldata _verifierParams) internal {
                    _setVerifier(IVerifier(_newVerifier));
                    _setVerifierParams(_verifierParams);
                }
                /// @notice Updates the bootloader hash and the hash of the default account
                /// @param _bootloaderHash The hash of the new bootloader bytecode. If zero, it will not be updated.
                /// @param _defaultAccountHash The hash of the new default account bytecode. If zero, it will not be updated.
                /// @param _patchOnly Whether only the patch part of the protocol version semver has changed.
                function _setBaseSystemContracts(bytes32 _bootloaderHash, bytes32 _defaultAccountHash, bool _patchOnly) internal {
                    _setL2BootloaderBytecodeHash(_bootloaderHash, _patchOnly);
                    _setL2DefaultAccountBytecodeHash(_defaultAccountHash, _patchOnly);
                }
                /// @notice Sets the hash of the L2 system contract upgrade transaction for the next batch to be committed
                /// @dev If the transaction is noop (i.e. its type is 0) it does nothing and returns 0.
                /// @param _l2ProtocolUpgradeTx The L2 system contract upgrade transaction.
                /// @param _factoryDeps The factory dependencies that are used by the transaction.
                /// @param _newMinorProtocolVersion The new minor protocol version. It must be used as the `nonce` field
                /// of the `_l2ProtocolUpgradeTx`.
                /// @param _patchOnly Whether only the patch part of the protocol version semver has changed.
                /// @return System contracts upgrade transaction hash. Zero if no upgrade transaction is set.
                function _setL2SystemContractUpgrade(
                    L2CanonicalTransaction calldata _l2ProtocolUpgradeTx,
                    bytes[] calldata _factoryDeps,
                    uint32 _newMinorProtocolVersion,
                    bool _patchOnly
                ) internal returns (bytes32) {
                    // If the type is 0, it is considered as noop and so will not be required to be executed.
                    if (_l2ProtocolUpgradeTx.txType == 0) {
                        return bytes32(0);
                    }
                    require(!_patchOnly, "Patch only upgrade can not set upgrade transaction");
                    require(_l2ProtocolUpgradeTx.txType == SYSTEM_UPGRADE_L2_TX_TYPE, "L2 system upgrade tx type is wrong");
                    bytes memory encodedTransaction = abi.encode(_l2ProtocolUpgradeTx);
                    TransactionValidator.validateL1ToL2Transaction(
                        _l2ProtocolUpgradeTx,
                        encodedTransaction,
                        s.priorityTxMaxGasLimit,
                        s.feeParams.priorityTxMaxPubdata
                    );
                    TransactionValidator.validateUpgradeTransaction(_l2ProtocolUpgradeTx);
                    // We want the hashes of l2 system upgrade transactions to be unique.
                    // This is why we require that the `nonce` field is unique to each upgrade.
                    require(
                        _l2ProtocolUpgradeTx.nonce == _newMinorProtocolVersion,
                        "The new protocol version should be included in the L2 system upgrade tx"
                    );
                    _verifyFactoryDeps(_factoryDeps, _l2ProtocolUpgradeTx.factoryDeps);
                    bytes32 l2ProtocolUpgradeTxHash = keccak256(encodedTransaction);
                    s.l2SystemContractsUpgradeTxHash = l2ProtocolUpgradeTxHash;
                    return l2ProtocolUpgradeTxHash;
                }
                /// @notice Verifies that the factory deps correspond to the proper hashes
                /// @param _factoryDeps The list of factory deps
                /// @param _expectedHashes The list of expected bytecode hashes
                function _verifyFactoryDeps(bytes[] calldata _factoryDeps, uint256[] calldata _expectedHashes) private pure {
                    require(_factoryDeps.length == _expectedHashes.length, "Wrong number of factory deps");
                    require(_factoryDeps.length <= MAX_NEW_FACTORY_DEPS, "Factory deps can be at most 32");
                    for (uint256 i = 0; i < _factoryDeps.length; ++i) {
                        require(
                            L2ContractHelper.hashL2Bytecode(_factoryDeps[i]) == bytes32(_expectedHashes[i]),
                            "Wrong factory dep hash"
                        );
                    }
                }
                /// @notice Changes the protocol version
                /// @param _newProtocolVersion The new protocol version
                function _setNewProtocolVersion(
                    uint256 _newProtocolVersion
                ) internal virtual returns (uint32 newMinorVersion, bool patchOnly) {
                    uint256 previousProtocolVersion = s.protocolVersion;
                    require(
                        _newProtocolVersion > previousProtocolVersion,
                        "New protocol version is not greater than the current one"
                    );
                    // slither-disable-next-line unused-return
                    (uint32 previousMajorVersion, uint32 previousMinorVersion, ) = SemVer.unpackSemVer(
                        SafeCast.toUint96(previousProtocolVersion)
                    );
                    require(previousMajorVersion == 0, "Implementation requires that the major version is 0 at all times");
                    uint32 newMajorVersion;
                    // slither-disable-next-line unused-return
                    (newMajorVersion, newMinorVersion, ) = SemVer.unpackSemVer(SafeCast.toUint96(_newProtocolVersion));
                    require(newMajorVersion == 0, "Major must always be 0");
                    // Since `_newProtocolVersion > previousProtocolVersion`, and both old and new major version is 0,
                    // the difference between minor versions is >= 0.
                    uint256 minorDelta = newMinorVersion - previousMinorVersion;
                    if (minorDelta == 0) {
                        patchOnly = true;
                    }
                    // While this is implicitly enforced by other checks above, we still double check just in case
                    require(minorDelta <= MAX_ALLOWED_MINOR_VERSION_DELTA, "Too big protocol version difference");
                    // If the minor version changes also, we need to ensure that the previous upgrade has been finalized.
                    // In case the minor version does not change, we permit to keep the old upgrade transaction in the system, but it
                    // must be ensured in the other parts of the upgrade that the is not overridden.
                    if (!patchOnly) {
                        // If the previous upgrade had an L2 system upgrade transaction, we require that it is finalized.
                        // Note it is important to keep this check, as otherwise hyperchains might skip upgrades by overwriting
                        require(s.l2SystemContractsUpgradeTxHash == bytes32(0), "Previous upgrade has not been finalized");
                        require(
                            s.l2SystemContractsUpgradeBatchNumber == 0,
                            "The batch number of the previous upgrade has not been cleaned"
                        );
                    }
                    s.protocolVersion = _newProtocolVersion;
                    emit NewProtocolVersion(previousProtocolVersion, _newProtocolVersion);
                }
                /// @notice Placeholder function for custom logic for upgrading L1 contract.
                /// Typically this function will never be used.
                /// @param _customCallDataForUpgrade Custom data for an upgrade, which may be interpreted differently for each
                /// upgrade.
                function _upgradeL1Contract(bytes calldata _customCallDataForUpgrade) internal virtual {}
                /// @notice placeholder function for custom logic for post-upgrade logic.
                /// Typically this function will never be used.
                /// @param _customCallDataForUpgrade Custom data for an upgrade, which may be interpreted differently for each
                /// upgrade.
                function _postUpgrade(bytes calldata _customCallDataForUpgrade) internal virtual {}
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {ProposedUpgrade} from "./BaseZkSyncUpgrade.sol";
            interface IDefaultUpgrade {
                function upgrade(ProposedUpgrade calldata _upgrade) external returns (bytes32);
            }
            

            File 5 of 5: ExecutorFacet
            // 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
            pragma solidity 0.8.24;
            /// @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;
            // TODO: change constant to the real root hash of empty Merkle tree (SMA-184)
            bytes32 constant DEFAULT_L2_LOGS_TREE_ROOT_HASH = bytes32(0);
            /// @dev Denotes the type of the zkSync transaction that came from L1.
            uint256 constant PRIORITY_OPERATION_L2_TX_TYPE = 255;
            /// @dev Denotes the type of the zkSync transaction that is used for system upgrades.
            uint256 constant SYSTEM_UPGRADE_L2_TX_TYPE = 254;
            /// @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 Timestamp - seconds since unix epoch.
            uint256 constant COMMIT_TIMESTAMP_NOT_OLDER = 3 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 = 32;
            /// @dev The L2 gasPricePerPubdata required to be used in bridges.
            uint256 constant REQUIRED_L2_GAS_PRICE_PER_PUBDATA = 800;
            /// @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;
            address constant ETH_TOKEN_ADDRESS = address(1);
            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));
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @dev The formal address of the initial program of the system: the bootloader
            address constant L2_BOOTLOADER_ADDRESS = address(0x8001);
            /// @dev The address of the known code storage system contract
            address constant L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR = address(0x8004);
            /// @dev The address of the L2 deployer system contract.
            address constant L2_DEPLOYER_SYSTEM_CONTRACT_ADDR = address(0x8006);
            /// @dev The special reserved L2 address. It is located in the system contracts space but doesn't have deployed
            /// bytecode.
            /// @dev The L2 deployer system contract allows changing bytecodes on any address if the `msg.sender` is this address.
            /// @dev So, whenever the governor wants to redeploy system contracts, it just initiates the L1 upgrade call deployer
            /// system contract
            /// via the L1 -> L2 transaction with `sender == L2_FORCE_DEPLOYER_ADDR`. For more details see the
            /// `diamond-initializers` contracts.
            address constant L2_FORCE_DEPLOYER_ADDR = address(0x8007);
            /// @dev The address of the special smart contract that can send arbitrary length message as an L2 log
            address constant L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR = address(0x8008);
            /// @dev The address of the eth token system contract
            address constant L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR = address(0x800a);
            /// @dev The address of the context system contract
            address constant L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR = address(0x800b);
            /// @dev The address of the pubdata chunk publisher contract
            address constant L2_PUBDATA_CHUNK_PUBLISHER_ADDR = address(0x8011);
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /**
             * @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
            pragma solidity 0.8.24;
            /**
             * @author Matter Labs
             * @custom:security-contact [email protected]
             * @dev The library provides a set of functions that help read data from an "abi.encodePacked" byte array.
             * @dev Each of the functions accepts the `bytes memory` and the offset where data should be read and returns a value of a certain type.
             *
             * @dev WARNING!
             * 1) Functions don't check the length of the bytes array, so it can go out of bounds.
             * The user of the library must check for bytes length before using any functions from the library!
             *
             * 2) Read variables are not cleaned up - https://docs.soliditylang.org/en/v0.8.16/internals/variable_cleanup.html.
             * Using data in inline assembly can lead to unexpected behavior!
             */
            library UnsafeBytes {
                function readUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32 result, uint256 offset) {
                    assembly {
                        offset := add(_start, 4)
                        result := mload(add(_bytes, offset))
                    }
                }
                function readAddress(bytes memory _bytes, uint256 _start) internal pure returns (address result, uint256 offset) {
                    assembly {
                        offset := add(_start, 20)
                        result := mload(add(_bytes, offset))
                    }
                }
                function readUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256 result, uint256 offset) {
                    assembly {
                        offset := add(_start, 32)
                        result := mload(add(_bytes, offset))
                    }
                }
                function readBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32 result, uint256 offset) {
                    assembly {
                        offset := add(_start, 32)
                        result := mload(add(_bytes, offset))
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @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`.
            struct BridgehubL2TransactionRequest {
                address sender;
                address contractL2;
                uint256 mintValue;
                uint256 l2Value;
                bytes l2Calldata;
                uint256 l2GasLimit;
                uint256 l2GasPerPubdataByteLimit;
                bytes[] factoryDeps;
                address refundRecipient;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /**
             * @custom:security-contact [email protected]
             * @dev Contract module that helps prevent reentrant calls to a function.
             *
             * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
             * available, which can be applied to functions to make sure there are no nested
             * (reentrant) calls to them.
             *
             * Note that because there is a single `nonReentrant` guard, functions marked as
             * `nonReentrant` may not call one another. This can be worked around by making
             * those functions `private`, and then adding `external` `nonReentrant` entry
             * points to them.
             *
             * TIP: If you would like to learn more about reentrancy and alternative ways
             * to protect against it, check out our blog post
             * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
             *
             * _Since v2.5.0:_ this module is now much more gas efficient, given net gas
             * metering changes introduced in the Istanbul hardfork.
             */
            abstract contract ReentrancyGuard {
                /// @dev Address of lock flag variable.
                /// @dev Flag is placed at random memory location to not interfere with Storage contract.
                // keccak256("ReentrancyGuard") - 1;
                uint256 private constant LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4;
                // solhint-disable-next-line max-line-length
                // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/566a774222707e424896c0c390a84dc3c13bdcb2/contracts/security/ReentrancyGuard.sol
                // The values being non-zero value makes deployment a bit more expensive,
                // but in exchange the refund on every call to nonReentrant will be lower in
                // amount. Since refunds are capped to a percentage of the total
                // transaction's gas, it is best to keep them low in cases like this one, to
                // increase the likelihood of the full refund coming into effect.
                uint256 private constant _NOT_ENTERED = 1;
                uint256 private constant _ENTERED = 2;
                modifier reentrancyGuardInitializer() {
                    _initializeReentrancyGuard();
                    _;
                }
                function _initializeReentrancyGuard() private {
                    uint256 lockSlotOldValue;
                    // Storing an initial non-zero value makes deployment a bit more
                    // expensive but in exchange every call to nonReentrant
                    // will be cheaper.
                    assembly {
                        lockSlotOldValue := sload(LOCK_FLAG_ADDRESS)
                        sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED)
                    }
                    // Check that storage slot for reentrancy guard is empty to rule out possibility of slot conflict
                    require(lockSlotOldValue == 0, "1B");
                }
                /**
                 * @dev Prevents a contract from calling itself, directly or indirectly.
                 * Calling a `nonReentrant` function from another `nonReentrant`
                 * function is not supported. It is possible to prevent this from happening
                 * by making the `nonReentrant` function external, and make it call a
                 * `private` function that does the actual work.
                 */
                modifier nonReentrant() {
                    uint256 _status;
                    assembly {
                        _status := sload(LOCK_FLAG_ADDRESS)
                    }
                    // On the first call to nonReentrant, _notEntered will be true
                    require(_status == _NOT_ENTERED, "r1");
                    // Any calls to nonReentrant after this point will fail
                    assembly {
                        sstore(LOCK_FLAG_ADDRESS, _ENTERED)
                    }
                    _;
                    // By storing the original value once again, a refund is triggered (see
                    // https://eips.ethereum.org/EIPS/eip-2200)
                    assembly {
                        sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {ZkSyncHyperchainBase} from "./ZkSyncHyperchainBase.sol";
            import {COMMIT_TIMESTAMP_NOT_OLDER, COMMIT_TIMESTAMP_APPROXIMATION_DELTA, EMPTY_STRING_KECCAK, L2_TO_L1_LOG_SERIALIZE_SIZE, MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES, PACKED_L2_BLOCK_TIMESTAMP_MASK, PUBLIC_INPUT_SHIFT, POINT_EVALUATION_PRECOMPILE_ADDR} from "../../../common/Config.sol";
            import {IExecutor, L2_LOG_ADDRESS_OFFSET, L2_LOG_KEY_OFFSET, L2_LOG_VALUE_OFFSET, SystemLogKey, LogProcessingOutput, PubdataSource, BLS_MODULUS, PUBDATA_COMMITMENT_SIZE, PUBDATA_COMMITMENT_CLAIMED_VALUE_OFFSET, PUBDATA_COMMITMENT_COMMITMENT_OFFSET, MAX_NUMBER_OF_BLOBS, TOTAL_BLOBS_IN_COMMITMENT, BLOB_SIZE_BYTES} from "../../chain-interfaces/IExecutor.sol";
            import {PriorityQueue, PriorityOperation} from "../../libraries/PriorityQueue.sol";
            import {UncheckedMath} from "../../../common/libraries/UncheckedMath.sol";
            import {UnsafeBytes} from "../../../common/libraries/UnsafeBytes.sol";
            import {L2_BOOTLOADER_ADDRESS, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_PUBDATA_CHUNK_PUBLISHER_ADDR} from "../../../common/L2ContractAddresses.sol";
            import {PubdataPricingMode} from "../ZkSyncHyperchainStorage.sol";
            import {IStateTransitionManager} from "../../IStateTransitionManager.sol";
            // While formally the following import is not used, it is needed to inherit documentation from it
            import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBase.sol";
            /// @title zkSync hyperchain Executor contract capable of processing events emitted in the zkSync hyperchain protocol.
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor {
                using UncheckedMath for uint256;
                using PriorityQueue for PriorityQueue.Queue;
                /// @inheritdoc IZkSyncHyperchainBase
                string public constant override getName = "ExecutorFacet";
                /// @dev Process one batch commit using the previous batch StoredBatchInfo
                /// @dev returns new batch StoredBatchInfo
                /// @notice Does not change storage
                function _commitOneBatch(
                    StoredBatchInfo memory _previousBatch,
                    CommitBatchInfo calldata _newBatch,
                    bytes32 _expectedSystemContractUpgradeTxHash
                ) internal view returns (StoredBatchInfo memory) {
                    require(_newBatch.batchNumber == _previousBatch.batchNumber + 1, "f"); // only commit next batch
                    uint8 pubdataSource = uint8(bytes1(_newBatch.pubdataCommitments[0]));
                    PubdataPricingMode pricingMode = s.feeParams.pubdataPricingMode;
                    require(
                        pricingMode == PubdataPricingMode.Validium ||
                            pubdataSource == uint8(PubdataSource.Calldata) ||
                            pubdataSource == uint8(PubdataSource.Blob),
                        "us"
                    );
                    // Check that batch contain all meta information for L2 logs.
                    // Get the chained hash of priority transaction hashes.
                    LogProcessingOutput memory logOutput = _processL2Logs(_newBatch, _expectedSystemContractUpgradeTxHash);
                    bytes32[] memory blobCommitments = new bytes32[](MAX_NUMBER_OF_BLOBS);
                    if (pricingMode == PubdataPricingMode.Validium) {
                        // skipping data validation for validium, we just check that the data is empty
                        require(_newBatch.pubdataCommitments.length == 1, "EF: v0l");
                        for (uint8 i = uint8(SystemLogKey.BLOB_ONE_HASH_KEY); i <= uint8(SystemLogKey.BLOB_SIX_HASH_KEY); i++) {
                            logOutput.blobHashes[i - uint8(SystemLogKey.BLOB_ONE_HASH_KEY)] = bytes32(0);
                        }
                    } else if (pubdataSource == uint8(PubdataSource.Blob)) {
                        // In this scenario, pubdataCommitments is a list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes)) = 144 bytes
                        blobCommitments = _verifyBlobInformation(_newBatch.pubdataCommitments[1:], logOutput.blobHashes);
                    } else if (pubdataSource == uint8(PubdataSource.Calldata)) {
                        // In this scenario pubdataCommitments is actual pubdata consisting of l2 to l1 logs, l2 to l1 message, compressed smart contract bytecode, and compressed state diffs
                        require(_newBatch.pubdataCommitments.length <= BLOB_SIZE_BYTES, "cz");
                        require(
                            logOutput.pubdataHash ==
                                keccak256(_newBatch.pubdataCommitments[1:_newBatch.pubdataCommitments.length - 32]),
                            "wp"
                        );
                        blobCommitments[0] = bytes32(
                            _newBatch.pubdataCommitments[_newBatch.pubdataCommitments.length - 32:_newBatch
                                .pubdataCommitments
                                .length]
                        );
                    }
                    require(_previousBatch.batchHash == logOutput.previousBatchHash, "l");
                    // Check that the priority operation hash in the L2 logs is as expected
                    require(logOutput.chainedPriorityTxsHash == _newBatch.priorityOperationsHash, "t");
                    // Check that the number of processed priority operations is as expected
                    require(logOutput.numberOfLayer1Txs == _newBatch.numberOfLayer1Txs, "ta");
                    // Check the timestamp of the new batch
                    _verifyBatchTimestamp(logOutput.packedBatchAndL2BlockTimestamp, _newBatch.timestamp, _previousBatch.timestamp);
                    // Create batch commitment for the proof verification
                    bytes32 commitment = _createBatchCommitment(
                        _newBatch,
                        logOutput.stateDiffHash,
                        blobCommitments,
                        logOutput.blobHashes
                    );
                    return
                        StoredBatchInfo({
                            batchNumber: _newBatch.batchNumber,
                            batchHash: _newBatch.newStateRoot,
                            indexRepeatedStorageChanges: _newBatch.indexRepeatedStorageChanges,
                            numberOfLayer1Txs: _newBatch.numberOfLayer1Txs,
                            priorityOperationsHash: _newBatch.priorityOperationsHash,
                            l2LogsTreeRoot: logOutput.l2LogsTreeRoot,
                            timestamp: _newBatch.timestamp,
                            commitment: commitment
                        });
                }
                /// @notice checks that the timestamps of both the new batch and the new L2 block are correct.
                /// @param _packedBatchAndL2BlockTimestamp - packed batch and L2 block timestamp in a format of batchTimestamp * 2**128 + l2BatchTimestamp
                /// @param _expectedBatchTimestamp - expected batch timestamp
                /// @param _previousBatchTimestamp - the timestamp of the previous batch
                function _verifyBatchTimestamp(
                    uint256 _packedBatchAndL2BlockTimestamp,
                    uint256 _expectedBatchTimestamp,
                    uint256 _previousBatchTimestamp
                ) internal view {
                    // Check that the timestamp that came from the system context is expected
                    uint256 batchTimestamp = _packedBatchAndL2BlockTimestamp >> 128;
                    require(batchTimestamp == _expectedBatchTimestamp, "tb");
                    // While the fact that _previousBatchTimestamp < batchTimestamp is already checked on L2,
                    // we double check it here for clarity
                    require(_previousBatchTimestamp < batchTimestamp, "h3");
                    uint256 lastL2BlockTimestamp = _packedBatchAndL2BlockTimestamp & PACKED_L2_BLOCK_TIMESTAMP_MASK;
                    // All L2 blocks have timestamps within the range of [batchTimestamp, lastL2BlockTimestamp].
                    // So here we need to only double check that:
                    // - The timestamp of the batch is not too small.
                    // - The timestamp of the last L2 block is not too big.
                    require(block.timestamp - COMMIT_TIMESTAMP_NOT_OLDER <= batchTimestamp, "h1"); // New batch timestamp is too small
                    require(lastL2BlockTimestamp <= block.timestamp + COMMIT_TIMESTAMP_APPROXIMATION_DELTA, "h2"); // The last L2 block timestamp is too big
                }
                /// @dev Check that L2 logs are proper and batch contain all meta information for them
                /// @dev The logs processed here should line up such that only one log for each key from the
                ///      SystemLogKey enum in Constants.sol is processed per new batch.
                /// @dev Data returned from here will be used to form the batch commitment.
                function _processL2Logs(
                    CommitBatchInfo calldata _newBatch,
                    bytes32 _expectedSystemContractUpgradeTxHash
                ) internal pure returns (LogProcessingOutput memory logOutput) {
                    // Copy L2 to L1 logs into memory.
                    bytes memory emittedL2Logs = _newBatch.systemLogs;
                    logOutput.blobHashes = new bytes32[](MAX_NUMBER_OF_BLOBS);
                    // Used as bitmap to set/check log processing happens exactly once.
                    // See SystemLogKey enum in Constants.sol for ordering.
                    uint256 processedLogs;
                    // linear traversal of the logs
                    for (uint256 i = 0; i < emittedL2Logs.length; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) {
                        // Extract the values to be compared to/used such as the log sender, key, and value
                        // slither-disable-next-line unused-return
                        (address logSender, ) = UnsafeBytes.readAddress(emittedL2Logs, i + L2_LOG_ADDRESS_OFFSET);
                        // slither-disable-next-line unused-return
                        (uint256 logKey, ) = UnsafeBytes.readUint256(emittedL2Logs, i + L2_LOG_KEY_OFFSET);
                        // slither-disable-next-line unused-return
                        (bytes32 logValue, ) = UnsafeBytes.readBytes32(emittedL2Logs, i + L2_LOG_VALUE_OFFSET);
                        // Ensure that the log hasn't been processed already
                        require(!_checkBit(processedLogs, uint8(logKey)), "kp");
                        processedLogs = _setBit(processedLogs, uint8(logKey));
                        // Need to check that each log was sent by the correct address.
                        if (logKey == uint256(SystemLogKey.L2_TO_L1_LOGS_TREE_ROOT_KEY)) {
                            require(logSender == L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, "lm");
                            logOutput.l2LogsTreeRoot = logValue;
                        } else if (logKey == uint256(SystemLogKey.TOTAL_L2_TO_L1_PUBDATA_KEY)) {
                            require(logSender == L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, "ln");
                            logOutput.pubdataHash = logValue;
                        } else if (logKey == uint256(SystemLogKey.STATE_DIFF_HASH_KEY)) {
                            require(logSender == L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, "lb");
                            logOutput.stateDiffHash = logValue;
                        } else if (logKey == uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY)) {
                            require(logSender == L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, "sc");
                            logOutput.packedBatchAndL2BlockTimestamp = uint256(logValue);
                        } else if (logKey == uint256(SystemLogKey.PREV_BATCH_HASH_KEY)) {
                            require(logSender == L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, "sv");
                            logOutput.previousBatchHash = logValue;
                        } else if (logKey == uint256(SystemLogKey.CHAINED_PRIORITY_TXN_HASH_KEY)) {
                            require(logSender == L2_BOOTLOADER_ADDRESS, "bl");
                            logOutput.chainedPriorityTxsHash = logValue;
                        } else if (logKey == uint256(SystemLogKey.NUMBER_OF_LAYER_1_TXS_KEY)) {
                            require(logSender == L2_BOOTLOADER_ADDRESS, "bk");
                            logOutput.numberOfLayer1Txs = uint256(logValue);
                        } else if (
                            logKey >= uint256(SystemLogKey.BLOB_ONE_HASH_KEY) && logKey <= uint256(SystemLogKey.BLOB_SIX_HASH_KEY)
                        ) {
                            require(logSender == L2_PUBDATA_CHUNK_PUBLISHER_ADDR, "pc");
                            uint8 blobNumber = uint8(logKey) - uint8(SystemLogKey.BLOB_ONE_HASH_KEY);
                            // While the fact that `blobNumber` is a valid blob number is implicitly checked by the fact
                            // that Solidity provides array overflow protection, we still double check it manually in case
                            // we accidentally put `unchecked` at the top of the loop and generally for better error messages.
                            require(blobNumber < MAX_NUMBER_OF_BLOBS, "b6");
                            logOutput.blobHashes[blobNumber] = logValue;
                        } else if (logKey == uint256(SystemLogKey.EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY)) {
                            require(logSender == L2_BOOTLOADER_ADDRESS, "bu");
                            require(_expectedSystemContractUpgradeTxHash == logValue, "ut");
                        } else if (logKey > uint256(SystemLogKey.EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY)) {
                            revert("ul");
                        }
                    }
                    // We only require 13 logs to be checked, the 14th is if we are expecting a protocol upgrade
                    // Without the protocol upgrade we expect 13 logs: 2^13 - 1 = 8191
                    // With the protocol upgrade we expect 14 logs: 2^14 - 1 = 16383
                    if (_expectedSystemContractUpgradeTxHash == bytes32(0)) {
                        require(processedLogs == 8191, "b7");
                    } else {
                        require(processedLogs == 16383, "b8");
                    }
                }
                /// @inheritdoc IExecutor
                function commitBatches(
                    StoredBatchInfo memory _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external nonReentrant onlyValidator {
                    _commitBatches(_lastCommittedBatchData, _newBatchesData);
                }
                /// @inheritdoc IExecutor
                function commitBatchesSharedBridge(
                    uint256, // _chainId
                    StoredBatchInfo memory _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external nonReentrant onlyValidator {
                    _commitBatches(_lastCommittedBatchData, _newBatchesData);
                }
                function _commitBatches(
                    StoredBatchInfo memory _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) internal {
                    // check that we have the right protocol version
                    // three comments:
                    // 1. A chain has to keep their protocol version up to date, as processing a block requires the latest or previous protocol version
                    // to solve this we will need to add the feature to create batches with only the protocol upgrade tx, without any other txs.
                    // 2. A chain might become out of sync if it launches while we are in the middle of a protocol upgrade. This would mean they cannot process their genesis upgrade
                    // as their protocolversion would be outdated, and they also cannot process the protocol upgrade tx as they have a pending upgrade.
                    // 3. The protocol upgrade is increased in the BaseZkSyncUpgrade, in the executor only the systemContractsUpgradeTxHash is checked
                    require(
                        IStateTransitionManager(s.stateTransitionManager).protocolVersionIsActive(s.protocolVersion),
                        "Executor facet: wrong protocol version"
                    );
                    // With the new changes for EIP-4844, namely the restriction on number of blobs per block, we only allow for a single batch to be committed at a time.
                    require(_newBatchesData.length == 1, "e4");
                    // Check that we commit batches after last committed batch
                    require(s.storedBatchHashes[s.totalBatchesCommitted] == _hashStoredBatchInfo(_lastCommittedBatchData), "i"); // incorrect previous batch data
                    bytes32 systemContractsUpgradeTxHash = s.l2SystemContractsUpgradeTxHash;
                    // Upgrades are rarely done so we optimize a case with no active system contracts upgrade.
                    if (systemContractsUpgradeTxHash == bytes32(0) || s.l2SystemContractsUpgradeBatchNumber != 0) {
                        _commitBatchesWithoutSystemContractsUpgrade(_lastCommittedBatchData, _newBatchesData);
                    } else {
                        _commitBatchesWithSystemContractsUpgrade(
                            _lastCommittedBatchData,
                            _newBatchesData,
                            systemContractsUpgradeTxHash
                        );
                    }
                    s.totalBatchesCommitted = s.totalBatchesCommitted + _newBatchesData.length;
                }
                /// @dev Commits new batches without any system contracts upgrade.
                /// @param _lastCommittedBatchData The data of the last committed batch.
                /// @param _newBatchesData An array of batch data that needs to be committed.
                function _commitBatchesWithoutSystemContractsUpgrade(
                    StoredBatchInfo memory _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) internal {
                    for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) {
                        _lastCommittedBatchData = _commitOneBatch(_lastCommittedBatchData, _newBatchesData[i], bytes32(0));
                        s.storedBatchHashes[_lastCommittedBatchData.batchNumber] = _hashStoredBatchInfo(_lastCommittedBatchData);
                        emit BlockCommit(
                            _lastCommittedBatchData.batchNumber,
                            _lastCommittedBatchData.batchHash,
                            _lastCommittedBatchData.commitment
                        );
                    }
                }
                /// @dev Commits new batches with a system contracts upgrade transaction.
                /// @param _lastCommittedBatchData The data of the last committed batch.
                /// @param _newBatchesData An array of batch data that needs to be committed.
                /// @param _systemContractUpgradeTxHash The transaction hash of the system contract upgrade.
                function _commitBatchesWithSystemContractsUpgrade(
                    StoredBatchInfo memory _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData,
                    bytes32 _systemContractUpgradeTxHash
                ) internal {
                    // The system contract upgrade is designed to be executed atomically with the new bootloader, a default account,
                    // ZKP verifier, and other system parameters. Hence, we ensure that the upgrade transaction is
                    // carried out within the first batch committed after the upgrade.
                    // While the logic of the contract ensures that the s.l2SystemContractsUpgradeBatchNumber is 0 when this function is called,
                    // this check is added just in case. Since it is a hot read, it does not encure noticeable gas cost.
                    require(s.l2SystemContractsUpgradeBatchNumber == 0, "ik");
                    // Save the batch number where the upgrade transaction was executed.
                    s.l2SystemContractsUpgradeBatchNumber = _newBatchesData[0].batchNumber;
                    for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) {
                        // The upgrade transaction must only be included in the first batch.
                        bytes32 expectedUpgradeTxHash = i == 0 ? _systemContractUpgradeTxHash : bytes32(0);
                        _lastCommittedBatchData = _commitOneBatch(
                            _lastCommittedBatchData,
                            _newBatchesData[i],
                            expectedUpgradeTxHash
                        );
                        s.storedBatchHashes[_lastCommittedBatchData.batchNumber] = _hashStoredBatchInfo(_lastCommittedBatchData);
                        emit BlockCommit(
                            _lastCommittedBatchData.batchNumber,
                            _lastCommittedBatchData.batchHash,
                            _lastCommittedBatchData.commitment
                        );
                    }
                }
                /// @dev Pops the priority operations from the priority queue and returns a rolling hash of operations
                function _collectOperationsFromPriorityQueue(uint256 _nPriorityOps) internal returns (bytes32 concatHash) {
                    concatHash = EMPTY_STRING_KECCAK;
                    for (uint256 i = 0; i < _nPriorityOps; i = i.uncheckedInc()) {
                        PriorityOperation memory priorityOp = s.priorityQueue.popFront();
                        concatHash = keccak256(abi.encode(concatHash, priorityOp.canonicalTxHash));
                    }
                }
                /// @dev Executes one batch
                /// @dev 1. Processes all pending operations (Complete priority requests)
                /// @dev 2. Finalizes batch on Ethereum
                /// @dev _executedBatchIdx is an index in the array of the batches that we want to execute together
                function _executeOneBatch(StoredBatchInfo memory _storedBatch, uint256 _executedBatchIdx) internal {
                    uint256 currentBatchNumber = _storedBatch.batchNumber;
                    require(currentBatchNumber == s.totalBatchesExecuted + _executedBatchIdx + 1, "k"); // Execute batches in order
                    require(
                        _hashStoredBatchInfo(_storedBatch) == s.storedBatchHashes[currentBatchNumber],
                        "exe10" // executing batch should be committed
                    );
                    bytes32 priorityOperationsHash = _collectOperationsFromPriorityQueue(_storedBatch.numberOfLayer1Txs);
                    require(priorityOperationsHash == _storedBatch.priorityOperationsHash, "x"); // priority operations hash does not match to expected
                    // Save root hash of L2 -> L1 logs tree
                    s.l2LogsRootHashes[currentBatchNumber] = _storedBatch.l2LogsTreeRoot;
                }
                /// @inheritdoc IExecutor
                function executeBatchesSharedBridge(
                    uint256,
                    StoredBatchInfo[] calldata _batchesData
                ) external nonReentrant onlyValidator {
                    _executeBatches(_batchesData);
                }
                /// @inheritdoc IExecutor
                function executeBatches(StoredBatchInfo[] calldata _batchesData) external nonReentrant onlyValidator {
                    _executeBatches(_batchesData);
                }
                function _executeBatches(StoredBatchInfo[] calldata _batchesData) internal {
                    uint256 nBatches = _batchesData.length;
                    for (uint256 i = 0; i < nBatches; i = i.uncheckedInc()) {
                        _executeOneBatch(_batchesData[i], i);
                        emit BlockExecution(_batchesData[i].batchNumber, _batchesData[i].batchHash, _batchesData[i].commitment);
                    }
                    uint256 newTotalBatchesExecuted = s.totalBatchesExecuted + nBatches;
                    s.totalBatchesExecuted = newTotalBatchesExecuted;
                    require(newTotalBatchesExecuted <= s.totalBatchesVerified, "n"); // Can't execute batches more than committed and proven currently.
                    uint256 batchWhenUpgradeHappened = s.l2SystemContractsUpgradeBatchNumber;
                    if (batchWhenUpgradeHappened != 0 && batchWhenUpgradeHappened <= newTotalBatchesExecuted) {
                        delete s.l2SystemContractsUpgradeTxHash;
                        delete s.l2SystemContractsUpgradeBatchNumber;
                    }
                }
                /// @inheritdoc IExecutor
                function proveBatches(
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) external nonReentrant onlyValidator {
                    _proveBatches(_prevBatch, _committedBatches, _proof);
                }
                /// @inheritdoc IExecutor
                function proveBatchesSharedBridge(
                    uint256, // _chainId
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) external nonReentrant onlyValidator {
                    _proveBatches(_prevBatch, _committedBatches, _proof);
                }
                function _proveBatches(
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) internal {
                    // Save the variables into the stack to save gas on reading them later
                    uint256 currentTotalBatchesVerified = s.totalBatchesVerified;
                    uint256 committedBatchesLength = _committedBatches.length;
                    // Initialize the array, that will be used as public input to the ZKP
                    uint256[] memory proofPublicInput = new uint256[](committedBatchesLength);
                    // Check that the batch passed by the validator is indeed the first unverified batch
                    require(_hashStoredBatchInfo(_prevBatch) == s.storedBatchHashes[currentTotalBatchesVerified], "t1");
                    bytes32 prevBatchCommitment = _prevBatch.commitment;
                    for (uint256 i = 0; i < committedBatchesLength; i = i.uncheckedInc()) {
                        currentTotalBatchesVerified = currentTotalBatchesVerified.uncheckedInc();
                        require(
                            _hashStoredBatchInfo(_committedBatches[i]) == s.storedBatchHashes[currentTotalBatchesVerified],
                            "o1"
                        );
                        bytes32 currentBatchCommitment = _committedBatches[i].commitment;
                        proofPublicInput[i] = _getBatchProofPublicInput(prevBatchCommitment, currentBatchCommitment);
                        prevBatchCommitment = currentBatchCommitment;
                    }
                    require(currentTotalBatchesVerified <= s.totalBatchesCommitted, "q");
                    _verifyProof(proofPublicInput, _proof);
                    emit BlocksVerification(s.totalBatchesVerified, currentTotalBatchesVerified);
                    s.totalBatchesVerified = currentTotalBatchesVerified;
                }
                function _verifyProof(uint256[] memory proofPublicInput, ProofInput calldata _proof) internal view {
                    // We can only process 1 batch proof at a time.
                    require(proofPublicInput.length == 1, "t4");
                    bool successVerifyProof = s.verifier.verify(
                        proofPublicInput,
                        _proof.serializedProof,
                        _proof.recursiveAggregationInput
                    );
                    require(successVerifyProof, "p"); // Proof verification fail
                }
                /// @dev Gets zk proof public input
                function _getBatchProofPublicInput(
                    bytes32 _prevBatchCommitment,
                    bytes32 _currentBatchCommitment
                ) internal pure returns (uint256) {
                    return
                        uint256(keccak256(abi.encodePacked(_prevBatchCommitment, _currentBatchCommitment))) >> PUBLIC_INPUT_SHIFT;
                }
                /// @inheritdoc IExecutor
                function revertBatches(uint256 _newLastBatch) external nonReentrant onlyValidatorOrStateTransitionManager {
                    _revertBatches(_newLastBatch);
                }
                /// @inheritdoc IExecutor
                function revertBatchesSharedBridge(uint256, uint256 _newLastBatch) external nonReentrant onlyValidator {
                    _revertBatches(_newLastBatch);
                }
                function _revertBatches(uint256 _newLastBatch) internal {
                    require(s.totalBatchesCommitted > _newLastBatch, "v1"); // The last committed batch is less than new last batch
                    require(_newLastBatch >= s.totalBatchesExecuted, "v2"); // Already executed batches cannot be reverted
                    if (_newLastBatch < s.totalBatchesVerified) {
                        s.totalBatchesVerified = _newLastBatch;
                    }
                    s.totalBatchesCommitted = _newLastBatch;
                    // Reset the batch number of the executed system contracts upgrade transaction if the batch
                    // where the system contracts upgrade was committed is among the reverted batches.
                    if (s.l2SystemContractsUpgradeBatchNumber > _newLastBatch) {
                        delete s.l2SystemContractsUpgradeBatchNumber;
                    }
                    emit BlocksRevert(s.totalBatchesCommitted, s.totalBatchesVerified, s.totalBatchesExecuted);
                }
                /// @dev Creates batch commitment from its data
                function _createBatchCommitment(
                    CommitBatchInfo calldata _newBatchData,
                    bytes32 _stateDiffHash,
                    bytes32[] memory _blobCommitments,
                    bytes32[] memory _blobHashes
                ) internal view returns (bytes32) {
                    bytes32 passThroughDataHash = keccak256(_batchPassThroughData(_newBatchData));
                    bytes32 metadataHash = keccak256(_batchMetaParameters());
                    bytes32 auxiliaryOutputHash = keccak256(
                        _batchAuxiliaryOutput(_newBatchData, _stateDiffHash, _blobCommitments, _blobHashes)
                    );
                    return keccak256(abi.encode(passThroughDataHash, metadataHash, auxiliaryOutputHash));
                }
                function _batchPassThroughData(CommitBatchInfo calldata _batch) internal pure returns (bytes memory) {
                    return
                        abi.encodePacked(
                            // solhint-disable-next-line func-named-parameters
                            _batch.indexRepeatedStorageChanges,
                            _batch.newStateRoot,
                            uint64(0), // index repeated storage changes in zkPorter
                            bytes32(0) // zkPorter batch hash
                        );
                }
                function _batchMetaParameters() internal view returns (bytes memory) {
                    bytes32 l2DefaultAccountBytecodeHash = s.l2DefaultAccountBytecodeHash;
                    return
                        abi.encodePacked(
                            s.zkPorterIsAvailable,
                            s.l2BootloaderBytecodeHash,
                            l2DefaultAccountBytecodeHash,
                            // VM 1.5.0 requires us to pass the EVM simulator code hash. For now it is the same as the default account.
                            l2DefaultAccountBytecodeHash
                        );
                }
                function _batchAuxiliaryOutput(
                    CommitBatchInfo calldata _batch,
                    bytes32 _stateDiffHash,
                    bytes32[] memory _blobCommitments,
                    bytes32[] memory _blobHashes
                ) internal pure returns (bytes memory) {
                    require(_batch.systemLogs.length <= MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES, "pu");
                    bytes32 l2ToL1LogsHash = keccak256(_batch.systemLogs);
                    return
                        // solhint-disable-next-line func-named-parameters
                        abi.encodePacked(
                            l2ToL1LogsHash,
                            _stateDiffHash,
                            _batch.bootloaderHeapInitialContentsHash,
                            _batch.eventsQueueStateHash,
                            _encodeBlobAuxiliaryOutput(_blobCommitments, _blobHashes)
                        );
                }
                /// @dev Encodes the commitment to blobs to be used in the auxiliary output of the batch commitment
                /// @param _blobCommitments - the commitments to the blobs
                /// @param _blobHashes - the hashes of the blobs
                /// @param blobAuxOutputWords - The circuit commitment to the blobs split into 32-byte words
                function _encodeBlobAuxiliaryOutput(
                    bytes32[] memory _blobCommitments,
                    bytes32[] memory _blobHashes
                ) internal pure returns (bytes32[] memory blobAuxOutputWords) {
                    // These invariants should be checked by the caller of this function, but we double check
                    // just in case.
                    require(_blobCommitments.length == MAX_NUMBER_OF_BLOBS, "b10");
                    require(_blobHashes.length == MAX_NUMBER_OF_BLOBS, "b11");
                    // for each blob we have:
                    // linear hash (hash of preimage from system logs) and
                    // output hash of blob commitments: keccak(versioned hash || opening point || evaluation value)
                    // These values will all be bytes32(0) when we submit pubdata via calldata instead of blobs.
                    //
                    // For now, only up to 6 blobs are supported by the contract, while 16 are required by the circuits.
                    // All the unfilled blobs will have their commitment as 0, including the case when we use only 1 blob.
                    blobAuxOutputWords = new bytes32[](2 * TOTAL_BLOBS_IN_COMMITMENT);
                    for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) {
                        blobAuxOutputWords[i * 2] = _blobHashes[i];
                        blobAuxOutputWords[i * 2 + 1] = _blobCommitments[i];
                    }
                }
                /// @notice Returns the keccak hash of the ABI-encoded StoredBatchInfo
                function _hashStoredBatchInfo(StoredBatchInfo memory _storedBatchInfo) internal pure returns (bytes32) {
                    return keccak256(abi.encode(_storedBatchInfo));
                }
                /// @notice Returns true if the bit at index {_index} is 1
                function _checkBit(uint256 _bitMap, uint8 _index) internal pure returns (bool) {
                    return (_bitMap & (1 << _index)) > 0;
                }
                /// @notice Sets the given bit in {_num} at index {_index} to 1.
                function _setBit(uint256 _bitMap, uint8 _index) internal pure returns (uint256) {
                    return _bitMap | (1 << _index);
                }
                /// @notice Calls the point evaluation precompile and verifies the output
                /// Verify p(z) = y given commitment that corresponds to the polynomial p(x) and a KZG proof.
                /// Also verify that the provided commitment matches the provided versioned_hash.
                ///
                function _pointEvaluationPrecompile(
                    bytes32 _versionedHash,
                    bytes32 _openingPoint,
                    bytes calldata _openingValueCommitmentProof
                ) internal view {
                    bytes memory precompileInput = abi.encodePacked(_versionedHash, _openingPoint, _openingValueCommitmentProof);
                    (bool success, bytes memory data) = POINT_EVALUATION_PRECOMPILE_ADDR.staticcall(precompileInput);
                    // We verify that the point evaluation precompile call was successful by testing the latter 32 bytes of the
                    // response is equal to BLS_MODULUS as defined in https://eips.ethereum.org/EIPS/eip-4844#point-evaluation-precompile
                    require(success, "failed to call point evaluation precompile");
                    (, uint256 result) = abi.decode(data, (uint256, uint256));
                    require(result == BLS_MODULUS, "precompile unexpected output");
                }
                /// @dev Verifies that the blobs contain the correct data by calling the point evaluation precompile. For the precompile we need:
                /// versioned hash || opening point || opening value || commitment || proof
                /// the _pubdataCommitments will contain the last 4 values, the versioned hash is pulled from the BLOBHASH opcode
                /// pubdataCommitments is a list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes)) = 144 bytes
                function _verifyBlobInformation(
                    bytes calldata _pubdataCommitments,
                    bytes32[] memory _blobHashes
                ) internal view returns (bytes32[] memory blobCommitments) {
                    uint256 versionedHashIndex = 0;
                    require(_pubdataCommitments.length > 0, "pl");
                    require(_pubdataCommitments.length <= PUBDATA_COMMITMENT_SIZE * MAX_NUMBER_OF_BLOBS, "bd");
                    require(_pubdataCommitments.length % PUBDATA_COMMITMENT_SIZE == 0, "bs");
                    blobCommitments = new bytes32[](MAX_NUMBER_OF_BLOBS);
                    for (uint256 i = 0; i < _pubdataCommitments.length; i += PUBDATA_COMMITMENT_SIZE) {
                        bytes32 blobVersionedHash = _getBlobVersionedHash(versionedHashIndex);
                        require(blobVersionedHash != bytes32(0), "vh");
                        // First 16 bytes is the opening point. While we get the point as 16 bytes, the point evaluation precompile
                        // requires it to be 32 bytes. The blob commitment must use the opening point as 16 bytes though.
                        bytes32 openingPoint = bytes32(
                            uint256(uint128(bytes16(_pubdataCommitments[i:i + PUBDATA_COMMITMENT_CLAIMED_VALUE_OFFSET])))
                        );
                        _pointEvaluationPrecompile(
                            blobVersionedHash,
                            openingPoint,
                            _pubdataCommitments[i + PUBDATA_COMMITMENT_CLAIMED_VALUE_OFFSET:i + PUBDATA_COMMITMENT_SIZE]
                        );
                        // Take the hash of the versioned hash || opening point || claimed value
                        blobCommitments[versionedHashIndex] = keccak256(
                            abi.encodePacked(blobVersionedHash, _pubdataCommitments[i:i + PUBDATA_COMMITMENT_COMMITMENT_OFFSET])
                        );
                        versionedHashIndex += 1;
                    }
                    // This check is required because we want to ensure that there aren't any extra blobs trying to be published.
                    // Calling the BLOBHASH opcode with an index > # blobs - 1 yields bytes32(0)
                    bytes32 versionedHash = _getBlobVersionedHash(versionedHashIndex);
                    require(versionedHash == bytes32(0), "lh");
                    // We verify that for each set of blobHash/blobCommitment are either both empty
                    // or there are values for both.
                    for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) {
                        require(
                            (_blobHashes[i] == bytes32(0) && blobCommitments[i] == bytes32(0)) ||
                                (_blobHashes[i] != bytes32(0) && blobCommitments[i] != bytes32(0)),
                            "bh"
                        );
                    }
                }
                function _getBlobVersionedHash(uint256 _index) internal view virtual returns (bytes32 versionedHash) {
                    assembly {
                        versionedHash := blobhash(_index)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {ZkSyncHyperchainStorage} from "../ZkSyncHyperchainStorage.sol";
            import {ReentrancyGuard} from "../../../common/ReentrancyGuard.sol";
            /// @title Base contract containing functions accessible to the other facets.
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            contract ZkSyncHyperchainBase is ReentrancyGuard {
                // slither-disable-next-line uninitialized-state
                ZkSyncHyperchainStorage internal s;
                /// @notice Checks that the message sender is an active admin
                modifier onlyAdmin() {
                    require(msg.sender == s.admin, "Hyperchain: not admin");
                    _;
                }
                /// @notice Checks if validator is active
                modifier onlyValidator() {
                    require(s.validators[msg.sender], "Hyperchain: not validator");
                    _;
                }
                modifier onlyStateTransitionManager() {
                    require(msg.sender == s.stateTransitionManager, "Hyperchain: not state transition manager");
                    _;
                }
                modifier onlyBridgehub() {
                    require(msg.sender == s.bridgehub, "Hyperchain: not bridgehub");
                    _;
                }
                modifier onlyAdminOrStateTransitionManager() {
                    require(
                        msg.sender == s.admin || msg.sender == s.stateTransitionManager,
                        "Hyperchain: Only by admin or state transition manager"
                    );
                    _;
                }
                modifier onlyValidatorOrStateTransitionManager() {
                    require(
                        s.validators[msg.sender] || msg.sender == s.stateTransitionManager,
                        "Hyperchain: Only by validator or state transition manager"
                    );
                    _;
                }
                modifier onlyBaseTokenBridge() {
                    require(msg.sender == s.baseTokenBridge, "Hyperchain: Only base token bridge can call this function");
                    _;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IVerifier, VerifierParams} from "../chain-interfaces/IVerifier.sol";
            import {PriorityQueue} from "../../state-transition/libraries/PriorityQueue.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 hyperchain 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.
            struct ZkSyncHyperchainStorage {
                /// @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 STM
                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 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.
                FeeParams feeParams;
                /// @dev Address of the blob versioned hash getter smart contract used for EIP-4844 versioned hashes.
                address blobVersionedHashRetriever;
                /// @dev The chainId of the chain
                uint256 chainId;
                /// @dev The address of the bridgehub
                address bridgehub;
                /// @dev The address of the StateTransitionManager
                address stateTransitionManager;
                /// @dev The address of the baseToken contract. Eth is address(1)
                address baseToken;
                /// @dev The address of the baseTokenbridge. Eth also uses the shared bridge
                address 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;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol";
            /// @dev Enum used by L2 System Contracts to differentiate logs.
            enum SystemLogKey {
                L2_TO_L1_LOGS_TREE_ROOT_KEY,
                TOTAL_L2_TO_L1_PUBDATA_KEY,
                STATE_DIFF_HASH_KEY,
                PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY,
                PREV_BATCH_HASH_KEY,
                CHAINED_PRIORITY_TXN_HASH_KEY,
                NUMBER_OF_LAYER_1_TXS_KEY,
                BLOB_ONE_HASH_KEY,
                BLOB_TWO_HASH_KEY,
                BLOB_THREE_HASH_KEY,
                BLOB_FOUR_HASH_KEY,
                BLOB_FIVE_HASH_KEY,
                BLOB_SIX_HASH_KEY,
                EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY
            }
            /// @dev Enum used to determine the source of pubdata. At first we will support calldata and blobs but this can be extended.
            enum PubdataSource {
                Calldata,
                Blob
            }
            struct LogProcessingOutput {
                uint256 numberOfLayer1Txs;
                bytes32 chainedPriorityTxsHash;
                bytes32 previousBatchHash;
                bytes32 pubdataHash;
                bytes32 stateDiffHash;
                bytes32 l2LogsTreeRoot;
                uint256 packedBatchAndL2BlockTimestamp;
                bytes32[] blobHashes;
            }
            /// @dev Total number of bytes in a blob. Blob = 4096 field elements * 31 bytes per field element
            /// @dev EIP-4844 defines it as 131_072 but we use 4096 * 31 within our circuits to always fit within a field element
            /// @dev Our circuits will prove that a EIP-4844 blob and our internal blob are the same.
            uint256 constant BLOB_SIZE_BYTES = 126_976;
            /// @dev Offset used to pull Address From Log. Equal to 4 (bytes for isService)
            uint256 constant L2_LOG_ADDRESS_OFFSET = 4;
            /// @dev Offset used to pull Key From Log. Equal to 4 (bytes for isService) + 20 (bytes for address)
            uint256 constant L2_LOG_KEY_OFFSET = 24;
            /// @dev Offset used to pull Value From Log. Equal to 4 (bytes for isService) + 20 (bytes for address) + 32 (bytes for key)
            uint256 constant L2_LOG_VALUE_OFFSET = 56;
            /// @dev BLS Modulus value defined in EIP-4844 and the magic value returned from a successful call to the
            /// point evaluation precompile
            uint256 constant BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513;
            /// @dev Packed pubdata commitments.
            /// @dev Format: list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes)) = 144 bytes
            uint256 constant PUBDATA_COMMITMENT_SIZE = 144;
            /// @dev Offset in pubdata commitment of blobs for claimed value
            uint256 constant PUBDATA_COMMITMENT_CLAIMED_VALUE_OFFSET = 16;
            /// @dev Offset in pubdata commitment of blobs for kzg commitment
            uint256 constant PUBDATA_COMMITMENT_COMMITMENT_OFFSET = 48;
            /// @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 IZkSyncHyperchainBase {
                /// @notice Rollup batch stored data
                /// @param batchNumber Rollup batch number
                /// @param batchHash Hash of L2 batch
                /// @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 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
                /// @param commitment Verified input for the zkSync circuit
                struct StoredBatchInfo {
                    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 pubdataCommitments 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 pubdataCommitments;
                }
                /// @notice Recursive proof input data (individual commitments are constructed onchain)
                struct ProofInput {
                    uint256[] recursiveAggregationInput;
                    uint256[] serializedProof;
                }
                /// @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 _lastCommittedBatchData Stored data of the last committed batch.
                /// @param _newBatchesData Data of the new batches to be committed.
                function commitBatches(
                    StoredBatchInfo calldata _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external;
                /// @notice same as `commitBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function commitBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo calldata _lastCommittedBatchData,
                    CommitBatchInfo[] calldata _newBatchesData
                ) external;
                /// @notice Batches commitment verification.
                /// @dev Only verifies batch commitments without any other processing.
                /// @param _prevBatch Stored data of the last committed batch.
                /// @param _committedBatches Stored data of the committed batches.
                /// @param _proof The zero knowledge proof.
                function proveBatches(
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) external;
                /// @notice same as `proveBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function proveBatchesSharedBridge(
                    uint256 _chainId,
                    StoredBatchInfo calldata _prevBatch,
                    StoredBatchInfo[] calldata _committedBatches,
                    ProofInput calldata _proof
                ) 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 _batchesData Data of the batches to be executed.
                function executeBatches(StoredBatchInfo[] calldata _batchesData) external;
                /// @notice same as `executeBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function executeBatchesSharedBridge(uint256 _chainId, StoredBatchInfo[] calldata _batchesData) external;
                /// @notice Reverts unexecuted batches
                /// @param _newLastBatch batch number after which batches should be reverted
                /// NOTE: Doesn't delete the stored data about batches, but only decreases
                /// counters that are responsible for the number of batches
                function revertBatches(uint256 _newLastBatch) external;
                /// @notice same as `revertBatches` but with the chainId so ValidatorTimelock can sort the inputs.
                function revertBatchesSharedBridge(uint256 _chainId, 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);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @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,
                    uint256[] calldata _recursiveAggregationInput
                ) 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 pure returns (bytes32);
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.24;
            /// @title The interface of the zkSync contract, responsible for the main zkSync logic.
            /// @author Matter Labs
            /// @custom:security-contact [email protected]
            interface IZkSyncHyperchainBase {
                /// @return Returns facet name.
                function getName() external view returns (string memory);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {Diamond} from "./libraries/Diamond.sol";
            import {L2CanonicalTransaction} from "../common/Messaging.sol";
            import {FeeParams} from "./chain-deps/ZkSyncHyperchainStorage.sol";
            /// @notice Struct that holds all data needed for initializing STM Proxy.
            /// @dev We use struct instead of raw parameters in `initialize` function to prevent "Stack too deep" error
            /// @param owner The address who can manage non-critical updates in the contract
            /// @param validatorTimelock The address that serves as consensus, i.e. can submit blocks to be processed
            /// @param chainCreationParams The struct that contains the fields that define how a new chain should be created
            /// @param protocolVersion The initial protocol version on the newly deployed chain
            struct StateTransitionManagerInitializeData {
                address owner;
                address validatorTimelock;
                ChainCreationParams chainCreationParams;
                uint256 protocolVersion;
            }
            /// @notice The struct that contains the fields that define how a new chain should be created
            /// within this STM.
            /// @param genesisUpgrade The address that is used in the diamond cut initialize address on chain creation
            /// @param genesisBatchHash Batch hash of the genesis (initial) batch
            /// @param genesisIndexRepeatedStorageChanges The serial number of the shortcut storage key for the genesis batch
            /// @param genesisBatchCommitment The zk-proof commitment for the genesis batch
            /// @param diamondCut The diamond cut for the first upgrade transaction on the newly deployed chain
            struct ChainCreationParams {
                address genesisUpgrade;
                bytes32 genesisBatchHash;
                uint64 genesisIndexRepeatedStorageChanges;
                bytes32 genesisBatchCommitment;
                Diamond.DiamondCutData diamondCut;
            }
            interface IStateTransitionManager {
                /// @dev Emitted when a new Hyperchain is added
                event NewHyperchain(uint256 indexed _chainId, address indexed _hyperchainContract);
                /// @dev emitted when an chain registers and a SetChainIdUpgrade happens
                event SetChainIdUpgrade(
                    address indexed _hyperchain,
                    L2CanonicalTransaction _l2Transaction,
                    uint256 indexed _protocolVersion
                );
                /// @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 ValidatorTimelock changed
                event NewValidatorTimelock(address indexed oldValidatorTimelock, address indexed newValidatorTimelock);
                /// @notice chain creation parameters changed
                event NewChainCreationParams(
                    address genesisUpgrade,
                    bytes32 genesisBatchHash,
                    uint64 genesisIndexRepeatedStorageChanges,
                    bytes32 genesisBatchCommitment,
                    bytes32 newInitialCutHash
                );
                /// @notice new UpgradeCutHash
                event NewUpgradeCutHash(uint256 indexed protocolVersion, bytes32 indexed upgradeCutHash);
                /// @notice new ProtocolVersion
                event NewProtocolVersion(uint256 indexed oldProtocolVersion, uint256 indexed newProtocolVersion);
                function BRIDGE_HUB() external view returns (address);
                function setPendingAdmin(address _newPendingAdmin) external;
                function acceptAdmin() external;
                function getAllHyperchains() external view returns (address[] memory);
                function getAllHyperchainChainIDs() external view returns (uint256[] memory);
                function getHyperchain(uint256 _chainId) external view returns (address);
                function storedBatchZero() external view returns (bytes32);
                function initialCutHash() external view returns (bytes32);
                function genesisUpgrade() external view returns (address);
                function upgradeCutHash(uint256 _protocolVersion) external view returns (bytes32);
                function protocolVersion() external view returns (uint256);
                function protocolVersionDeadline(uint256 _protocolVersion) external view returns (uint256);
                function protocolVersionIsActive(uint256 _protocolVersion) external view returns (bool);
                function initialize(StateTransitionManagerInitializeData calldata _initializeData) external;
                function setValidatorTimelock(address _validatorTimelock) external;
                function setChainCreationParams(ChainCreationParams calldata _chainCreationParams) external;
                function getChainAdmin(uint256 _chainId) external view returns (address);
                function createNewChain(
                    uint256 _chainId,
                    address _baseToken,
                    address _sharedBridge,
                    address _admin,
                    bytes calldata _diamondCut
                ) external;
                function registerAlreadyDeployedHyperchain(uint256 _chainId, address _hyperchain) external;
                function setNewVersionUpgrade(
                    Diamond.DiamondCutData calldata _cutData,
                    uint256 _oldProtocolVersion,
                    uint256 _oldprotocolVersionDeadline,
                    uint256 _newProtocolVersion
                ) external;
                function setUpgradeDiamondCut(Diamond.DiamondCutData calldata _cutData, uint256 _oldProtocolVersion) external;
                function executeUpgrade(uint256 _chainId, Diamond.DiamondCutData calldata _diamondCut) external;
                function setPriorityTxMaxGasLimit(uint256 _chainId, uint256 _maxGasLimit) external;
                function freezeChain(uint256 _chainId) external;
                function unfreezeChain(uint256 _chainId) external;
                function setTokenMultiplier(uint256 _chainId, uint128 _nominator, uint128 _denominator) external;
                function changeFeeParams(uint256 _chainId, FeeParams calldata _newFeeParams) external;
                function setValidator(uint256 _chainId, address _validator, bool _active) external;
                function setPorterAvailability(uint256 _chainId, bool _zkPorterIsAvailable) external;
                function upgradeChainFromVersion(
                    uint256 _chainId,
                    uint256 _oldProtocolVersion,
                    Diamond.DiamondCutData calldata _diamondCut
                ) external;
                function getSemverProtocolVersion() external view returns (uint32, uint32, uint32);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
            import {UncheckedMath} from "../../common/libraries/UncheckedMath.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
                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;
                        require(selectors.length > 0, "B"); // no functions for diamond cut
                        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("C"); // undefined diamond cut action
                        }
                    }
                    _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.
                    require(_facet.code.length > 0, "G");
                    // 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];
                        require(oldFacet.facetAddress == address(0), "J"); // facet for this selector already exists
                        _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.
                    require(_facet.code.length > 0, "K");
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "L"); // it is impossible to replace the facet with zero address
                        _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();
                    require(_facet == address(0), "a1"); // facet address must be zero
                    uint256 selectorsLength = _selectors.length;
                    for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
                        bytes4 selector = _selectors[i];
                        SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
                        require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet
                        _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];
                        require(_isSelectorFreezable == ds.selectorToFacet[selector0].isFreezable, "J1");
                    }
                    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)) {
                        require(_calldata.length == 0, "H"); // Non-empty calldata for zero address
                    } 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("I"); // delegatecall failed
                            }
                            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.
                        require(data.length == 32, "lp");
                        require(abi.decode(data, (bytes32)) == DIAMOND_INIT_SUCCESS_RETURN_VALUE, "lp1");
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.24;
            /// @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) {
                    require(!_queue.isEmpty(), "D"); // priority queue is empty
                    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) {
                    require(!_queue.isEmpty(), "s"); // priority queue is empty
                    // 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;
                }
            }