ETH Price: $3,183.41 (+3.46%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Amount:> 0.00001
Reset Filter

Transaction Hash
Method
Block
From
To

There are no matching entries

Update your filters to view other transactions

Amount:> 0.00001
Reset Filter

Advanced mode:
Parent Transaction Hash Method Block
From
To

There are no matching entries

Update your filters to view other transactions

View All Internal Transactions
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AggchainECDSAMultisig

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 999999 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;

import "../lib/AggchainBase.sol";

/**
 * @title AggchainECDSAMultisig
 * @notice Generic aggchain based on ECDSA multisig signature.
 * An array of addresses signs the new_ler and the commit_imported_bridge_exits in order to do state
 * transitions on the pessimistic trees (local_exit_tree, local_balance_tree, nullifier_tree & height).
 * The addresses and threshold are managed by the aggchainManager.
 */
contract AggchainECDSAMultisig is AggchainBase {
    ////////////////////////////////////////////////////////////
    //                  Transient Storage                     //
    ////////////////////////////////////////////////////////////
    uint8 private transient _initializerVersion;

    ////////////////////////////////////////////////////////////
    //                  Constants & Immutables                //
    ////////////////////////////////////////////////////////////
    // Aggchain type selector, hardcoded value used to force the last 2 bytes of aggchain selector to retrieve the aggchain verification key
    bytes2 public constant AGGCHAIN_TYPE = 0x0000;

    /// @notice Aggchain version
    string public constant AGGCHAIN_ECDSA_MULTISIG_VERSION = "v1.0.0";

    ////////////////////////////////////////////////////////////
    //                         Errors                         //
    ////////////////////////////////////////////////////////////
    /// @notice Thrown when trying to initialize the wrong initialize function.
    error InvalidInitializer();

    /// @notice Thrown when calling a function that is not supported by this implementation.
    error FunctionNotSupported();

    ////////////////////////////////////////////////////////////
    //                         Events                         //
    ////////////////////////////////////////////////////////////
    /// @notice Emitted when pessimistic verification is completed.
    event OnVerifyPessimisticECDSAMultisig();

    ////////////////////////////////////////////////////////////
    //                        Modifiers                       //
    ////////////////////////////////////////////////////////////
    /// @dev Modifier to retrieve initializer version value previous on using the reinitializer modifier, its used in the initialize function.
    modifier getInitializedVersion() {
        // Get initializer version from OZ initializer smart contract
        _initializerVersion = _getInitializedVersion();
        _;
    }

    ////////////////////////////////////////////////////////////
    //                       Constructor                      //
    ////////////////////////////////////////////////////////////
    /**
     * @param _globalExitRootManager Global exit root manager address.
     * @param _pol POL token contract address.
     * @param _bridgeAddress Bridge contract address.
     * @param _rollupManager Rollup manager contract address.
     * @param _aggLayerGateway AgglayerGateway contract address.
     */
    constructor(
        IAgglayerGER _globalExitRootManager,
        IERC20Upgradeable _pol,
        IAgglayerBridge _bridgeAddress,
        AgglayerManager _rollupManager,
        IAgglayerGateway _aggLayerGateway
    )
        AggchainBase(
            _globalExitRootManager,
            _pol,
            _bridgeAddress,
            _rollupManager,
            _aggLayerGateway
        )
    {}

    ////////////////////////////////////////////////////////////
    //              Functions: initialization                 //
    ////////////////////////////////////////////////////////////
    /**
     * @notice Initialize the AggchainECDSAMultisig contract
     * @param _admin Admin address
     * @param _trustedSequencer Trusted sequencer address
     * @param _gasTokenAddress Gas token address
     * @param _trustedSequencerURL Trusted sequencer URL
     * @param _networkName Network name
     * @param _useDefaultSigners Whether to use default signers from gateway
     * @param _signersToAdd Array of signers to add
     * @param _newThreshold New threshold for multisig operations
     * @custom:security First initialization takes into account this contracts and all the inheritance contracts
     *                  This function can only be called when the contract is first deployed (version 0)
     * @dev The reinitializer(2) is set to support the upgrade from PolygonPessimisticConsensus to AggchainECDSAMultisig, where PolygonPessimisticConsensus is already initialized
     */
    function initialize(
        address _admin,
        address _trustedSequencer,
        address _gasTokenAddress,
        string memory _trustedSequencerURL,
        string memory _networkName,
        bool _useDefaultSigners,
        SignerInfo[] memory _signersToAdd,
        uint256 _newThreshold
    ) external onlyAggchainManager getInitializedVersion reinitializer(2) {
        if (_initializerVersion != 0) {
            revert InvalidInitializer();
        }

        // initOwnedAggchainVKey, initAggchainVKeySelector, and useDefaultVkeys are not used in this aggchain.
        _initializeAggchainBaseAndConsensusBase(
            _admin,
            _trustedSequencer,
            _gasTokenAddress,
            _trustedSequencerURL,
            _networkName,
            false, // useDefaultVkeys
            _useDefaultSigners,
            bytes32(0), // initOwnedAggchainVKey
            bytes4(0) // initAggchainVKeySelector
        );

        // Check the used default signers is consistent
        if (_useDefaultSigners) {
            if (_signersToAdd.length != 0 || threshold != 0) {
                revert ConflictingDefaultSignersConfiguration();
            }
        } else {
            // update signers and threshold
            _updateSignersAndThreshold(
                new RemoveSignerInfo[](0), // No signers to remove
                _signersToAdd,
                _newThreshold
            );
        }
    }

    /**
     * @notice Migrates from PolygonPessimisticConsensus or PolygonRollupBaseEtrog to AggchainECDSAMultisig
     * @dev This function is called when upgrading from a PolygonPessimisticConsensus contract.
     *      - Therefore the consensusBase is already initialized.
     *      - The AggchainBase is initialized using the values from the ConsensusBase.
     *      It sets up the initial multisig configuration using the existing admin and trustedSequencer,
     *      Sets the threshold to 1, and adds the trustedSequencer as the only signer.
     */
    function migrateFromLegacyConsensus()
        external
        onlyRollupManager
        getInitializedVersion
        reinitializer(2)
    {
        if (_initializerVersion != 1) {
            revert InvalidInitializer();
        }

        // aggchainManager
        aggchainManager = admin;

        // _initializeAggchainBase(
        //            _useDefaultVkeys, // false
        //            _useDefaultSigners, // false
        //            _initOwnedAggchainVKey, // not used
        //            _initAggchainVKeySelector // not used
        //        );

        // set signer to trustedSequencer and threshold to 1
        // handle trustedSequencerURL as empty string
        if (bytes(trustedSequencerURL).length == 0) {
            _addSignerInternal(trustedSequencer, "NO_URL"); // cannot be empty string
        } else {
            _addSignerInternal(trustedSequencer, trustedSequencerURL);
        }
        threshold = 1;

        // update aggchainMultisigHash
        _updateAggchainMultisigHash();
    }

    ////////////////////////////////////////////////////////////
    //                    Functions: pure                    //
    ////////////////////////////////////////////////////////////

    /// @notice Validates the provided aggchain data and returns the computed aggchain parameters and vkey
    /// @dev For ECDSA multisig, no data is needed as verification is done through signatures
    /// @param aggchainData custom bytes provided by the chain, encoded in ABI solidity format
    ///
    ///     aggchain_vkey: set to zero to skip verification in the PP
    ///     aggchain_params: set to zero to skip verification in the PP
    ///
    /// @return aggchainVKey Always returns bytes32(0) as ECDSA doesn't use verification keys
    /// @return aggchainParams Always returns bytes32(0) as ECDSA doesn't use verification
    /// @inheritdoc AggchainBase
    ///
    function getVKeyAndAggchainParams(
        bytes memory aggchainData
    ) public pure override returns (bytes32, bytes32) {
        if (aggchainData.length != 0) {
            revert InvalidAggchainDataLength();
        }

        // aggchainParams is not used in this implementation (signersHash and threshold are added directly in base)
        return (bytes32(0), bytes32(0));
    }

    /**
     * @notice Function to retrieve the current version of the contract.
     * @return version String representation of the contract version
     */
    function version() external pure returns (string memory) {
        return AGGCHAIN_ECDSA_MULTISIG_VERSION;
    }

    ////////////////////////////////////////////////////////////
    //               Functions: Callbacks                     //
    ////////////////////////////////////////////////////////////

    /**
     * @notice Callback when pessimistic proof is verified
     * @dev For ECDSA multisig, just validates empty data and emits event
     * @param aggchainData Must be empty for ECDSA implementation
     * @inheritdoc IAggchainBase
     */
    function onVerifyPessimistic(
        bytes calldata aggchainData
    ) external onlyRollupManager {
        if (aggchainData.length != 0) {
            revert InvalidAggchainDataLength();
        }

        // Only aggchainVKeySelector is provided (bytes4 ABI-encoded as 32 bytes), no need to decode anything
        // Just emit event to confirm verification
        emit OnVerifyPessimisticECDSAMultisig();
    }

    ////////////////////////////////////////////////////////////
    //                      Overrides                         //
    ////////////////////////////////////////////////////////////

    /**
     * @notice This function is not supported in ECDSA multisig implementation
     * @dev Overridden to prevent usage as ECDSA doesn't use verification keys
     * @custom:security Always reverts with FunctionNotSupported error
     */
    function enableUseDefaultVkeysFlag()
        external
        view
        override
        onlyAggchainManager
    {
        revert FunctionNotSupported();
    }

    /**
     * @notice This function is not supported in ECDSA multisig implementation
     * @dev Overridden to prevent usage as ECDSA doesn't use verification keys
     * @custom:security Always reverts with FunctionNotSupported error
     */
    function disableUseDefaultVkeysFlag()
        external
        view
        override
        onlyAggchainManager
    {
        revert FunctionNotSupported();
    }

    /**
     * @notice This function is not supported in ECDSA multisig implementation
     * @dev Overridden to prevent usage as ECDSA doesn't use verification keys
     * @custom:security Always reverts with FunctionNotSupported error
     */
    function addOwnedAggchainVKey(
        bytes4,
        bytes32
    ) external view override onlyAggchainManager {
        revert FunctionNotSupported();
    }

    /**
     * @notice This function is not supported in ECDSA multisig implementation
     * @dev Overridden to prevent usage as ECDSA doesn't use verification keys
     * @custom:security Always reverts with FunctionNotSupported error
     */
    function updateOwnedAggchainVKey(
        bytes4,
        bytes32
    ) external view override onlyAggchainManager {
        revert FunctionNotSupported();
    }

    /**
     * @notice Returns the aggchain verification key - always returns zero in ECDSA multisig
     * @dev Overridden to return bytes32(0) since verification keys are not used in ECDSA multisig
     * @return aggchainVKey Always returns bytes32(0) as ECDSA doesn't use verification keys
     */
    function getAggchainVKey(
        bytes4
    ) public pure override returns (bytes32 aggchainVKey) {
        // ECDSA multisig doesn't use vkeys, always return zero
        return bytes32(0);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControlUpgradeable {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (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]
 * ```
 * 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 v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20PermitUpgradeable {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";
import "../extensions/draft-IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20Upgradeable {
    using AddressUpgradeable for address;

    function safeTransfer(
        IERC20Upgradeable token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20Upgradeable token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20Upgradeable token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20Upgradeable token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20Upgradeable token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20PermitUpgradeable token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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
     * ====
     *
     * [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://diligence.consensys.net/posts/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.5.11/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 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 v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../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;
    }

    /**
     * @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 v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    /**
     * @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 v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library MathUpgradeable {
    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) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 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 10, 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 * 8) < value ? 1 : 0);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/MathUpgradeable.sol";

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = MathUpgradeable.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, MathUpgradeable.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _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);
    }
}

File 15 of 52 : IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)

pragma solidity ^0.8.20;

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 */
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 (last updated v5.0.0) (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.20;

/**
 * @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.
     *
     * {UpgradeableBeacon} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)

pragma solidity ^0.8.20;

import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "./ERC1967Utils.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 {
    /**
     * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
     *
     * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
     * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
     *
     * Requirements:
     *
     * - If `data` is empty, `msg.value` must be zero.
     */
    constructor(address implementation, bytes memory _data) payable {
        ERC1967Utils.upgradeToAndCall(implementation, _data);
    }

    /**
     * @dev Returns the current implementation address.
     *
     * 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 _implementation() internal view virtual override returns (address) {
        return ERC1967Utils.getImplementation();
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)

pragma solidity ^0.8.20;

import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 */
library ERC1967Utils {
    // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
    // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
    /**
     * @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);

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev The `implementation` of the proxy is invalid.
     */
    error ERC1967InvalidImplementation(address implementation);

    /**
     * @dev The `admin` of the proxy is invalid.
     */
    error ERC1967InvalidAdmin(address admin);

    /**
     * @dev The `beacon` of the proxy is invalid.
     */
    error ERC1967InvalidBeacon(address beacon);

    /**
     * @dev An upgrade function sees `msg.value > 0` that may be lost.
     */
    error ERC1967NonPayable();

    /**
     * @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 {
        if (newImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(newImplementation);
        }
        StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Performs implementation upgrade with additional setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);

        if (data.length > 0) {
            Address.functionDelegateCall(newImplementation, data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @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 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 {
        if (newAdmin == address(0)) {
            revert ERC1967InvalidAdmin(address(0));
        }
        StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    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 {
        if (newBeacon.code.length == 0) {
            revert ERC1967InvalidBeacon(newBeacon);
        }

        StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;

        address beaconImplementation = IBeacon(newBeacon).implementation();
        if (beaconImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(beaconImplementation);
        }
    }

    /**
     * @dev Change the beacon and trigger a setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-BeaconUpgraded} event.
     *
     * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
     * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
     * efficiency.
     */
    function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);

        if (data.length > 0) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
     * if an upgrade doesn't perform an initialization call.
     */
    function _checkNonPayable() private {
        if (msg.value > 0) {
            revert ERC1967NonPayable();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)

pragma solidity ^0.8.20;

/**
 * @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 {
        _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();
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol)

pragma solidity ^0.8.20;

import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
import {Ownable} from "../../access/Ownable.sol";

/**
 * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
 * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
 */
contract ProxyAdmin is Ownable {
    /**
     * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)`
     * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
     * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string.
     * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must
     * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
     * during an upgrade.
     */
    string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";

    /**
     * @dev Sets the initial owner who can perform upgrades.
     */
    constructor(address initialOwner) Ownable(initialOwner) {}

    /**
     * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation.
     * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}.
     *
     * Requirements:
     *
     * - This contract must be the admin of `proxy`.
     * - If `data` is empty, `msg.value` must be zero.
     */
    function upgradeAndCall(
        ITransparentUpgradeableProxy proxy,
        address implementation,
        bytes memory data
    ) public payable virtual onlyOwner {
        proxy.upgradeToAndCall{value: msg.value}(implementation, data);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)

pragma solidity ^0.8.20;

import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {ProxyAdmin} from "./ProxyAdmin.sol";

/**
 * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
 * does not implement this interface directly, and its upgradeability mechanism is 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 upgradeToAndCall(address, bytes calldata) external payable;
}

/**
 * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance.
 *
 * 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 the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself.
 * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to
 * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating
 * the proxy admin cannot fallback to the target implementation.
 *
 * These properties mean that the admin account can only be used for upgrading the proxy, 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. For this reason, the proxy deploys an instance of {ProxyAdmin} and
 * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative
 * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership.
 *
 * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
 * inherit from that interface, and instead `upgradeToAndCall` is 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.
 *
 * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a
 * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract.
 *
 * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an
 * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be
 * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an
 * undesirable state where the admin slot is different from the actual admin.
 *
 * 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 `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency.
 */
contract TransparentUpgradeableProxy is ERC1967Proxy {
    // An immutable address for the admin to avoid unnecessary SLOADs before each call
    // at the expense of removing the ability to change the admin once it's set.
    // This is acceptable if the admin is always a ProxyAdmin instance or similar contract
    // with its own ability to transfer the permissions to another account.
    address private immutable _admin;

    /**
     * @dev The proxy caller is the current admin, and can't fallback to the proxy target.
     */
    error ProxyDeniedAdminAccess();

    /**
     * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
     * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
     * {ERC1967Proxy-constructor}.
     */
    constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
        _admin = address(new ProxyAdmin(initialOwner));
        // Set the storage value and emit an event for ERC-1967 compatibility
        ERC1967Utils.changeAdmin(_proxyAdmin());
    }

    /**
     * @dev Returns the admin of this proxy.
     */
    function _proxyAdmin() internal virtual returns (address) {
        return _admin;
    }

    /**
     * @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 == _proxyAdmin()) {
            if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
                revert ProxyDeniedAdminAccess();
            } else {
                _dispatchUpgradeToAndCall();
            }
        } else {
            super._fallback();
        }
    }

    /**
     * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
     *
     * Requirements:
     *
     * - If `data` is empty, `msg.value` must be zero.
     */
    function _dispatchUpgradeToAndCall() private {
        (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
        ERC1967Utils.upgradeToAndCall(newImplementation, data);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @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 or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) 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 FailedInnerCall();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @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(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol)

pragma solidity ^0.8.24;

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

/**
 * @dev Variant of {ReentrancyGuard} that uses transient storage.
 *
 * NOTE: This variant only works on networks where EIP-1153 is available.
 *
 * _Available since v5.1._
 */
abstract contract ReentrancyGuardTransient {
    using TransientSlot for *;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    /**
     * @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 making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);
    }

    function _nonReentrantAfter() private {
        REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return REENTRANCY_GUARD_STORAGE.asBoolean().tload();
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.

pragma solidity ^0.8.24;

/**
 * @dev Library for reading and writing value-types to specific transient storage slots.
 *
 * Transient slots are often used to store temporary values that are removed after the current transaction.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 *  * Example reading and writing values using transient storage:
 * ```solidity
 * contract Lock {
 *     using TransientSlot for *;
 *
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
 *
 *     modifier locked() {
 *         require(!_LOCK_SLOT.asBoolean().tload());
 *
 *         _LOCK_SLOT.asBoolean().tstore(true);
 *         _;
 *         _LOCK_SLOT.asBoolean().tstore(false);
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library TransientSlot {
    /**
     * @dev UDVT that represent a slot holding a address.
     */
    type AddressSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a AddressSlot.
     */
    function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
        return AddressSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represent a slot holding a bool.
     */
    type BooleanSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a BooleanSlot.
     */
    function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
        return BooleanSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represent a slot holding a bytes32.
     */
    type Bytes32Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Bytes32Slot.
     */
    function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
        return Bytes32Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represent a slot holding a uint256.
     */
    type Uint256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Uint256Slot.
     */
    function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
        return Uint256Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represent a slot holding a int256.
     */
    type Int256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Int256Slot.
     */
    function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
        return Int256Slot.wrap(slot);
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(AddressSlot slot) internal view returns (address value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(AddressSlot slot, address value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(BooleanSlot slot) internal view returns (bool value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(BooleanSlot slot, bool value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Bytes32Slot slot, bytes32 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Uint256Slot slot) internal view returns (uint256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Uint256Slot slot, uint256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Int256Slot slot) internal view returns (int256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Int256Slot slot, int256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }
}

File 27 of 52 : AgglayerManager.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity 0.8.28;

import "./interfaces/IAgglayerGER.sol";
import "./interfaces/IPolygonZkEVMBridge.sol";
import "./interfaces/IPolygonRollupBase.sol";
import "./interfaces/IVerifierRollup.sol";
import "./lib/EmergencyManager.sol";
import "@openzeppelin/contracts-upgradeable4/token/ERC20/utils/SafeERC20Upgradeable.sol";
// @dev For ReentrancyGuardTransient there is no difference between upgradable and not upgradable contracts
import "@openzeppelin/contracts52/utils/ReentrancyGuardTransient.sol";
import "./lib/PolygonTransparentProxy.sol";
import "./lib/PolygonAccessControlUpgradeable.sol";
import "./lib/LegacyZKEVMStateVariables.sol";
import "./lib/PolygonConstantsBase.sol";
import "./interfaces/IPolygonPessimisticConsensus.sol";
import "./interfaces/ISP1Verifier.sol";
import "./interfaces/IAgglayerManager.sol";
import "./interfaces/IAggchainBase.sol";
import "./interfaces/IAgglayerGateway.sol";
import "./interfaces/IVersion.sol";
import "./lib/Hashes.sol";

/**
 * Contract responsible for managing rollups and the verification of their batches.
 * This contract will create and update rollups and store all the hashed sequenced data from them.
 * The logic for sequence batches is moved to the `consensus` contracts, while the verification of all of
 * them will be done in this one. In this way, the proof aggregation of the rollups will be easier on a close future.
 */
contract AgglayerManager is
    PolygonAccessControlUpgradeable,
    EmergencyManager,
    LegacyZKEVMStateVariables,
    PolygonConstantsBase,
    IAgglayerManager,
    ReentrancyGuardTransient,
    IVersion
{
    using SafeERC20Upgradeable for IERC20Upgradeable;

    /**
     * @notice Struct which to store the rollup type data
     * @param consensusImplementation Consensus implementation ( contains the consensus logic for the transparent proxy)
     * @param address verifier
     * @param forkID fork ID
     * @param rollupVerifierType Rollup compatibility ID, to check upgradability between rollup types
     * @param obsolete Indicates if the rollup type is obsolete
     * @param genesis Genesis block of the rollup, note that will only be used on creating new rollups, not upgrade them
     * @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
     */
    struct RollupType {
        address consensusImplementation;
        address verifier;
        uint64 forkID;
        /// @custom:oz-renamed-from rollupCompatibilityID
        /// @custom:oz-retyped-from uint8
        VerifierType rollupVerifierType;
        bool obsolete;
        bytes32 genesis;
        bytes32 programVKey;
    }

    /**
     * @notice Struct which to store the rollup data of each chain
     * @param rollupContract Rollup consensus contract, which manages everything
     * related to sequencing transactions
     * @param chainID Chain ID of the rollup
     * @param verifier Verifier contract
     * @param forkID ForkID of the rollup
     * @param batchNumToStateRoot State root mapping
     * @param sequencedBatches Queue of batches that defines the virtual state
     * @param _legacyPendingStateTransitions Pending state mapping (deprecated)
     * @param lastLocalExitRoot Last exit root verified, used for compute the rollupExitRoot
     * @param lastBatchSequenced Last batch sent by the consensus contract
     * @param lastVerifiedBatch Last batch verified
     * @param _legacyLastPendingState Last pending state (deprecated)
     * @param _legacyLastPendingStateConsolidated Last pending state consolidated (deprecated)
     * @param lastVerifiedBatchBeforeUpgrade Last batch verified before the last upgrade
     * @param rollupTypeID Rollup type ID, can be 0 if it was added as an existing rollup
     * @param rollupVerifierType Rollup ID used for compatibility checks when upgrading
     * @param lastPessimisticRoot Pessimistic info, currently contains the local balance tree and the local nullifier tree hashed
     * @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
     */
    struct RollupData {
        address rollupContract;
        uint64 chainID;
        address verifier;
        uint64 forkID;
        mapping(uint64 batchNum => bytes32) batchNumToStateRoot;
        mapping(uint64 batchNum => SequencedBatchData) sequencedBatches;
        /// @custom:oz-renamed-from pendingStateTransitions
        mapping(uint256 pendingStateNum => PendingState) _legacyPendingStateTransitions;
        bytes32 lastLocalExitRoot;
        uint64 lastBatchSequenced;
        uint64 lastVerifiedBatch;
        /// @custom:oz-renamed-from lastPendingState
        uint64 _legacyLastPendingState;
        /// @custom:oz-renamed-from lastPendingStateConsolidated
        uint64 _legacyLastPendingStateConsolidated;
        uint64 lastVerifiedBatchBeforeUpgrade;
        uint64 rollupTypeID;
        /// @custom:oz-renamed-from rollupCompatibilityID
        /// @custom:oz-retyped-from uint8
        VerifierType rollupVerifierType;
        bytes32 lastPessimisticRoot;
        bytes32 programVKey;
    }

    /**
     * @notice Struct to return all the necessary rollup info: VerifierType StateTransition
     * @param rollupContract Rollup consensus contract, which manages everything
     * related to sequencing transactions
     * @param chainID Chain ID of the rollup
     * @param verifier Verifier contract
     * @param forkID ForkID of the rollup
     * @param lastLocalExitRoot Last exit root verified, used for compute the rollupExitRoot
     * @param lastBatchSequenced Last batch sent by the consensus contract
     * @param lastVerifiedBatch Last batch verified
     * @param _legacyLastPendingState Last pending state (deprecated)
     * @param _legacyLastPendingStateConsolidated Last pending state consolidated (deprecated)
     * @param lastVerifiedBatchBeforeUpgrade Last batch verified before the last upgrade
     * @param rollupTypeID Rollup type ID, can be 0 if it was added as an existing rollup
     * @param rollupVerifierType Rollup ID used for compatibility checks when upgrading
     */
    struct RollupDataReturn {
        address rollupContract;
        uint64 chainID;
        address verifier;
        uint64 forkID;
        bytes32 lastLocalExitRoot;
        uint64 lastBatchSequenced;
        uint64 lastVerifiedBatch;
        uint64 _legacyLastPendingState;
        uint64 _legacyLastPendingStateConsolidated;
        uint64 lastVerifiedBatchBeforeUpgrade;
        uint64 rollupTypeID;
        VerifierType rollupVerifierType;
    }

    /**
     * @notice Struct which to store the rollup data of each chain
     * @param rollupContract Rollup consensus contract, which manages everything
     * related to sequencing transactions
     * @param chainID Chain ID of the rollup
     * @param verifier Verifier contract
     * @param forkID ForkID of the rollup
     * @param lastLocalExitRoot Last exit root verified, used for compute the rollupExitRoot
     * @param lastBatchSequenced Last batch sent by the consensus contract
     * @param lastVerifiedBatch Last batch verified
     * @param lastVerifiedBatchBeforeUpgrade Last batch verified before the last upgrade
     * @param rollupTypeID Rollup type ID, can be 0 if it was added as an existing rollup
     * @param rollupVerifierType Rollup ID used for compatibility checks when upgrading
     * @param lastPessimisticRoot Pessimistic info, currently contains the local balance tree and the local nullifier tree hashed
     * @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
     */
    struct RollupDataReturnV2 {
        address rollupContract;
        uint64 chainID;
        address verifier;
        uint64 forkID;
        bytes32 lastLocalExitRoot;
        uint64 lastBatchSequenced;
        uint64 lastVerifiedBatch;
        uint64 lastVerifiedBatchBeforeUpgrade;
        uint64 rollupTypeID;
        VerifierType rollupVerifierType;
        bytes32 lastPessimisticRoot;
        bytes32 programVKey;
    }

    // Modulus zkSNARK
    uint256 internal constant _RFIELD =
        21888242871839275222246405745257275088548364400416034343698204186575808495617;

    // Max batch fee value
    uint256 internal constant _MAX_BATCH_FEE = 1000 ether;

    // Min value batch fee
    uint256 internal constant _MIN_BATCH_FEE = 1 gwei;

    // Goldilocks prime field
    uint256 internal constant _GOLDILOCKS_PRIME_FIELD = 0xFFFFFFFF00000001; // 2 ** 64 - 2 ** 32 + 1

    // Max uint64
    uint256 internal constant _MAX_UINT_64 = type(uint64).max; // 0xFFFFFFFFFFFFFFFF

    // Exit merkle tree levels
    uint256 internal constant _EXIT_TREE_DEPTH = 32;

    // Roles

    // Be able to add a new rollup type
    bytes32 internal constant _ADD_ROLLUP_TYPE_ROLE =
        keccak256("ADD_ROLLUP_TYPE_ROLE");

    // Be able to obsolete a rollup type, which means that new rollups cannot use this type
    bytes32 internal constant _OBSOLETE_ROLLUP_TYPE_ROLE =
        keccak256("OBSOLETE_ROLLUP_TYPE_ROLE");

    // Be able to create a new rollup using a rollup type
    bytes32 internal constant _CREATE_ROLLUP_ROLE =
        keccak256("CREATE_ROLLUP_ROLE");

    // Be able to create a new rollup which does not have to follow any rollup type.
    // Also sets the genesis block for that network
    bytes32 internal constant _ADD_EXISTING_ROLLUP_ROLE =
        keccak256("ADD_EXISTING_ROLLUP_ROLE");

    // Be able to update a rollup to a new rollup type that it's compatible
    bytes32 internal constant _UPDATE_ROLLUP_ROLE =
        keccak256("UPDATE_ROLLUP_ROLE");

    // Be able to that has priority to verify batches and consolidates the state instantly
    bytes32 internal constant _TRUSTED_AGGREGATOR_ROLE =
        keccak256("TRUSTED_AGGREGATOR_ROLE");

    // Be able to set the trusted aggregator address
    bytes32 internal constant _TRUSTED_AGGREGATOR_ROLE_ADMIN =
        keccak256("TRUSTED_AGGREGATOR_ROLE_ADMIN");

    // Be able to tweak parameters
    bytes32 internal constant _TWEAK_PARAMETERS_ROLE =
        keccak256("TWEAK_PARAMETERS_ROLE");

    // Be able to set the current batch fee
    bytes32 internal constant _SET_FEE_ROLE = keccak256("SET_FEE_ROLE");

    // Be able to stop the emergency state
    bytes32 internal constant _STOP_EMERGENCY_ROLE =
        keccak256("STOP_EMERGENCY_ROLE");

    // Be able to activate the emergency state without any further condition
    bytes32 internal constant _EMERGENCY_COUNCIL_ROLE =
        keccak256("EMERGENCY_COUNCIL_ROLE");

    // Be able to set the emergency council address
    bytes32 internal constant _EMERGENCY_COUNCIL_ADMIN =
        keccak256("EMERGENCY_COUNCIL_ADMIN");

    // Current rollup manager version
    string public constant ROLLUP_MANAGER_VERSION = "v1.0.0";

    // Hardcoded address used to indicate that this address triggered in an event should not be considered as valid.
    address private constant _NO_ADDRESS =
        0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;

    // Global Exit Root address
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    IAgglayerGER public immutable globalExitRootManager;

    // PolygonZkEVM Bridge Address
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    IPolygonZkEVMBridge public immutable bridgeAddress;

    // POL token address
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    IERC20Upgradeable public immutable pol;

    // Polygon Verifier Gateway address
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    IAgglayerGateway public immutable aggLayerGateway;

    // Number of rollup types added, every new type will be assigned sequentially a new ID
    uint32 public rollupTypeCount;

    // Rollup type mapping
    /// @custom:oz-retyped-from PolygonRollupManagerPrevious.RollupType
    mapping(uint32 rollupTypeID => RollupType) public rollupTypeMap;

    // Number of rollups added, every new rollup will be assigned sequentially a new ID
    uint32 public rollupCount;

    // Rollups ID mapping
    /// @custom:oz-retyped-from PolygonRollupManagerPrevious.RollupData
    mapping(uint32 rollupID => RollupData) internal _rollupIDToRollupData;

    // Rollups address mapping
    mapping(address rollupAddress => uint32 rollupID) public rollupAddressToID;

    // Chain ID mapping for nullifying
    // note we will take care to avoid that current known chainIDs are not reused in our networks (example: 1)
    mapping(uint64 chainID => uint32 rollupID) public chainIDToRollupID;

    // Total sequenced batches across all rollups
    uint64 public totalSequencedBatches;

    // Total verified batches across all rollups
    uint64 public totalVerifiedBatches;

    // Last timestamp when an aggregation happen
    uint64 public lastAggregationTimestamp;

    // Trusted aggregator timeout, if a sequence is not verified in this time frame,
    // everyone can verify that sequence
    /// @custom:oz-renamed-from trustedAggregatorTimeout
    uint64 internal __legacyTrustedAggregatorTimeout;

    // Once a pending state exceeds this timeout it can be consolidated (deprecated)
    /// @custom:oz-renamed-from pendingStateTimeout
    uint64 internal __legacyPendingStateTimeout;

    // Time target of the verification of a batch
    // Adaptively the batchFee will be updated to achieve this target
    /// @custom:oz-renamed-from verifyBatchTimeTarget
    uint64 internal __legacyVerifyBatchTimeTarget;

    // Batch fee multiplier with 3 decimals that goes from 1000 - 1023
    /// @custom:oz-renamed-from multiplierBatchFee
    uint16 internal __legacyMultiplierBatchFee;

    // Current POL fee per batch sequenced
    // note This variable is internal, since the view function getBatchFee is likely to be upgraded
    uint256 internal _batchFee;

    // Timestamp when the last emergency state was deactivated
    uint64 public lastDeactivatedEmergencyStateTimestamp;

    // Mapping to track chains in migration
    mapping(uint32 rollupID => bool) public isRollupMigrating;

    /**
     * @dev Emitted when a new rollup type is added
     */
    event AddNewRollupType(
        uint32 indexed rollupTypeID,
        address consensusImplementation,
        address verifier,
        uint64 forkID,
        VerifierType rollupVerifierType,
        bytes32 genesis,
        string description,
        bytes32 programVKey
    );

    /**
     * @dev Emitted when a a rollup type is obsoleted
     */
    event ObsoleteRollupType(uint32 indexed rollupTypeID);

    /**
     * @dev Emitted when a new rollup is created based on a rollupType
     */
    event CreateNewRollup(
        uint32 indexed rollupID,
        uint32 rollupTypeID,
        address rollupAddress,
        uint64 chainID,
        address gasTokenAddress
    );

    /**
     * @dev Emitted when an existing rollup is added
     */
    event AddExistingRollup(
        uint32 indexed rollupID,
        uint64 forkID,
        address rollupAddress,
        uint64 chainID,
        VerifierType rollupVerifierType,
        uint64 lastVerifiedBatchBeforeUpgrade,
        bytes32 programVKey,
        bytes32 initPessimisticRoot
    );

    /**
     * @dev Emitted when a rollup is updated
     */
    event UpdateRollup(
        uint32 indexed rollupID,
        uint32 newRollupTypeID,
        uint64 lastVerifiedBatchBeforeUpgrade
    );

    /**
     * @dev Emitted when a new verifier is added
     */
    event OnSequenceBatches(uint32 indexed rollupID, uint64 lastBatchSequenced);

    /**
     * @dev Emitted when the trusted aggregator verifies batches
     */
    event VerifyBatchesTrustedAggregator(
        uint32 indexed rollupID,
        uint64 numBatch,
        bytes32 stateRoot,
        bytes32 exitRoot,
        address indexed aggregator
    );

    /**
     * @dev Emitted when rollback batches
     */
    event RollbackBatches(
        uint32 indexed rollupID,
        uint64 indexed targetBatch,
        bytes32 accInputHashToRollback
    );

    /**
     * @dev Emitted when is updated the trusted aggregator address
     */
    event SetTrustedAggregator(address newTrustedAggregator);

    /**
     * @dev Emitted when is updated the batch fee
     */
    event SetBatchFee(uint256 newBatchFee);

    /**
     * @dev Emitted when rollup manager is upgraded
     */
    event UpdateRollupManagerVersion(string rollupManagerVersion);

    /**
     * @notice Emitted when a ALGateway or Pessimistic chain verifies a pessimistic proof
     * @param rollupID Rollup ID
     * @param prevPessimisticRoot Previous pessimistic root
     * @param newPessimisticRoot New pessimistic root
     * @param prevLocalExitRoot Previous local exit root
     * @param newLocalExitRoot New local exit root
     * @param l1InfoRoot L1 info root
     * @param trustedAggregator Trusted aggregator address
     */
    event VerifyPessimisticStateTransition(
        uint32 indexed rollupID,
        bytes32 prevPessimisticRoot,
        bytes32 newPessimisticRoot,
        bytes32 prevLocalExitRoot,
        bytes32 newLocalExitRoot,
        bytes32 l1InfoRoot,
        address indexed trustedAggregator
    );

    /**
     * @dev Emitted when a new rollup is created based on a rollupType
     */
    event CreateNewAggchain(
        uint32 indexed rollupID,
        uint32 rollupTypeID,
        address rollupAddress,
        uint64 chainID,
        uint8 rollupVerifierType,
        bytes initializeBytesAggchain
    );

    /**
     * @dev Emitted when `initMigration` is called
     * @param rollupID Rollup ID that is being migrated
     * @param newRollupTypeID New rollup type ID that the rollup will be migrated to
     */
    event InitMigration(uint32 indexed rollupID, uint32 newRollupTypeID);

    /**
     * @dev Emitted when a rollup completes the migration to Pessimistic or ALGateway, just after proving bootstrapped batch
     * @param rollupID Rollup ID that completed the migration
     */
    event CompletedMigration(uint32 indexed rollupID);

    /**
     * @param _globalExitRootManager Global exit root manager address
     * @param _pol POL token address
     * @param _bridgeAddress Bridge address
     * @param _aggLayerGateway Polygon Verifier Gateway address
     */
    constructor(
        IAgglayerGER _globalExitRootManager,
        IERC20Upgradeable _pol,
        IPolygonZkEVMBridge _bridgeAddress,
        IAgglayerGateway _aggLayerGateway
    ) {
        // Check non zero inputs
        if (
            address(_globalExitRootManager) == address(0) ||
            address(_pol) == address(0) ||
            address(_bridgeAddress) == address(0) ||
            address(_aggLayerGateway) == address(0)
        ) {
            revert InvalidConstructorInputs();
        }
        globalExitRootManager = _globalExitRootManager;
        pol = _pol;
        bridgeAddress = _bridgeAddress;
        aggLayerGateway = _aggLayerGateway;

        // Disable initializers on the implementation following the best practices
        _disableInitializers();
    }

    /**
     * Initializer function to set new rollup manager version
     */
    function initialize() external virtual reinitializer(5) {
        emit UpdateRollupManagerVersion(ROLLUP_MANAGER_VERSION);
    }

    ///////////////////////////////////////
    // Rollups management functions
    ///////////////////////////////////////

    ////////////////
    // Rollups Types
    ////////////////

    /**
     * @notice Add a new rollup type
     * @param consensusImplementation Consensus implementation
     * @param verifier Verifier address
     * @param forkID ForkID of the verifier
     * @param rollupVerifierType rollup verifier type
     * @param genesis Genesis block of the rollup
     * @param description Description of the rollup type
     * @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
     */
    function addNewRollupType(
        address consensusImplementation,
        address verifier,
        uint64 forkID,
        VerifierType rollupVerifierType,
        bytes32 genesis,
        string memory description,
        bytes32 programVKey
    ) external onlyRole(_ADD_ROLLUP_TYPE_ROLE) {
        // Check proposed address is not this contract to avoid self-referential loops causing infinite delegate calls
        if (consensusImplementation == address(this)) {
            revert InvalidImplementationAddress();
        }

        uint32 rollupTypeID = ++rollupTypeCount;

        if (rollupVerifierType == VerifierType.Pessimistic) {
            // No genesis on pessimistic rollups
            if (genesis != bytes32(0)) revert InvalidRollupType();
        } else if (rollupVerifierType == VerifierType.ALGateway) {
            // Those params should be zero for ALGateway rollup types
            if (
                verifier != address(0) ||
                forkID != 0 ||
                genesis != bytes32(0) ||
                programVKey != bytes32(0)
            ) revert InvalidRollupType();
        } else if (rollupVerifierType == VerifierType.StateTransition) {
            // No programVKey on state transition rollups
            if (programVKey != bytes32(0)) revert InvalidRollupType();
        } else {
            // unreachable code since solidity enforces the enum input rollupVerifierType to be one of the enum values
            revert InvalidRollupType();
        }

        rollupTypeMap[rollupTypeID] = RollupType({
            consensusImplementation: consensusImplementation,
            verifier: verifier,
            forkID: forkID,
            rollupVerifierType: rollupVerifierType,
            obsolete: false,
            genesis: genesis,
            programVKey: programVKey
        });

        emit AddNewRollupType(
            rollupTypeID,
            consensusImplementation,
            verifier,
            forkID,
            rollupVerifierType,
            genesis,
            description,
            programVKey
        );
    }

    /**
     * @notice Obsolete Rollup type
     * @param rollupTypeID Rollup type to obsolete
     */
    function obsoleteRollupType(
        uint32 rollupTypeID
    ) external onlyRole(_OBSOLETE_ROLLUP_TYPE_ROLE) {
        // Check that rollup type exists
        if (rollupTypeID == 0 || rollupTypeID > rollupTypeCount) {
            revert RollupTypeDoesNotExist();
        }

        // Check rollup type is not obsolete
        RollupType storage currentRollupType = rollupTypeMap[rollupTypeID];
        if (currentRollupType.obsolete) {
            revert RollupTypeObsolete();
        }

        currentRollupType.obsolete = true;

        emit ObsoleteRollupType(rollupTypeID);
    }

    /**
     * @notice Create a new rollup
     * @param rollupTypeID Rollup type to deploy
     * @param chainID ChainID of the rollup, must be a new one, can not have more than 32 bits
     * @param initializeBytesAggchain Encoded params to initialize the chain. Each aggchain has its encoded params.
     * @dev in case of rollupType state transition or pessimistic, the encoded params
     * are the following: (address admin, address sequencer, address gasTokenAddress, string sequencerURL, string networkName)
     */
    function attachAggchainToAL(
        uint32 rollupTypeID,
        uint64 chainID,
        bytes memory initializeBytesAggchain
    ) external onlyRole(_CREATE_ROLLUP_ROLE) {
        // Check that rollup type exists
        if (rollupTypeID == 0 || rollupTypeID > rollupTypeCount) {
            revert RollupTypeDoesNotExist();
        }
        // Check rollup type is not obsolete
        RollupType storage rollupType = rollupTypeMap[rollupTypeID];
        if (rollupType.obsolete) {
            revert RollupTypeObsolete();
        }

        // check chainID max value
        // Currently we have this limitation by the circuit, might be removed in a future
        if (chainID > type(uint32).max) {
            revert ChainIDOutOfRange();
        }
        // Check chainID nullifier
        if (chainIDToRollupID[chainID] != 0) {
            revert ChainIDAlreadyExist();
        }

        // Create a new Rollup, using a transparent proxy pattern
        // Consensus will be the implementation, and this contract the admin
        uint32 rollupID = ++rollupCount;
        address rollupAddress = address(
            new PolygonTransparentProxy(
                rollupType.consensusImplementation,
                address(this),
                new bytes(0)
            )
        );

        // Set chainID to rollup id mapping
        chainIDToRollupID[chainID] = rollupID;
        // Set rollup address to rollup id mapping
        rollupAddressToID[rollupAddress] = rollupID;

        // Set rollup data
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        rollup.rollupContract = rollupAddress;
        rollup.chainID = chainID;
        rollup.rollupTypeID = rollupTypeID;
        rollup.rollupVerifierType = rollupType.rollupVerifierType;

        if (rollupType.rollupVerifierType == VerifierType.ALGateway) {
            // Emit create new aggchain event
            emit CreateNewAggchain(
                rollupID,
                rollupTypeID,
                rollupAddress,
                chainID,
                uint8(rollupType.rollupVerifierType),
                initializeBytesAggchain
            );

            // This event is emitted for backwards compatibility
            /// @dev the address is hardcoded as it doesn't apply for aggchains and zero address is used for ether
            emit CreateNewRollup(
                rollupID,
                rollupTypeID,
                rollupAddress,
                chainID,
                _NO_ADDRESS
            );

            address aggchainManager = abi.decode(
                initializeBytesAggchain,
                (address)
            );

            // Set the aggchain manager, aggchain contract will be initialized later
            // through the aggchain manager
            IAggchainBase(rollupAddress).initAggchainManager(aggchainManager);
        } else {
            // assign non ALGateway values to rollup data
            rollup.forkID = rollupType.forkID;
            rollup.verifier = rollupType.verifier;
            rollup.batchNumToStateRoot[0] = rollupType.genesis;
            rollup.programVKey = rollupType.programVKey;

            // custom parsing of the initializeBytesAggchain for a sate transition or pessimistic rollup
            (
                address admin,
                address sequencer,
                address gasTokenAddress,
                string memory sequencerURL,
                string memory networkName
            ) = abi.decode(
                    initializeBytesAggchain,
                    (address, address, address, string, string)
                );

            // Emit create new rollup event
            emit CreateNewRollup(
                rollupID,
                rollupTypeID,
                rollupAddress,
                chainID,
                gasTokenAddress
            );

            // Initialize new rollup
            IPolygonRollupBase(rollupAddress).initialize(
                admin,
                sequencer,
                rollupID,
                gasTokenAddress,
                sequencerURL,
                networkName
            );
        }
    }

    /**
     * @notice Add an already deployed rollup
     * note that this rollup does not follow any rollupType
     * @param rollupAddress Rollup address
     * @param verifier Verifier address, must be added before
     * @param forkID Fork id of the added rollup
     * @param chainID Chain id of the added rollup
     * @param initRoot Genesis block for StateTransitionChains & localExitRoot for pessimistic chain
     * @param rollupVerifierType Compatibility ID for the added rollup
     * @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
     * @param initPessimisticRoot Pessimistic root to init the chain.
     */
    function addExistingRollup(
        address rollupAddress,
        address verifier,
        uint64 forkID,
        uint64 chainID,
        bytes32 initRoot,
        VerifierType rollupVerifierType,
        bytes32 programVKey,
        bytes32 initPessimisticRoot
    ) external onlyRole(_ADD_EXISTING_ROLLUP_ROLE) {
        // Check chainID nullifier
        if (chainIDToRollupID[chainID] != 0) {
            revert ChainIDAlreadyExist();
        }

        // check chainID max value
        // Currently we have this limitation by the circuit, might be removed in a future
        if (chainID > type(uint32).max) {
            revert ChainIDOutOfRange();
        }

        // Check if rollup address was already added
        if (rollupAddressToID[address(rollupAddress)] != 0) {
            revert RollupAddressAlreadyExist();
        }

        // Check proposed address is not this contract to avoid self-referential loops causing infinite delegate calls
        if (rollupAddress == address(this) || rollupAddress.code.length == 0) {
            revert InvalidImplementationAddress();
        }

        // Increment rollup count
        uint32 rollupID = ++rollupCount;

        // Set chainID nullifier
        chainIDToRollupID[chainID] = rollupID;

        // Store rollup data
        rollupAddressToID[address(rollupAddress)] = rollupID;

        RollupData storage rollup = _rollupIDToRollupData[rollupID];
        rollup.rollupContract = rollupAddress;
        rollup.forkID = forkID;
        rollup.verifier = verifier;
        rollup.chainID = chainID;
        rollup.rollupVerifierType = rollupVerifierType;

        // Check verifier type
        if (rollupVerifierType == VerifierType.Pessimistic) {
            rollup.programVKey = programVKey;
            rollup.lastPessimisticRoot = initPessimisticRoot;
            rollup.lastLocalExitRoot = initRoot;
            if (verifier.code.length == 0) {
                revert InvalidVerifierAddress();
            }
        } else if (rollupVerifierType == VerifierType.ALGateway) {
            if (
                verifier != address(0) ||
                forkID != 0 ||
                programVKey != bytes32(0)
            ) {
                revert InvalidInputsForRollupType();
            }

            rollup.lastPessimisticRoot = initPessimisticRoot;
            rollup.lastLocalExitRoot = initRoot;
        } else {
            if (
                programVKey != bytes32(0) || initPessimisticRoot != bytes32(0)
            ) {
                revert InvalidInputsForRollupType();
            }

            rollup.batchNumToStateRoot[0] = initRoot;
            if (verifier.code.length == 0) {
                revert InvalidVerifierAddress();
            }
        }

        emit AddExistingRollup(
            rollupID,
            forkID,
            address(rollupAddress),
            chainID,
            rollupVerifierType,
            0,
            programVKey,
            initPessimisticRoot
        );
    }

    /**
     * @notice Upgrade an existing rollup from the rollup admin address
     * This address is able to update the rollup with more restrictions that the _UPDATE_ROLLUP_ROLE
     * @param rollupContract Rollup consensus proxy address
     * @param newRollupTypeID New rollupTypeID to upgrade to
     */
    function updateRollupByRollupAdmin(
        ITransparentUpgradeableProxy rollupContract,
        uint32 newRollupTypeID
    ) external {
        RollupData storage rollup = _rollupIDToRollupData[
            rollupAddressToID[address(rollupContract)]
        ];

        if (rollup.rollupVerifierType == VerifierType.ALGateway) {
            // Check aggchain manager is msg.sender
            if (
                IAggchainBase(address(rollupContract)).aggchainManager() !=
                msg.sender
            ) {
                revert OnlyAggchainManager();
            }

            // Check AGGCHAIN_TYPE is the same (both are ALGateway at this point)
            if (
                IAggchainBase(address(rollupContract)).AGGCHAIN_TYPE() !=
                IAggchainBase(
                    rollupTypeMap[newRollupTypeID].consensusImplementation
                ).AGGCHAIN_TYPE()
            ) {
                revert UpdateNotCompatible();
            }
        } else {
            // Check admin of the network is msg.sender
            if (
                IPolygonRollupBase(address(rollupContract)).admin() !=
                msg.sender
            ) {
                revert OnlyRollupAdmin();
            }

            // Check all sequenced batches are verified
            if (rollup.lastBatchSequenced != rollup.lastVerifiedBatch) {
                revert AllSequencedMustBeVerified();
            }
        }

        // Not allowed to update to an older rollup type id, only supported from updateRollup function
        // Rollups added via 'addExistingRollup' has rollupTypeID = 0
        if (rollup.rollupTypeID >= newRollupTypeID) {
            revert UpdateToOldRollupTypeID();
        }

        // note that for rollups via 'addExistingRollup', the rollupTypeID is set to 0
        // Admin can't update to a different rollup type
        if (
            rollup.rollupVerifierType !=
            rollupTypeMap[newRollupTypeID].rollupVerifierType
        ) {
            revert UpdateNotCompatible();
        }

        _updateRollup(rollupContract, newRollupTypeID, new bytes(0));
    }

    /**
     * @notice Upgrade an existing rollup
     * @param rollupContract Rollup consensus proxy address
     * @param newRollupTypeID New rollupTypeID to upgrade to
     * @param upgradeData Upgrade data
     */
    function updateRollup(
        ITransparentUpgradeableProxy rollupContract,
        uint32 newRollupTypeID,
        bytes memory upgradeData
    ) external onlyRole(_UPDATE_ROLLUP_ROLE) {
        uint32 rollupID = rollupAddressToID[address(rollupContract)];
        RollupData storage rollup = _rollupIDToRollupData[rollupID];
        // Only allow update rollupVerifierType when updating to ALGateway
        if (
            rollupTypeMap[newRollupTypeID].rollupVerifierType !=
            VerifierType.ALGateway &&
            rollup.rollupVerifierType !=
            rollupTypeMap[newRollupTypeID].rollupVerifierType
        ) {
            revert UpdateNotCompatible();
        }

        _updateRollup(rollupContract, newRollupTypeID, upgradeData);
    }

    /**
     * @notice Upgrade an existing rollup
     * @param rollupContract Rollup consensus proxy address
     * @param newRollupTypeID New rollupTypeID to upgrade to
     * @param upgradeData Upgrade data
     */
    function _updateRollup(
        ITransparentUpgradeableProxy rollupContract,
        uint32 newRollupTypeID,
        bytes memory upgradeData
    ) internal {
        // Check that rollup type exists
        if (newRollupTypeID == 0 || newRollupTypeID > rollupTypeCount) {
            revert RollupTypeDoesNotExist();
        }

        // Check the rollup exists
        uint32 rollupID = rollupAddressToID[address(rollupContract)];
        if (rollupID == 0) {
            revert RollupMustExist();
        }

        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        // The update must be to a new rollup type
        if (rollup.rollupTypeID == newRollupTypeID) {
            revert UpdateToSameRollupTypeID();
        }

        RollupType storage newRollupType = rollupTypeMap[newRollupTypeID];

        // Check rollup type is not obsolete
        if (newRollupType.obsolete) {
            revert RollupTypeObsolete();
        }

        // Update rollup parameters
        rollup.verifier = newRollupType.verifier;
        rollup.forkID = newRollupType.forkID;
        rollup.programVKey = newRollupType.programVKey;
        rollup.rollupTypeID = newRollupTypeID;
        rollup.rollupVerifierType = newRollupType.rollupVerifierType;

        uint64 lastVerifiedBatch = getLastVerifiedBatch(rollupID);
        rollup.lastVerifiedBatchBeforeUpgrade = lastVerifiedBatch;
        // Upgrade rollup
        rollupContract.upgradeToAndCall(
            newRollupType.consensusImplementation,
            upgradeData
        );
        emit UpdateRollup(rollupID, newRollupTypeID, lastVerifiedBatch);
    }

    /**
     * @notice Function to init migration to PP or ALGateway
     * @param rollupID Rollup ID that is being migrated
     * @param newRollupTypeID New rollup type ID that the rollup will be migrated to
     * @param upgradeData Upgrade data
     */
    function initMigration(
        uint32 rollupID,
        uint32 newRollupTypeID,
        bytes memory upgradeData
    ) external onlyRole(_UPDATE_ROLLUP_ROLE) {
        /// @dev Rollup existence check is done at `_updateRollup`function
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        // Only for StateTransition chains
        require(
            rollup.rollupVerifierType == VerifierType.StateTransition,
            OnlyStateTransitionChains()
        );

        // No pending batches to verify allowed before migration
        if (rollup.lastBatchSequenced != rollup.lastVerifiedBatch) {
            revert AllSequencedMustBeVerified();
        }

        // NewRollupType must be pessimistic or ALGateway
        require(
            rollupTypeMap[newRollupTypeID].rollupVerifierType !=
                VerifierType.StateTransition,
            NewRollupTypeMustBePessimisticOrALGateway()
        );

        // Add rollupID to migration mapping
        isRollupMigrating[rollupID] = true;

        // Update rollup type to new type
        _updateRollup(
            ITransparentUpgradeableProxy(rollup.rollupContract),
            newRollupTypeID,
            upgradeData
        );

        // Emit event
        emit InitMigration(rollupID, newRollupTypeID);
    }

    /**
     * @notice Rollback batches of the target rollup
     * Only applies to state transition rollups
     * @param rollupContract Rollup consensus proxy address
     * @param targetBatch Batch to rollback up to but not including this batch
     */
    function rollbackBatches(
        IPolygonRollupBase rollupContract,
        uint64 targetBatch
    ) external nonReentrant {
        // Check msg.sender has _UPDATE_ROLLUP_ROLE rol or is the admin of the network
        if (
            !hasRole(_UPDATE_ROLLUP_ROLE, msg.sender) &&
            IPolygonRollupBase(address(rollupContract)).admin() != msg.sender
        ) {
            revert NotAllowedAddress();
        }

        // Check the rollup exists
        uint32 rollupID = rollupAddressToID[address(rollupContract)];
        if (rollupID == 0) {
            revert RollupMustExist();
        }

        // Load rollup
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        if (rollup.rollupVerifierType != VerifierType.StateTransition) {
            revert OnlyStateTransitionChains();
        }

        uint64 lastBatchSequenced = rollup.lastBatchSequenced;

        // Batch to rollback should be already sequenced
        if (
            targetBatch >= lastBatchSequenced ||
            targetBatch < rollup.lastVerifiedBatch
        ) {
            revert RollbackBatchIsNotValid();
        }

        uint64 currentBatch = lastBatchSequenced;

        // delete sequence batches structs until the targetBatch
        while (currentBatch != targetBatch) {
            // Load previous end of sequence batch
            uint64 previousBatch = rollup
                .sequencedBatches[currentBatch]
                .previousLastBatchSequenced;

            // Batch to rollback must be end of a sequence
            if (previousBatch < targetBatch) {
                revert RollbackBatchIsNotEndOfSequence();
            }

            // delete sequence information
            delete rollup.sequencedBatches[currentBatch];

            // Update current batch for next iteration
            currentBatch = previousBatch;
        }

        // Update last batch sequenced on rollup data
        rollup.lastBatchSequenced = targetBatch;

        // Update totalSequencedBatches
        totalSequencedBatches -= lastBatchSequenced - targetBatch;

        // Clean pending state if any
        rollupContract.rollbackBatches(
            targetBatch,
            rollup.sequencedBatches[targetBatch].accInputHash
        );

        emit RollbackBatches(
            rollupID,
            targetBatch,
            rollup.sequencedBatches[targetBatch].accInputHash
        );
    }

    /////////////////////////////////////
    // Sequence/Verify batches functions
    ////////////////////////////////////

    /**
     * @notice Sequence batches, callback called by one of the consensus managed by this contract
     * @param newSequencedBatches Number of batches sequenced
     * @param newAccInputHash New accumulate input hash
     */
    function onSequenceBatches(
        uint64 newSequencedBatches,
        bytes32 newAccInputHash
    ) external ifNotEmergencyState returns (uint64) {
        // Check that the msg.sender is an added rollup
        uint32 rollupID = rollupAddressToID[msg.sender];
        if (rollupID == 0) {
            revert SenderMustBeRollup();
        }

        // This prevents overwriting sequencedBatches
        if (newSequencedBatches == 0) {
            revert MustSequenceSomeBatch();
        }

        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        if (rollup.rollupVerifierType != VerifierType.StateTransition) {
            revert OnlyStateTransitionChains();
        }

        // Update total sequence parameters
        totalSequencedBatches += newSequencedBatches;

        // Update sequenced batches of the current rollup
        uint64 previousLastBatchSequenced = rollup.lastBatchSequenced;
        uint64 newLastBatchSequenced = previousLastBatchSequenced +
            newSequencedBatches;

        rollup.lastBatchSequenced = newLastBatchSequenced;
        rollup.sequencedBatches[newLastBatchSequenced] = SequencedBatchData({
            accInputHash: newAccInputHash,
            sequencedTimestamp: uint64(block.timestamp),
            previousLastBatchSequenced: previousLastBatchSequenced
        });

        emit OnSequenceBatches(rollupID, newLastBatchSequenced);

        return newLastBatchSequenced;
    }

    /**
     * @notice Allows a trusted aggregator to verify multiple batches
     * @param rollupID Rollup identifier
     * @param pendingStateNum Init pending state, 0 if consolidated state is used (deprecated)
     * @param initNumBatch Batch which the aggregator starts the verification
     * @param finalNewBatch Last batch aggregator intends to verify
     * @param newLocalExitRoot New local exit root once the batch is processed
     * @param newStateRoot New State root once the batch is processed
     * @param beneficiary Address that will receive the verification reward
     * @param proof Fflonk proof
     */
    function verifyBatchesTrustedAggregator(
        uint32 rollupID,
        uint64 pendingStateNum,
        uint64 initNumBatch,
        uint64 finalNewBatch,
        bytes32 newLocalExitRoot,
        bytes32 newStateRoot,
        address beneficiary,
        bytes32[24] calldata proof
    ) external onlyRole(_TRUSTED_AGGREGATOR_ROLE) {
        // Pending state became deprecated,
        // It's still there just to have backwards compatibility interface
        if (pendingStateNum != 0) {
            revert PendingStateNumExist();
        }

        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        if (rollup.rollupVerifierType != VerifierType.StateTransition) {
            revert OnlyStateTransitionChains();
        }

        _verifyAndRewardBatches(
            rollup,
            initNumBatch,
            finalNewBatch,
            newLocalExitRoot,
            newStateRoot,
            beneficiary,
            proof
        );

        // Consolidate state
        rollup.lastVerifiedBatch = finalNewBatch;
        rollup.batchNumToStateRoot[finalNewBatch] = newStateRoot;
        rollup.lastLocalExitRoot = newLocalExitRoot;

        // Interact with globalExitRootManager
        globalExitRootManager.updateExitRoot(getRollupExitRoot());

        emit VerifyBatchesTrustedAggregator(
            rollupID,
            finalNewBatch,
            newStateRoot,
            newLocalExitRoot,
            msg.sender
        );
    }

    /**
     * @notice Verify and reward batches internal function
     * @param rollup Rollup Data storage pointer that will be used to the verification
     * @param initNumBatch Batch which the aggregator starts the verification
     * @param finalNewBatch Last batch aggregator intends to verify
     * @param newLocalExitRoot New local exit root once the batch is processed
     * @param newStateRoot New State root once the batch is processed
     * @param beneficiary Address that will receive the verification reward
     * @param proof Fflonk proof
     */
    function _verifyAndRewardBatches(
        RollupData storage rollup,
        uint64 initNumBatch,
        uint64 finalNewBatch,
        bytes32 newLocalExitRoot,
        bytes32 newStateRoot,
        address beneficiary,
        bytes32[24] calldata proof
    ) internal virtual {
        bytes32 oldStateRoot;

        uint64 currentLastVerifiedBatch = _getLastVerifiedBatch(rollup);

        if (initNumBatch < rollup.lastVerifiedBatchBeforeUpgrade) {
            revert InitBatchMustMatchCurrentForkID();
        }

        // Use consolidated state
        oldStateRoot = rollup.batchNumToStateRoot[initNumBatch];

        if (oldStateRoot == bytes32(0)) {
            revert OldStateRootDoesNotExist();
        }

        // Check initNumBatch is inside the range, sanity check
        if (initNumBatch > currentLastVerifiedBatch) {
            revert InitNumBatchAboveLastVerifiedBatch();
        }

        // Check final batch
        if (finalNewBatch <= currentLastVerifiedBatch) {
            revert FinalNumBatchBelowLastVerifiedBatch();
        }

        // Get snark bytes
        bytes memory snarkHashBytes = _getInputSnarkBytes(
            rollup,
            initNumBatch,
            finalNewBatch,
            newLocalExitRoot,
            oldStateRoot,
            newStateRoot
        );

        // Calculate the snark input
        uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD;

        // Verify proof
        if (
            !IVerifierRollup(rollup.verifier).verifyProof(proof, [inputSnark])
        ) {
            revert InvalidProof();
        }

        // Pay POL rewards
        uint64 newVerifiedBatches = finalNewBatch - currentLastVerifiedBatch;

        pol.safeTransfer(
            beneficiary,
            calculateRewardPerBatch() * newVerifiedBatches
        );

        // Update aggregation parameters
        totalVerifiedBatches += newVerifiedBatches;
        lastAggregationTimestamp = uint64(block.timestamp);

        // Callback to the rollup address
        IPolygonRollupBase(rollup.rollupContract).onVerifyBatches(
            finalNewBatch,
            newStateRoot,
            msg.sender
        );
    }

    /**
     * @notice Allows a trusted aggregator to verify pessimistic proof
     * @param rollupID Rollup identifier
     * @param l1InfoTreeLeafCount Count of the L1InfoTree leaf that will be used to verify imported bridge exits
     * @param newLocalExitRoot New local exit root
     * @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot)
     * @param proof SP1 proof (Plonk)
     * @param aggchainData Specific custom data to verify Aggregation layer chains
     * @dev A reentrancy measure has been applied because this function calls `onVerifyPessimistic`, is an open function implemented by the aggchains
     * @dev the function can not be a view because the nonReentrant uses a transient storage variable
     */
    function verifyPessimisticTrustedAggregator(
        uint32 rollupID,
        uint32 l1InfoTreeLeafCount,
        bytes32 newLocalExitRoot,
        bytes32 newPessimisticRoot,
        bytes calldata proof,
        bytes calldata aggchainData
    ) external onlyRole(_TRUSTED_AGGREGATOR_ROLE) nonReentrant {
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        // Not for state transition chains
        if (rollup.rollupVerifierType == VerifierType.StateTransition) {
            revert StateTransitionChainsNotAllowed();
        }

        // Not aggchainData for VerifierType.Pessimistic
        if (
            rollup.rollupVerifierType == VerifierType.Pessimistic &&
            aggchainData.length != 0
        ) {
            revert AggchainDataMustBeZeroForPessimisticVerifierType();
        }

        // Check l1InfoTreeLeafCount has a valid l1InfoTreeRoot
        bytes32 l1InfoRoot = globalExitRootManager.l1InfoRootMap(
            l1InfoTreeLeafCount
        );

        if (l1InfoRoot == bytes32(0)) {
            revert L1InfoTreeLeafCountInvalid();
        }

        // In case of a chain in migration, the inputs are a special case.
        if (isRollupMigrating[rollupID]) {
            // If we are migrating, the proof is proving a "bootstrapCertificate" containing all the bridges involved in the network since the genesis.
            // It's a hard requirement that the newLocalExitRoot matches the current lastLocalExitRoot meaning that the certificates covers all the bridges
            /// @dev  If the lastLocalExitRoot is zero, it means that the rollup has never verified a batch with bridges.
            ///       In this special case, newLocalExitRoot must also be zero as defined in the PP program circuit.
            require(
                newLocalExitRoot == rollup.lastLocalExitRoot,
                InvalidNewLocalExitRoot()
            );
            // In this special case, we consider lastLocalExitRoot is zero.
            // This is intentional, as we need a valid prover input.
            // Since the proof includes all bridges involved in the network, we assume
            // lastLocalExitRoot is bytes32(0), and the expectedNewLocalExitRoot will
            // already contain the full network state (lastLocalExitRoot).
            rollup.lastLocalExitRoot = bytes32(0);
            // Finally, after proving the "bootstrapCertificate", the migration will be completed
            isRollupMigrating[rollupID] = false;

            // Emit event
            emit CompletedMigration(rollupID);
        }

        bytes memory inputPessimisticBytes = _getInputPessimisticBytes(
            rollupID,
            rollup,
            l1InfoRoot,
            newLocalExitRoot,
            newPessimisticRoot,
            aggchainData
        );

        if (rollup.rollupVerifierType == VerifierType.ALGateway) {
            // Verify proof. The pessimistic proof selector is attached at the first 4 bytes of the proof
            // proof[0:4]: 4 bytes selector pp
            // proof[4:8]: 4 bytes selector SP1 verifier
            // proof[8:]: proof
            aggLayerGateway.verifyPessimisticProof(
                inputPessimisticBytes,
                proof
            );
        } else {
            // Verify proof
            ISP1Verifier(rollup.verifier).verifyProof(
                rollup.programVKey,
                inputPessimisticBytes,
                proof
            );
        }

        // Update aggregation parameters
        lastAggregationTimestamp = uint64(block.timestamp);

        // Consolidate state
        bytes32 prevLocalExitRoot = rollup.lastLocalExitRoot;
        rollup.lastLocalExitRoot = newLocalExitRoot;
        bytes32 prevPessimisticRoot = rollup.lastPessimisticRoot;
        rollup.lastPessimisticRoot = newPessimisticRoot;

        // Interact with globalExitRootManager
        globalExitRootManager.updateExitRoot(getRollupExitRoot());

        // Same event as verifyBatches to support current bridge service to synchronize everything
        /// @dev moved newLocalExitRoot to aux variable to avoid stack too deep errors at compilation
        bytes32 newLocalExitRootAux = newLocalExitRoot;
        emit VerifyBatchesTrustedAggregator(
            rollupID,
            0, // final batch: does not  apply in pessimistic
            bytes32(0), // new state root: does not apply in pessimistic
            newLocalExitRootAux,
            msg.sender
        );

        /// @dev emit a second event with more data, not updated/removed the other one for backwards compatibility reasons
        emit VerifyPessimisticStateTransition(
            rollupID,
            prevPessimisticRoot,
            newPessimisticRoot,
            prevLocalExitRoot,
            newLocalExitRootAux,
            l1InfoRoot,
            msg.sender
        );

        if (rollup.rollupVerifierType == VerifierType.ALGateway) {
            // Allow chains to manage customData
            // Callback to the rollup address
            IAggchainBase(rollup.rollupContract).onVerifyPessimistic(
                aggchainData
            );
        }
    }

    ////////////////////////
    // Emergency state functions
    ////////////////////////

    /**
     * @notice Function to activate emergency state, which also enables the emergency mode on both AgglayerManager and PolygonZkEVMBridge contracts
     * If not called by the owner must not have been aggregated in a _HALT_AGGREGATION_TIMEOUT period and an emergency state was not happened in the same period
     */
    function activateEmergencyState() external {
        if (!hasRole(_EMERGENCY_COUNCIL_ROLE, msg.sender)) {
            if (
                lastAggregationTimestamp == 0 ||
                lastAggregationTimestamp + _HALT_AGGREGATION_TIMEOUT >
                block.timestamp ||
                lastDeactivatedEmergencyStateTimestamp +
                    _HALT_AGGREGATION_TIMEOUT >
                block.timestamp
            ) {
                revert HaltTimeoutNotExpired();
            }
        }
        _activateEmergencyState();
    }

    /**
     * @notice Function to deactivate emergency state on both AgglayerManager and PolygonZkEVMBridge contracts
     */
    function deactivateEmergencyState()
        external
        onlyRole(_STOP_EMERGENCY_ROLE)
    {
        // Set last deactivated emergency state
        lastDeactivatedEmergencyStateTimestamp = uint64(block.timestamp);

        // Deactivate emergency state on PolygonZkEVMBridge
        bridgeAddress.deactivateEmergencyState();

        // Deactivate emergency state on this contract
        super._deactivateEmergencyState();
    }

    /**
     * @notice Internal function to activate emergency state on both AgglayerManager and PolygonZkEVMBridge contracts
     */
    function _activateEmergencyState() internal override {
        // Activate emergency state on PolygonZkEVM Bridge
        bridgeAddress.activateEmergencyState();

        // Activate emergency state on this contract
        super._activateEmergencyState();
    }

    //////////////////
    // Setter functions
    //////////////////

    /**
     * @notice Set the current batch fee
     * @param newBatchFee new batch fee
     */
    function setBatchFee(uint256 newBatchFee) external onlyRole(_SET_FEE_ROLE) {
        // check fees min and max
        if (newBatchFee > _MAX_BATCH_FEE || newBatchFee < _MIN_BATCH_FEE) {
            revert BatchFeeOutOfRange();
        }
        _batchFee = newBatchFee;
        emit SetBatchFee(newBatchFee);
    }

    ////////////////////////
    // view/pure functions
    ///////////////////////

    /**
     * @notice Get the current rollup exit root
     * Compute using all the local exit roots of all rollups the rollup exit root
     * Since it's expected to have no more than 10 rollups in this first version, even if this approach
     * has a gas consumption that scales linearly with the rollups added, it's ok
     * In a future versions this computation will be done inside the circuit
     */
    function getRollupExitRoot() public view returns (bytes32) {
        uint256 currentNodes = rollupCount;

        // If there are no nodes return 0
        if (currentNodes == 0) {
            return bytes32(0);
        }

        // This array will contain the nodes of the current iteration
        bytes32[] memory tmpTree = new bytes32[](currentNodes);

        // In the first iteration the nodes will be the leafs which are the local exit roots of each network
        for (uint256 i = 0; i < currentNodes; i++) {
            // The first rollup ID starts on 1
            tmpTree[i] = _rollupIDToRollupData[uint32(i + 1)].lastLocalExitRoot;
        }

        // This variable will keep track of the zero hashes
        bytes32 currentZeroHashHeight = 0;

        // This variable will keep track of the remaining levels to compute
        uint256 remainingLevels = _EXIT_TREE_DEPTH;

        // Calculate the root of the sub-tree that contains all the localExitRoots
        while (currentNodes != 1) {
            uint256 nextIterationNodes = currentNodes / 2 + (currentNodes % 2);
            bytes32[] memory nextTmpTree = new bytes32[](nextIterationNodes);
            for (uint256 i = 0; i < nextIterationNodes; i++) {
                // if we are on the last iteration of the current level and the nodes are odd
                if (i == nextIterationNodes - 1 && (currentNodes % 2) == 1) {
                    nextTmpTree[i] = Hashes.efficientKeccak256(
                        tmpTree[i * 2],
                        currentZeroHashHeight
                    );
                } else {
                    nextTmpTree[i] = Hashes.efficientKeccak256(
                        tmpTree[i * 2],
                        tmpTree[(i * 2) + 1]
                    );
                }
            }

            // Update tree variables
            tmpTree = nextTmpTree;
            currentNodes = nextIterationNodes;
            currentZeroHashHeight = Hashes.efficientKeccak256(
                currentZeroHashHeight,
                currentZeroHashHeight
            );
            remainingLevels--;
        }

        bytes32 currentRoot = tmpTree[0];

        // Calculate remaining levels, since it's a sequential merkle tree, the rest of the tree are zeroes
        for (uint256 i = 0; i < remainingLevels; i++) {
            currentRoot = Hashes.efficientKeccak256(
                currentRoot,
                currentZeroHashHeight
            );
            currentZeroHashHeight = Hashes.efficientKeccak256(
                currentZeroHashHeight,
                currentZeroHashHeight
            );
        }
        return currentRoot;
    }

    /**
     * @notice Get the last verified batch
     */
    function getLastVerifiedBatch(
        uint32 rollupID
    ) public view returns (uint64) {
        return _getLastVerifiedBatch(_rollupIDToRollupData[rollupID]);
    }

    /**
     * @notice Get the last verified batch
     */
    function _getLastVerifiedBatch(
        RollupData storage rollup
    ) internal view returns (uint64) {
        return rollup.lastVerifiedBatch;
    }

    /**
     * @notice Function to calculate the reward to verify a single batch
     */
    function calculateRewardPerBatch() public view returns (uint256) {
        uint256 currentBalance = pol.balanceOf(address(this));

        // Total Batches to be verified = total Sequenced Batches - total verified Batches
        uint256 totalBatchesToVerify = totalSequencedBatches -
            totalVerifiedBatches;

        if (totalBatchesToVerify == 0) return 0;
        return currentBalance / totalBatchesToVerify;
    }

    /**
     * @notice Get batch fee
     * This function is used instead of the automatic public view one,
     * because in a future might change the behavior and we will be able to maintain the interface
     */
    function getBatchFee() public view returns (uint256) {
        return _batchFee;
    }

    /**
     * @notice Get forced batch fee
     */
    function getForcedBatchFee() public view returns (uint256) {
        return _batchFee * 100;
    }

    /**
     * @notice Function to calculate the pessimistic input bytes
     * @param rollupID Rollup id used to calculate the input snark bytes
     * @param l1InfoTreeRoot L1 Info tree root to proof imported bridges
     * @param newLocalExitRoot New local exit root
     * @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot)
     * @param aggchainData Specific custom data to verify Aggregation layer chains
     */
    function getInputPessimisticBytes(
        uint32 rollupID,
        bytes32 l1InfoTreeRoot,
        bytes32 newLocalExitRoot,
        bytes32 newPessimisticRoot,
        bytes calldata aggchainData
    ) external view returns (bytes memory) {
        return
            _getInputPessimisticBytes(
                rollupID,
                _rollupIDToRollupData[rollupID],
                l1InfoTreeRoot,
                newLocalExitRoot,
                newPessimisticRoot,
                aggchainData
            );
    }

    /**
     * @notice Function to calculate the input snark bytes
     * @param rollupID Rollup identifier
     * @param rollup Rollup data storage pointer
     * @param l1InfoTreeRoot L1 Info tree root to proof imported bridges
     * @param newLocalExitRoot New local exit root
     * @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot)
     */
    function _getInputPessimisticBytes(
        uint32 rollupID,
        RollupData storage rollup,
        bytes32 l1InfoTreeRoot,
        bytes32 newLocalExitRoot,
        bytes32 newPessimisticRoot,
        bytes calldata aggchainData
    ) internal view returns (bytes memory inputPessimisticBytes) {
        // Different consensusHash and encoding if the rollup is ALGateway or pessimistic
        if (rollup.rollupVerifierType == VerifierType.ALGateway) {
            bytes32 aggchainHash = IAggchainBase(rollup.rollupContract)
                .getAggchainHash(aggchainData);

            inputPessimisticBytes = abi.encodePacked(
                rollup.lastLocalExitRoot,
                rollup.lastPessimisticRoot,
                l1InfoTreeRoot,
                rollupID,
                aggchainHash,
                newLocalExitRoot,
                newPessimisticRoot
            );
        } else {
            bytes32 consensusHash = IPolygonPessimisticConsensus(
                address(rollup.rollupContract)
            ).getConsensusHash();

            inputPessimisticBytes = abi.encodePacked(
                rollup.lastLocalExitRoot,
                rollup.lastPessimisticRoot,
                l1InfoTreeRoot,
                rollupID,
                consensusHash,
                newLocalExitRoot,
                newPessimisticRoot
            );
        }
    }

    /**
     * @notice Function to calculate the input snark bytes
     * @param rollupID Rollup id used to calculate the input snark bytes
     * @param initNumBatch Batch which the aggregator starts the verification
     * @param finalNewBatch Last batch aggregator intends to verify
     * @param newLocalExitRoot New local exit root once the batch is processed
     * @param oldStateRoot State root before batch is processed
     * @param newStateRoot New State root once the batch is processed
     */
    function getInputSnarkBytes(
        uint32 rollupID,
        uint64 initNumBatch,
        uint64 finalNewBatch,
        bytes32 newLocalExitRoot,
        bytes32 oldStateRoot,
        bytes32 newStateRoot
    ) public view returns (bytes memory) {
        return
            _getInputSnarkBytes(
                _rollupIDToRollupData[rollupID],
                initNumBatch,
                finalNewBatch,
                newLocalExitRoot,
                oldStateRoot,
                newStateRoot
            );
    }

    /**
     * @notice Function to calculate the input snark bytes
     * @param rollup Rollup data storage pointer
     * @param initNumBatch Batch which the aggregator starts the verification
     * @param finalNewBatch Last batch aggregator intends to verify
     * @param newLocalExitRoot New local exit root once the batch is processed
     * @param oldStateRoot State root before batch is processed
     * @param newStateRoot New State root once the batch is processed
     */
    function _getInputSnarkBytes(
        RollupData storage rollup,
        uint64 initNumBatch,
        uint64 finalNewBatch,
        bytes32 newLocalExitRoot,
        bytes32 oldStateRoot,
        bytes32 newStateRoot
    ) internal view returns (bytes memory) {
        // Sanity check
        bytes32 oldAccInputHash = rollup
            .sequencedBatches[initNumBatch]
            .accInputHash;

        bytes32 newAccInputHash = rollup
            .sequencedBatches[finalNewBatch]
            .accInputHash;

        // Sanity check
        if (initNumBatch != 0 && oldAccInputHash == bytes32(0)) {
            revert OldAccInputHashDoesNotExist();
        }

        if (newAccInputHash == bytes32(0)) {
            revert NewAccInputHashDoesNotExist();
        }

        // Check that new state root is inside goldilocks field
        if (!_checkStateRootInsidePrime(uint256(newStateRoot))) {
            revert NewStateRootNotInsidePrime();
        }

        return
            abi.encodePacked(
                msg.sender,
                oldStateRoot,
                oldAccInputHash,
                initNumBatch,
                rollup.chainID,
                rollup.forkID,
                newStateRoot,
                newAccInputHash,
                newLocalExitRoot,
                finalNewBatch
            );
    }

    /**
     * @notice Function to check if the state root is inside of the prime field
     * @param newStateRoot New State root once the batch is processed
     */
    function _checkStateRootInsidePrime(
        uint256 newStateRoot
    ) internal pure returns (bool) {
        if (
            ((newStateRoot & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) &&
            (((newStateRoot >> 64) & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) &&
            (((newStateRoot >> 128) & _MAX_UINT_64) <
                _GOLDILOCKS_PRIME_FIELD) &&
            ((newStateRoot >> 192) < _GOLDILOCKS_PRIME_FIELD)
        ) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @notice Get rollup state root given a batch number
     * @param rollupID Rollup identifier
     * @param batchNum Batch number
     */
    function getRollupBatchNumToStateRoot(
        uint32 rollupID,
        uint64 batchNum
    ) public view returns (bytes32) {
        return _rollupIDToRollupData[rollupID].batchNumToStateRoot[batchNum];
    }

    /**
     * @notice Get rollup sequence batches struct given a batch number
     * @param rollupID Rollup identifier
     * @param batchNum Batch number
     */
    function getRollupSequencedBatches(
        uint32 rollupID,
        uint64 batchNum
    ) public view returns (SequencedBatchData memory) {
        return _rollupIDToRollupData[rollupID].sequencedBatches[batchNum];
    }

    /**
     * @notice Get rollup data: VerifierType StateTransition
     * @param rollupID Rollup identifier
     */
    function rollupIDToRollupData(
        uint32 rollupID
    ) public view returns (RollupDataReturn memory rollupData) {
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        rollupData.rollupContract = rollup.rollupContract;
        rollupData.chainID = rollup.chainID;
        rollupData.verifier = rollup.verifier;
        rollupData.forkID = rollup.forkID;
        rollupData.lastLocalExitRoot = rollup.lastLocalExitRoot;
        rollupData.lastBatchSequenced = rollup.lastBatchSequenced;
        rollupData.lastVerifiedBatch = rollup.lastVerifiedBatch;
        rollupData._legacyLastPendingState = rollup._legacyLastPendingState;
        rollupData._legacyLastPendingStateConsolidated = rollup
            ._legacyLastPendingStateConsolidated;
        rollupData.lastVerifiedBatchBeforeUpgrade = rollup
            .lastVerifiedBatchBeforeUpgrade;
        rollupData.rollupTypeID = rollup.rollupTypeID;
        rollupData.rollupVerifierType = rollup.rollupVerifierType;
    }

    /**
     * @notice Get rollup data: VerifierType State transition
     * @param rollupID Rollup identifier
     */
    function rollupIDToRollupDataDeserialized(
        uint32 rollupID
    )
        public
        view
        returns (
            address rollupContract,
            uint64 chainID,
            address verifier,
            uint64 forkID,
            bytes32 lastLocalExitRoot,
            uint64 lastBatchSequenced,
            uint64 lastVerifiedBatch,
            uint64 legacyLastPendingState,
            uint64 legacyLastPendingStateConsolidated,
            uint64 lastVerifiedBatchBeforeUpgrade,
            uint64 rollupTypeID,
            VerifierType rollupVerifierType
        )
    {
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        rollupContract = rollup.rollupContract;
        chainID = rollup.chainID;
        verifier = rollup.verifier;
        forkID = rollup.forkID;
        lastLocalExitRoot = rollup.lastLocalExitRoot;
        lastBatchSequenced = rollup.lastBatchSequenced;
        lastVerifiedBatch = rollup.lastVerifiedBatch;
        legacyLastPendingState = rollup._legacyLastPendingState;
        legacyLastPendingStateConsolidated = rollup
            ._legacyLastPendingStateConsolidated;
        lastVerifiedBatchBeforeUpgrade = rollup.lastVerifiedBatchBeforeUpgrade;
        rollupTypeID = rollup.rollupTypeID;
        rollupVerifierType = rollup.rollupVerifierType;
    }

    /**
     * @notice Get rollup data: VerifierType Pessimistic
     * @param rollupID Rollup identifier
     */
    function rollupIDToRollupDataV2(
        uint32 rollupID
    ) public view returns (RollupDataReturnV2 memory rollupData) {
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        rollupData.rollupContract = rollup.rollupContract;
        rollupData.chainID = rollup.chainID;
        rollupData.verifier = rollup.verifier;
        rollupData.forkID = rollup.forkID;
        rollupData.lastLocalExitRoot = rollup.lastLocalExitRoot;
        rollupData.lastBatchSequenced = rollup.lastBatchSequenced;
        rollupData.lastVerifiedBatch = rollup.lastVerifiedBatch;
        rollupData.lastVerifiedBatchBeforeUpgrade = rollup
            .lastVerifiedBatchBeforeUpgrade;
        rollupData.rollupTypeID = rollup.rollupTypeID;
        rollupData.rollupVerifierType = rollup.rollupVerifierType;
        rollupData.lastPessimisticRoot = rollup.lastPessimisticRoot;
        rollupData.programVKey = rollup.programVKey;
    }

    /**
     * @notice Get rollup data deserialized
     * @dev A deserialized version of the rollup data done for a better parsing from etherscan
     * @param rollupID Rollup identifier
     */
    function rollupIDToRollupDataV2Deserialized(
        uint32 rollupID
    )
        public
        view
        returns (
            address rollupContract,
            uint64 chainID,
            address verifier,
            uint64 forkID,
            bytes32 lastLocalExitRoot,
            uint64 lastBatchSequenced,
            uint64 lastVerifiedBatch,
            uint64 lastVerifiedBatchBeforeUpgrade,
            uint64 rollupTypeID,
            VerifierType rollupVerifierType,
            bytes32 lastPessimisticRoot,
            bytes32 programVKey
        )
    {
        RollupData storage rollup = _rollupIDToRollupData[rollupID];

        rollupContract = rollup.rollupContract;
        chainID = rollup.chainID;
        verifier = rollup.verifier;
        forkID = rollup.forkID;
        lastLocalExitRoot = rollup.lastLocalExitRoot;
        lastBatchSequenced = rollup.lastBatchSequenced;
        lastVerifiedBatch = rollup.lastVerifiedBatch;
        lastVerifiedBatchBeforeUpgrade = rollup.lastVerifiedBatchBeforeUpgrade;
        rollupTypeID = rollup.rollupTypeID;
        rollupVerifierType = rollup.rollupVerifierType;
        lastPessimisticRoot = rollup.lastPessimisticRoot;
        programVKey = rollup.programVKey;
    }

    /**
     * @notice Function to retrieve the current version of the contract.
     * @return version of the contract.
     */
    function version() external pure returns (string memory) {
        return ROLLUP_MANAGER_VERSION;
    }
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity 0.8.28;

import "./IAggchainSigners.sol";

/**
 * @title IAggchainBaseEvents
 * @notice Events emitted by AggchainBase implementations
 */
interface IAggchainBaseEvents {
    /**
     * @notice Emitted when the admin adds an aggchain verification key.
     * @param selector The selector of the verification key to add.
     * @param newAggchainVKey The new aggchain verification key.
     */
    event AddAggchainVKey(bytes4 selector, bytes32 newAggchainVKey);
    /**
     * @notice Emitted when the admin updates the aggchain verification key.
     * @param selector The selector of the verification key to update.
     * @param previousAggchainVKey The previous aggchain verification key.
     * @param newAggchainVKey The new new aggchain verification key.
     */
    event UpdateAggchainVKey(
        bytes4 selector,
        bytes32 previousAggchainVKey,
        bytes32 newAggchainVKey
    );
    /**
     * @notice Emitted when the admin set the flag useDefaultVkeys to true.
     */
    event EnableUseDefaultVkeysFlag();

    /**
     * @notice Emitted when the admin set the flag useDefaultVkeys to false.
     */
    event DisableUseDefaultVkeysFlag();

    /**
     * @notice Emitted when the admin set the flag useDefaultSigners to true.
     */
    event EnableUseDefaultSignersFlag();

    /**
     * @notice Emitted when the admin set the flag useDefaultSigners to false.
     */
    event DisableUseDefaultSignersFlag();

    /// @dev Emitted when the aggchainManager starts the two-step transfer role setting a new pending newAggchainManager
    /// @param currentAggchainManager The current pending aggchainManager
    /// @param newPendingAggchainManager The new pending aggchainManager
    event TransferAggchainManagerRole(
        address currentAggchainManager,
        address newPendingAggchainManager
    );

    /// @notice Emitted when the pending aggchainManager accepts the aggchainManager role
    /// @param oldAggchainManager The old aggchainManager
    /// @param newAggchainManager The new aggchainManager
    event AcceptAggchainManagerRole(
        address oldAggchainManager,
        address newAggchainManager
    );

    /**
     * @notice Emitted when metadata is set or updated.
     * @param key The metadata key.
     * @param value The metadata value.
     */
    event AggchainMetadataSet(string indexed key, string value);

    /**
     * @notice Emitted when the aggchain metadata manager is set.
     * @param oldAggchainMetadataManager The old aggchain metadata manager.
     * @param newAggchainMetadataManager The new aggchain metadata manager.
     */
    event SetAggchainMetadataManager(
        address oldAggchainMetadataManager,
        address newAggchainMetadataManager
    );
}

/**
 * @title IAggchainBaseErrors
 * @notice Error definitions for AggchainBase implementations
 */
interface IAggchainBaseErrors {
    /// @notice Thrown when trying to add zero value verification key.
    error ZeroValueAggchainVKey();
    /// @notice Thrown when trying to add an aggchain verification key that already exists.
    error OwnedAggchainVKeyAlreadyAdded();
    /// @notice Thrown when trying to retrieve an aggchain verification key that does not exist.
    error OwnedAggchainVKeyNotFound();
    /// @notice Thrown when trying to initialize the incorrect initialize function.
    error InvalidInitializeFunction();
    /// @notice Thrown when trying to enable the default vkeys when it is already enabled.
    error UseDefaultVkeysAlreadyEnabled();
    /// @notice Thrown when trying to disable the default vkeys when it is already disabled.
    error UseDefaultVkeysAlreadyDisabled();
    /// @notice Thrown when trying to enable the default signers when it is already enabled.
    error UseDefaultSignersAlreadyEnabled();
    /// @notice Thrown when trying to disable the default signers when it is already disabled.
    error UseDefaultSignersAlreadyDisabled();
    /// @notice Thrown when trying to retrieve an aggchain verification key from the mapping that doesn't exists.
    error AggchainVKeyNotFound();
    /// @notice Thrown when trying to set the aggchain manager to zero address.
    error AggchainManagerCannotBeZero();
    /// @notice Thrown when the aggchain manager is already initialized.
    error AggchainManagerAlreadyInitialized();
    /// @notice Thrown when an invalid initial aggchain vkey is provided.
    error InvalidInitAggchainVKey();
    /// @notice Thrown when trying to use default signers but also providing signers to add
    error ConflictingDefaultSignersConfiguration();
    /// @notice Thrown when the caller is not the aggchain manager
    error OnlyAggchainManager();
    /// @notice Thrown when the caller is not the pending aggchain manager
    error OnlyPendingAggchainManager();
    /// @notice Thrown when trying to call a function with an input zero address
    error InvalidZeroAddress();
    /// @notice Thrown when the aggchainData has an invalid format
    error InvalidAggchainDataLength();
    /// @notice Thrown when the aggchainvKeySelector contains an invalid aggchain type.
    error InvalidAggchainType();
    /// @notice Thrown when threshold is zero, greater than the number of aggchainSigners.
    error InvalidThreshold();
    /// @notice Thrown when trying to add a signer that already exists.
    error SignerAlreadyExists();
    /// @notice Thrown when trying to remove a signer that doesn't exist.
    error SignerDoesNotExist();
    /// @notice Thrown when trying to add a zero address as a signer.
    error SignerCannotBeZero();
    /// @notice Thrown when the aggchainSingers is greater than 255.
    error AggchainSignersTooHigh();
    /// @notice Thrown when trying to add a signer with an empty URL.
    error SignerURLCannotBeEmpty();
    /// @notice Thrown when the indices for signer removal are not in descending order.
    error IndicesNotInDescendingOrder();
    /// @notice Thrown when trying to compute the aggchain hash without initializing the signers hash.
    error AggchainSignersHashNotInitialized();
    /// @notice Thrown when the keys and values arrays have different lengths in batch metadata operations.
    error MetadataArrayLengthMismatch();
    /// @notice Thrown when the caller is not the aggchain metadata manager
    error OnlyAggchainMetadataManager();
}

/**
 * @title IAggchainBase
 * @notice Core interface for aggchain implementations
 * @dev All aggchain contracts must implement these functions for integration with the rollup manager.
 *      Different implementations (FEP, ECDSA) may handle these functions differently based on their consensus mechanism.
 */
interface IAggchainBase is
    IAggchainBaseErrors,
    IAggchainBaseEvents,
    IAggchainSigners
{
    /**
     * @notice Gets aggchain hash for consensus verification
     * @dev Each implementation computes this hash differently based on its consensus mechanism.
     *      The hash is used by the rollup manager to verify state transitions.
     * @param aggchainData Custom chain data to build the consensus hash
     * @return The computed aggchain hash for verification
     */
    function getAggchainHash(
        bytes calldata aggchainData
    ) external view returns (bytes32);

    /**
     * @notice Callback from the AgglayerManager after successful pessimistic proof verification
     * @dev Each implementation handles state updates differently
     * @param aggchainData Custom chain data containing state update information
     */
    function onVerifyPessimistic(bytes calldata aggchainData) external;

    /**
     * @notice Sets the initial aggchain manager during contract deployment
     * @dev Can only be called once by the rollup manager during initialization.
     *      The aggchain manager has privileged access to modify consensus parameters.
     * @param newAggchainManager The address of the new aggchain manager
     */
    function initAggchainManager(address newAggchainManager) external;

    /// @notice Returns the unique aggchain type identifier.
    function AGGCHAIN_TYPE() external view returns (bytes2);

    /**
     * @notice Returns the current aggchain manager address
     * @dev The aggchain manager has administrative privileges over consensus parameters
     * @return The address of the current aggchain manager
     */
    function aggchainManager() external view returns (address);
}

// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;

/**
 * @title IAggchainSigners
 * @notice Interface for multisig signer management functionality
 * @dev This interface is implemented by both AggchainBase contracts and AgglayerGateway,
 *      providing a unified way to manage signers for consensus verification.
 *      Implementations may use local storage or delegate to a gateway contract.
 */
interface IAggchainSigners {
    ////////////////////////////////////////////////////////////
    //                       Structs                          //
    ////////////////////////////////////////////////////////////

    /**
     * @notice Struct to hold signer information
     * @param addr The address of the signer
     * @param url The URL associated with the signer
     */
    struct SignerInfo {
        address addr;
        string url;
    }

    /**
     * @notice Struct to hold information for removing a signer
     * @param addr The address of the signer to remove
     * @param index The index of the signer in the aggchainSigners array
     */
    struct RemoveSignerInfo {
        address addr;
        uint256 index;
    }

    /**
     * @notice Emitted when signers and threshold are updated in a batch operation.
     * @param aggchainSigners The updated array of signer addresses.
     * @param newThreshold The new threshold value.
     * @param newAggchainMultisigHash The new hash of the aggchainMultisig configuration.
     */
    event SignersAndThresholdUpdated(
        address[] aggchainSigners,
        uint256 newThreshold,
        bytes32 newAggchainMultisigHash
    );

    ////////////////////////////////////////////////////////////
    //                    View Functions                      //
    ////////////////////////////////////////////////////////////

    /**
     * @notice Check if an address is a signer
     * @param _signer Address to check
     * @return True if the address is a signer
     */
    function isSigner(address _signer) external view returns (bool);

    /**
     * @notice Get the minimum number of signatures required for consensus
     * @dev Returns the threshold value for multisig validation
     * @return threshold Minimum number of signatures required
     */
    function getThreshold() external view returns (uint256);

    /**
     * @notice Get the total number of registered signers
     * @dev Returns the count of active signers in the multisig
     * @return count Total number of aggchainSigners currently registered
     */
    function getAggchainSignersCount() external view returns (uint256);

    /**
     * @notice Get all registered signer addresses
     * @dev Returns the complete list of active signers
     * @return signers Array containing all signer addresses
     */
    function getAggchainSigners() external view returns (address[] memory);

    /**
     * @notice Returns the hash of current multisig configuration
     * @dev Computed as keccak256(abi.encodePacked(threshold, aggchainSigners)).
     *      Used by aggchain contracts for efficient consensus verification.
     * @return multisigHash The current aggchainMultisigHash for validation
     */
    function getAggchainMultisigHash() external view returns (bytes32);

    /**
     * @notice Get detailed information for all registered signers
     * @dev Returns both addresses and associated URLs/endpoints for each signer
     * @return signerInfos Array of SignerInfo structs containing complete signer details
     */
    function getAggchainSignerInfos()
        external
        view
        returns (SignerInfo[] memory);
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;
import "./IBaseLegacyAgglayerGER.sol";

interface IAgglayerBridge {
    /**
     * @dev Thrown when the destination network is invalid
     */
    error DestinationNetworkInvalid();

    /**
     * @dev Thrown when the amount does not match msg.value
     */
    error AmountDoesNotMatchMsgValue();

    /**
     * @dev Thrown when user is bridging tokens and is also sending a value
     */
    error MsgValueNotZero();

    /**
     * @dev Thrown when the Ether transfer on claimAsset fails
     */
    error EtherTransferFailed();

    /**
     * @dev Thrown when the message transaction on claimMessage fails
     */
    error MessageFailed();

    /**
     * @dev Thrown when the global exit root does not exist
     */
    error GlobalExitRootInvalid();

    /**
     * @dev Thrown when the smt proof does not match
     */
    error InvalidSmtProof();

    /**
     * @dev Thrown when an index is already claimed
     */
    error AlreadyClaimed();

    /**
     * @dev Thrown when the amount of the permit does not match
     */
    error NotValidAmount();

    /**
     * @dev Thrown when sender is not the rollup manager
     */
    error OnlyRollupManager();

    /**
     * @dev Thrown when the permit data contains an invalid signature
     */
    error NativeTokenIsEther();

    /**
     * @dev Thrown when the permit data contains an invalid signature
     */
    error NoValueInMessagesOnGasTokenNetworks();

    /**
     * @dev Thrown when the permit data contains an invalid signature
     */
    error GasTokenNetworkMustBeZeroOnEther();

    /**
     * @dev Thrown when the wrapped token proxy deployment fails
     */
    error FailedProxyDeployment();

    /**
     * @dev Thrown when try to set a zero address to a non valid zero address field
     */
    error InvalidZeroAddress();

    /**
     * @dev Thrown when sender is not the proxied tokens manager
     */
    error OnlyProxiedTokensManager();

    /**
     * @dev Thrown when trying to call a function that only the pending ProxiedTokensManager can call.
     */
    error OnlyPendingProxiedTokensManager();

    /**
     * @dev Thrown when trying to set bridgeAddress to as proxied tokens manager role.
     */
    error BridgeAddressNotAllowed();

    /**
     * @dev Thrown when trying to initialize the incorrect initialize function
     */
    error InvalidInitializeFunction();

    /**
     * @dev Thrown when failing to retrieve the owner from proxyAdmin
     */
    error InvalidProxyAdmin(address proxyAdmin);

    /**
     * @dev Thrown when the owner of a proxyAdmin is zero address
     */
    error InvalidZeroProxyAdminOwner(address proxyAdmin);

    /**
     * @dev Thrown when the global index has any unused bits set to 1
     */
    error InvalidGlobalIndex();

    function wrappedTokenToTokenInfo(
        address destinationAddress
    ) external view returns (uint32, address);

    function updateGlobalExitRoot() external;

    function activateEmergencyState() external;

    function deactivateEmergencyState() external;

    function bridgeAsset(
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        address token,
        bool forceUpdateGlobalExitRoot,
        bytes calldata permitData
    ) external payable;

    function bridgeMessage(
        uint32 destinationNetwork,
        address destinationAddress,
        bool forceUpdateGlobalExitRoot,
        bytes calldata metadata
    ) external payable;

    function bridgeMessageWETH(
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amountWETH,
        bool forceUpdateGlobalExitRoot,
        bytes calldata metadata
    ) external;

    function claimAsset(
        bytes32[32] calldata smtProofLocalExitRoot,
        bytes32[32] calldata smtProofRollupExitRoot,
        uint256 globalIndex,
        bytes32 mainnetExitRoot,
        bytes32 rollupExitRoot,
        uint32 originNetwork,
        address originTokenAddress,
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        bytes calldata metadata
    ) external;

    function claimMessage(
        bytes32[32] calldata smtProofLocalExitRoot,
        bytes32[32] calldata smtProofRollupExitRoot,
        uint256 globalIndex,
        bytes32 mainnetExitRoot,
        bytes32 rollupExitRoot,
        uint32 originNetwork,
        address originAddress,
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        bytes calldata metadata
    ) external;

    function initialize(
        uint32 _networkID,
        address _gasTokenAddress,
        uint32 _gasTokenNetwork,
        IBaseLegacyAgglayerGER _globalExitRootManager,
        address _polygonRollupManager,
        bytes memory _gasTokenMetadata
    ) external;

    function getTokenMetadata(
        address token
    ) external view returns (bytes memory);

    function getWrappedTokenBridgeImplementation()
        external
        view
        returns (address);

    function getProxiedTokensManager() external view returns (address);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "./IAggchainSigners.sol";

// based on: https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol

interface IAgglayerGatewayEvents {
    /// @notice Emitted when a verifier route is added.
    /// @param selector The verifier selector that was added.
    /// @param verifier The address of the verifier contract.
    /// @param pessimisticVKey The verification key
    event RouteAdded(
        bytes4 selector,
        address verifier,
        bytes32 pessimisticVKey
    );

    /// @notice Emitted when a verifier route is frozen.
    /// @param selector The verifier selector that was frozen.
    /// @param verifier The address of the verifier contract.
    event RouteFrozen(
        bytes4 selector,
        address verifier,
        bytes32 pessimisticVKey
    );

    /**
     * Emitted when a new default aggchain verification key is added
     * @param selector The 4 bytes selector of the added default aggchain verification key.
     * @param newVKey New aggchain verification key to be added
     */
    event AddDefaultAggchainVKey(bytes4 selector, bytes32 newVKey);

    /**
     * Emitted when a default aggchain verification key is update
     * @param selector The 4 bytes selector of the updated default aggchain verification key.
     * @param previousVKey Aggchain verification key previous value
     * @param newVKey Aggchain verification key updated value
     */
    event UpdateDefaultAggchainVKey(
        bytes4 selector,
        bytes32 previousVKey,
        bytes32 newVKey
    );

    /**
     * Emitted when a default aggchain verification key is set to zero
     * @param selector The 4 bytes selector of the updated default aggchain verification key.
     */
    event UnsetDefaultAggchainVKey(bytes4 selector);
}

/// @dev Extended error events from https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGatewayErrors {
    /// @notice Thrown when the verifier route is not found.
    /// @param selector The verifier selector that was specified.
    error RouteNotFound(bytes4 selector);

    /// @notice Thrown when the verifier route is found, but is frozen.
    /// @param selector The verifier selector that was specified.
    error RouteIsFrozen(bytes4 selector);

    /// @notice Thrown when trying to freeze a route that is already frozen.
    /// @param selector The pessimistic verification key selector that was specified.
    error RouteIsAlreadyFrozen(bytes4 selector);

    /// @notice Thrown when adding a verifier route and the selector already contains a route.
    /// @param selector The pessimistic verification key selector that was specified.
    /// @param verifier The address of the verifier contract in the existing route.
    error RouteAlreadyExists(bytes4 selector, address verifier);

    /// @notice Thrown when adding a verifier route and the selector returned by the verifier is
    /// zero.
    error PPSelectorCannotBeZero();

    /// @notice Thrown when adding a verifier key with value zero
    error VKeyCannotBeZero();

    /// @notice Thrown when the caller is not the AggLayerAdmin
    error OnlyAggLayerAdmin();

    //// @notice Thrown when the caller is not the pending AggLayerAdmin
    error OnlyPendingAggLayerAdmin();

    /// @notice Thrown when trying to add an aggchain verification key that already exists
    error AggchainVKeyAlreadyExists();

    /// @notice Thrown when trying to retrieve an aggchain verification key from the mapping that doesn't exists
    error AggchainVKeyNotFound();

    /// @notice Thrown when trying to call a function with an input zero address
    error InvalidZeroAddress();

    /// @notice Thrown when trying to call a function with an invalid initializer version
    error InvalidInitializer();

    /// @notice Thrown when the input proof bytes are invalid.
    error InvalidProofBytesLength();

    /// @notice Thrown when the aggchain signers hash has not been initialized
    error AggchainSignersHashNotInitialized();

    /// @notice Thrown when indices for signer removal are not in descending order
    error IndicesNotInDescendingOrder();

    /// @notice Thrown when trying to set more than 255 signers
    error AggchainSignersTooHigh();

    /// @notice Thrown when the threshold exceeds the number of signers
    error InvalidThreshold();

    /// @notice Thrown when trying to add a zero address as signer
    error SignerCannotBeZero();

    /// @notice Thrown when trying to add a signer with empty URL
    error SignerURLCannotBeEmpty();

    /// @notice Thrown when trying to add a signer that already exists
    error SignerAlreadyExists();

    /// @notice Thrown when trying to remove a signer that doesn't exist
    error SignerDoesNotExist();
}

/// @title IAgglayerGateway
/// @notice This contract is the interface for the AgglayerGateway.
/// @notice Based on https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGateway is
    IAgglayerGatewayEvents,
    IAgglayerGatewayErrors,
    IAggchainSigners
{
    /**
     * Struct that defines a verifier route
     * @param verifier The address of the verifier contract.
     * @param pessimisticVKey The verification key to be used for verifying pessimistic proofs.
     * @param frozen Whether the route is frozen.
     */
    struct AggLayerVerifierRoute {
        address verifier; // SP1 Verifier. It contains sanity check SP1 version with the 4 first bytes of the proof. proof[4:]
        bytes32 pessimisticVKey;
        bool frozen;
    }

    /**
     * @notice returns the current aggchain verification key, used to verify chain's FEP.
     * @dev This function is necessary to query the map from an external function. In solidity maps are not
     * directly accessible from external functions like other state variables.
     */
    function getDefaultAggchainVKey(
        bytes4 defaultAggchainSelector
    ) external view returns (bytes32);

    /// @notice Verifies a pessimistic proof with given public values and proof.
    /// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
    /// target verifier's VERIFIER_HASH.
    /// @param publicValues The public values encoded as bytes.
    /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
    function verifyPessimisticProof(
        bytes calldata publicValues,
        bytes calldata proofBytes
    ) external view;

    /// @notice Adds a verifier route. This enable proofs to be routed to this verifier.
    /// @dev Only callable by the owner. The owner is responsible for ensuring that the specified
    /// verifier is correct with a valid VERIFIER_HASH. Once a route to a verifier is added, it
    /// cannot be removed.
    /// @param pessimisticVKeySelector The verifier selector to add.
    /// @param verifier The address of the verifier contract. This verifier MUST implement the
    /// ISP1VerifierWithHash interface.
    /// @param pessimisticVKey The verification key to be used for verifying pessimistic proofs.
    function addPessimisticVKeyRoute(
        bytes4 pessimisticVKeySelector,
        address verifier,
        bytes32 pessimisticVKey
    ) external;

    /// @notice Freezes a verifier route. This prevents proofs from being routed to this verifier.
    /// @dev Only callable by the owner. Once a route to a verifier is frozen, it cannot be
    /// unfrozen.
    /// @param pessimisticVKeySelector The verifier selector to freeze.
    function freezePessimisticVKeyRoute(
        bytes4 pessimisticVKeySelector
    ) external;

    ////////////////////////////////////////////////////////////
    //                  Multisig Functions                    //
    ////////////////////////////////////////////////////////////

    /**
     * @notice Updates signers and threshold for multisig operations
     * @dev Removes signers first (in descending index order), then adds new signers, then updates threshold
     * @param _signersToRemove Array of signers to remove with their indices (MUST be in descending index order)
     * @param _signersToAdd Array of new signers to add with their URLs
     * @param _newThreshold New threshold value
     */
    function updateSignersAndThreshold(
        RemoveSignerInfo[] memory _signersToRemove,
        SignerInfo[] memory _signersToAdd,
        uint256 _newThreshold
    ) external;
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;
import "./IBaseLegacyAgglayerGER.sol";

interface IAgglayerGER is IBaseLegacyAgglayerGER {
    function getLastGlobalExitRoot() external view returns (bytes32);

    function getRoot() external view returns (bytes32);

    function l1InfoRootMap(uint32 depositCount) external view returns (bytes32);
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

import "./IVerifierRollup.sol";
import "./IPolygonRollupBase.sol";
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts5/proxy/transparent/TransparentUpgradeableProxy.sol";

interface IAgglayerManager {
    /**
     * @dev Thrown when sender is not the PolygonZkEVM address
     */
    error UpdateToSameRollupTypeID();

    /**
     * @dev Thrown when sender is not the PolygonZkEVM address
     */
    error RollupMustExist();

    /**
     * @dev Thrown when sender is not the PolygonZkEVM address
     */
    error SenderMustBeRollup();

    /**
     * @dev Thrown when sender is not the PolygonZkEVM address
     */
    error TrustedAggregatorTimeoutNotExpired();

    /**
     * @dev Thrown when sender is not the PolygonZkEVM address
     */
    error ExceedMaxVerifyBatches();

    /**
     * @dev Thrown when attempting to access a pending state that does not exist
     */
    error PendingStateDoesNotExist();

    /**
     * @dev Thrown when the init num batch does not match with the one in the pending state
     */
    error InitNumBatchDoesNotMatchPendingState();

    /**
     * @dev Thrown when the old state root of a certain batch does not exist
     */
    error OldStateRootDoesNotExist();

    /**
     * @dev Thrown when the init verification batch is above the last verification batch
     */
    error InitNumBatchAboveLastVerifiedBatch();

    /**
     * @dev Thrown when the final verification batch is below or equal the last verification batch
     */
    error FinalNumBatchBelowLastVerifiedBatch();

    /**
     * @dev Thrown when the zkproof is not valid
     */
    error InvalidProof();

    /**
     * @dev Thrown when attempting to consolidate a pending state not yet consolidable
     */
    error PendingStateNotConsolidable();

    /**
     * @dev Thrown when attempting to consolidate a pending state that is already consolidated or does not exist
     */
    error PendingStateInvalid();

    /**
     * @dev Thrown when the new accumulate input hash does not exist
     */
    error NewAccInputHashDoesNotExist();

    /**
     * @dev Thrown when the new state root is not inside prime
     */
    error NewStateRootNotInsidePrime();

    /**
     * @dev Thrown when the final pending state num is not in a valid range
     */
    error FinalPendingStateNumInvalid();

    /**
     * @dev Thrown when the final num batch does not match with the one in the pending state
     */
    error FinalNumBatchDoesNotMatchPendingState();

    /**
     * @dev Thrown when the stored root matches the new root proving a different state
     */
    error StoredRootMustBeDifferentThanNewRoot();

    /**
     * @dev Thrown when the halt timeout is not expired when attempting to activate the emergency state
     */
    error HaltTimeoutNotExpired();

    /**
     * @dev Thrown when the old accumulate input hash does not exist
     */
    error OldAccInputHashDoesNotExist();

    /**
     * @dev Thrown when attempting to set a new trusted aggregator timeout equal or bigger than current one
     */
    error NewTrustedAggregatorTimeoutMustBeLower();

    /**
     * @dev Thrown when attempting to set a new pending state timeout equal or bigger than current one
     */
    error NewPendingStateTimeoutMustBeLower();

    /**
     * @dev Thrown when attempting to set a new multiplier batch fee in a invalid range of values
     */
    error InvalidRangeMultiplierBatchFee();

    /**
     * @dev Thrown when attempting to set a batch time target in an invalid range of values
     */
    error InvalidRangeBatchTimeTarget();

    /**
     * @dev Thrown when the caller is not the pending admin
     */
    error ChainIDAlreadyExist();

    /**
     * @dev Thrown when the caller is not the pending admin
     */
    error MustSequenceSomeBatch();

    /**
     * @dev When a rollup type does not exist
     */
    error RollupTypeDoesNotExist();

    /**
     * @dev When a rollup type does not exist
     */
    error RollupTypeObsolete();

    /**
     * @dev When a rollup type does not exist
     */
    error InitBatchMustMatchCurrentForkID();

    /**
     * @dev When a rollup type does not exist
     */
    error UpdateNotCompatible();

    /**
     * @dev When a rollup type does not exist
     */
    error BatchFeeOutOfRange();

    /**
     * @dev When a rollup type does not exist
     */
    error AllzkEVMSequencedBatchesMustBeVerified();

    /**
     * @dev When adding an existing rollup where the rollup address already was added
     */
    error RollupAddressAlreadyExist();

    /**
     * @dev When verifying proof for multiple roolups and they are not ordered by ID
     */
    error RollupIDNotAscendingOrder();

    /**
     * @dev When try to create a new rollup and set a chainID bigger than 32 bits
     */
    error ChainIDOutOfRange();

    /**
     * @dev When try to upgrade a rollup a sender that's not the admin of the rollup
     */
    error OnlyRollupAdmin();

    /**
     * @dev When try to upgrade a rollup a sender that's not the aggchain manager
     */
    error OnlyAggchainManager();

    /**
     * @dev When try to update a rollup with sequences pending to verify
     */
    error AllSequencedMustBeVerified();

    /**
     * @dev Thrown when do not sequence any blob
     */
    error MustSequenceSomeBlob();

    /**
     * @dev Thrown when the final verification sequence is below or equal the last verification sequence
     */
    error FinalNumSequenceBelowLastVerifiedSequence();

    /**
     * @dev When the init sequence was verified in another forkID
     */
    error InitSequenceMustMatchCurrentForkID();

    /**
     * @dev Thrown when the init num sequence does not match with the one in the pending state
     */
    error InitSequenceNumDoesNotMatchPendingState();

    /**
     * @dev Thrown when the final num sequence does not match with the one in the pending state
     */
    error FinalNumSequenceDoesNotMatchPendingState();

    /**
     * @dev Thrown when attempting to set a new multiplier zkgas in a invalid range of values
     */
    error InvalidRangeMultiplierZkGasPrice();

    /**
     * @dev Thrown when attempting to set a seuqnece time target in an invalid range of values
     */
    error InvalidRangeSequenceTimeTarget();

    /**
     * @dev When a set a zkgasprice out of range
     */
    error zkGasPriceOfRange();

    /**
     * @dev Cannot update from network admin with unconsolidated pending state
     */
    error CannotUpdateWithUnconsolidatedPendingState();

    /**
     * @dev Try to verify batches without any sequence data
     */
    error EmptyVerifySequencesData();

    /**
     * @dev Update to old rollup ID
     */
    error UpdateToOldRollupTypeID();

    /**
     * @dev All batches must be verified before the upgrade
     */
    error AllBatchesMustBeVerified();

    /**
     * @dev Rollback batch is not sequenced
     */
    error RollbackBatchIsNotValid();

    /**
     * @dev Rollback batch is not the end of any sequence
     */
    error RollbackBatchIsNotEndOfSequence();

    /**
     * @dev rollbackBatches is called from a non authorized address
     */
    error NotAllowedAddress();

    /**
     * @dev Invalid Rollup type parameters
     */
    error InvalidRollupType();

    /**
     * @dev Invalid Rollup parameters
     */
    error InvalidRollup();

    /**
     * @dev Not valid L1 info tree leaf count
     */
    error L1InfoTreeLeafCountInvalid();

    /**
     * @dev Only State Transition Chains
     */
    error OnlyStateTransitionChains();

    /**
     * @dev Pending state num exist
     */
    error PendingStateNumExist();

    /**
     * @dev Thrown when a function is executed for a State transition chains when it is not allowed
     * @dev This function was previously called `OnlyChainsWithPessimisticProofs`but with the new ALGateway verifier Type
     *      state transitions must be excluded
     */
    error StateTransitionChainsNotAllowed();

    /**
     * @dev Custom chain data must be zero for pessimistic verifier type
     */
    error AggchainDataMustBeZeroForPessimisticVerifierType();

    /**
     * @dev Invalid Pessimistic proof
     */
    error InvalidPessimisticProof();

    /**
     * @dev Invalid Verifier Type when getting rollup data
     */
    error InvalidVerifierType();

    /**
     * @dev Thrown when trying to deploy rollup Manager with some zero address as the input
     */
    error InvalidConstructorInputs();

    /**
     * @dev Thrown when trying to create a rollup but the input parameters are not  according with the chosen rollupType
     */
    error InvalidInputsForRollupType();

    /**
     * @dev Thrown when trying to add an existing rollup or create a new rollup type with an invalid consensus implementation address
     */
    error InvalidImplementationAddress();

    /**
     * @dev Thrown when trying to create rollup or rollup type with an invalid verifier address
     */
    error InvalidVerifierAddress();

    /**
     * @dev Thrown when trying to migrate a rollup to a non pessimistic rollup type with `initMigration` function.
     */
    error NewRollupTypeMustBePessimisticOrALGateway();

    /**
     * @dev Thrown when trying to finish a migration of a rollup to a pessimistic rollup type with `verifyPessimisticTrustedAggregator` function and the proposed new local exit root does not match the expected new local exit root
     */
    error InvalidNewLocalExitRoot();

    enum VerifierType {
        StateTransition,
        Pessimistic,
        ALGateway
    }

    function addNewRollupType(
        address consensusImplementation,
        address verifier,
        uint64 forkID,
        VerifierType rollupVerifierType,
        bytes32 initRoot,
        string memory description,
        bytes32 programVKey
    ) external;

    function obsoleteRollupType(uint32 rollupTypeID) external;

    function attachAggchainToAL(
        uint32 rollupTypeID,
        uint64 chainID,
        bytes memory initializeBytesAggchain
    ) external;

    function addExistingRollup(
        address rollupAddress,
        address verifier,
        uint64 forkID,
        uint64 chainID,
        bytes32 initRoot,
        VerifierType rollupVerifierType,
        bytes32 programVKey,
        bytes32 initPessimisticRoot
    ) external;

    function updateRollupByRollupAdmin(
        ITransparentUpgradeableProxy rollupContract,
        uint32 newRollupTypeID
    ) external;

    function updateRollup(
        ITransparentUpgradeableProxy rollupContract,
        uint32 newRollupTypeID,
        bytes memory upgradeData
    ) external;

    function rollbackBatches(
        IPolygonRollupBase rollupContract,
        uint64 targetBatch
    ) external;

    function onSequenceBatches(
        uint64 newSequencedBatches,
        bytes32 newAccInputHash
    ) external returns (uint64);

    function verifyBatchesTrustedAggregator(
        uint32 rollupID,
        uint64 pendingStateNum,
        uint64 initNumBatch,
        uint64 finalNewBatch,
        bytes32 newLocalExitRoot,
        bytes32 newStateRoot,
        address beneficiary,
        bytes32[24] calldata proof
    ) external;

    function verifyPessimisticTrustedAggregator(
        uint32 rollupID,
        uint32 l1InfoTreeLeafCount,
        bytes32 newLocalExitRoot,
        bytes32 newPessimisticRoot,
        bytes calldata proof,
        bytes memory aggchainData
    ) external;

    function activateEmergencyState() external;

    function deactivateEmergencyState() external;

    function setBatchFee(uint256 newBatchFee) external;

    function getRollupExitRoot() external view returns (bytes32);

    function getLastVerifiedBatch(
        uint32 rollupID
    ) external view returns (uint64);

    function calculateRewardPerBatch() external view returns (uint256);

    function getBatchFee() external view returns (uint256);

    function getForcedBatchFee() external view returns (uint256);

    function getInputPessimisticBytes(
        uint32 rollupID,
        bytes32 selectedGlobalExitRoot,
        bytes32 newLocalExitRoot,
        bytes32 newPessimisticRoot,
        bytes memory aggchainData
    ) external view returns (bytes memory);

    function getInputSnarkBytes(
        uint32 rollupID,
        uint64 initNumBatch,
        uint64 finalNewBatch,
        bytes32 newLocalExitRoot,
        bytes32 oldStateRoot,
        bytes32 newStateRoot
    ) external view returns (bytes memory);

    function getRollupBatchNumToStateRoot(
        uint32 rollupID,
        uint64 batchNum
    ) external view returns (bytes32);

    function lastDeactivatedEmergencyStateTimestamp()
        external
        view
        returns (uint64);
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

interface IBaseLegacyAgglayerGER {
    /**
     * @dev Thrown when the caller is not the allowed contracts
     */
    error OnlyAllowedContracts();

    /**
     * @dev Thrown when the caller is not the coinbase neither the globalExitRootUpdater
     */
    error OnlyGlobalExitRootUpdater();

    /**
     * @dev Thrown when trying to call a function that only the pending GlobalExitRootUpdater can call.
     */
    error OnlyPendingGlobalExitRootUpdater();

    /**
     * @dev Thrown when the caller is not the globalExitRootRemover
     */
    error OnlyGlobalExitRootRemover();

    /**
     * @dev Thrown when trying to call a function that only the pending GlobalExitRootRemover can call.
     */
    error OnlyPendingGlobalExitRootRemover();

    /**
     * @dev Thrown when trying to insert a global exit root that is already set
     */
    error GlobalExitRootAlreadySet();

    /**
     * @dev Thrown when trying to remove a ger that doesn't exist
     */
    error GlobalExitRootNotFound();

    /**
     * @dev Thrown when trying to call a function with an input zero address
     */
    error InvalidZeroAddress();

    function updateExitRoot(bytes32 newRollupExitRoot) external;

    function globalExitRootMap(
        bytes32 globalExitRootNum
    ) external returns (uint256);
}

File 35 of 52 : IEmergencyManager.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

interface IEmergencyManager {
    /**
     * @dev Thrown when emergency state is active, and the function requires otherwise
     */
    error OnlyNotEmergencyState();

    /**
     * @dev Thrown when emergency state is not active, and the function requires otherwise
     */
    error OnlyEmergencyState();

    /**
     * @dev Emitted when emergency state is activated
     */
    event EmergencyStateActivated();

    /**
     * @dev Emitted when emergency state is deactivated
     */
    event EmergencyStateDeactivated();

    /**
     * @notice Returns whether the emergency state is active
     */
    function isEmergencyState() external view returns (bool);
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

interface IPolygonConsensusBase {
    /**
     * @dev Thrown when trying to set the admin to the zero address
     */
    error AdminCannotBeZeroAddress();

    function initialize(
        address _admin,
        address sequencer,
        uint32 networkID,
        address gasTokenAddress,
        string memory sequencerURL,
        string memory _networkName
    ) external;

    function admin() external view returns (address);
}

File 37 of 52 : IPolygonPessimisticConsensus.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

interface IPolygonPessimisticConsensus {
    function getConsensusHash() external view returns (bytes32);
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

import "./IPolygonConsensusBase.sol";

interface IPolygonRollupBase is IPolygonConsensusBase {
    function onVerifyBatches(
        uint64 lastVerifiedBatch,
        bytes32 newStateRoot,
        address aggregator
    ) external;

    function rollbackBatches(
        uint64 targetBatch,
        bytes32 accInputHashToRollback
    ) external;
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

interface IPolygonZkEVMBridge {
    /**
     * @dev Thrown when sender is not the PolygonZkEVM address
     */
    error OnlyPolygonZkEVM();

    /**
     * @dev Thrown when the destination network is invalid
     */
    error DestinationNetworkInvalid();

    /**
     * @dev Thrown when the amount does not match msg.value
     */
    error AmountDoesNotMatchMsgValue();

    /**
     * @dev Thrown when user is bridging tokens and is also sending a value
     */
    error MsgValueNotZero();

    /**
     * @dev Thrown when the Ether transfer on claimAsset fails
     */
    error EtherTransferFailed();

    /**
     * @dev Thrown when the message transaction on claimMessage fails
     */
    error MessageFailed();

    /**
     * @dev Thrown when the global exit root does not exist
     */
    error GlobalExitRootInvalid();

    /**
     * @dev Thrown when the smt proof does not match
     */
    error InvalidSmtProof();

    /**
     * @dev Thrown when an index is already claimed
     */
    error AlreadyClaimed();

    /**
     * @dev Thrown when the owner of permit does not match the sender
     */
    error NotValidOwner();

    /**
     * @dev Thrown when the spender of the permit does not match this contract address
     */
    error NotValidSpender();

    /**
     * @dev Thrown when the amount of the permit does not match
     */
    error NotValidAmount();

    /**
     * @dev Thrown when the permit data contains an invalid signature
     */
    error NotValidSignature();

    function bridgeAsset(
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        address token,
        bool forceUpdateGlobalExitRoot,
        bytes calldata permitData
    ) external payable;

    function bridgeMessage(
        uint32 destinationNetwork,
        address destinationAddress,
        bool forceUpdateGlobalExitRoot,
        bytes calldata metadata
    ) external payable;

    function claimAsset(
        bytes32[32] calldata smtProof,
        uint32 index,
        bytes32 mainnetExitRoot,
        bytes32 rollupExitRoot,
        uint32 originNetwork,
        address originTokenAddress,
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        bytes calldata metadata
    ) external;

    function claimMessage(
        bytes32[32] calldata smtProof,
        uint32 index,
        bytes32 mainnetExitRoot,
        bytes32 rollupExitRoot,
        uint32 originNetwork,
        address originAddress,
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        bytes calldata metadata
    ) external;

    function updateGlobalExitRoot() external;

    function activateEmergencyState() external;

    function deactivateEmergencyState() external;
}

File 40 of 52 : IPolygonZkEVMErrors.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

interface IPolygonZkEVMErrors {
    /**
     * @dev Thrown when the pending state timeout exceeds the _HALT_AGGREGATION_TIMEOUT
     */
    error PendingStateTimeoutExceedHaltAggregationTimeout();

    /**
     * @dev Thrown when the trusted aggregator timeout exceeds the _HALT_AGGREGATION_TIMEOUT
     */
    error TrustedAggregatorTimeoutExceedHaltAggregationTimeout();

    /**
     * @dev Thrown when the caller is not the admin
     */
    error OnlyAdmin();

    /**
     * @dev Thrown when the caller is not the trusted sequencer
     */
    error OnlyTrustedSequencer();

    /**
     * @dev Thrown when the caller is not the trusted aggregator
     */
    error OnlyTrustedAggregator();

    /**
     * @dev Thrown when attempting to sequence 0 batches
     */
    error SequenceZeroBatches();

    /**
     * @dev Thrown when attempting to sequence or verify more batches than _MAX_VERIFY_BATCHES
     */
    error ExceedMaxVerifyBatches();

    /**
     * @dev Thrown when the forced data does not match
     */
    error ForcedDataDoesNotMatch();

    /**
     * @dev Thrown when the sequenced timestamp is below the forced minimum timestamp
     */
    error SequencedTimestampBelowForcedTimestamp();

    /**
     * @dev Thrown when a global exit root is not zero and does not exist
     */
    error GlobalExitRootNotExist();

    /**
     * @dev Thrown when transactions array length is above _MAX_TRANSACTIONS_BYTE_LENGTH.
     */
    error TransactionsLengthAboveMax();

    /**
     * @dev Thrown when a sequenced timestamp is not inside a correct range.
     */
    error SequencedTimestampInvalid();

    /**
     * @dev Thrown when there are more sequenced force batches than were actually submitted, should be unreachable
     */
    error ForceBatchesOverflow();

    /**
     * @dev Thrown when there are more sequenced force batches than were actually submitted
     */
    error TrustedAggregatorTimeoutNotExpired();

    /**
     * @dev Thrown when attempting to access a pending state that does not exist
     */
    error PendingStateDoesNotExist();

    /**
     * @dev Thrown when the init num batch does not match with the one in the pending state
     */
    error InitNumBatchDoesNotMatchPendingState();

    /**
     * @dev Thrown when the old state root of a certain batch does not exist
     */
    error OldStateRootDoesNotExist();

    /**
     * @dev Thrown when the init verification batch is above the last verification batch
     */
    error InitNumBatchAboveLastVerifiedBatch();

    /**
     * @dev Thrown when the final verification batch is below or equal the last verification batch
     */
    error FinalNumBatchBelowLastVerifiedBatch();

    /**
     * @dev Thrown when the zkproof is not valid
     */
    error InvalidProof();

    /**
     * @dev Thrown when attempting to consolidate a pending state not yet consolidable
     */
    error PendingStateNotConsolidable();

    /**
     * @dev Thrown when attempting to consolidate a pending state that is already consolidated or does not exist
     */
    error PendingStateInvalid();

    /**
     * @dev Thrown when the matic amount is below the necessary matic fee
     */
    error NotEnoughMaticAmount();

    /**
     * @dev Thrown when attempting to sequence a force batch using sequenceForceBatches and the
     * force timeout did not expire
     */
    error ForceBatchTimeoutNotExpired();

    /**
     * @dev Thrown when attempting to set a new trusted aggregator timeout equal or bigger than current one
     */
    error NewTrustedAggregatorTimeoutMustBeLower();

    /**
     * @dev Thrown when attempting to set a new pending state timeout equal or bigger than current one
     */
    error NewPendingStateTimeoutMustBeLower();

    /**
     * @dev Thrown when attempting to set a new multiplier batch fee in a invalid range of values
     */
    error InvalidRangeMultiplierBatchFee();

    /**
     * @dev Thrown when attempting to set a batch time target in an invalid range of values
     */
    error InvalidRangeBatchTimeTarget();

    /**
     * @dev Thrown when attempting to set a force batch timeout in an invalid range of values
     */
    error InvalidRangeForceBatchTimeout();

    /**
     * @dev Thrown when the caller is not the pending admin
     */
    error OnlyPendingAdmin();

    /**
     * @dev Thrown when the final pending state num is not in a valid range
     */
    error FinalPendingStateNumInvalid();

    /**
     * @dev Thrown when the final num batch does not match with the one in the pending state
     */
    error FinalNumBatchDoesNotMatchPendingState();

    /**
     * @dev Thrown when the stored root matches the new root proving a different state
     */
    error StoredRootMustBeDifferentThanNewRoot();

    /**
     * @dev Thrown when the batch is already verified when attempting to activate the emergency state
     */
    error BatchAlreadyVerified();

    /**
     * @dev Thrown when the batch is not sequenced or not at the end of a sequence when attempting to activate the emergency state
     */
    error BatchNotSequencedOrNotSequenceEnd();

    /**
     * @dev Thrown when the halt timeout is not expired when attempting to activate the emergency state
     */
    error HaltTimeoutNotExpired();

    /**
     * @dev Thrown when the old accumulate input hash does not exist
     */
    error OldAccInputHashDoesNotExist();

    /**
     * @dev Thrown when the new accumulate input hash does not exist
     */
    error NewAccInputHashDoesNotExist();

    /**
     * @dev Thrown when the new state root is not inside prime
     */
    error NewStateRootNotInsidePrime();

    /**
     * @dev Thrown when force batch is not allowed
     */
    error ForceBatchNotAllowed();

    /**
     * @dev Thrown when try to activate force batches when they are already active
     */
    error ForceBatchesAlreadyActive();
}

File 41 of 52 : IPolygonZkEVMEtrogErrors.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;
import "./IPolygonZkEVMErrors.sol";

interface IPolygonZkEVMEtrogErrors is IPolygonZkEVMErrors {
    /**
     * @dev Thrown when the caller is not the trusted sequencer
     */
    error OnlyRollupManager();

    /**
     * @dev Thrown when the caller is not the trusted sequencer
     */
    error NotEnoughPOLAmount();

    /**
     * @dev Thrown when the caller is not the trusted sequencer
     */
    error InvalidInitializeTransaction();

    /**
     * @dev Thrown when the caller is not the trusted sequencer
     */
    error GasTokenNetworkMustBeZeroOnEther();

    /**
     * @dev Thrown when the try to initialize with a gas token with huge metadata
     */
    error HugeTokenMetadataNotSupported();

    /**
     * @dev Thrown when trying force a batch during emergency state
     */
    error ForceBatchesNotAllowedOnEmergencyState();

    /**
     * @dev Thrown when the try to sequence force batches before the halt timeout period
     */
    error HaltTimeoutNotExpiredAfterEmergencyState();

    /**
     * @dev Thrown when the try to update the force batch address once is set to address(0)
     */
    error ForceBatchesDecentralized();

    /**
     * @dev Thrown when the last sequenced batch nmber does not match the init sequeced batch number
     */
    error InitSequencedBatchDoesNotMatch();

    /**
     * @dev Thrown when the max timestamp is out of range
     */
    error MaxTimestampSequenceInvalid();

    /**
     * @dev Thrown when l1 info tree leafCount does not exist
     */
    error L1InfoTreeLeafCountInvalid();

    /**
     * @dev Thrown when the acc input hash does not match the predicted by the sequencer
     */
    error FinalAccInputHashDoesNotMatch();
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// imported from: https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1Verifier.sol

/// @title SP1 Verifier Interface
/// @author Succinct Labs
/// @notice This contract is the interface for the SP1 Verifier.
interface ISP1Verifier {
    /// @notice Verifies a proof with given public values and vkey.
    /// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
    /// target verifier's VERIFIER_HASH.
    /// @param programVKey The verification key for the RISC-V program.
    /// @param publicValues The public values encoded as bytes.
    /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
    function verifyProof(
        bytes32 programVKey,
        bytes calldata publicValues,
        bytes calldata proofBytes
    ) external view;
}

interface ISP1VerifierWithHash is ISP1Verifier {
    /// @notice Returns the hash of the verifier.
    function VERIFIER_HASH() external pure returns (bytes32);
}

File 43 of 52 : IVerifierRollup.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

/**
 * @dev Define interface verifier
 */
interface IVerifierRollup {
    function verifyProof(
        bytes32[24] calldata proof,
        uint256[1] calldata pubSignals
    ) external view returns (bool);
}

File 44 of 52 : IVersion.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IVersion {
    function version() external pure returns (string memory);
}

// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;

import "@openzeppelin/contracts-upgradeable4/proxy/utils/Initializable.sol";
import "./PolygonConsensusBase.sol";
import "../interfaces/IAgglayerGateway.sol";
import "../interfaces/IAggchainBase.sol";
import "../interfaces/IVersion.sol";

/**
 * @title AggchainBase
 * @notice Base contract for aggchain implementations. This contract is imported by other aggchain implementations to reuse the common logic.
 */
abstract contract AggchainBase is
    PolygonConsensusBase,
    IAggchainBase,
    IVersion
{
    ////////////////////////////////////////////////////////////
    //                  Constants & Immutables                //
    ////////////////////////////////////////////////////////////
    // Consensus type that supports generic aggchain hash
    // Naming has been kept as CONSENSUS_TYPE for consistency with the previous consensus type (PolygonPessimisticConsensus.sol)
    uint32 public constant CONSENSUS_TYPE = 1;

    // Maximum number of aggchain signers supported
    uint256 public constant MAX_AGGCHAIN_SIGNERS = 255;

    // AgglayerGateway address, used in case the flag `useDefaultGateway` is set to true, the aggchains keys are managed by the gateway
    IAgglayerGateway public immutable aggLayerGateway;

    ////////////////////////////////////////////////////////////
    //                       Variables                        //
    ////////////////////////////////////////////////////////////
    // Added legacy storage values to avoid storage collision with PolygonValidiumEtrog contract in case this consensus contract is upgraded to aggchain
    address private _legacyDataAvailabilityProtocol;
    bool private _legacyIsSequenceWithDataAvailabilityAllowed;

    // Added legacy storage values from previous aggchainBase
    /// @custom:oz-renamed-from vKeyManager
    address public _legacyvKeyManager;
    /// @custom:oz-renamed-from pendingVKeyManager
    address public _legacypendingVKeyManager;

    // Flag to enable/disable the use of the default verification keys from the gateway
    /// @custom:oz-renamed-from useDefaultGateway
    bool public useDefaultVkeys;

    // Flag to enable or disable the use of default signers from the gateway.
    // Introduced in this version of the contract. This variable is packed into
    // the same storage slot as `useDefaultVkeys`, so there is no risk of storage
    // layout collision with previous versions.
    bool public useDefaultSigners;

    /// @notice Address that manages all the functionalities related to the aggchain
    address public aggchainManager;

    /// @notice This account will be able to accept the aggchainManager role
    address public pendingAggchainManager;

    ////////////////////////////////////////////////////////////
    //                       Mappings                         //
    ////////////////////////////////////////////////////////////
    // AggchainVKeys mapping
    mapping(bytes4 aggchainVKeySelector => bytes32 ownedAggchainVKey)
        public ownedAggchainVKeys;

    ////////////////////////////////////////////////////////////
    //                      Multisig                          //
    ////////////////////////////////////////////////////////////

    /// @notice Array of multisig aggchainSigners
    address[] public aggchainSigners;

    /// @notice Mapping that stores the URL of each signer
    /// It's used as well to check if an address is a signer
    mapping(address => string) public signerToURLs;

    /// @notice Threshold required for multisig operations
    uint256 public threshold;

    /// @notice Hash of the current multisig configuration.
    /// @dev Computed as keccak256(abi.encodePacked(threshold, aggchainSigners))
    bytes32 public aggchainMultisigHash;

    ////////////////////////////////////////////////////////////
    //                      Metadata                          //
    ////////////////////////////////////////////////////////////

    /// @notice Address that manages the metadata functionality
    address public aggchainMetadataManager;

    /// @notice Optional mapping to store metadata for the aggchain
    mapping(string => string) public aggchainMetadata;

    /**
     * @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.
     */
    /// @custom:oz-renamed-from _gap
    uint256[44] private __gap;

    ////////////////////////////////////////////////////////////
    //                        Modifiers                       //
    ////////////////////////////////////////////////////////////

    /// @dev Only allows a function to be callable if the message sender is the aggchain manager
    modifier onlyAggchainManager() {
        if (aggchainManager != msg.sender) {
            revert OnlyAggchainManager();
        }
        _;
    }

    /// @dev Only allows a function to be callable if the message sender is the aggchain metadata manager
    modifier onlyAggchainMetadataManager() {
        if (aggchainMetadataManager != msg.sender) {
            revert OnlyAggchainMetadataManager();
        }
        _;
    }

    ////////////////////////////////////////////////////////////
    //                       Constructor                      //
    ////////////////////////////////////////////////////////////
    /**
     * @param _globalExitRootManager Global exit root manager address.
     * @param _pol POL token address.
     * @param _bridgeAddress Bridge address.
     * @param _rollupManager Rollup manager address.
     * @param _aggLayerGateway AgglayerGateway address.
     */
    constructor(
        IAgglayerGER _globalExitRootManager,
        IERC20Upgradeable _pol,
        IAgglayerBridge _bridgeAddress,
        AgglayerManager _rollupManager,
        IAgglayerGateway _aggLayerGateway
    )
        PolygonConsensusBase(
            _globalExitRootManager,
            _pol,
            _bridgeAddress,
            _rollupManager
        )
    {
        // Check if the gateway address is valid
        if (
            address(_aggLayerGateway) == address(0) ||
            address(_globalExitRootManager) == address(0) ||
            address(_pol) == address(0) ||
            address(_bridgeAddress) == address(0) ||
            address(_rollupManager) == address(0)
        ) {
            revert InvalidZeroAddress();
        }
        aggLayerGateway = _aggLayerGateway;
    }

    ////////////////////////////////////////////////////////////
    //                  Initialization                        //
    ////////////////////////////////////////////////////////////

    /**
     * @notice Sets the aggchain manager
     * @dev Can only be called by the rollup manager during initialization
     * @param newAggchainManager The address of the new aggchain manager
     */
    function initAggchainManager(
        address newAggchainManager
    ) external onlyRollupManager {
        // Can only be initialized if current aggchainmanger is zero
        if (aggchainManager != address(0)) {
            revert AggchainManagerAlreadyInitialized();
        }

        if (newAggchainManager == address(0)) {
            revert AggchainManagerCannotBeZero();
        }

        aggchainManager = newAggchainManager;

        emit AcceptAggchainManagerRole(address(0), aggchainManager);
    }

    /**
     * @notice Initializer AggchainBase storage
     * @param _admin Admin address
     * @param sequencer Trusted sequencer address
     * @param _gasTokenAddress Indicates the token address in mainnet that will be used as a gas token
     * @dev If a wrapped token of the bridge is used, the original network and address of this wrapped are used instead
     * @param sequencerURL Trusted sequencer URL
     * @param _networkName L2 network name
     * @param _useDefaultVkeys Flag to use default verification keys from gateway
     * @param _useDefaultSigners Flag to use default signers from gateway
     * @param _initOwnedAggchainVKey Initial owned aggchain verification key
     * @param _initAggchainVKeySelector Initial aggchain selector
     */
    function _initializeAggchainBaseAndConsensusBase(
        address _admin,
        address sequencer,
        address _gasTokenAddress,
        string memory sequencerURL,
        string memory _networkName,
        bool _useDefaultVkeys,
        bool _useDefaultSigners,
        bytes32 _initOwnedAggchainVKey,
        bytes4 _initAggchainVKeySelector
    ) internal onlyInitializing {
        if (address(_admin) == address(0) || address(sequencer) == address(0)) {
            revert InvalidZeroAddress();
        }

        // Initialize PolygonConsensusBase
        _initializePolygonConsensusBase(
            _admin,
            sequencer,
            _gasTokenAddress,
            sequencerURL,
            _networkName
        );

        _initializeAggchainBase(
            _useDefaultVkeys,
            _useDefaultSigners,
            _initOwnedAggchainVKey,
            _initAggchainVKeySelector
        );
    }

    /**
     * @notice Initializer AggchainBase storage
     * @param _useDefaultVkeys Flag to use default verification keys from gateway
     * @param _useDefaultSigners Flag to use default signers from gateway
     * @param _initOwnedAggchainVKey Initial owned aggchain verification key
     * @param _initAggchainVKeySelector Initial aggchain selector
     */
    function _initializeAggchainBase(
        bool _useDefaultVkeys,
        bool _useDefaultSigners,
        bytes32 _initOwnedAggchainVKey,
        bytes4 _initAggchainVKeySelector
    ) internal onlyInitializing {
        useDefaultVkeys = _useDefaultVkeys;
        useDefaultSigners = _useDefaultSigners;
        // set the initial aggchain keys
        ownedAggchainVKeys[_initAggchainVKeySelector] = _initOwnedAggchainVKey;
    }

    /**
     * @notice Override the function to prevent the contract from being initialized with the initializer implemented at PolygonConsensusBase.
     * @dev removing this function can cause critical security issues.
     */
    function initialize(
        address, // _admin
        address, // sequencer
        uint32, //networkID,
        address, // _gasTokenAddress,
        string memory, // sequencerURL,
        string memory // _networkName
    ) external pure override(PolygonConsensusBase) {
        // Set initialize variables
        revert InvalidInitializeFunction();
    }

    ///////////////////////////////////////////////
    //              Virtual functions            //
    ///////////////////////////////////////////////

    /**
     * @notice Abstract function to extract aggchain parameters and verification key from aggchain data
     * @dev This function must be implemented by the inheriting contract
     * @param aggchainData Custom bytes provided by the chain containing the aggchain data
     * @return aggchainVKey The extracted aggchain verification key
     * @return aggchainParams The extracted aggchain parameters
     */
    function getVKeyAndAggchainParams(
        bytes memory aggchainData
    ) public view virtual returns (bytes32, bytes32);

    ///////////////////////////////////////////////
    //     Rollup manager callback functions     //
    ///////////////////////////////////////////////

    /**
     * @notice Callback while pessimistic proof is being verified from the rollup manager
     *
     *     aggchain_hash:
     *     Field:           | CONSENSUS_TYPE | aggchain_vkey  | aggchain_params  | multisig_hash |
     *     length (bits):   | 32             | 256            | 256              | 256           |
     *
     * @dev Returns the aggchain hash for a given aggchain data
     * @param aggchainData Custom bytes provided by the chain containing the aggchain data
     * @return aggchainHash resulting aggchain hash
     */
    function getAggchainHash(
        bytes memory aggchainData
    ) external view returns (bytes32) {
        // Get signers hash from gateway if using default signers, otherwise use local storage
        bytes32 cachedMultisigHash = getAggchainMultisigHash();

        (
            bytes32 aggchainVKey,
            bytes32 aggchainParams
        ) = getVKeyAndAggchainParams(aggchainData);

        return
            keccak256(
                abi.encodePacked(
                    CONSENSUS_TYPE,
                    aggchainVKey,
                    aggchainParams,
                    cachedMultisigHash
                )
            );
    }

    ///////////////////////////////////////////////
    //        aggchainManager functions          //
    ///////////////////////////////////////////////

    /**
     * @notice Updates signers and threshold for multisig operations
     * @dev External wrapper for _updateSignersAndThreshold, restricted to aggchainManager
     * @param _signersToRemove Array of signers to remove with their indices
     * @param _signersToAdd Array of new signers to add with their URLs
     * @param _newThreshold New threshold value for multisig operations
     */
    function updateSignersAndThreshold(
        RemoveSignerInfo[] memory _signersToRemove,
        SignerInfo[] memory _signersToAdd,
        uint256 _newThreshold
    ) external onlyAggchainManager {
        _updateSignersAndThreshold(
            _signersToRemove,
            _signersToAdd,
            _newThreshold
        );
    }

    /**
     * @notice Batch update signers and threshold in a single transaction
     * @dev Removes signers first (in descending index order), then adds new signers, then updates threshold
     * @param _signersToRemove Array of signers to remove with their indices (MUST be in descending index order)
     * @param _signersToAdd Array of new signers to add with their URLs
     * @param _newThreshold New threshold value
     */
    function _updateSignersAndThreshold(
        RemoveSignerInfo[] memory _signersToRemove,
        SignerInfo[] memory _signersToAdd,
        uint256 _newThreshold
    ) internal {
        // Validate descending order of indices for removal to avoid index shifting issues
        // When removing multiple signers, we must process them from highest index to lowest
        if (_signersToRemove.length > 1) {
            for (uint256 i = 0; i < _signersToRemove.length - 1; i++) {
                if (
                    _signersToRemove[i].index <= _signersToRemove[i + 1].index
                ) {
                    revert IndicesNotInDescendingOrder();
                }
            }
        }

        // Remove signers (in descending index order to avoid index shifting issues)
        for (uint256 i = 0; i < _signersToRemove.length; i++) {
            _removeSignerInternal(
                _signersToRemove[i].addr,
                _signersToRemove[i].index
            );
        }

        // Add new signers
        for (uint256 i = 0; i < _signersToAdd.length; i++) {
            _addSignerInternal(_signersToAdd[i].addr, _signersToAdd[i].url);
        }

        if (aggchainSigners.length > MAX_AGGCHAIN_SIGNERS) {
            revert AggchainSignersTooHigh();
        }

        if (
            _newThreshold > aggchainSigners.length ||
            (aggchainSigners.length != 0 && _newThreshold == 0)
        ) {
            revert InvalidThreshold();
        }

        threshold = _newThreshold;

        // Update the signers hash once after all operations
        _updateAggchainMultisigHash();
    }

    /**
     * @notice Starts the aggchainManager role transfer
     * @dev This is a two step process, the pending aggchainManager must accept to finalize the process
     * @param newAggchainManager Address of the new aggchainManager
     */
    function transferAggchainManagerRole(
        address newAggchainManager
    ) external onlyAggchainManager {
        if (newAggchainManager == address(0)) {
            revert InvalidZeroAddress();
        }

        pendingAggchainManager = newAggchainManager;

        emit TransferAggchainManagerRole(aggchainManager, newAggchainManager);
    }

    /**
     * @notice Allow the current pending aggchainManager to accept the aggchainManager role
     * @dev Can only be called by the pending aggchainManager
     */
    function acceptAggchainManagerRole() external {
        if (pendingAggchainManager != msg.sender) {
            revert OnlyPendingAggchainManager();
        }

        address oldAggchainManager = aggchainManager;
        aggchainManager = pendingAggchainManager;
        delete pendingAggchainManager;

        emit AcceptAggchainManagerRole(oldAggchainManager, aggchainManager);
    }

    /**
     * @notice Sets the aggchain metadata manager
     * @dev Can only be called by the aggchain manager
     * @param newAggchainMetadataManager Address of the new aggchain metadata manager
     */
    function setAggchainMetadataManager(
        address newAggchainMetadataManager
    ) external onlyAggchainManager {
        address oldAggchainMetadataManager = aggchainMetadataManager;
        aggchainMetadataManager = newAggchainMetadataManager;

        emit SetAggchainMetadataManager(
            oldAggchainMetadataManager,
            newAggchainMetadataManager
        );
    }

    /**
     * @notice Enable the use of default verification keys from gateway
     */
    function enableUseDefaultVkeysFlag() external virtual onlyAggchainManager {
        if (useDefaultVkeys) {
            revert UseDefaultVkeysAlreadyEnabled();
        }

        useDefaultVkeys = true;

        // Emit event
        emit EnableUseDefaultVkeysFlag();
    }

    /**
     * @notice Disable the use of default verification keys from gateway
     */
    function disableUseDefaultVkeysFlag() external virtual onlyAggchainManager {
        if (!useDefaultVkeys) {
            revert UseDefaultVkeysAlreadyDisabled();
        }

        useDefaultVkeys = false;

        // Emit event
        emit DisableUseDefaultVkeysFlag();
    }

    /**
     * @notice Enable the use of default signers from gateway
     */
    function enableUseDefaultSignersFlag() external onlyAggchainManager {
        if (useDefaultSigners) {
            revert UseDefaultSignersAlreadyEnabled();
        }

        useDefaultSigners = true;

        // Emit event
        emit EnableUseDefaultSignersFlag();
    }

    /**
     * @notice Disable the use of default signers from gateway
     */
    function disableUseDefaultSignersFlag() external onlyAggchainManager {
        if (!useDefaultSigners) {
            revert UseDefaultSignersAlreadyDisabled();
        }

        useDefaultSigners = false;

        // Emit event
        emit DisableUseDefaultSignersFlag();
    }

    /**
     * @notice Add a new aggchain verification key to the aggchain contract.
     * @param aggchainVKeySelector The selector for the verification key query. This selector identifies the aggchain key
     * @param newAggchainVKey The new aggchain verification key to be added.
     */
    function addOwnedAggchainVKey(
        bytes4 aggchainVKeySelector,
        bytes32 newAggchainVKey
    ) external virtual onlyAggchainManager {
        if (newAggchainVKey == bytes32(0)) {
            revert ZeroValueAggchainVKey();
        }
        // Check if proposed selector has already a verification key assigned
        if (ownedAggchainVKeys[aggchainVKeySelector] != bytes32(0)) {
            revert OwnedAggchainVKeyAlreadyAdded();
        }

        ownedAggchainVKeys[aggchainVKeySelector] = newAggchainVKey;

        emit AddAggchainVKey(aggchainVKeySelector, newAggchainVKey);
    }

    /**
     * @notice Update the aggchain verification key in the aggchain contract.
     * @param aggchainVKeySelector The selector for the verification key query. This selector identifies the aggchain key
     * @param updatedAggchainVKey The updated aggchain verification key value.
     */
    function updateOwnedAggchainVKey(
        bytes4 aggchainVKeySelector,
        bytes32 updatedAggchainVKey
    ) external virtual onlyAggchainManager {
        // Check already added
        if (ownedAggchainVKeys[aggchainVKeySelector] == bytes32(0)) {
            revert OwnedAggchainVKeyNotFound();
        }

        bytes32 previousAggchainVKey = ownedAggchainVKeys[aggchainVKeySelector];
        ownedAggchainVKeys[aggchainVKeySelector] = updatedAggchainVKey;

        emit UpdateAggchainVKey(
            aggchainVKeySelector,
            previousAggchainVKey,
            updatedAggchainVKey
        );
    }

    /**
     * @notice Sets or updates metadata for the aggchain.
     * @dev Can only be called by the aggchain metadata manager. Empty values are allowed to clear metadata.
     * @param key The metadata key to set.
     * @param value The metadata value to set.
     */
    function setAggchainMetadata(
        string calldata key,
        string calldata value
    ) external onlyAggchainMetadataManager {
        _setAggchainMetadataInternal(key, value);
    }

    /**
     * @notice Sets or updates multiple metadata entries in a single transaction.
     * @dev Can only be called by the aggchain metadata manager.
     * @param keys Array of metadata keys to set.
     * @param values Array of metadata values to set (must be same length as keys).
     */
    function batchSetAggchainMetadata(
        string[] calldata keys,
        string[] calldata values
    ) external onlyAggchainMetadataManager {
        uint256 length = keys.length;
        if (length != values.length) {
            revert MetadataArrayLengthMismatch();
        }

        for (uint256 i = 0; i < length; i++) {
            _setAggchainMetadataInternal(keys[i], values[i]);
        }
    }

    //////////////////////////
    //    view functions    //
    //////////////////////////

    /**
     * @notice returns the current aggchain verification key. If the flag `useDefaultVkeys` is set to true, the gateway verification key is returned, else, the custom chain verification key is returned.
     * @param aggchainVKeySelector The selector for the verification key query. This selector identifies the aggchain type + sp1 verifier version
     * @return aggchainVKey The verification key for the specified selector
     */
    function getAggchainVKey(
        bytes4 aggchainVKeySelector
    ) public view virtual returns (bytes32 aggchainVKey) {
        if (useDefaultVkeys == false) {
            aggchainVKey = ownedAggchainVKeys[aggchainVKeySelector];

            if (aggchainVKey == bytes32(0)) {
                revert AggchainVKeyNotFound();
            }
        } else {
            // Retrieve aggchain key from AgglayerGateway
            aggchainVKey = aggLayerGateway.getDefaultAggchainVKey(
                aggchainVKeySelector
            );
        }
    }

    /**
     * @notice Computes the selector for the aggchain verification key from the aggchain type and the aggchainVKeyVersion.
     * @dev It joins two bytes2 values into a bytes4 value.
     * @param aggchainVKeyVersion The aggchain verification key version, used to identify the aggchain verification key.
     * @param aggchainType The aggchain type, hardcoded in the aggchain contract.
     * @return getAggchainVKeySelector computed bytes4 selector combining version and type
     * [            aggchainVKeySelector         ]
     * [  aggchainVKeyVersion   |  AGGCHAIN_TYPE ]
     * [        2 bytes         |    2 bytes     ]
     */
    function getAggchainVKeySelector(
        bytes2 aggchainVKeyVersion,
        bytes2 aggchainType
    ) public pure returns (bytes4) {
        return bytes4(aggchainVKeyVersion) | (bytes4(aggchainType) >> 16);
    }

    /**
     * @notice Computes the aggchainType from the aggchainVKeySelector.
     * @param aggchainVKeySelector The aggchain verification key selector.
     * @return AGGCHAIN_TYPE extracted aggchain type (last 2 bytes)
     * [            aggchainVKeySelector         ]
     * [  aggchainVKeyVersion   |  AGGCHAIN_TYPE ]
     * [        2 bytes         |    2 bytes     ]
     */
    function getAggchainTypeFromSelector(
        bytes4 aggchainVKeySelector
    ) public pure returns (bytes2) {
        return bytes2(aggchainVKeySelector << 16);
    }

    /**
     * @notice Computes the aggchainVKeyVersion from the aggchainVKeySelector.
     * @param aggchainVKeySelector The aggchain verification key selector.
     * @return aggchainVKeyVersion extracted aggchain verification key version (first 2 bytes)
     * [            aggchainVKeySelector         ]
     * [  aggchainVKeyVersion   |  AGGCHAIN_TYPE ]
     * [        2 bytes         |    2 bytes     ]
     */
    function getAggchainVKeyVersionFromSelector(
        bytes4 aggchainVKeySelector
    ) public pure returns (bytes2) {
        return bytes2(aggchainVKeySelector);
    }

    /**
     * @notice Get the threshold for the multisig
     * @return threshold for the multisig
     */
    function getThreshold() external view returns (uint256) {
        if (useDefaultSigners) {
            return aggLayerGateway.getThreshold();
        }
        return threshold;
    }

    /**
     * @notice Check if an address is a signer
     * @param _signer Address to check
     * @return True if the address is a signer
     */
    function isSigner(address _signer) public view returns (bool) {
        if (useDefaultSigners) {
            return aggLayerGateway.isSigner(_signer);
        }
        return bytes(signerToURLs[_signer]).length > 0;
    }

    /**
     * @notice Get the number of aggchainSigners
     * @return Number of aggchainSigners in the multisig
     */
    function getAggchainSignersCount() external view returns (uint256) {
        if (useDefaultSigners) {
            return aggLayerGateway.getAggchainSignersCount();
        }
        return aggchainSigners.length;
    }

    /**
     * @notice Get all aggchainSigners
     * @return Array of signer addresses
     */
    function getAggchainSigners() external view returns (address[] memory) {
        if (useDefaultSigners) {
            return aggLayerGateway.getAggchainSigners();
        }
        return aggchainSigners;
    }

    /**
     * @notice Get the aggchain signers hash
     * @return The aggchain signers hash
     */
    function getAggchainMultisigHash() public view returns (bytes32) {
        if (useDefaultSigners) {
            return aggLayerGateway.getAggchainMultisigHash();
        }

        // Sanity check to realize earlier that the aggchainMultisigHash has not been set given
        // that the proof cannot be computed since there is no hash reconstruction to be 0
        if (aggchainMultisigHash == bytes32(0)) {
            revert AggchainSignersHashNotInitialized();
        }

        return aggchainMultisigHash;
    }
    /**
     * @notice Get all aggchainSigners with their URLs
     * @return Array of SignerInfo structs containing signer addresses and URLs
     */
    function getAggchainSignerInfos()
        external
        view
        returns (SignerInfo[] memory)
    {
        if (useDefaultSigners) {
            // Get signers with URLs directly from gateway
            return aggLayerGateway.getAggchainSignerInfos();
        } else {
            // Use local aggchainSigners
            SignerInfo[] memory signerInfos = new SignerInfo[](
                aggchainSigners.length
            );
            for (uint256 i = 0; i < aggchainSigners.length; i++) {
                signerInfos[i] = SignerInfo({
                    addr: aggchainSigners[i],
                    url: signerToURLs[aggchainSigners[i]]
                });
            }
            return signerInfos;
        }
    }

    ////////////////////////////////////////////////////////////
    //                   Internal Functions                   //
    ////////////////////////////////////////////////////////////

    /**
     * @notice Internal function to add a signer with validation
     * @dev Validates that signer is not zero address, URL is not empty, and signer doesn't already exist
     * @param _signer Address of the signer to add
     * @param url URL associated with the signer
     */
    function _addSignerInternal(address _signer, string memory url) internal {
        if (_signer == address(0)) {
            revert SignerCannotBeZero();
        }

        if (bytes(url).length == 0) {
            revert SignerURLCannotBeEmpty();
        }

        if (bytes(signerToURLs[_signer]).length > 0) {
            revert SignerAlreadyExists();
        }

        aggchainSigners.push(_signer);
        signerToURLs[_signer] = url;
    }

    /**
     * @notice Internal function to remove a signer with validation
     * @dev Validates index bounds and that the signer at the index matches the provided address
     * @param _signer Address of the signer to remove
     * @param _signerIndex Index of the signer in the aggchainSigners array
     */
    function _removeSignerInternal(
        address _signer,
        uint256 _signerIndex
    ) internal {
        // Cache array length
        uint256 signersLength = aggchainSigners.length;

        // Validate input parameters
        if (_signerIndex >= signersLength) {
            revert SignerDoesNotExist();
        }

        if (aggchainSigners[_signerIndex] != _signer) {
            revert SignerDoesNotExist();
        }

        // Remove from mapping
        delete signerToURLs[_signer];

        // Move the last element to the deleted spot and remove the last element
        aggchainSigners[_signerIndex] = aggchainSigners[signersLength - 1];

        aggchainSigners.pop();
    }

    /**
     * @notice Update the hash of the aggchainSigners array
     * @dev Combines threshold and signers array into a single hash for efficient verification
     */
    function _updateAggchainMultisigHash() internal {
        aggchainMultisigHash = keccak256(
            abi.encodePacked(threshold, aggchainSigners)
        );

        emit SignersAndThresholdUpdated(
            aggchainSigners,
            threshold,
            aggchainMultisigHash
        );
    }

    /**
     * @notice Internal function to set or update metadata for the aggchain
     * @dev Empty values are allowed to clear metadata
     * @param key The metadata key to set
     * @param value The metadata value to set
     */
    function _setAggchainMetadataInternal(
        string memory key,
        string memory value
    ) internal {
        aggchainMetadata[key] = value;
        emit AggchainMetadataSet(key, value);
    }

    /**
     * @dev Internal function to validate VKeys consistency
     * @param _useDefaultVkeys Whether to use default verification keys
     * @param _initAggchainVKeySelector The aggchain verification key selector
     * @param _initOwnedAggchainVKey The owned aggchain verification key
     * @param aggchainType The expected aggchain type
     */
    function _validateVKeysConsistency(
        bool _useDefaultVkeys,
        bytes4 _initAggchainVKeySelector,
        bytes32 _initOwnedAggchainVKey,
        bytes2 aggchainType
    ) internal pure {
        // Check the use default vkeys is consistent
        if (_useDefaultVkeys) {
            if (
                _initAggchainVKeySelector != bytes4(0) ||
                _initOwnedAggchainVKey != bytes32(0)
            ) {
                revert InvalidInitAggchainVKey();
            }
        } else {
            if (
                getAggchainTypeFromSelector(_initAggchainVKeySelector) !=
                aggchainType
            ) {
                revert InvalidAggchainType();
            }
        }
    }
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

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

/**
 * @dev Contract helper responsible to manage the emergency state
 */
contract EmergencyManager is IEmergencyManager {
    /**
     * @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.
     */
    /// @custom:oz-renamed-from _gap
    uint256[10] private __gap;

    // Indicates whether the emergency state is active or not
    bool public isEmergencyState;

    /**
     * @notice Only allows a function to be callable if emergency state is unactive
     */
    modifier ifNotEmergencyState() {
        if (isEmergencyState) {
            revert OnlyNotEmergencyState();
        }
        _;
    }

    /**
     * @notice Only allows a function to be callable if emergency state is active
     */
    modifier ifEmergencyState() {
        if (!isEmergencyState) {
            revert OnlyEmergencyState();
        }
        _;
    }

    /**
     * @notice Activate emergency state
     */
    function _activateEmergencyState() internal virtual ifNotEmergencyState {
        isEmergencyState = true;
        emit EmergencyStateActivated();
    }

    /**
     * @notice Deactivate emergency state
     */
    function _deactivateEmergencyState() internal virtual ifEmergencyState {
        isEmergencyState = false;
        emit EmergencyStateDeactivated();
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/Hashes.sol)

pragma solidity ^0.8.20;

/**
 * @dev Library of standard hash functions.
 * @notice This code is a copy from OpenZeppelin Contracts v5.1.0 (utils/cryptography/Hashes.sol) with a minor change:
 *         function visibility is modified from 'private' to 'internal' so it can be used in other contracts.
 * @notice OpenZeppelin already did this change: https://github.com/OpenZeppelin/openzeppelin-contracts/commit/441dc141ac99622de7e535fa75dfc74af939019c
 *         to be included in next version of OpenZeppelin Contracts.
 * _Available since v5.1._
 */
library Hashes {
    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function efficientKeccak256(
        bytes32 a,
        bytes32 b
    ) internal pure returns (bytes32 value) {
        assembly ("memory-safe") {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 48 of 52 : LegacyZKEVMStateVariables.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.20;

/**
 * Since the current contract of PolygonZkEVM will be upgraded to a AgglayerManager there's defined
 * all the legacy public variables in order to not use previous used storage slots
 * The variables will be used by the RollupManager only for initialize the zkEVM inside the initializer function
 */
contract LegacyZKEVMStateVariables {
    /**
     * @notice Struct which will be stored for every batch sequence
     * @param accInputHash Hash chain that contains all the information to process a batch:
     * Before etrog: keccak256(bytes32 oldAccInputHash, keccak256(bytes transactions), bytes32 globalExitRoot, uint64 timestamp, address seqAddress)
     * Etrog: keccak256(bytes32 oldAccInputHash, keccak256(bytes transactions), bytes32 l1InfoRoot/forcedGlobalExitRoot, uint64 currentTimestamp/forcedTimestamp, address l2Coinbase, bytes32 0/forcedBlockHashL1)
     * @param sequencedTimestamp Sequenced timestamp
     * @param previousLastBatchSequenced Previous last batch sequenced before the current one, this is used to properly calculate the fees
     */
    struct SequencedBatchData {
        bytes32 accInputHash;
        uint64 sequencedTimestamp;
        uint64 previousLastBatchSequenced;
    }

    /**
     * @notice Struct to store the pending states
     * Pending state will be an intermediary state, that after a timeout can be consolidated, which means that will be added
     * to the state root mapping, and the global exit root will be updated
     * This is a protection mechanism against soundness attacks, that will be turned off in the future
     * @param timestamp Timestamp where the pending state is added to the queue
     * @param lastVerifiedBatch Last batch verified batch of this pending state
     * @param exitRoot Pending exit root
     * @param stateRoot Pending state root
     */
    struct PendingState {
        uint64 timestamp;
        uint64 lastVerifiedBatch;
        bytes32 exitRoot;
        bytes32 stateRoot;
    }

    // Time target of the verification of a batch
    // Adaptatly the batchFee will be updated to achieve this target
    /// @custom:oz-renamed-from verifyBatchTimeTarget
    uint64 internal _legacyVerifyBatchTimeTarget;

    // Batch fee multiplier with 3 decimals that goes from 1000 - 1023
    /// @custom:oz-renamed-from multiplierBatchFee
    uint16 internal _legacyMultiplierBatchFee;

    // Trusted sequencer address
    /// @custom:oz-renamed-from trustedSequencer
    address internal _legacyTrustedSequencer;

    // Current matic fee per batch sequenced
    /// @custom:oz-renamed-from batchFee
    uint256 internal _legacyBatchFee;

    // Queue of forced batches with their associated data
    // ForceBatchNum --> hashedForcedBatchData
    // hashedForcedBatchData: hash containing the necessary information to force a batch:
    // keccak256(keccak256(bytes transactions), bytes32 globalExitRoot, unint64 minForcedTimestamp)
    /// @custom:oz-renamed-from forcedBatches
    mapping(uint64 => bytes32) internal _legacyForcedBatches;

    // Queue of batches that defines the virtual state
    // SequenceBatchNum --> SequencedBatchData
    /// @custom:oz-renamed-from sequencedBatches
    mapping(uint64 => SequencedBatchData) internal _legacySequencedBatches;

    // Last sequenced timestamp
    /// @custom:oz-renamed-from lastTimestamp
    uint64 internal _legacyLastTimestamp;

    // Last batch sent by the sequencers
    /// @custom:oz-renamed-from lastBatchSequenced
    uint64 internal _legacylastBatchSequenced;

    // Last forced batch included in the sequence
    /// @custom:oz-renamed-from lastForceBatchSequenced
    uint64 internal _legacyLastForceBatchSequenced;

    // Last forced batch
    /// @custom:oz-renamed-from lastForceBatch
    uint64 internal _legacyLastForceBatch;

    // Last batch verified by the aggregators
    /// @custom:oz-renamed-from lastVerifiedBatch
    uint64 internal _legacyLastVerifiedBatch;

    // Trusted aggregator address
    /// @custom:oz-renamed-from trustedAggregator
    address internal _legacyTrustedAggregator;

    // State root mapping
    // BatchNum --> state root
    /// @custom:oz-renamed-from batchNumToStateRoot
    mapping(uint64 => bytes32) internal _legacyBatchNumToStateRoot;

    // Trusted sequencer URL
    /// @custom:oz-renamed-from trustedSequencerURL
    string internal _legacyTrustedSequencerURL;

    // L2 network name
    /// @custom:oz-renamed-from networkName
    string internal _legacyNetworkName;

    // Pending state mapping
    // pendingStateNumber --> PendingState
    /// @custom:oz-renamed-from pendingStateTransitions
    mapping(uint256 => PendingState) internal _legacyPendingStateTransitions;

    // Last pending state
    /// @custom:oz-renamed-from lastPendingState
    uint64 internal _legacyLastPendingState;

    // Last pending state consolidated
    /// @custom:oz-renamed-from lastPendingStateConsolidated
    uint64 internal _legacyLastPendingStateConsolidated;

    // Once a pending state exceeds this timeout it can be consolidated
    /// @custom:oz-renamed-from pendingStateTimeout
    uint64 internal _legacyPendingStateTimeout;

    // Trusted aggregator timeout, if a sequence is not verified in this time frame,
    // everyone can verify that sequence
    /// @custom:oz-renamed-from trustedAggregatorTimeout
    uint64 internal _legacyTrustedAggregatorTimeout;

    // Address that will be able to adjust contract parameters or stop the emergency state
    /// @custom:oz-renamed-from admin
    address internal _legacyAdmin;

    // This account will be able to accept the admin role
    /// @custom:oz-renamed-from pendingAdmin
    address internal _legacyPendingAdmin;

    // Force batch timeout
    /// @custom:oz-renamed-from forceBatchTimeout
    uint64 internal _legacyForceBatchTimeout;

    // Indicates if forced batches are disallowed
    /// @custom:oz-renamed-from isForcedBatchDisallowed
    bool internal _legacyIsForcedBatchDisallowed;

    // Indicates the current version
    /// @custom:oz-renamed-from version
    uint256 internal _legacyVersion;

    // Last batch verified before the last upgrade
    /// @custom:oz-renamed-from lastVerifiedBatchBeforeUpgrade
    uint256 internal _legacyLastVerifiedBatchBeforeUpgrade;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable4/access/IAccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/utils/StringsUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/utils/introspection/ERC165Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/proxy/utils/Initializable.sol";

/**
 * @dev Contract AccessControlUpgradeable from Openzeppelin with the following modifications:
 * - Delete ERC165Upgradeable dependencies, which is not important to our contract and save us the "gap"
 * variables and let us have consistent storage
 * - Add the legacy Owner variable, to be consistent with the previous one
 * - Add custom errors
 * - Replace _msgSender() with msg.sender
 */
abstract contract PolygonAccessControlUpgradeable is
    Initializable,
    ContextUpgradeable,
    IAccessControlUpgradeable
{
    function __AccessControl_init() internal onlyInitializing {}

    // Legacy variable
    /// @custom:oz-renamed-from _owner
    address internal _legacyOwner;

    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Thrown when the addres does not have the required role
     */
    error AddressDoNotHaveRequiredRole();

    /**
     * @dev Thrown when the renounce address is not the message sender
     */
    error AccessControlOnlyCanRenounceRolesForSelf();

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(
        bytes32 role,
        address account
    ) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `msg.sender` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, msg.sender);
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AddressDoNotHaveRequiredRole();
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(
        bytes32 role
    ) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(
        bytes32 role,
        address account
    ) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(
        bytes32 role,
        address account
    ) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(
        bytes32 role,
        address account
    ) public virtual override {
        if (account != msg.sender) {
            revert AccessControlOnlyCanRenounceRolesForSelf();
        }

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, msg.sender);
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, msg.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[48] private __gap;
}

// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable4/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "../interfaces/IAgglayerGER.sol";
import "@openzeppelin/contracts-upgradeable4/proxy/utils/Initializable.sol";
import "../interfaces/IPolygonZkEVMErrors.sol";
import "../interfaces/IPolygonZkEVMEtrogErrors.sol";
import "../interfaces/IPolygonConsensusBase.sol";
import "../interfaces/IPolygonRollupBase.sol";
import "../interfaces/IAgglayerBridge.sol";
import "@openzeppelin/contracts-upgradeable4/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import "./PolygonConstantsBase.sol";
import "../AgglayerManager.sol";

/**
 * Contract responsible for managing the states and the updates of L2 network.
 * There will be a trusted sequencer, which is able to send transactions.
 * Any user can force some transaction and the sequencer will have a timeout to add them in the queue.
 * The sequenced state is deterministic and can be precalculated before it's actually verified by a zkProof.
 * The aggregators will be able to verify the sequenced state with zkProofs and therefore make available the withdrawals from L2 network.
 * To enter and exit of the L2 network will be used a PolygonZkEVMBridge smart contract that will be deployed in both networks.
 */
abstract contract PolygonConsensusBase is
    Initializable,
    IPolygonConsensusBase,
    IPolygonZkEVMEtrogErrors
{
    // POL token address
    IERC20Upgradeable public immutable pol;

    // Global Exit Root interface
    IAgglayerGER public immutable globalExitRootManager;

    // PolygonZkEVM Bridge Address
    IAgglayerBridge public immutable bridgeAddress;

    // Rollup manager
    AgglayerManager public immutable rollupManager;

    // Address that will be able to adjust contract parameters
    address public admin;

    // This account will be able to accept the admin role
    address public pendingAdmin;

    // Trusted sequencer address
    address public trustedSequencer;

    // Trusted sequencer URL
    string public trustedSequencerURL;

    // L2 network name
    string public networkName;

    // Current accumulate input hash
    bytes32 public lastAccInputHash;

    // Queue of forced batches with their associated data
    // ForceBatchNum --> hashedForcedBatchData
    // hashedForcedBatchData: hash containing the necessary information to force a batch:
    // keccak256(keccak256(bytes transactions), bytes32 forcedGlobalExitRoot, unint64 forcedTimestamp, bytes32 forcedBlockHashL1)
    mapping(uint64 => bytes32) public forcedBatches;

    // Last forced batch
    uint64 public lastForceBatch;

    // Last forced batch included in the sequence
    uint64 public lastForceBatchSequenced;

    // Force batch timeout
    uint64 public forceBatchTimeout;

    // Indicates what address is able to do forced batches
    // If the address is set to 0, forced batches are open to everyone
    address public forceBatchAddress;

    // Token address that will be used to pay gas fees in this rollup. This variable it's just for read purposes
    address public gasTokenAddress;

    // Native network of the token address of the gas tokena address. This variable it's just for read purposes
    uint32 public gasTokenNetwork;

    /**
     * @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.
     */
    /// @custom:oz-renamed-from _gap
    uint256[50] private __gap;

    /**
     * @dev Emitted when the admin updates the trusted sequencer address
     */
    event SetTrustedSequencer(address newTrustedSequencer);

    /**
     * @dev Emitted when the admin updates the sequencer URL
     */
    event SetTrustedSequencerURL(string newTrustedSequencerURL);

    /**
     * @dev Emitted when the admin starts the two-step transfer role setting a new pending admin
     */
    event TransferAdminRole(address newPendingAdmin);

    /**
     * @dev Emitted when the pending admin accepts the admin role
     */
    event AcceptAdminRole(address newAdmin);

    // General parameters that will have in common all networks that deploys rollup manager

    /**
     * @param _globalExitRootManager Global exit root manager address
     * @param _pol POL token address
     * @param _bridgeAddress Bridge address
     * @param _rollupManager Global exit root manager address
     */
    constructor(
        IAgglayerGER _globalExitRootManager,
        IERC20Upgradeable _pol,
        IAgglayerBridge _bridgeAddress,
        AgglayerManager _rollupManager
    ) {
        globalExitRootManager = _globalExitRootManager;
        pol = _pol;
        bridgeAddress = _bridgeAddress;
        rollupManager = _rollupManager;

        // Disable initializers on the implementation following the best practices
        _disableInitializers();
    }

    /**
     * @param _admin Admin address
     * @param sequencer Trusted sequencer address
     * @param _gasTokenAddress Indicates the token address in mainnet that will be used as a gas token
     * Note if a wrapped token of the bridge is used, the original network and address of this wrapped are used instead
     * @param sequencerURL Trusted sequencer URL
     * @param _networkName L2 network name
     */
    function initialize(
        address _admin,
        address sequencer,
        uint32, //networkID,
        address _gasTokenAddress,
        string memory sequencerURL,
        string memory _networkName
    ) external virtual onlyRollupManager initializer {
        _initializePolygonConsensusBase(
            _admin,
            sequencer,
            _gasTokenAddress,
            sequencerURL,
            _networkName
        );
    }

    /**
     * @param _admin Admin address
     * @param sequencer Trusted sequencer address
     * @param _gasTokenAddress Indicates the token address in mainnet that will be used as a gas token
     * Note if a wrapped token of the bridge is used, the original network and address of this wrapped are used instead
     * @param sequencerURL Trusted sequencer URL
     * @param _networkName L2 network name
     */
    function _initializePolygonConsensusBase(
        address _admin,
        address sequencer,
        address _gasTokenAddress,
        string memory sequencerURL,
        string memory _networkName
    ) internal {
        if (_admin == address(0)) {
            revert AdminCannotBeZeroAddress();
        }

        admin = _admin;
        trustedSequencer = sequencer;

        trustedSequencerURL = sequencerURL;
        networkName = _networkName;

        gasTokenAddress = _gasTokenAddress;
    }

    modifier onlyAdmin() {
        if (admin != msg.sender) {
            revert OnlyAdmin();
        }
        _;
    }

    modifier onlyRollupManager() {
        if (address(rollupManager) != msg.sender) {
            revert OnlyRollupManager();
        }
        _;
    }

    //////////////////
    // admin functions
    //////////////////

    /**
     * @notice Allow the admin to set a new trusted sequencer
     * @param newTrustedSequencer Address of the new trusted sequencer
     */
    function setTrustedSequencer(
        address newTrustedSequencer
    ) external onlyAdmin {
        trustedSequencer = newTrustedSequencer;

        emit SetTrustedSequencer(newTrustedSequencer);
    }

    /**
     * @notice Allow the admin to set the trusted sequencer URL
     * @param newTrustedSequencerURL URL of trusted sequencer
     */
    function setTrustedSequencerURL(
        string memory newTrustedSequencerURL
    ) external onlyAdmin {
        trustedSequencerURL = newTrustedSequencerURL;

        emit SetTrustedSequencerURL(newTrustedSequencerURL);
    }

    /**
     * @notice Starts the admin role transfer
     * This is a two step process, the pending admin must accepted to finalize the process
     * @param newPendingAdmin Address of the new pending admin
     */
    function transferAdminRole(address newPendingAdmin) external onlyAdmin {
        pendingAdmin = newPendingAdmin;
        emit TransferAdminRole(newPendingAdmin);
    }

    /**
     * @notice Allow the current pending admin to accept the admin role
     */
    function acceptAdminRole() external {
        if (pendingAdmin != msg.sender) {
            revert OnlyPendingAdmin();
        }

        admin = pendingAdmin;
        emit AcceptAdminRole(pendingAdmin);
    }
}

File 51 of 52 : PolygonConstantsBase.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;

/**
 * This contract will contain the constants used across different contracts
 */
contract PolygonConstantsBase {
    // If the system a does not verify a batch inside this time window, the contract enters in emergency mode
    uint64 internal constant _HALT_AGGREGATION_TIMEOUT = 1 weeks;

    // Maximum batches that can be verified in one call. It depends on our current metrics
    // This should be a protection against someone that tries to generate huge chunk of invalid batches, and we can't prove otherwise before the pending timeout expires
    uint64 internal constant _MAX_VERIFY_BATCHES = 1000;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)

pragma solidity ^0.8.20;

import {ERC1967Utils} from "@openzeppelin/contracts5/proxy/ERC1967/ERC1967Utils.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts5/proxy/ERC1967/ERC1967Proxy.sol";
import {IERC1967} from "@openzeppelin/contracts5/interfaces/IERC1967.sol";
import {ProxyAdmin} from "@openzeppelin/contracts5/proxy/transparent/ProxyAdmin.sol";
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts5/proxy/transparent/TransparentUpgradeableProxy.sol";

/**
 * @dev Contract TransparentUpgradeableProxy from Openzeppelin v5 with the following modifications:
 * - Admin is a parameter in the constructor ( like previous versions) instead of being deployed
 * - Let the admin get access to the proxy
 * - Replace _msgSender() with msg.sender
 */
contract PolygonTransparentProxy is ERC1967Proxy {
    // An immutable address for the admin to avoid unnecessary SLOADs before each call
    // at the expense of removing the ability to change the admin once it's set.
    // This is acceptable if the admin is always a ProxyAdmin instance or similar contract
    // with its own ability to transfer the permissions to another account.
    address private immutable _admin;

    /**
     * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
     * 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) {
        _admin = admin;
        // Set the storage value and emit an event for ERC-1967 compatibility
        ERC1967Utils.changeAdmin(_proxyAdmin());
    }

    /**
     * @dev Returns the admin of this proxy.
     */
    function _proxyAdmin() internal virtual returns (address) {
        return _admin;
    }

    /**
     * @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 == _proxyAdmin()) {
            if (
                msg.sig !=
                ITransparentUpgradeableProxy.upgradeToAndCall.selector
            ) {
                super._fallback();
            } else {
                _dispatchUpgradeToAndCall();
            }
        } else {
            super._fallback();
        }
    }

    /**
     * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
     *
     * Requirements:
     *
     * - If `data` is empty, `msg.value` must be zero.
     */
    function _dispatchUpgradeToAndCall() private {
        (address newImplementation, bytes memory data) = abi.decode(
            msg.data[4:],
            (address, bytes)
        );
        ERC1967Utils.upgradeToAndCall(newImplementation, data);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 999999
  },
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IAgglayerGER","name":"_globalExitRootManager","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"_pol","type":"address"},{"internalType":"contract IAgglayerBridge","name":"_bridgeAddress","type":"address"},{"internalType":"contract AgglayerManager","name":"_rollupManager","type":"address"},{"internalType":"contract IAgglayerGateway","name":"_aggLayerGateway","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"AggchainManagerAlreadyInitialized","type":"error"},{"inputs":[],"name":"AggchainManagerCannotBeZero","type":"error"},{"inputs":[],"name":"AggchainSignersHashNotInitialized","type":"error"},{"inputs":[],"name":"AggchainSignersTooHigh","type":"error"},{"inputs":[],"name":"AggchainVKeyNotFound","type":"error"},{"inputs":[],"name":"BatchAlreadyVerified","type":"error"},{"inputs":[],"name":"BatchNotSequencedOrNotSequenceEnd","type":"error"},{"inputs":[],"name":"ConflictingDefaultSignersConfiguration","type":"error"},{"inputs":[],"name":"ExceedMaxVerifyBatches","type":"error"},{"inputs":[],"name":"FinalAccInputHashDoesNotMatch","type":"error"},{"inputs":[],"name":"FinalNumBatchBelowLastVerifiedBatch","type":"error"},{"inputs":[],"name":"FinalNumBatchDoesNotMatchPendingState","type":"error"},{"inputs":[],"name":"FinalPendingStateNumInvalid","type":"error"},{"inputs":[],"name":"ForceBatchNotAllowed","type":"error"},{"inputs":[],"name":"ForceBatchTimeoutNotExpired","type":"error"},{"inputs":[],"name":"ForceBatchesAlreadyActive","type":"error"},{"inputs":[],"name":"ForceBatchesDecentralized","type":"error"},{"inputs":[],"name":"ForceBatchesNotAllowedOnEmergencyState","type":"error"},{"inputs":[],"name":"ForceBatchesOverflow","type":"error"},{"inputs":[],"name":"ForcedDataDoesNotMatch","type":"error"},{"inputs":[],"name":"FunctionNotSupported","type":"error"},{"inputs":[],"name":"GasTokenNetworkMustBeZeroOnEther","type":"error"},{"inputs":[],"name":"GlobalExitRootNotExist","type":"error"},{"inputs":[],"name":"HaltTimeoutNotExpired","type":"error"},{"inputs":[],"name":"HaltTimeoutNotExpiredAfterEmergencyState","type":"error"},{"inputs":[],"name":"HugeTokenMetadataNotSupported","type":"error"},{"inputs":[],"name":"IndicesNotInDescendingOrder","type":"error"},{"inputs":[],"name":"InitNumBatchAboveLastVerifiedBatch","type":"error"},{"inputs":[],"name":"InitNumBatchDoesNotMatchPendingState","type":"error"},{"inputs":[],"name":"InitSequencedBatchDoesNotMatch","type":"error"},{"inputs":[],"name":"InvalidAggchainDataLength","type":"error"},{"inputs":[],"name":"InvalidAggchainType","type":"error"},{"inputs":[],"name":"InvalidInitAggchainVKey","type":"error"},{"inputs":[],"name":"InvalidInitializeFunction","type":"error"},{"inputs":[],"name":"InvalidInitializeTransaction","type":"error"},{"inputs":[],"name":"InvalidInitializer","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidRangeBatchTimeTarget","type":"error"},{"inputs":[],"name":"InvalidRangeForceBatchTimeout","type":"error"},{"inputs":[],"name":"InvalidRangeMultiplierBatchFee","type":"error"},{"inputs":[],"name":"InvalidThreshold","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[],"name":"L1InfoTreeLeafCountInvalid","type":"error"},{"inputs":[],"name":"MaxTimestampSequenceInvalid","type":"error"},{"inputs":[],"name":"MetadataArrayLengthMismatch","type":"error"},{"inputs":[],"name":"NewAccInputHashDoesNotExist","type":"error"},{"inputs":[],"name":"NewPendingStateTimeoutMustBeLower","type":"error"},{"inputs":[],"name":"NewStateRootNotInsidePrime","type":"error"},{"inputs":[],"name":"NewTrustedAggregatorTimeoutMustBeLower","type":"error"},{"inputs":[],"name":"NotEnoughMaticAmount","type":"error"},{"inputs":[],"name":"NotEnoughPOLAmount","type":"error"},{"inputs":[],"name":"OldAccInputHashDoesNotExist","type":"error"},{"inputs":[],"name":"OldStateRootDoesNotExist","type":"error"},{"inputs":[],"name":"OnlyAdmin","type":"error"},{"inputs":[],"name":"OnlyAggchainManager","type":"error"},{"inputs":[],"name":"OnlyAggchainMetadataManager","type":"error"},{"inputs":[],"name":"OnlyPendingAdmin","type":"error"},{"inputs":[],"name":"OnlyPendingAggchainManager","type":"error"},{"inputs":[],"name":"OnlyRollupManager","type":"error"},{"inputs":[],"name":"OnlyTrustedAggregator","type":"error"},{"inputs":[],"name":"OnlyTrustedSequencer","type":"error"},{"inputs":[],"name":"OwnedAggchainVKeyAlreadyAdded","type":"error"},{"inputs":[],"name":"OwnedAggchainVKeyNotFound","type":"error"},{"inputs":[],"name":"PendingStateDoesNotExist","type":"error"},{"inputs":[],"name":"PendingStateInvalid","type":"error"},{"inputs":[],"name":"PendingStateNotConsolidable","type":"error"},{"inputs":[],"name":"PendingStateTimeoutExceedHaltAggregationTimeout","type":"error"},{"inputs":[],"name":"SequenceZeroBatches","type":"error"},{"inputs":[],"name":"SequencedTimestampBelowForcedTimestamp","type":"error"},{"inputs":[],"name":"SequencedTimestampInvalid","type":"error"},{"inputs":[],"name":"SignerAlreadyExists","type":"error"},{"inputs":[],"name":"SignerCannotBeZero","type":"error"},{"inputs":[],"name":"SignerDoesNotExist","type":"error"},{"inputs":[],"name":"SignerURLCannotBeEmpty","type":"error"},{"inputs":[],"name":"StoredRootMustBeDifferentThanNewRoot","type":"error"},{"inputs":[],"name":"TransactionsLengthAboveMax","type":"error"},{"inputs":[],"name":"TrustedAggregatorTimeoutExceedHaltAggregationTimeout","type":"error"},{"inputs":[],"name":"TrustedAggregatorTimeoutNotExpired","type":"error"},{"inputs":[],"name":"UseDefaultSignersAlreadyDisabled","type":"error"},{"inputs":[],"name":"UseDefaultSignersAlreadyEnabled","type":"error"},{"inputs":[],"name":"UseDefaultVkeysAlreadyDisabled","type":"error"},{"inputs":[],"name":"UseDefaultVkeysAlreadyEnabled","type":"error"},{"inputs":[],"name":"ZeroValueAggchainVKey","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AcceptAdminRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAggchainManager","type":"address"},{"indexed":false,"internalType":"address","name":"newAggchainManager","type":"address"}],"name":"AcceptAggchainManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes32","name":"newAggchainVKey","type":"bytes32"}],"name":"AddAggchainVKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"value","type":"string"}],"name":"AggchainMetadataSet","type":"event"},{"anonymous":false,"inputs":[],"name":"DisableUseDefaultSignersFlag","type":"event"},{"anonymous":false,"inputs":[],"name":"DisableUseDefaultVkeysFlag","type":"event"},{"anonymous":false,"inputs":[],"name":"EnableUseDefaultSignersFlag","type":"event"},{"anonymous":false,"inputs":[],"name":"EnableUseDefaultVkeysFlag","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[],"name":"OnVerifyPessimisticECDSAMultisig","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAggchainMetadataManager","type":"address"},{"indexed":false,"internalType":"address","name":"newAggchainMetadataManager","type":"address"}],"name":"SetAggchainMetadataManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTrustedSequencer","type":"address"}],"name":"SetTrustedSequencer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newTrustedSequencerURL","type":"string"}],"name":"SetTrustedSequencerURL","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"aggchainSigners","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"newThreshold","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"newAggchainMultisigHash","type":"bytes32"}],"name":"SignersAndThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"TransferAdminRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currentAggchainManager","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAggchainManager","type":"address"}],"name":"TransferAggchainManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes32","name":"previousAggchainVKey","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newAggchainVKey","type":"bytes32"}],"name":"UpdateAggchainVKey","type":"event"},{"inputs":[],"name":"AGGCHAIN_ECDSA_MULTISIG_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AGGCHAIN_TYPE","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONSENSUS_TYPE","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_AGGCHAIN_SIGNERS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_legacypendingVKeyManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_legacyvKeyManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptAggchainManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"addOwnedAggchainVKey","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggLayerGateway","outputs":[{"internalType":"contract IAgglayerGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggchainManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"aggchainMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggchainMetadataManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggchainMultisigHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"aggchainSigners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string[]","name":"keys","type":"string[]"},{"internalType":"string[]","name":"values","type":"string[]"}],"name":"batchSetAggchainMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeAddress","outputs":[{"internalType":"contract IAgglayerBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableUseDefaultSignersFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableUseDefaultVkeysFlag","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableUseDefaultSignersFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableUseDefaultVkeysFlag","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceBatchAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceBatchTimeout","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"forcedBatches","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasTokenNetwork","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"aggchainData","type":"bytes"}],"name":"getAggchainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainMultisigHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainSignerInfos","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"url","type":"string"}],"internalType":"struct IAggchainSigners.SignerInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainSigners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainSignersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"aggchainVKeySelector","type":"bytes4"}],"name":"getAggchainTypeFromSelector","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"getAggchainVKey","outputs":[{"internalType":"bytes32","name":"aggchainVKey","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes2","name":"aggchainVKeyVersion","type":"bytes2"},{"internalType":"bytes2","name":"aggchainType","type":"bytes2"}],"name":"getAggchainVKeySelector","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"aggchainVKeySelector","type":"bytes4"}],"name":"getAggchainVKeyVersionFromSelector","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"aggchainData","type":"bytes"}],"name":"getVKeyAndAggchainParams","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"globalExitRootManager","outputs":[{"internalType":"contract IAgglayerGER","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAggchainManager","type":"address"}],"name":"initAggchainManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_trustedSequencer","type":"address"},{"internalType":"address","name":"_gasTokenAddress","type":"address"},{"internalType":"string","name":"_trustedSequencerURL","type":"string"},{"internalType":"string","name":"_networkName","type":"string"},{"internalType":"bool","name":"_useDefaultSigners","type":"bool"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"url","type":"string"}],"internalType":"struct IAggchainSigners.SignerInfo[]","name":"_signersToAdd","type":"tuple[]"},{"internalType":"uint256","name":"_newThreshold","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"},{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"isSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastAccInputHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastForceBatch","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastForceBatchSequenced","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrateFromLegacyConsensus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"networkName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"aggchainData","type":"bytes"}],"name":"onVerifyPessimistic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"aggchainVKeySelector","type":"bytes4"}],"name":"ownedAggchainVKeys","outputs":[{"internalType":"bytes32","name":"ownedAggchainVKey","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAggchainManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pol","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollupManager","outputs":[{"internalType":"contract AgglayerManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setAggchainMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAggchainMetadataManager","type":"address"}],"name":"setAggchainMetadataManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTrustedSequencer","type":"address"}],"name":"setTrustedSequencer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newTrustedSequencerURL","type":"string"}],"name":"setTrustedSequencerURL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"signerToURLs","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"threshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"transferAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAggchainManager","type":"address"}],"name":"transferAggchainManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedSequencer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedSequencerURL","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"updateOwnedAggchainVKey","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IAggchainSigners.RemoveSignerInfo[]","name":"_signersToRemove","type":"tuple[]"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"url","type":"string"}],"internalType":"struct IAggchainSigners.SignerInfo[]","name":"_signersToAdd","type":"tuple[]"},{"internalType":"uint256","name":"_newThreshold","type":"uint256"}],"name":"updateSignersAndThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"useDefaultSigners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"useDefaultVkeys","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]

610120604052348015610010575f5ffd5b506040516144e73803806144e783398101604081905261002f916101c4565b6001600160a01b0380861660a05280851660805280841660c052821660e05284848484848484848461005f6100f0565b505050506001600160a01b038116158061008057506001600160a01b038516155b8061009257506001600160a01b038416155b806100a457506001600160a01b038316155b806100b657506001600160a01b038216155b156100d45760405163f6b2911f60e01b815260040160405180910390fd5b6001600160a01b03166101005250610235975050505050505050565b5f54610100900460ff161561015b5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff90811610156101ab575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146101c1575f5ffd5b50565b5f5f5f5f5f60a086880312156101d8575f5ffd5b85516101e3816101ad565b60208701519095506101f4816101ad565b6040870151909450610205816101ad565b6060870151909350610216816101ad565b6080870151909250610227816101ad565b809150509295509295909350565b60805160a05160c05160e051610100516142366102b15f395f8181610958015281816113740152818161166701528181611c3a0152818161248d01528181612547015261265c01525f818161072d01528181610c1f01528181611db1015261202401525f61091e01525f610a3301525f610a8201526142365ff3fe608060405234801561000f575f5ffd5b5060043610610441575f3560e01c80636e7fbce911610243578063c754c7ed11610148578063e75235b8116100c3578063effb847911610093578063f851a44011610079578063f851a44014610b03578063fc5014d614610b28578063fd7d249314610b4d575f5ffd5b8063effb847914610ad1578063f51f563a14610af0575f5ffd5b8063e75235b814610aa4578063e7a7ed0214610aac578063e90a340914610ac0578063efe6c9f41461049d575f5ffd5b8063cea5a4c011610118578063d02103ca116100fe578063d02103ca14610a2e578063d9c2853914610a55578063e46761c414610a7d575f5ffd5b8063cea5a4c014610a06578063cfa8ed4714610a0e575f5ffd5b8063c754c7ed146109bb578063c89e42df146109e3578063ca69e7dc146109f6578063cce7d0df146109fe575f5ffd5b80638c3d7301116101d8578063ab0475cf116101a8578063b3a326f71161018e578063b3a326f71461098d578063bdfbed7e146109a0578063be647d03146109b3575f5ffd5b8063ab0475cf14610953578063ada8f9191461097a575f5ffd5b80638c3d7301146108fe5780639ee4afa314610906578063a3c573eb14610919578063a8d31bd914610940575f5ffd5b806374f0b0c11161021357806374f0b0c114610887578063750a6e72146108a7578063759664d4146108af5780637df73e27146108eb575f5ffd5b80636e7fbce91461083a5780636ff512cc1461084157806371257022146108545780637388c43614610867575f5ffd5b806339b7ec1611610349578063527570f1116102de5780635ecaca2b116102ae5780636a55f66c116102945780636a55f66c146107ff5780636b8616ce146108125780636e05d2cd14610831575f5ffd5b80635ecaca2b146107cc578063697427f6146107ec575f5ffd5b8063527570f114610758578063542028d51461077857806354fd4d501461078057806359a03e0f146107b9575f5ffd5b806342cde4e81161031957806342cde4e8146106e657806345605267146106ef57806349b7b802146107285780634a5db0c11461074f575f5ffd5b806339b7ec16146106545780633c351e10146106745780633cbc795b146106945780633e1e0121146106d1575f5ffd5b806319451a8f116103d95780632c111c06116103a9578063349d40461161038f578063349d40461461061957806335acd6c21461062e57806336cd6b5b14610641575f5ffd5b80632c111c06146105f9578063314eb17b146104f6575f5ffd5b806319451a8f146104f65780631d0b435e14610509578063267822471461054d57806326f9b76d14610592575f5ffd5b80631489e707116104145780631489e7071461049d578063153c3b7f146104a557806315981b29146104b8578063188d9180146104c0575f5ffd5b806301fcf6a014610445578063052358be1461046b57806306e7666514610480578063107bf28c14610488575b5f5ffd5b6104586104533660046132ae565b505f90565b6040519081526020015b60405180910390f35b61047e610479366004613313565b610b55565b005b61047e610c1d565b610490610fb6565b60405161046291906133cb565b61047e611042565b61047e6104b336600461341e565b6110c5565b61047e611224565b603e546104e6907501000000000000000000000000000000000000000000900460ff1681565b6040519015158152602001610462565b61047e61050436600461347e565b611042565b61051c6105173660046134d5565b6112fb565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610462565b60015461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610462565b6105c86105a03660046132ae565b60101b7fffff0000000000000000000000000000000000000000000000000000000000001690565b6040517fffff0000000000000000000000000000000000000000000000000000000000009091168152602001610462565b60085461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61062161134b565b6040516104629190613506565b61056d61063c3660046135b4565b6115f1565b61049061064f3660046135f7565b611626565b60465461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60095461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b6009546106bc9074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610462565b6106d961163e565b6040516104629190613612565b61045860445481565b60075461070f9068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610462565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b61045860455481565b60405461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61049061177d565b60408051808201909152600681527f76312e302e3000000000000000000000000000000000000000000000000000006020820152610490565b6104906107c73660046137ad565b61178a565b603d5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61047e6107fa36600461391c565b6117ae565b61045861080d3660046139f7565b611a5a565b610458610820366004613a3c565b60066020525f908152604090205481565b61045860055481565b6105c85f81565b61047e61084f3660046135f7565b611ad4565b61047e610862366004613a63565b611b9d565b603f5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b603e5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61045860ff81565b6104906040518060400160405280600681526020017f76312e302e30000000000000000000000000000000000000000000000000000081525081565b6104e66108f93660046135f7565b611bcf565b61047e611cdc565b61047e610914366004613b17565b611daf565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b61047e61094e3660046135f7565b611e82565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b61047e6109883660046135f7565b611f59565b61047e61099b3660046135f7565b612022565b61047e6109ae3660046135f7565b6121a8565b61047e6122c2565b60075461070f90700100000000000000000000000000000000900467ffffffffffffffff1681565b61047e6109f13660046137ad565b6123d3565b610458612465565b61045861251f565b6106bc600181565b60025461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b610a68610a633660046139f7565b6125ee565b60408051928352602083019190915201610462565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b610458612634565b60075461070f9067ffffffffffffffff1681565b6105c8610ace3660046132ae565b90565b610458610adf3660046132ae565b60416020525f908152604090205481565b61047e610afe366004613b56565b6126ca565b5f5461056d9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b603e546104e69074010000000000000000000000000000000000000000900460ff1681565b61047e61272b565b60465473ffffffffffffffffffffffffffffffffffffffff163314610ba6576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c1784848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f880181900481028201810190925286815292508691508590819084018382808284375f9201919091525061282392505050565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c8c576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff16158015610cdc57505f5460ff8083169116105b610d6d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c16600114610ddd576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f54603f80546201000090920473ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff000000000000000000000000000000000000000090921691909117905560038054610e3790613c49565b90505f03610e9b5760025460408051808201909152600681527f4e4f5f55524c00000000000000000000000000000000000000000000000000006020820152610e969173ffffffffffffffffffffffffffffffffffffffff16906128a0565b610f48565b60025460038054610f489273ffffffffffffffffffffffffffffffffffffffff169190610ec790613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610ef390613c49565b8015610f3e5780601f10610f1557610100808354040283529160200191610f3e565b820191905f5260205f20905b815481529060010190602001808311610f2157829003601f168201915b50505050506128a0565b6001604455610f55612a15565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a150565b60048054610fc390613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610fef90613c49565b801561103a5780601f106110115761010080835404028352916020019161103a565b820191905f5260205f20905b81548152906001019060200180831161101d57829003601f168201915b505050505081565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611093576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd37a223a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60465473ffffffffffffffffffffffffffffffffffffffff163314611116576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82818114611150576040517f059d0ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b8181101561121c5761121486868381811061116f5761116f613c94565b90506020028101906111819190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508892508791508590508181106111c9576111c9613c94565b90506020028101906111db9190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061282392505050565b600101611152565b505050505050565b60405473ffffffffffffffffffffffffffffffffffffffff163314611275576040517f3ac87ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80546040805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682179096559490911682558151921680835260208301939093527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b7fffff00000000000000000000000000000000000000000000000000000000000082167dffff00000000000000000000000000000000000000000000000000000000601083901c16175b92915050565b603e546060907501000000000000000000000000000000000000000000900460ff1615611424577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663349d40466040518163ffffffff1660e01b81526004015f60405180830381865afa1580156113da573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613d22565b905090565b6042545f9067ffffffffffffffff8111156114415761144161366a565b60405190808252806020026020018201604052801561148657816020015b604080518082019091525f81526060602082015281526020019060019003908161145f5790505b5090505f5b6042548110156115eb576040518060400160405280604283815481106114b3576114b3613c94565b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160435f6042858154811061150c5761150c613c94565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020805461154790613c49565b80601f016020809104026020016040519081016040528092919081815260200182805461157390613c49565b80156115be5780601f10611595576101008083540402835291602001916115be565b820191905f5260205f20905b8154815290600101906020018083116115a157829003601f168201915b50505050508152508282815181106115d8576115d8613c94565b602090810291909101015260010161148b565b50919050565b60428181548110611600575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60436020525f908152604090208054610fc390613c49565b603e546060907501000000000000000000000000000000000000000000900460ff1615611712577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633e1e01216040518163ffffffff1660e01b81526004015f60405180830381865afa1580156116cd573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613e82565b604280548060200260200160405190810160405280929190818152602001828054801561177357602002820191905f5260205f20905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611748575b5050505050905090565b60038054610fc390613c49565b805160208183018101805160478252928201919093012091528054610fc390613c49565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146117ff576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff1615801561184f57505f5460ff8083169116105b6118db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610d64565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c1615611949576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61195a89898989895f8a8180612a99565b83156119ac578251151580611970575060445415155b156119a7576040517f996c343000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119f2565b604080515f808252602082019092526119f2916119ea565b604080518082019091525f80825260208201528152602001906001900390816119c45790505b508484612bc1565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b5f5f611a6461251f565b90505f5f611a71856125ee565b6040517c010000000000000000000000000000000000000000000000000000000060208201526024810183905260448101829052606481018690529193509150608401604051602081830303815290604052805190602001209350505050919050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611b2a576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff54144f9611984021529f814a1cb6a41e22c58351510a0d9f7e822618abb9cc090602001610fab565b6040517ff57ac68300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e545f907501000000000000000000000000000000000000000000900460ff1615611ca3576040517f7df73e2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527f00000000000000000000000000000000000000000000000000000000000000001690637df73e2790602401602060405180830381865afa158015611c7f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113459190613f1c565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526043602052604081208054611cd290613c49565b9050119050919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d2d576040517fd1ec4b2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff9092166201000081029290921790556040519081527f056dc487bbf0795d0bbb1b4f0af523a855503cff740bfb4d5475f7a90c091e8e906020015b60405180910390a1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314611e1e576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015611e56576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc118263690a4306c74bd1bc80b55962addc2d9e61619ac0b2c2883badbbd01d8905f90a15050565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611ed3576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6046805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f82ae2ec69f24a6de4517a5a45d4983651b578b3d8dc9262af5e352572fc64373910160405180910390a15050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611faf576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa5b56b7906fd0a20e3f35120dd8343db1e12e037a6c90111c7e42885e82a1ce690602001610fab565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314612091576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f5473ffffffffffffffffffffffffffffffffffffffff16156120e1576040517f257bb0bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661212e576040517fd6bdac3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080515f815260208101929092527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146121f9576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612246576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178355603f5483519116815260208101919091527fa3d8e5d045432398be30f83ce7c35a7bfc220c1b66cc5bf3f4dd4d539d93fab69101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff163314612313576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff1615612369576040517f278d998800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790556040517f67ec953bdc8546ede08f8ee91e5205a1d1814e126cb8f5d00a918ddb1eaa292b905f90a1565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314612429576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60036124358282613f82565b507f6b8f723a4c7a5335cafae8a598a0aa0301be1387c037dccc085b62add6448b2081604051610fab91906133cb565b603e545f907501000000000000000000000000000000000000000000900460ff1615612518577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ca69e7dc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061141f9190614099565b5060425490565b603e545f907501000000000000000000000000000000000000000000900460ff16156125ae577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663cce7d0df6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b6045546125e7576040517fdd41f1ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060455490565b5f5f82515f1461262a576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f928392509050565b603e545f907501000000000000000000000000000000000000000000900460ff16156126c3577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e75235b86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b5060445490565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461271b576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612726838383612bc1565b505050565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461277c576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff166127d1576040517f5aa930a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556040517f4c75580a56c734245a7418eb07d8a311e1bff79f982fed747da3589630e414be905f90a1565b8060478360405161283491906140b0565b9081526020016040518091039020908161284e9190613f82565b508160405161285d91906140b0565b60405180910390207f2779f9edd5ec4e0a99bffdea4008c8b979200959062a2bf00142acb939ca1b648260405161289491906133cb565b60405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff82166128ed576040517f7b3a0df600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80515f03612927576040517f8715f5fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152604360205260408120805461295690613c49565b90501115612990576040517f38615ecc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60428054600181019091557f38dfe4635b27babeca8be38d3b448cb5161a639b899a14825ba9c8d7892eb8c30180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f9081526043602052604090206127268282613f82565b6044546042604051602001612a2b9291906140c6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052805160209091012060458190556044547f66d7b0647fdd512b69cbf4f8e1ce8068bfe0b236168e2704ba13b07425eaa74392611da59260429291614119565b5f54610100900460ff16612b2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b73ffffffffffffffffffffffffffffffffffffffff89161580612b66575073ffffffffffffffffffffffffffffffffffffffff8816155b15612b9d576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612baa8989898989612db2565b612bb684848484612ee0565b505050505050505050565b600183511115612c69575f5b60018451612bdb91906141ad565b811015612c675783612bee8260016141c0565b81518110612bfe57612bfe613c94565b602002602001015160200151848281518110612c1c57612c1c613c94565b60200260200101516020015111612c5f576040517fb9a11d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101612bcd565b505b5f5b8351811015612cbf57612cb7848281518110612c8957612c89613c94565b60200260200101515f0151858381518110612ca657612ca6613c94565b602002602001015160200151613036565b600101612c6b565b505f5b8251811015612d1657612d0e838281518110612ce057612ce0613c94565b60200260200101515f0151848381518110612cfd57612cfd613c94565b6020026020010151602001516128a0565b600101612cc2565b5060425460ff1015612d54576040517f5a7f382c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604254811180612d6e575060425415801590612d6e575080155b15612da5576040517faabd5a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6044819055612726612a15565b73ffffffffffffffffffffffffffffffffffffffff8516612dff576040517fe6cd565400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff8881169190910291909117909155600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000169186169190911790556003612e868382613f82565b506004612e938282613f82565b5050600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9390931692909217909155505050565b5f54610100900460ff16612f76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b603e80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000951515959095027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1694909417750100000000000000000000000000000000000000000093151593909302929092179092557fffffffff00000000000000000000000000000000000000000000000000000000165f90815260416020526040902055565b604254808210613072576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166042838154811061309c5761309c613c94565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16146130f4576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260436020526040812061312191613228565b604261312e6001836141ad565b8154811061313e5761313e613c94565b5f918252602090912001546042805473ffffffffffffffffffffffffffffffffffffffff909216918490811061317657613176613c94565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060428054806131cc576131cc6141d3565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505050565b50805461323490613c49565b5f825580601f10613243575050565b601f0160209004905f5260205f209081019061325f9190613262565b50565b5b80821115613276575f8155600101613263565b5090565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b919050565b5f602082840312156132be575f5ffd5b6132c78261327a565b9392505050565b5f5f83601f8401126132de575f5ffd5b50813567ffffffffffffffff8111156132f5575f5ffd5b60208301915083602082850101111561330c575f5ffd5b9250929050565b5f5f5f5f60408587031215613326575f5ffd5b843567ffffffffffffffff81111561333c575f5ffd5b613348878288016132ce565b909550935050602085013567ffffffffffffffff811115613367575f5ffd5b613373878288016132ce565b95989497509550505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6132c7602083018461337f565b5f5f83601f8401126133ed575f5ffd5b50813567ffffffffffffffff811115613404575f5ffd5b6020830191508360208260051b850101111561330c575f5ffd5b5f5f5f5f60408587031215613431575f5ffd5b843567ffffffffffffffff811115613447575f5ffd5b613453878288016133dd565b909550935050602085013567ffffffffffffffff811115613472575f5ffd5b613373878288016133dd565b5f5f6040838503121561348f575f5ffd5b6134988361327a565b946020939093013593505050565b80357fffff000000000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b5f5f604083850312156134e6575f5ffd5b6134ef836134a6565b91506134fd602084016134a6565b90509250929050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156135a8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815173ffffffffffffffffffffffffffffffffffffffff81511686526020810151905060406020870152613592604087018261337f565b955050602093840193919091019060010161352c565b50929695505050505050565b5f602082840312156135c4575f5ffd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461325f575f5ffd5b80356132a9816135cb565b5f60208284031215613607575f5ffd5b81356132c7816135cb565b602080825282518282018190525f918401906040840190835b8181101561365f57835173ffffffffffffffffffffffffffffffffffffffff1683526020938401939092019160010161362b565b509095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff811182821017156136ba576136ba61366a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156137075761370761366a565b604052919050565b5f67ffffffffffffffff8211156137285761372861366a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f6137666137618461370f565b6136c0565b9050828152838383011115613779575f5ffd5b828260208301375f602084830101529392505050565b5f82601f83011261379e575f5ffd5b6132c783833560208501613754565b5f602082840312156137bd575f5ffd5b813567ffffffffffffffff8111156137d3575f5ffd5b6137df8482850161378f565b949350505050565b801515811461325f575f5ffd5b80356132a9816137e7565b5f67ffffffffffffffff8211156138185761381861366a565b5060051b60200190565b5f82601f830112613831575f5ffd5b813561383f613761826137ff565b8082825260208201915060208360051b860101925085831115613860575f5ffd5b602085015b8381101561391257803567ffffffffffffffff811115613883575f5ffd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156138b6575f5ffd5b6138be613697565b60208201356138cc816135cb565b8152604082013567ffffffffffffffff8111156138e7575f5ffd5b6138f68a60208386010161378f565b6020830152508085525050602083019250602081019050613865565b5095945050505050565b5f5f5f5f5f5f5f5f610100898b031215613934575f5ffd5b61393d896135ec565b975061394b60208a016135ec565b965061395960408a016135ec565b9550606089013567ffffffffffffffff811115613974575f5ffd5b6139808b828c0161378f565b955050608089013567ffffffffffffffff81111561399c575f5ffd5b6139a88b828c0161378f565b9450506139b760a08a016137f4565b925060c089013567ffffffffffffffff8111156139d2575f5ffd5b6139de8b828c01613822565b989b979a50959894979396929550929360e00135925050565b5f60208284031215613a07575f5ffd5b813567ffffffffffffffff811115613a1d575f5ffd5b8201601f81018413613a2d575f5ffd5b6137df84823560208401613754565b5f60208284031215613a4c575f5ffd5b813567ffffffffffffffff811681146132c7575f5ffd5b5f5f5f5f5f5f60c08789031215613a78575f5ffd5b8635613a83816135cb565b95506020870135613a93816135cb565b9450604087013563ffffffff81168114613aab575f5ffd5b93506060870135613abb816135cb565b9250608087013567ffffffffffffffff811115613ad6575f5ffd5b613ae289828a0161378f565b92505060a087013567ffffffffffffffff811115613afe575f5ffd5b613b0a89828a0161378f565b9150509295509295509295565b5f5f60208385031215613b28575f5ffd5b823567ffffffffffffffff811115613b3e575f5ffd5b613b4a858286016132ce565b90969095509350505050565b5f5f5f60608486031215613b68575f5ffd5b833567ffffffffffffffff811115613b7e575f5ffd5b8401601f81018613613b8e575f5ffd5b8035613b9c613761826137ff565b8082825260208201915060208360061b850101925088831115613bbd575f5ffd5b6020840193505b82841015613c0d576040848a031215613bdb575f5ffd5b613be3613697565b8435613bee816135cb565b8152602085810135818301529083526040909401939190910190613bc4565b9550505050602084013567ffffffffffffffff811115613c2b575f5ffd5b613c3786828701613822565b93969395505050506040919091013590565b600181811c90821680613c5d57607f821691505b6020821081036115eb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613cf4575f5ffd5b83018035915067ffffffffffffffff821115613d0e575f5ffd5b60200191503681900382131561330c575f5ffd5b5f60208284031215613d32575f5ffd5b815167ffffffffffffffff811115613d48575f5ffd5b8201601f81018413613d58575f5ffd5b8051613d66613761826137ff565b8082825260208201915060208360051b850101925086831115613d87575f5ffd5b602084015b83811015613e7757805167ffffffffffffffff811115613daa575f5ffd5b85016040818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011215613ddd575f5ffd5b613de5613697565b6020820151613df3816135cb565b8152604082015167ffffffffffffffff811115613e0e575f5ffd5b60208184010192505089601f830112613e25575f5ffd5b8151613e336137618261370f565b8181528b6020838601011115613e47575f5ffd5b8160208501602083015e5f6020838301015280602084015250508085525050602083019250602081019050613d8c565b509695505050505050565b5f60208284031215613e92575f5ffd5b815167ffffffffffffffff811115613ea8575f5ffd5b8201601f81018413613eb8575f5ffd5b8051613ec6613761826137ff565b8082825260208201915060208360051b850101925086831115613ee7575f5ffd5b6020840193505b82841015613f12578351613f01816135cb565b825260209384019390910190613eee565b9695505050505050565b5f60208284031215613f2c575f5ffd5b81516132c7816137e7565b601f82111561272657805f5260205f20601f840160051c81016020851015613f5c5750805b601f840160051c820191505b81811015613f7b575f8155600101613f68565b5050505050565b815167ffffffffffffffff811115613f9c57613f9c61366a565b613fb081613faa8454613c49565b84613f37565b6020601f821160018114614001575f8315613fcb5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455613f7b565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561404e578785015182556020948501946001909201910161402e565b508482101561408a57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b5f602082840312156140a9575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b8281525f602082018354845f5260205f205f5b8281101561410d57815473ffffffffffffffffffffffffffffffffffffffff168452602090930192600191820191016140d9565b50919695505050505050565b606080825284549082018190525f8581526020812090916080840190835b8181101561416b57835473ffffffffffffffffffffffffffffffffffffffff16835260019384019360209093019201614137565b50506020840195909552505060400152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561134557611345614180565b8082018082111561134557611345614180565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212204c8d89fafb3caf45617cd4d4b662407a5f97b0708f57d8518c4bda54f7b3cad464736f6c634300081c0033000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f60000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab2000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b3

Deployed Bytecode

0x608060405234801561000f575f5ffd5b5060043610610441575f3560e01c80636e7fbce911610243578063c754c7ed11610148578063e75235b8116100c3578063effb847911610093578063f851a44011610079578063f851a44014610b03578063fc5014d614610b28578063fd7d249314610b4d575f5ffd5b8063effb847914610ad1578063f51f563a14610af0575f5ffd5b8063e75235b814610aa4578063e7a7ed0214610aac578063e90a340914610ac0578063efe6c9f41461049d575f5ffd5b8063cea5a4c011610118578063d02103ca116100fe578063d02103ca14610a2e578063d9c2853914610a55578063e46761c414610a7d575f5ffd5b8063cea5a4c014610a06578063cfa8ed4714610a0e575f5ffd5b8063c754c7ed146109bb578063c89e42df146109e3578063ca69e7dc146109f6578063cce7d0df146109fe575f5ffd5b80638c3d7301116101d8578063ab0475cf116101a8578063b3a326f71161018e578063b3a326f71461098d578063bdfbed7e146109a0578063be647d03146109b3575f5ffd5b8063ab0475cf14610953578063ada8f9191461097a575f5ffd5b80638c3d7301146108fe5780639ee4afa314610906578063a3c573eb14610919578063a8d31bd914610940575f5ffd5b806374f0b0c11161021357806374f0b0c114610887578063750a6e72146108a7578063759664d4146108af5780637df73e27146108eb575f5ffd5b80636e7fbce91461083a5780636ff512cc1461084157806371257022146108545780637388c43614610867575f5ffd5b806339b7ec1611610349578063527570f1116102de5780635ecaca2b116102ae5780636a55f66c116102945780636a55f66c146107ff5780636b8616ce146108125780636e05d2cd14610831575f5ffd5b80635ecaca2b146107cc578063697427f6146107ec575f5ffd5b8063527570f114610758578063542028d51461077857806354fd4d501461078057806359a03e0f146107b9575f5ffd5b806342cde4e81161031957806342cde4e8146106e657806345605267146106ef57806349b7b802146107285780634a5db0c11461074f575f5ffd5b806339b7ec16146106545780633c351e10146106745780633cbc795b146106945780633e1e0121146106d1575f5ffd5b806319451a8f116103d95780632c111c06116103a9578063349d40461161038f578063349d40461461061957806335acd6c21461062e57806336cd6b5b14610641575f5ffd5b80632c111c06146105f9578063314eb17b146104f6575f5ffd5b806319451a8f146104f65780631d0b435e14610509578063267822471461054d57806326f9b76d14610592575f5ffd5b80631489e707116104145780631489e7071461049d578063153c3b7f146104a557806315981b29146104b8578063188d9180146104c0575f5ffd5b806301fcf6a014610445578063052358be1461046b57806306e7666514610480578063107bf28c14610488575b5f5ffd5b6104586104533660046132ae565b505f90565b6040519081526020015b60405180910390f35b61047e610479366004613313565b610b55565b005b61047e610c1d565b610490610fb6565b60405161046291906133cb565b61047e611042565b61047e6104b336600461341e565b6110c5565b61047e611224565b603e546104e6907501000000000000000000000000000000000000000000900460ff1681565b6040519015158152602001610462565b61047e61050436600461347e565b611042565b61051c6105173660046134d5565b6112fb565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610462565b60015461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610462565b6105c86105a03660046132ae565b60101b7fffff0000000000000000000000000000000000000000000000000000000000001690565b6040517fffff0000000000000000000000000000000000000000000000000000000000009091168152602001610462565b60085461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61062161134b565b6040516104629190613506565b61056d61063c3660046135b4565b6115f1565b61049061064f3660046135f7565b611626565b60465461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60095461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b6009546106bc9074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610462565b6106d961163e565b6040516104629190613612565b61045860445481565b60075461070f9068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610462565b61056d7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab281565b61045860455481565b60405461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61049061177d565b60408051808201909152600681527f76312e302e3000000000000000000000000000000000000000000000000000006020820152610490565b6104906107c73660046137ad565b61178a565b603d5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61047e6107fa36600461391c565b6117ae565b61045861080d3660046139f7565b611a5a565b610458610820366004613a3c565b60066020525f908152604090205481565b61045860055481565b6105c85f81565b61047e61084f3660046135f7565b611ad4565b61047e610862366004613a63565b611b9d565b603f5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b603e5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61045860ff81565b6104906040518060400160405280600681526020017f76312e302e30000000000000000000000000000000000000000000000000000081525081565b6104e66108f93660046135f7565b611bcf565b61047e611cdc565b61047e610914366004613b17565b611daf565b61056d7f0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede81565b61047e61094e3660046135f7565b611e82565b61056d7f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b381565b61047e6109883660046135f7565b611f59565b61047e61099b3660046135f7565b612022565b61047e6109ae3660046135f7565b6121a8565b61047e6122c2565b60075461070f90700100000000000000000000000000000000900467ffffffffffffffff1681565b61047e6109f13660046137ad565b6123d3565b610458612465565b61045861251f565b6106bc600181565b60025461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61056d7f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb81565b610a68610a633660046139f7565b6125ee565b60408051928352602083019190915201610462565b61056d7f000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f681565b610458612634565b60075461070f9067ffffffffffffffff1681565b6105c8610ace3660046132ae565b90565b610458610adf3660046132ae565b60416020525f908152604090205481565b61047e610afe366004613b56565b6126ca565b5f5461056d9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b603e546104e69074010000000000000000000000000000000000000000900460ff1681565b61047e61272b565b60465473ffffffffffffffffffffffffffffffffffffffff163314610ba6576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c1784848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f880181900481028201810190925286815292508691508590819084018382808284375f9201919091525061282392505050565b50505050565b7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab273ffffffffffffffffffffffffffffffffffffffff163314610c8c576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff16158015610cdc57505f5460ff8083169116105b610d6d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c16600114610ddd576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f54603f80546201000090920473ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff000000000000000000000000000000000000000090921691909117905560038054610e3790613c49565b90505f03610e9b5760025460408051808201909152600681527f4e4f5f55524c00000000000000000000000000000000000000000000000000006020820152610e969173ffffffffffffffffffffffffffffffffffffffff16906128a0565b610f48565b60025460038054610f489273ffffffffffffffffffffffffffffffffffffffff169190610ec790613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610ef390613c49565b8015610f3e5780601f10610f1557610100808354040283529160200191610f3e565b820191905f5260205f20905b815481529060010190602001808311610f2157829003601f168201915b50505050506128a0565b6001604455610f55612a15565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a150565b60048054610fc390613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610fef90613c49565b801561103a5780601f106110115761010080835404028352916020019161103a565b820191905f5260205f20905b81548152906001019060200180831161101d57829003601f168201915b505050505081565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611093576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd37a223a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60465473ffffffffffffffffffffffffffffffffffffffff163314611116576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82818114611150576040517f059d0ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b8181101561121c5761121486868381811061116f5761116f613c94565b90506020028101906111819190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508892508791508590508181106111c9576111c9613c94565b90506020028101906111db9190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061282392505050565b600101611152565b505050505050565b60405473ffffffffffffffffffffffffffffffffffffffff163314611275576040517f3ac87ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80546040805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682179096559490911682558151921680835260208301939093527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b7fffff00000000000000000000000000000000000000000000000000000000000082167dffff00000000000000000000000000000000000000000000000000000000601083901c16175b92915050565b603e546060907501000000000000000000000000000000000000000000900460ff1615611424577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663349d40466040518163ffffffff1660e01b81526004015f60405180830381865afa1580156113da573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613d22565b905090565b6042545f9067ffffffffffffffff8111156114415761144161366a565b60405190808252806020026020018201604052801561148657816020015b604080518082019091525f81526060602082015281526020019060019003908161145f5790505b5090505f5b6042548110156115eb576040518060400160405280604283815481106114b3576114b3613c94565b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160435f6042858154811061150c5761150c613c94565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020805461154790613c49565b80601f016020809104026020016040519081016040528092919081815260200182805461157390613c49565b80156115be5780601f10611595576101008083540402835291602001916115be565b820191905f5260205f20905b8154815290600101906020018083116115a157829003601f168201915b50505050508152508282815181106115d8576115d8613c94565b602090810291909101015260010161148b565b50919050565b60428181548110611600575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60436020525f908152604090208054610fc390613c49565b603e546060907501000000000000000000000000000000000000000000900460ff1615611712577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff16633e1e01216040518163ffffffff1660e01b81526004015f60405180830381865afa1580156116cd573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613e82565b604280548060200260200160405190810160405280929190818152602001828054801561177357602002820191905f5260205f20905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611748575b5050505050905090565b60038054610fc390613c49565b805160208183018101805160478252928201919093012091528054610fc390613c49565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146117ff576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff1615801561184f57505f5460ff8083169116105b6118db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610d64565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c1615611949576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61195a89898989895f8a8180612a99565b83156119ac578251151580611970575060445415155b156119a7576040517f996c343000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119f2565b604080515f808252602082019092526119f2916119ea565b604080518082019091525f80825260208201528152602001906001900390816119c45790505b508484612bc1565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b5f5f611a6461251f565b90505f5f611a71856125ee565b6040517c010000000000000000000000000000000000000000000000000000000060208201526024810183905260448101829052606481018690529193509150608401604051602081830303815290604052805190602001209350505050919050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611b2a576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff54144f9611984021529f814a1cb6a41e22c58351510a0d9f7e822618abb9cc090602001610fab565b6040517ff57ac68300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e545f907501000000000000000000000000000000000000000000900460ff1615611ca3576040517f7df73e2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b31690637df73e2790602401602060405180830381865afa158015611c7f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113459190613f1c565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526043602052604081208054611cd290613c49565b9050119050919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d2d576040517fd1ec4b2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff9092166201000081029290921790556040519081527f056dc487bbf0795d0bbb1b4f0af523a855503cff740bfb4d5475f7a90c091e8e906020015b60405180910390a1565b7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab273ffffffffffffffffffffffffffffffffffffffff163314611e1e576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015611e56576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc118263690a4306c74bd1bc80b55962addc2d9e61619ac0b2c2883badbbd01d8905f90a15050565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611ed3576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6046805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f82ae2ec69f24a6de4517a5a45d4983651b578b3d8dc9262af5e352572fc64373910160405180910390a15050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611faf576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa5b56b7906fd0a20e3f35120dd8343db1e12e037a6c90111c7e42885e82a1ce690602001610fab565b7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab273ffffffffffffffffffffffffffffffffffffffff163314612091576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f5473ffffffffffffffffffffffffffffffffffffffff16156120e1576040517f257bb0bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661212e576040517fd6bdac3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080515f815260208101929092527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146121f9576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612246576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178355603f5483519116815260208101919091527fa3d8e5d045432398be30f83ce7c35a7bfc220c1b66cc5bf3f4dd4d539d93fab69101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff163314612313576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff1615612369576040517f278d998800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790556040517f67ec953bdc8546ede08f8ee91e5205a1d1814e126cb8f5d00a918ddb1eaa292b905f90a1565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314612429576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60036124358282613f82565b507f6b8f723a4c7a5335cafae8a598a0aa0301be1387c037dccc085b62add6448b2081604051610fab91906133cb565b603e545f907501000000000000000000000000000000000000000000900460ff1615612518577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663ca69e7dc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061141f9190614099565b5060425490565b603e545f907501000000000000000000000000000000000000000000900460ff16156125ae577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663cce7d0df6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b6045546125e7576040517fdd41f1ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060455490565b5f5f82515f1461262a576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f928392509050565b603e545f907501000000000000000000000000000000000000000000900460ff16156126c3577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663e75235b86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b5060445490565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461271b576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612726838383612bc1565b505050565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461277c576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff166127d1576040517f5aa930a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556040517f4c75580a56c734245a7418eb07d8a311e1bff79f982fed747da3589630e414be905f90a1565b8060478360405161283491906140b0565b9081526020016040518091039020908161284e9190613f82565b508160405161285d91906140b0565b60405180910390207f2779f9edd5ec4e0a99bffdea4008c8b979200959062a2bf00142acb939ca1b648260405161289491906133cb565b60405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff82166128ed576040517f7b3a0df600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80515f03612927576040517f8715f5fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152604360205260408120805461295690613c49565b90501115612990576040517f38615ecc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60428054600181019091557f38dfe4635b27babeca8be38d3b448cb5161a639b899a14825ba9c8d7892eb8c30180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f9081526043602052604090206127268282613f82565b6044546042604051602001612a2b9291906140c6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052805160209091012060458190556044547f66d7b0647fdd512b69cbf4f8e1ce8068bfe0b236168e2704ba13b07425eaa74392611da59260429291614119565b5f54610100900460ff16612b2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b73ffffffffffffffffffffffffffffffffffffffff89161580612b66575073ffffffffffffffffffffffffffffffffffffffff8816155b15612b9d576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612baa8989898989612db2565b612bb684848484612ee0565b505050505050505050565b600183511115612c69575f5b60018451612bdb91906141ad565b811015612c675783612bee8260016141c0565b81518110612bfe57612bfe613c94565b602002602001015160200151848281518110612c1c57612c1c613c94565b60200260200101516020015111612c5f576040517fb9a11d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101612bcd565b505b5f5b8351811015612cbf57612cb7848281518110612c8957612c89613c94565b60200260200101515f0151858381518110612ca657612ca6613c94565b602002602001015160200151613036565b600101612c6b565b505f5b8251811015612d1657612d0e838281518110612ce057612ce0613c94565b60200260200101515f0151848381518110612cfd57612cfd613c94565b6020026020010151602001516128a0565b600101612cc2565b5060425460ff1015612d54576040517f5a7f382c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604254811180612d6e575060425415801590612d6e575080155b15612da5576040517faabd5a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6044819055612726612a15565b73ffffffffffffffffffffffffffffffffffffffff8516612dff576040517fe6cd565400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff8881169190910291909117909155600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000169186169190911790556003612e868382613f82565b506004612e938282613f82565b5050600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9390931692909217909155505050565b5f54610100900460ff16612f76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b603e80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000951515959095027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1694909417750100000000000000000000000000000000000000000093151593909302929092179092557fffffffff00000000000000000000000000000000000000000000000000000000165f90815260416020526040902055565b604254808210613072576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166042838154811061309c5761309c613c94565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16146130f4576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260436020526040812061312191613228565b604261312e6001836141ad565b8154811061313e5761313e613c94565b5f918252602090912001546042805473ffffffffffffffffffffffffffffffffffffffff909216918490811061317657613176613c94565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060428054806131cc576131cc6141d3565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505050565b50805461323490613c49565b5f825580601f10613243575050565b601f0160209004905f5260205f209081019061325f9190613262565b50565b5b80821115613276575f8155600101613263565b5090565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b919050565b5f602082840312156132be575f5ffd5b6132c78261327a565b9392505050565b5f5f83601f8401126132de575f5ffd5b50813567ffffffffffffffff8111156132f5575f5ffd5b60208301915083602082850101111561330c575f5ffd5b9250929050565b5f5f5f5f60408587031215613326575f5ffd5b843567ffffffffffffffff81111561333c575f5ffd5b613348878288016132ce565b909550935050602085013567ffffffffffffffff811115613367575f5ffd5b613373878288016132ce565b95989497509550505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6132c7602083018461337f565b5f5f83601f8401126133ed575f5ffd5b50813567ffffffffffffffff811115613404575f5ffd5b6020830191508360208260051b850101111561330c575f5ffd5b5f5f5f5f60408587031215613431575f5ffd5b843567ffffffffffffffff811115613447575f5ffd5b613453878288016133dd565b909550935050602085013567ffffffffffffffff811115613472575f5ffd5b613373878288016133dd565b5f5f6040838503121561348f575f5ffd5b6134988361327a565b946020939093013593505050565b80357fffff000000000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b5f5f604083850312156134e6575f5ffd5b6134ef836134a6565b91506134fd602084016134a6565b90509250929050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156135a8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815173ffffffffffffffffffffffffffffffffffffffff81511686526020810151905060406020870152613592604087018261337f565b955050602093840193919091019060010161352c565b50929695505050505050565b5f602082840312156135c4575f5ffd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461325f575f5ffd5b80356132a9816135cb565b5f60208284031215613607575f5ffd5b81356132c7816135cb565b602080825282518282018190525f918401906040840190835b8181101561365f57835173ffffffffffffffffffffffffffffffffffffffff1683526020938401939092019160010161362b565b509095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff811182821017156136ba576136ba61366a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156137075761370761366a565b604052919050565b5f67ffffffffffffffff8211156137285761372861366a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f6137666137618461370f565b6136c0565b9050828152838383011115613779575f5ffd5b828260208301375f602084830101529392505050565b5f82601f83011261379e575f5ffd5b6132c783833560208501613754565b5f602082840312156137bd575f5ffd5b813567ffffffffffffffff8111156137d3575f5ffd5b6137df8482850161378f565b949350505050565b801515811461325f575f5ffd5b80356132a9816137e7565b5f67ffffffffffffffff8211156138185761381861366a565b5060051b60200190565b5f82601f830112613831575f5ffd5b813561383f613761826137ff565b8082825260208201915060208360051b860101925085831115613860575f5ffd5b602085015b8381101561391257803567ffffffffffffffff811115613883575f5ffd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156138b6575f5ffd5b6138be613697565b60208201356138cc816135cb565b8152604082013567ffffffffffffffff8111156138e7575f5ffd5b6138f68a60208386010161378f565b6020830152508085525050602083019250602081019050613865565b5095945050505050565b5f5f5f5f5f5f5f5f610100898b031215613934575f5ffd5b61393d896135ec565b975061394b60208a016135ec565b965061395960408a016135ec565b9550606089013567ffffffffffffffff811115613974575f5ffd5b6139808b828c0161378f565b955050608089013567ffffffffffffffff81111561399c575f5ffd5b6139a88b828c0161378f565b9450506139b760a08a016137f4565b925060c089013567ffffffffffffffff8111156139d2575f5ffd5b6139de8b828c01613822565b989b979a50959894979396929550929360e00135925050565b5f60208284031215613a07575f5ffd5b813567ffffffffffffffff811115613a1d575f5ffd5b8201601f81018413613a2d575f5ffd5b6137df84823560208401613754565b5f60208284031215613a4c575f5ffd5b813567ffffffffffffffff811681146132c7575f5ffd5b5f5f5f5f5f5f60c08789031215613a78575f5ffd5b8635613a83816135cb565b95506020870135613a93816135cb565b9450604087013563ffffffff81168114613aab575f5ffd5b93506060870135613abb816135cb565b9250608087013567ffffffffffffffff811115613ad6575f5ffd5b613ae289828a0161378f565b92505060a087013567ffffffffffffffff811115613afe575f5ffd5b613b0a89828a0161378f565b9150509295509295509295565b5f5f60208385031215613b28575f5ffd5b823567ffffffffffffffff811115613b3e575f5ffd5b613b4a858286016132ce565b90969095509350505050565b5f5f5f60608486031215613b68575f5ffd5b833567ffffffffffffffff811115613b7e575f5ffd5b8401601f81018613613b8e575f5ffd5b8035613b9c613761826137ff565b8082825260208201915060208360061b850101925088831115613bbd575f5ffd5b6020840193505b82841015613c0d576040848a031215613bdb575f5ffd5b613be3613697565b8435613bee816135cb565b8152602085810135818301529083526040909401939190910190613bc4565b9550505050602084013567ffffffffffffffff811115613c2b575f5ffd5b613c3786828701613822565b93969395505050506040919091013590565b600181811c90821680613c5d57607f821691505b6020821081036115eb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613cf4575f5ffd5b83018035915067ffffffffffffffff821115613d0e575f5ffd5b60200191503681900382131561330c575f5ffd5b5f60208284031215613d32575f5ffd5b815167ffffffffffffffff811115613d48575f5ffd5b8201601f81018413613d58575f5ffd5b8051613d66613761826137ff565b8082825260208201915060208360051b850101925086831115613d87575f5ffd5b602084015b83811015613e7757805167ffffffffffffffff811115613daa575f5ffd5b85016040818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011215613ddd575f5ffd5b613de5613697565b6020820151613df3816135cb565b8152604082015167ffffffffffffffff811115613e0e575f5ffd5b60208184010192505089601f830112613e25575f5ffd5b8151613e336137618261370f565b8181528b6020838601011115613e47575f5ffd5b8160208501602083015e5f6020838301015280602084015250508085525050602083019250602081019050613d8c565b509695505050505050565b5f60208284031215613e92575f5ffd5b815167ffffffffffffffff811115613ea8575f5ffd5b8201601f81018413613eb8575f5ffd5b8051613ec6613761826137ff565b8082825260208201915060208360051b850101925086831115613ee7575f5ffd5b6020840193505b82841015613f12578351613f01816135cb565b825260209384019390910190613eee565b9695505050505050565b5f60208284031215613f2c575f5ffd5b81516132c7816137e7565b601f82111561272657805f5260205f20601f840160051c81016020851015613f5c5750805b601f840160051c820191505b81811015613f7b575f8155600101613f68565b5050505050565b815167ffffffffffffffff811115613f9c57613f9c61366a565b613fb081613faa8454613c49565b84613f37565b6020601f821160018114614001575f8315613fcb5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455613f7b565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561404e578785015182556020948501946001909201910161402e565b508482101561408a57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b5f602082840312156140a9575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b8281525f602082018354845f5260205f205f5b8281101561410d57815473ffffffffffffffffffffffffffffffffffffffff168452602090930192600191820191016140d9565b50919695505050505050565b606080825284549082018190525f8581526020812090916080840190835b8181101561416b57835473ffffffffffffffffffffffffffffffffffffffff16835260019384019360209093019201614137565b50506020840195909552505060400152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561134557611345614180565b8082018082111561134557611345614180565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212204c8d89fafb3caf45617cd4d4b662407a5f97b0708f57d8518c4bda54f7b3cad464736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f60000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab2000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b3

-----Decoded View---------------
Arg [0] : _globalExitRootManager (address): 0x580bda1e7A0CFAe92Fa7F6c20A3794F169CE3CFb
Arg [1] : _pol (address): 0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6
Arg [2] : _bridgeAddress (address): 0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe
Arg [3] : _rollupManager (address): 0x5132A183E9F3CB7C848b0AAC5Ae0c4f0491B7aB2
Arg [4] : _aggLayerGateway (address): 0x046Bb8bb98Db4ceCbB2929542686B74b516274b3

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb
Arg [1] : 000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f6
Arg [2] : 0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede
Arg [3] : 0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab2
Arg [4] : 000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b3


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.