creation_sourcecode: {{
    "language": "Solidity",
    "settings": {
      "evmVersion": "shanghai",
      "libraries": {},
      "metadata": {
        "bytecodeHash": "ipfs",
        "useLiteralContent": true
      },
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "remappings": [],
      "viaIR": true,
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    },
    "sources": {
      "@openzeppelin/contracts/access/AccessControl.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n    struct RoleData {\n        mapping(address => bool) members;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with a standardized message including the required role.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     *\n     * _Available since v4.1._\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n        return _roles[role].members[account];\n    }\n\n    /**\n     * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n     * Overriding this function changes the behavior of the {onlyRole} modifier.\n     *\n     * Format of the revert message is described in {_checkRole}.\n     *\n     * _Available since v4.6._\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Revert with a standard message if `account` is missing `role`.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert(\n                string(\n                    abi.encodePacked(\n                        \"AccessControl: account \",\n                        Strings.toHexString(account),\n                        \" is missing role \",\n                        Strings.toHexString(uint256(role), 32)\n                    )\n                )\n            );\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address account) public virtual override {\n        require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event. Note that unlike {grantRole}, this function doesn't perform any\n     * checks on the calling account.\n     *\n     * May emit a {RoleGranted} event.\n     *\n     * [WARNING]\n     * ====\n     * This function should only be called from the constructor when setting\n     * up the initial roles for the system.\n     *\n     * Using this function in any other way is effectively circumventing the admin\n     * system imposed by {AccessControl}.\n     * ====\n     *\n     * NOTE: This function is deprecated in favor of {_grantRole}.\n     */\n    function _setupRole(bytes32 role, address account) internal virtual {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual {\n        if (!hasRole(role, account)) {\n            _roles[role].members[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n        }\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual {\n        if (hasRole(role, account)) {\n            _roles[role].members[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/access/IAccessControl.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"
      },
      "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Strings.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toString(int256 value) internal pure returns (string memory) {\n        return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/ERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SafeCast.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     *\n     * _Available since v3.0._\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        require(value >= 0, \"SafeCast: value must be positive\");\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     *\n     * _Available since v3.0._\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n        return int256(value);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SignedMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
      },
      "contracts/Structs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { DCSProduct, DCSVault } from \"./cega-strategies/dcs/DCSStructs.sol\";\nimport { FCNProduct, FCNVault } from \"./cega-strategies/fcn/FCNStructs.sol\";\nimport { IOracleEntry } from \"./oracle-entry/interfaces/IOracleEntry.sol\";\n\nuint32 constant DCS_STRATEGY_ID = 1;\nuint32 constant FCN_STRATEGY_ID = 2;\n\nstruct DepositQueue {\n    uint128 queuedDepositsTotalAmount;\n    uint128 processedIndex;\n    mapping(address => uint128) amounts;\n    address[] depositors;\n    mapping(address => bool) depositorExists;\n}\n\nstruct Withdrawer {\n    address account;\n    uint32 nextProductId;\n}\n\nstruct ProductMetadata {\n    string name;\n    string tradeWinnerNftImage;\n}\n\nstruct WithdrawalQueue {\n    uint128 queuedWithdrawalSharesAmount;\n    uint128 processedIndex;\n    mapping(address => mapping(uint32 => uint256)) amounts;\n    Withdrawer[] withdrawers;\n    mapping(address => bool) withdrawingWithProxy;\n}\n\nstruct CegaGlobalStorage {\n    // Global information\n    uint32 strategyIdCounter;\n    uint32 productIdCounter;\n    uint32[] strategyIds;\n    mapping(uint32 => uint32) strategyOfProduct;\n    mapping(uint32 => ProductMetadata) productMetadata;\n    mapping(address => Vault) vaults;\n    // DCS information\n    mapping(uint32 => DCSProduct) dcsProducts;\n    // Shared\n    mapping(uint32 => DepositQueue) depositQueues;\n    // DCS information\n    mapping(address => DCSVault) dcsVaults;\n    // Shared\n    mapping(address => WithdrawalQueue) withdrawalQueues;\n    // vaultAddress => (asset/s hash => timestamp => price)\n    mapping(address => mapping(bytes32 => mapping(uint40 => uint128))) oraclePriceOverride;\n    // this will be a bitmap that has all the configs for pausing\n    uint256 protocolPauseConfig;\n    // FCN information\n    mapping(uint32 => FCNProduct) fcnProducts;\n    mapping(address => FCNVault) fcnVaults;\n    mapping(address => bool) fcnBondAllowList;\n}\n\nstruct Vault {\n    uint128 totalAssets;\n    uint64 auctionWinnerTokenId;\n    uint16 yieldFeeBps;\n    uint16 managementFeeBps;\n    uint32 productId;\n    address auctionWinner;\n    uint40 tradeStartDate;\n    VaultStatus vaultStatus;\n    IOracleEntry.DataSource dataSource;\n    bool isInDispute;\n    bool isDefaulted;\n}\n\nenum OldVaultStatus {\n    DepositsClosed,\n    DepositsOpen,\n    NotTraded,\n    Traded,\n    TradeExpired,\n    FeesCollected,\n    WithdrawalQueueProcessed,\n    Zombie\n}\n\nenum VaultStatus {\n    DepositsClosed,\n    DepositsOpen,\n    PreAuction,\n    Auctioned,\n    Traded,\n    AwaitingSettlement,\n    Settled,\n    FeesCollected,\n    WithdrawalQueueProcessed,\n    Zombie\n}\n\nstruct MMNFTMetadata {\n    address vaultAddress;\n    uint40 tradeStartDate;\n    uint40 tradeEndDate;\n    uint16 aprBps;\n    uint128 notional;\n    uint128 initialSpotPrice;\n    uint128 strikePrice;\n}\n\nstruct VaultCreationParams {\n    string tokenName;\n    string tokenSymbol;\n    uint16 yieldFeeBps;\n    uint16 managementFeeBps;\n}\n"
      },
      "contracts/aux/interfaces/IACLManager.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\n\ninterface IACLManager {\n    /**\n     * @notice Sets the admin role for a specific role.\n     * @param role The role for which to set the admin.\n     * @param adminRole The admin role to be set for the specified role.\n     */\n    function setRoleAdmin(bytes32 role, bytes32 adminRole) external;\n\n    /**\n     * @notice Adds a new Cega Admin.\n     * @param admin The address to be granted Cega Admin role.\n     */\n    function addCegaAdmin(address admin) external;\n\n    /**\n     * @notice Removes a Cega Admin.\n     * @param admin The address to be removed from Cega Admin role.\n     */\n    function removeCegaAdmin(address admin) external;\n\n    /**\n     * @notice Adds a new Trader Admin.\n     * @param admin The address to be granted Trader Admin role.\n     */\n    function addTraderAdmin(address admin) external;\n\n    /**\n     * @notice Removes a Trader Admin.\n     * @param admin The address to be removed from Trader Admin role.\n     */\n    function removeTraderAdmin(address admin) external;\n\n    /**\n     * @notice Adds a new Operator Admin.\n     * @param admin The address to be granted Operator Admin role.\n     */\n    function addOperatorAdmin(address admin) external;\n\n    /**\n     * @notice Removes an Operator Admin.\n     * @param admin The address to be removed from Operator Admin role.\n     */\n    function removeOperatorAdmin(address admin) external;\n\n    /**\n     * @notice Adds a new Service Admin.\n     * @param admin The address to be granted Service Admin role.\n     */\n    function addServiceAdmin(address admin) external;\n\n    /**\n     * @notice Removes a Service Admin.\n     * @param admin The address to be removed from Service Admin role.\n     */\n    function removeServiceAdmin(address admin) external;\n\n    /**\n     * @notice Checks if an address is a Cega Admin.\n     * @param admin The address to check for Cega Admin role.\n     * @return bool True if the address is a Cega Admin, false otherwise.\n     */\n    function isCegaAdmin(address admin) external view returns (bool);\n\n    /**\n     * @notice Checks if an address is a Trader Admin.\n     * @param admin The address to check for Trader Admin role.\n     * @return bool True if the address is a Trader Admin, false otherwise.\n     */\n    function isTraderAdmin(address admin) external view returns (bool);\n\n    /**\n     * @notice Checks if an address is an Operator Admin.\n     * @param admin The address to check for Operator Admin role.\n     * @return bool True if the address is an Operator Admin, false otherwise.\n     */\n    function isOperatorAdmin(address admin) external view returns (bool);\n\n    /**\n     * @notice Checks if an address is a Service Admin.\n     * @param admin The address to check for Service Admin role.\n     * @return bool True if the address is a Service Admin, false otherwise.\n     */\n    function isServiceAdmin(address admin) external view returns (bool);\n}\n"
      },
      "contracts/aux/interfaces/IAddressManager.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.24;\n\nimport { ICegaEntry } from \"../../cega-entry/interfaces/ICegaEntry.sol\";\n\ninterface IAddressManager {\n    /**\n     * @dev Emitted when a new CegaEntry is created.\n     * @param id The identifier of the proxy\n     * @param proxyAddress The address of the created proxy contract\n     * @param implementationParams The params of the implementation update\n     */\n    event CegaEntryCreated(\n        bytes32 indexed id,\n        address indexed proxyAddress,\n        ICegaEntry.ProxyImplementation[] indexed implementationParams\n    );\n\n    /**\n     * @dev Emitted when the CegaEntry is updated.\n     * @param implementationParams The old address of the CegaEntry\n     * @param _init The new address to call upon upgrade\n     * @param _calldata The calldata input for the call\n     */\n    event CegaEntryUpdated(\n        ICegaEntry.ProxyImplementation[] indexed implementationParams,\n        address _init,\n        bytes _calldata\n    );\n\n    /**\n     * @dev Emitted when a new address is set\n     * @param id The identifier of the proxy\n     * @param oldAddress The previous address assoicated with the id\n     * @param newAddress The new address set to the id\n     */\n    event AddressSet(\n        bytes32 indexed id,\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when asset wrapping proxy is updated\n     * @param asset The address of the asset.\n     * @param proxy The address of the new proxy.\n     */\n    event AssetProxyUpdated(address asset, address proxy);\n\n    /**\n     * @dev Returns the address of the Cega Oracle.\n     * @return The address of the Cega Oracle.\n     */\n    function getCegaOracle() external view returns (address);\n\n    /**\n     * @dev Returns the address of the Cega Entry.\n     * @return The address of the Cega Entry.\n     */\n    function getCegaEntry() external view returns (address);\n\n    /**\n     * @dev Returns the address of the Trade Winner NFT.\n     * @return The address of the Trade Winner NFT.\n     */\n    function getTradeWinnerNFT() external view returns (address);\n\n    /**\n     * @dev Returns the address of the ACL Manager.\n     * @return The address of the ACL Manager.\n     */\n    function getACLManager() external view returns (address);\n\n    /**\n     * @dev Returns the address of the Redeposit Manager.\n     * @return The address of the Redeposit Manager.\n     */\n    function getRedepositManager() external view returns (address);\n\n    /**\n     * @dev Returns the address of the Cega Fee Receiver.\n     * @return The address of the Cega Fee Receiver.\n     */\n    function getCegaFeeReceiver() external view returns (address);\n\n    /**\n     * @dev Retrieves the address associated with a given ID.\n     * @param id The bytes32 ID.\n     * @return The associated address.\n     */\n    function getAddress(bytes32 id) external view returns (address);\n\n    /**\n     * @dev Retrieves the asset wrapping proxy address for a given asset.\n     * @param asset The address of the asset.\n     * @return The address of the asset wrapping proxy.\n     */\n    function getAssetWrappingProxy(\n        address asset\n    ) external view returns (address);\n\n    /**\n     * @dev Sets the address of the Cega Entry contract.\n     * @param newAddress The new address of the Cega Entry contract.\n     */\n    function setCegaEntry(address newAddress) external;\n\n    /**\n     * @dev Sets the address of the Trade Winner NFT contract.\n     * @param newAddress The new address of the Trade Winner NFT contract.\n     */\n    function setTradeWinnerNFT(address newAddress) external;\n\n    /**\n     * @dev Sets the address of the Cega Oracle contract.\n     * @param newAddress The new address of the Cega Oracle contract.\n     */\n    function setCegaOracle(address newAddress) external;\n\n    /**\n     * @dev Sets the address of the Redeposit Manager contract.\n     * @param newAddress The new address of the Redeposit Manager contract.\n     */\n    function setRedepositManager(address newAddress) external;\n\n    /**\n     * @dev Sets the address of the Cega Fee Receiver address.\n     * @param newAddress The new address of the Cega Fee Receiver contract.\n     */\n    function setCegaFeeReceiver(address newAddress) external;\n\n    /**\n     * @dev Sets the address of the ACL Manager contract.\n     * @param newAddress The new address of the ACL Manager contract.\n     */\n    function setACLManager(address newAddress) external;\n\n    /**\n     * @dev Sets a new address for a given ID.\n     * @param id The bytes32 ID.\n     * @param newAddress The new address to be associated with the ID.\n     */\n    function setAddress(bytes32 id, address newAddress) external;\n\n    /**\n     * @dev Sets a new asset wrapping proxy for a given asset.\n     * @param asset The address of the asset.\n     * @param proxy The address of the new proxy.\n     */\n    function setAssetWrappingProxy(address asset, address proxy) external;\n\n    /**\n     * @dev Updates the implementation of the Cega Entry.\n     * @param implementationParams An array of new implementation parameters.\n     * @param _init The address to call upon upgrade.\n     * @param _calldata The calldata input for the call.\n     */\n    function updateCegaEntryImpl(\n        ICegaEntry.ProxyImplementation[] calldata implementationParams,\n        address _init,\n        bytes calldata _calldata\n    ) external;\n}\n"
      },
      "contracts/aux/interfaces/ITradeWinnerNFT.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport \"erc721a-upgradeable/contracts/IERC721AUpgradeable.sol\";\nimport { MMNFTMetadata } from \"../../Structs.sol\";\n\ninterface ITradeWinnerNFT is IERC721AUpgradeable {\n    /**\n     * @dev Mints new nft to a given address\n     * @param _tokenMetadata The metadata to be stored for the token\n     * @return The id of the minted nft\n     */\n    function mint(\n        address to,\n        MMNFTMetadata calldata _tokenMetadata\n    ) external returns (uint256);\n\n    /**\n     * @dev Mints multiple nfts to a given address\n     * @param _tokensMetadata The list of metadata to be stored for the each token\n     * @return The list ids of the minted nfts\n     */\n    function mintBatch(\n        address to,\n        MMNFTMetadata[] calldata _tokensMetadata\n    ) external returns (uint256[] memory);\n}\n"
      },
      "contracts/cega-entry/interfaces/ICegaEntry.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.10;\n\n/******************************************************************************\\\n* EIP-2535: https://eips.ethereum.org/EIPS/eip-2535\n/******************************************************************************/\n\ninterface ICegaEntry {\n    enum ProxyImplementationAction {\n        Add,\n        Replace,\n        Remove\n    }\n    // Add=0, Replace=1, Remove=2\n\n    struct ProxyImplementation {\n        address implAddress;\n        ProxyImplementationAction action;\n        bytes4[] functionSelectors;\n    }\n\n    /// @notice Add/replace/remove any number of functions and optionally execute\n    ///         a function with delegatecall\n    /// @param _implementationParams Contains the implementation addresses and function selectors\n    /// @param _init The address of the contract or implementation to execute _calldata\n    /// @param _calldata A function call, including function selector and arguments\n    ///                  _calldata is executed with delegatecall on _init\n    function diamondCut(\n        ProxyImplementation[] calldata _implementationParams,\n        address _init,\n        bytes calldata _calldata\n    ) external;\n\n    event DiamondCut(\n        ProxyImplementation[] _diamondCut,\n        address _init,\n        bytes _calldata\n    );\n}\n"
      },
      "contracts/cega-strategies/common/CommonStructs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nstruct AddToDepositQueueParams {\n    uint32 productId;\n    uint128 amount;\n    address receiver;\n    address depositAsset;\n    bool isDepositQueueOpen;\n    uint128 minDepositAmount;\n    uint128 sumVaultUnderlyingAmounts;\n    uint128 maxUnderlyingAmountLimit;\n}\n\nstruct RemoveFromDepositQueueParams {\n    uint32 productId;\n    uint128 amount;\n    address depositor;\n    address depositAsset;\n    uint128 minDepositAmount;\n}\n\nstruct ProcessQueueParams {\n    uint32 productId;\n    address vaultAddress;\n    address depositAsset;\n    uint128 sumVaultUnderlyingAmounts;\n    uint256 maxProcessCount;\n}\n"
      },
      "contracts/cega-strategies/common/interfaces/ICommonEvents.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { VaultStatus, OldVaultStatus } from \"../../../Structs.sol\";\n\ninterface ICommonEvents {\n    event DepositQueued(\n        uint32 indexed productId,\n        address sender,\n        address receiver,\n        uint128 amount\n    );\n\n    event DepositRemoved(\n        uint32 indexed productId,\n        address depositor,\n        uint128 amount\n    );\n\n    event DepositProcessed(\n        address indexed vaultAddress,\n        address receiver,\n        uint128 amount\n    );\n\n    event WithdrawalQueued(\n        address indexed vaultAddress,\n        uint256 sharesAmount,\n        address owner,\n        uint32 nextProductId,\n        bool withProxy\n    );\n\n    event WithdrawalProcessed(\n        address indexed vaultAddress,\n        uint256 sharesAmount,\n        address owner,\n        uint32 nextProductId\n    );\n\n    event CommonVaultStatusUpdated(\n        address indexed vaultAddress,\n        VaultStatus vaultStatus\n    );\n\n    event VaultDefaultUpdated(address indexed vaultAddress, bool value);\n\n    event OraclePriceOverriden(\n        address indexed vaultAddress,\n        address indexed asset,\n        uint256 timestamp,\n        uint256 newPrice\n    );\n\n    event ManagementFeeUpdated(address indexed vaultAddress, uint16 value);\n\n    event YieldFeeUpdated(address indexed vaultAddress, uint16 value);\n\n    event ProductNameUpdated(uint32 indexed productId, string name);\n\n    event TradeWinnerNftImageUpdated(uint32 indexed productId, string imageUrl);\n\n    // Legacy event, left for compatibility\n\n    event VaultStatusUpdated(\n        address indexed vaultAddress,\n        OldVaultStatus vaultStatus\n    );\n}\n"
      },
      "contracts/cega-strategies/common/lib/ProductLogic.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport {\n    AddToDepositQueueParams,\n    RemoveFromDepositQueueParams,\n    ProcessQueueParams\n} from \"../CommonStructs.sol\";\nimport { CegaStorage } from \"../../../storage/CegaStorage.sol\";\nimport { Errors } from \"../../../utils/Errors.sol\";\nimport { Transfers } from \"../../../utils/Transfers.sol\";\nimport {\n    CegaGlobalStorage,\n    Vault,\n    VaultStatus,\n    DepositQueue,\n    WithdrawalQueue,\n    Withdrawer,\n    MMNFTMetadata\n} from \"../../../Structs.sol\";\nimport { VaultLogic } from \"./VaultLogic.sol\";\nimport { ICegaVault } from \"../../../vaults/interfaces/ICegaVault.sol\";\nimport { ITreasury } from \"../../../treasuries/interfaces/ITreasury.sol\";\nimport { IAddressManager } from \"../../../aux/interfaces/IAddressManager.sol\";\nimport { IWrappingProxy } from \"../../../proxies/interfaces/IWrappingProxy.sol\";\nimport {\n    IRedepositManager\n} from \"../../../redeposits/interfaces/IRedepositManager.sol\";\nimport { ICommonEvents } from \"../interfaces/ICommonEvents.sol\";\n\nlibrary ProductLogic {\n    using Transfers for address;\n    using SafeCast for uint256;\n\n    function addToDepositQueue(\n        CegaGlobalStorage storage cgs,\n        address treasury,\n        AddToDepositQueueParams memory params\n    ) internal {\n        require(params.isDepositQueueOpen, Errors.DEPOSIT_QUEUE_NOT_OPEN);\n        require(\n            params.amount >= params.minDepositAmount,\n            Errors.VALUE_TOO_SMALL\n        );\n\n        DepositQueue storage depositQueue = cgs.depositQueues[params.productId];\n\n        uint128 _queuedDepositsTotalAmount = depositQueue\n            .queuedDepositsTotalAmount + params.amount;\n        depositQueue.queuedDepositsTotalAmount = _queuedDepositsTotalAmount;\n        require(\n            params.sumVaultUnderlyingAmounts + _queuedDepositsTotalAmount <=\n                params.maxUnderlyingAmountLimit,\n            Errors.MAX_DEPOSIT_LIMIT_REACHED\n        );\n\n        uint128 currentQueuedAmount = depositQueue.amounts[params.receiver];\n        if (currentQueuedAmount == 0) {\n            bool exists = depositQueue.depositorExists[params.receiver];\n            if (!exists) {\n                depositQueue.depositors.push(params.receiver);\n                depositQueue.depositorExists[params.receiver] = true;\n            }\n        }\n        depositQueue.amounts[params.receiver] =\n            currentQueuedAmount +\n            params.amount;\n\n        params.depositAsset.receiveTo(treasury, params.amount);\n\n        emit ICommonEvents.DepositQueued(\n            params.productId,\n            msg.sender,\n            params.receiver,\n            params.amount\n        );\n    }\n\n    function removeFromDepositQueue(\n        CegaGlobalStorage storage cgs,\n        ITreasury treasury,\n        RemoveFromDepositQueueParams memory params\n    ) internal {\n        DepositQueue storage depositQueue = cgs.depositQueues[params.productId];\n\n        uint128 queuedAmount = depositQueue.amounts[params.depositor];\n        require(queuedAmount > 0, Errors.VALUE_IS_ZERO);\n\n        if (params.amount == 0) {\n            params.amount = queuedAmount;\n        }\n\n        require(\n            params.amount == queuedAmount ||\n                queuedAmount - params.amount >= params.minDepositAmount,\n            Errors.VALUE_TOO_SMALL\n        );\n\n        depositQueue.amounts[params.depositor] = queuedAmount - params.amount;\n        depositQueue.queuedDepositsTotalAmount -= params.amount;\n\n        treasury.withdraw(\n            params.depositAsset,\n            params.depositor,\n            params.amount,\n            false\n        );\n\n        emit ICommonEvents.DepositRemoved(\n            params.productId,\n            params.depositor,\n            params.amount\n        );\n    }\n\n    function processDepositQueue(\n        CegaGlobalStorage storage cgs,\n        ProcessQueueParams memory params,\n        function(\n            CegaGlobalStorage storage,\n            uint32,\n            uint128\n        ) processDepositQueueHook\n    ) internal returns (uint256 processCount) {\n        Vault storage vaultData = cgs.vaults[params.vaultAddress];\n        uint256 totalSupply = ICegaVault(params.vaultAddress).totalSupply();\n        uint128 totalAssets = VaultLogic.totalAssets(cgs, params.vaultAddress);\n\n        require(\n            vaultData.vaultStatus == VaultStatus.DepositsOpen,\n            Errors.INVALID_VAULT_STATUS\n        );\n        require(\n            !(totalAssets == 0 && totalSupply > 0),\n            Errors.VAULT_IN_ZOMBIE_STATE\n        );\n\n        DepositQueue storage queue = cgs.depositQueues[params.productId];\n        uint256 queueLength = queue.depositors.length;\n        uint256 index = queue.processedIndex;\n        processCount = params.maxProcessCount == 0\n            ? queueLength - index\n            : Math.min(queueLength - index, params.maxProcessCount);\n\n        uint128 totalDepositsAmount;\n\n        for (uint256 i = 0; i < processCount; i++) {\n            address depositor = queue.depositors[index + i];\n            uint128 depositAmount = queue.amounts[depositor];\n            delete queue.depositorExists[depositor];\n\n            if (depositAmount > 0) {\n                totalDepositsAmount += depositAmount;\n\n                uint256 sharesAmount = VaultLogic.convertToShares(\n                    totalSupply,\n                    totalAssets,\n                    VaultLogic.getAssetDecimals(params.depositAsset),\n                    depositAmount\n                );\n                ICegaVault(params.vaultAddress).mint(depositor, sharesAmount);\n\n                delete queue.amounts[depositor];\n\n                emit ICommonEvents.DepositProcessed(\n                    params.vaultAddress,\n                    depositor,\n                    depositAmount\n                );\n            }\n        }\n        queue.processedIndex += processCount.toUint128();\n\n        queue.queuedDepositsTotalAmount -= totalDepositsAmount;\n\n        processDepositQueueHook(cgs, params.productId, totalDepositsAmount);\n\n        vaultData.totalAssets = totalAssets + totalDepositsAmount;\n\n        if (processCount + index == queueLength) {\n            VaultLogic.setVaultStatus(\n                cgs,\n                params.vaultAddress,\n                VaultStatus.PreAuction\n            );\n        }\n    }\n\n    /**\n     * @dev Processes the withdrawal queue for a specific vault.\n     * @param cgs The Cega global storage.\n     * @param treasury The treasury contract.\n     * @param addressManager The address manager.\n     * @param vaultAddress The address of the vault.\n     * @param maxProcessCount The maximum number of withdrawals to process.\n     * @return processCount The number of processed withdrawals.\n     */\n    function processWithdrawalQueue(\n        CegaGlobalStorage storage cgs,\n        ITreasury treasury,\n        IAddressManager addressManager,\n        address vaultAddress,\n        uint256 maxProcessCount,\n        address settlementAsset,\n        function(CegaGlobalStorage storage, address, uint128)\n            internal postWithdrawalHook\n    ) internal returns (uint256 processCount) {\n        require(\n            VaultLogic.isWithdrawalPossible(cgs, vaultAddress),\n            Errors.INVALID_VAULT_STATUS\n        );\n\n        Vault storage vaultData = cgs.vaults[vaultAddress];\n\n        uint128 totalAssets = vaultData.totalAssets;\n        uint256 totalSupply = ICegaVault(vaultAddress).totalSupply();\n        address wrappingProxy = addressManager.getAssetWrappingProxy(\n            settlementAsset\n        );\n\n        WithdrawalQueue storage queue = cgs.withdrawalQueues[vaultAddress];\n        uint256 queueLength = queue.withdrawers.length;\n        uint256 index = queue.processedIndex;\n        processCount = maxProcessCount == 0\n            ? queueLength - index\n            : Math.min(queueLength - index, maxProcessCount);\n        uint256 totalSharesWithdrawn;\n        uint128 totalAssetsWithdrawn;\n        uint256 sharesAmount;\n\n        for (uint256 i = 0; i < processCount; i++) {\n            Withdrawer memory withdrawer = queue.withdrawers[index + i];\n            sharesAmount = queue.amounts[withdrawer.account][\n                withdrawer.nextProductId\n            ];\n            delete queue.amounts[withdrawer.account][withdrawer.nextProductId];\n            uint128 assetAmount = processWithdrawal(\n                withdrawer.account,\n                sharesAmount,\n                withdrawer.nextProductId,\n                queue.withdrawingWithProxy[withdrawer.account],\n                treasury,\n                addressManager,\n                vaultAddress,\n                settlementAsset,\n                totalAssets,\n                totalSupply,\n                wrappingProxy\n            );\n            totalSharesWithdrawn += sharesAmount;\n            totalAssetsWithdrawn += assetAmount;\n        }\n\n        ICegaVault(vaultAddress).burn(vaultAddress, totalSharesWithdrawn);\n        queue.queuedWithdrawalSharesAmount -= totalSharesWithdrawn.toUint128();\n        queue.processedIndex += processCount.toUint128();\n        vaultData.totalAssets -= totalAssetsWithdrawn;\n\n        postWithdrawalHook(cgs, vaultAddress, totalAssetsWithdrawn);\n\n        if (index + processCount == queueLength) {\n            VaultLogic.setVaultStatus(\n                cgs,\n                vaultAddress,\n                VaultStatus.WithdrawalQueueProcessed\n            );\n        }\n    }\n\n    /**\n     * @dev Adds a request to the withdrawal queue for a specific vault or withdraw instatly if possible.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @param sharesAmount The amount of shares to withdraw.\n     * @param nextProductId The product ID for the next investment cycle, if applicable.\n     * @param useProxy Whether to use a proxy for withdrawal.\n     */\n    function withdrawOrAddToWithdrawalQueue(\n        CegaGlobalStorage storage cgs,\n        ITreasury treasury,\n        IAddressManager addressManager,\n        address vaultAddress,\n        uint128 sharesAmount,\n        uint32 nextProductId,\n        bool useProxy,\n        uint128 minWithdrawalAmount,\n        address settlementAsset,\n        function(CegaGlobalStorage storage, address, uint128)\n            internal postWithdrawalHook\n    ) internal {\n        require(sharesAmount >= minWithdrawalAmount, Errors.VALUE_TOO_SMALL);\n        uint256 sharesBalance = ICegaVault(vaultAddress).balanceOf(msg.sender);\n        require(\n            sharesBalance >= sharesAmount &&\n                (sharesBalance - sharesAmount == 0 ||\n                    sharesBalance - sharesAmount >= minWithdrawalAmount),\n            Errors.REMAINING_VALUE_TOO_SMALL\n        );\n\n        require(nextProductId == 0 || !useProxy, Errors.NO_PROXY_FOR_REDEPOSIT);\n\n        if (VaultLogic.isWithdrawalPossible(cgs, vaultAddress)) {\n            withdrawInstantly(\n                cgs,\n                treasury,\n                addressManager,\n                vaultAddress,\n                sharesAmount,\n                nextProductId,\n                useProxy,\n                settlementAsset,\n                postWithdrawalHook\n            );\n        } else {\n            addToWithdrawalQueue(\n                cgs,\n                vaultAddress,\n                sharesAmount,\n                nextProductId,\n                useProxy\n            );\n        }\n    }\n\n    function withdrawInstantly(\n        CegaGlobalStorage storage cgs,\n        ITreasury treasury,\n        IAddressManager addressManager,\n        address vaultAddress,\n        uint128 sharesAmount,\n        uint32 nextProductId,\n        bool useProxy,\n        address settlementAsset,\n        function(CegaGlobalStorage storage, address, uint128)\n            internal postWithdrawalHook\n    ) internal {\n        Vault storage vaultData = cgs.vaults[vaultAddress];\n        uint128 totalAssets = vaultData.totalAssets;\n        uint256 totalSupply = ICegaVault(vaultAddress).totalSupply();\n        address wrappingProxy = addressManager.getAssetWrappingProxy(\n            settlementAsset\n        );\n\n        ICegaVault(vaultAddress).burn(msg.sender, sharesAmount);\n        uint128 assetAmount = processWithdrawal(\n            msg.sender,\n            sharesAmount,\n            nextProductId,\n            useProxy,\n            treasury,\n            addressManager,\n            vaultAddress,\n            settlementAsset,\n            totalAssets,\n            totalSupply,\n            wrappingProxy\n        );\n\n        vaultData.totalAssets -= assetAmount;\n\n        postWithdrawalHook(cgs, vaultAddress, assetAmount);\n    }\n\n    function addToWithdrawalQueue(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        uint128 sharesAmount,\n        uint32 nextProductId,\n        bool useProxy\n    ) internal {\n        ICegaVault(vaultAddress).transferFrom(\n            msg.sender,\n            vaultAddress,\n            sharesAmount\n        );\n\n        WithdrawalQueue storage queue = cgs.withdrawalQueues[vaultAddress];\n        uint256 currentQueuedAmount = queue.amounts[msg.sender][nextProductId];\n        if (currentQueuedAmount == 0) {\n            queue.withdrawers.push(\n                Withdrawer({\n                    account: msg.sender,\n                    nextProductId: nextProductId\n                })\n            );\n        }\n        queue.amounts[msg.sender][nextProductId] =\n            currentQueuedAmount +\n            sharesAmount;\n        queue.withdrawingWithProxy[msg.sender] = useProxy;\n\n        queue.queuedWithdrawalSharesAmount += sharesAmount;\n\n        emit ICommonEvents.WithdrawalQueued(\n            vaultAddress,\n            sharesAmount,\n            msg.sender,\n            nextProductId,\n            useProxy\n        );\n    }\n\n    function processWithdrawal(\n        address account,\n        uint256 sharesAmount,\n        uint32 nextProductId,\n        bool withdrawingWithProxy,\n        ITreasury treasury,\n        IAddressManager addressManager,\n        address vaultAddress,\n        address settlementAsset,\n        uint128 totalAssets,\n        uint256 totalSupply,\n        address wrappingProxy\n    ) private returns (uint128 assetAmount) {\n        assetAmount = VaultLogic.convertToAssets(\n            totalSupply,\n            totalAssets,\n            sharesAmount\n        );\n\n        if (nextProductId == 0) {\n            if (wrappingProxy != address(0) && withdrawingWithProxy) {\n                treasury.withdraw(\n                    settlementAsset,\n                    wrappingProxy,\n                    assetAmount,\n                    true\n                );\n                IWrappingProxy(wrappingProxy).unwrapAndTransfer(\n                    account,\n                    assetAmount\n                );\n            } else {\n                treasury.withdraw(settlementAsset, account, assetAmount, false);\n            }\n        } else {\n            redeposit(\n                treasury,\n                addressManager,\n                settlementAsset,\n                assetAmount,\n                account,\n                nextProductId\n            );\n        }\n\n        emit ICommonEvents.WithdrawalProcessed(\n            vaultAddress,\n            sharesAmount,\n            account,\n            nextProductId\n        );\n    }\n\n    function redeposit(\n        ITreasury treasury,\n        IAddressManager addressManager,\n        address asset,\n        uint128 amount,\n        address owner,\n        uint32 nextProductId\n    ) private {\n        address redepositManager = addressManager.getRedepositManager();\n        // TODO add code for redeposit\n        IRedepositManager(redepositManager).redeposit(\n            treasury,\n            nextProductId,\n            asset,\n            amount,\n            owner\n        );\n    }\n}\n"
      },
      "contracts/cega-strategies/common/lib/VaultLogic.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport {\n    IERC20Metadata,\n    IERC20\n} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { CegaGlobalStorage, Vault, VaultStatus } from \"../../../Structs.sol\";\nimport { ICommonEvents } from \"../interfaces/ICommonEvents.sol\";\nimport { Errors } from \"../../../utils/Errors.sol\";\n\nlibrary VaultLogic {\n    using SafeCast for uint256;\n\n    // CONSTANTS\n\n    uint128 internal constant DAYS_IN_YEAR = 365;\n\n    uint128 internal constant BPS_DECIMALS = 1e4;\n\n    uint8 internal constant VAULT_DECIMALS = 18;\n\n    uint8 internal constant NATIVE_ASSET_DECIMALS = 18;\n\n    // FUNCTIONS\n\n    /**\n     * @notice Retrieves the decimals for a given asset.\n     * @param asset The address of the asset.\n     * @return uint8 The number of decimals of the asset.\n     */\n    function getAssetDecimals(address asset) internal view returns (uint8) {\n        return\n            asset == address(0)\n                ? NATIVE_ASSET_DECIMALS\n                : IERC20Metadata(asset).decimals();\n    }\n\n    /**\n     * @notice Retrieves the total assets of a given vault.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @return uint128 The total assets of the vault.\n     */\n    function totalAssets(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal view returns (uint128) {\n        return cgs.vaults[vaultAddress].totalAssets;\n    }\n\n    /**\n     * @notice Converts share amount to equivalent asset amount.\n     * @param _totalSupply The total supply of shares in the vault.\n     * @param _totalAssets The total assets held in the vault.\n     * @param _shares The number of shares to convert.\n     * @return uint128 The equivalent asset amount.\n     */\n    function convertToAssets(\n        uint256 _totalSupply,\n        uint128 _totalAssets,\n        uint256 _shares\n    ) internal pure returns (uint128) {\n        // assumption: all assets we support have <= 18 decimals\n        return ((_shares * _totalAssets) / _totalSupply).toUint128();\n    }\n\n    /**\n     * @notice Converts share amount to equivalent asset amount for a specific vault.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @param shares The number of shares to convert.\n     * @return uint128 The equivalent asset amount.\n     */\n    function convertToAssets(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        uint256 shares\n    ) internal view returns (uint128) {\n        uint256 _totalSupply = IERC20(vaultAddress).totalSupply();\n\n        if (_totalSupply == 0) return 0;\n        // assumption: all assets we support have <= 18 decimals\n        // shares and _totalSupply have 18 decimals\n        return\n            ((shares * totalAssets(cgs, vaultAddress)) / _totalSupply)\n                .toUint128();\n    }\n\n    /**\n     * @notice Converts asset amount to equivalent share amount.\n     * @param _totalSupply The total supply of shares in the vault.\n     * @param _totalAssets The total assets held in the vault.\n     * @param _depositAssetDecimals The decimals of the deposit asset.\n     * @param assets The amount of assets to convert.\n     * @return uint256 The equivalent share amount.\n     */\n    function convertToShares(\n        uint256 _totalSupply,\n        uint128 _totalAssets,\n        uint8 _depositAssetDecimals,\n        uint128 assets\n    ) internal pure returns (uint256) {\n        if (_totalAssets == 0 || _totalSupply == 0) {\n            return assets * 10 ** (VAULT_DECIMALS - _depositAssetDecimals);\n        } else {\n            // _totalSupply has 18 decimals, assets and _totalAssets have the same decimals\n            return (_totalSupply * assets) / (_totalAssets);\n        }\n    }\n\n    /**\n     * @notice Checks if withdrawals are possible for a given vault.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @return bool True if withdrawals are possible, false otherwise.\n     */\n    function isWithdrawalPossible(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal view returns (bool) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n\n        VaultStatus vaultStatus = vault.vaultStatus;\n        if (\n            vaultStatus == VaultStatus.FeesCollected ||\n            vaultStatus == VaultStatus.WithdrawalQueueProcessed ||\n            vaultStatus == VaultStatus.Zombie\n        ) {\n            return true;\n        }\n\n        return (vaultStatus == VaultStatus.Auctioned && vault.isDefaulted);\n    }\n\n    /**\n     * @notice Determines if a vault has defaulted based on the current date and product parameters.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @return bool True if the vault has defaulted, false otherwise.\n     */\n    function getIsAuctionDefaulted(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        uint8 daysToStartAuctionDefault\n    ) internal view returns (bool) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        if (vault.vaultStatus != VaultStatus.Auctioned) {\n            return false;\n        }\n        uint40 startDate = cgs.vaults[vaultAddress].tradeStartDate;\n        uint40 daysLate = getDaysLate(startDate);\n        return daysLate >= daysToStartAuctionDefault;\n    }\n\n    /**\n     * @notice Calculates the number of days that have passed since a given start date.\n     * @param startDate The start date.\n     * @return uint40 The number of days that have passed.\n     */\n    function getDaysLate(uint40 startDate) internal view returns (uint40) {\n        uint40 currentTime = block.timestamp.toUint40();\n        if (currentTime < startDate) {\n            return 0;\n        } else {\n            return (currentTime - startDate) / 1 days;\n        }\n    }\n\n    /**\n     * @notice Calculates the coupon payment for a given set of parameters.\n     * @param underlyingAmount The amount of underlying asset.\n     * @param tradeStartDate The start date of the trade.\n     * @param tenorInSeconds The tenor of the product in seconds.\n     * @param aprBps The annual percentage rate in basis points.\n     * @param endDate The end date for the coupon payment calculation.\n     * @return uint128 The calculated coupon payment.\n     */\n    function calculateCouponPayment(\n        uint128 underlyingAmount,\n        uint40 tradeStartDate,\n        uint40 tenorInSeconds,\n        uint16 aprBps,\n        uint40 endDate\n    ) internal pure returns (uint128) {\n        uint40 secondsPassed = endDate - tradeStartDate;\n        uint40 couponSeconds = secondsPassed < tenorInSeconds\n            ? secondsPassed\n            : tenorInSeconds;\n        return\n            ((uint256(underlyingAmount) * couponSeconds * aprBps) /\n                (DAYS_IN_YEAR * BPS_DECIMALS * 1 days)).toUint128();\n    }\n\n    /**\n     * @notice Calculates the late fee based on the coupon, start date, and late fee parameters.\n     * @param coupon The coupon amount.\n     * @param startDate The start date of the period.\n     * @param lateFeeBps The late fee in basis points.\n     * @param daysToStartLateFees The number of days to start charging late fees.\n     * @param daysToStartAuctionDefault The number of days to start auction default.\n     * @return uint128 The calculated late fee.\n     */\n    function calculateLateFee(\n        uint128 coupon,\n        uint40 startDate,\n        uint16 lateFeeBps,\n        uint8 daysToStartLateFees,\n        uint8 daysToStartAuctionDefault\n    ) internal view returns (uint128) {\n        uint40 daysLate = getDaysLate(startDate);\n        if (daysLate < daysToStartLateFees) {\n            return 0;\n        } else {\n            if (daysLate >= daysToStartAuctionDefault) {\n                daysLate = daysToStartAuctionDefault;\n            }\n            return (coupon * daysLate * lateFeeBps) / (BPS_DECIMALS);\n        }\n    }\n\n    function calculateFees(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        uint64 tenorInSeconds,\n        uint128 underlyingAmount,\n        uint128 totalYield\n    ) internal view returns (uint128, uint128, uint128) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n\n        uint128 managementFee = (underlyingAmount *\n            tenorInSeconds *\n            vault.managementFeeBps) / (DAYS_IN_YEAR * 1 days * BPS_DECIMALS);\n        uint128 yieldFee = (totalYield * vault.yieldFeeBps) / BPS_DECIMALS;\n        uint128 totalFee = managementFee + yieldFee;\n\n        return (totalFee, managementFee, yieldFee);\n    }\n\n    /**\n     * @notice Sets the status of a vault in the global storage.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @param status The new status to be set for the vault.\n     */\n    function setVaultStatus(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        VaultStatus status\n    ) internal {\n        cgs.vaults[vaultAddress].vaultStatus = status;\n\n        emit ICommonEvents.CommonVaultStatusUpdated(vaultAddress, status);\n    }\n\n    function setIsDefaulted(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        bool value\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n\n        vault.isDefaulted = value;\n\n        emit ICommonEvents.VaultDefaultUpdated(vaultAddress, value);\n    }\n\n    /**\n     * @notice Opens a vault for deposits.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     */\n    function openVaultDeposits(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal {\n        require(\n            cgs.vaults[vaultAddress].vaultStatus == VaultStatus.DepositsClosed,\n            Errors.INVALID_VAULT_STATUS\n        );\n        setVaultStatus(cgs, vaultAddress, VaultStatus.DepositsOpen);\n    }\n\n    function getAssetCode(address asset) internal pure returns (bytes32) {\n        return keccak256(abi.encode(asset));\n    }\n\n    /**\n     * @notice Overrides the oracle price for a specific vault and timestamp.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @param timestamp The timestamp for which the price is overridden.\n     * @param newPrice The new price to override.\n     */\n    function overrideOraclePrice(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        address asset,\n        uint40 timestamp,\n        uint128 newPrice\n    ) internal {\n        require(newPrice != 0, Errors.INVALID_PRICE);\n\n        cgs.oraclePriceOverride[vaultAddress][getAssetCode(asset)][\n            timestamp\n        ] = newPrice;\n\n        emit ICommonEvents.OraclePriceOverriden(\n            vaultAddress,\n            asset,\n            timestamp,\n            newPrice\n        );\n    }\n}\n"
      },
      "contracts/cega-strategies/dcs/DCSStructs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nenum DCSOptionType {\n    BuyLow,\n    SellHigh\n}\n\nenum SettlementStatus {\n    NotAuctioned,\n    Auctioned,\n    InitialPremiumPaid,\n    AwaitingSettlement,\n    Settled,\n    Defaulted\n}\n\nstruct DCSProductCreationParams {\n    uint128 maxUnderlyingAmountLimit;\n    uint128 minDepositAmount;\n    uint128 minWithdrawalAmount;\n    address quoteAssetAddress;\n    address baseAssetAddress;\n    DCSOptionType dcsOptionType;\n    uint8 daysToStartLateFees;\n    uint8 daysToStartAuctionDefault;\n    uint8 daysToStartSettlementDefault;\n    uint16 lateFeeBps;\n    uint16 strikeBarrierBps;\n    uint40 tenorInSeconds;\n    uint8 disputePeriodInHours;\n    uint8 disputeGraceDelayInHours;\n    string name;\n    string tradeWinnerNftImage;\n}\n\nstruct DCSProduct {\n    uint128 maxUnderlyingAmountLimit;\n    uint128 minDepositAmount;\n    uint128 minWithdrawalAmount;\n    uint128 sumVaultUnderlyingAmounts; //revisit later\n    address quoteAssetAddress; // should be immutable\n    uint40 tenorInSeconds;\n    uint16 lateFeeBps;\n    uint8 daysToStartLateFees;\n    address baseAssetAddress; // should be immutable\n    uint16 strikeBarrierBps;\n    uint8 daysToStartAuctionDefault;\n    uint8 daysToStartSettlementDefault;\n    uint8 disputePeriodInHours;\n    DCSOptionType dcsOptionType;\n    bool isDepositQueueOpen;\n    address[] vaults;\n    uint8 disputeGraceDelayInHours;\n}\n\nstruct DCSVault {\n    uint128 initialSpotPrice;\n    uint128 strikePrice;\n    uint128 totalYield;\n    uint16 aprBps;\n    SettlementStatus settlementStatus; // DEPRECATED\n    bool isPayoffInDepositAsset;\n}\n"
      },
      "contracts/cega-strategies/fcn/FCNBulkActionsEntry.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { CegaGlobalStorage, CegaStorage } from \"../../storage/CegaStorage.sol\";\nimport {\n    MMNFTMetadata,\n    VaultStatus,\n    Vault,\n    FCN_STRATEGY_ID\n} from \"../../Structs.sol\";\nimport {\n    AddToDepositQueueParams,\n    ProcessQueueParams\n} from \"../common/CommonStructs.sol\";\nimport { ProductLogic } from \"../common/lib/ProductLogic.sol\";\nimport { IAddressManager } from \"../../aux/interfaces/IAddressManager.sol\";\nimport { ITradeWinnerNFT } from \"../../aux/interfaces/ITradeWinnerNFT.sol\";\nimport { ITreasury } from \"../../treasuries/interfaces/ITreasury.sol\";\nimport { IACLManager } from \"../../aux/interfaces/IACLManager.sol\";\nimport { IOracleEntry } from \"../../oracle-entry/interfaces/IOracleEntry.sol\";\nimport { Errors } from \"../../utils/Errors.sol\";\nimport { Transfers } from \"../../utils/Transfers.sol\";\nimport { EntryBase } from \"../../common/EntryBase.sol\";\nimport { FCNProduct, FCNOptionBarrier } from \"./FCNStructs.sol\";\nimport { FCNProductLogic } from \"./lib/FCNProductLogic.sol\";\nimport { FCNVaultLogic } from \"./lib/FCNVaultLogic.sol\";\nimport { IFCNBulkActionsEntry } from \"./interfaces/IFCNBulkActionsEntry.sol\";\n\ncontract FCNBulkActionsEntry is IFCNBulkActionsEntry, EntryBase {\n    using SafeCast for uint256;\n\n    // IMMUTABLE\n\n    ITreasury private immutable treasury;\n\n    // CONSTRUCTOR\n\n    constructor(\n        IAddressManager _addressManager,\n        ITreasury _treasury\n    ) EntryBase(_addressManager) {\n        treasury = _treasury;\n    }\n\n    // FUNCTIONS\n\n    function fcnBulkProcessDepositQueues(\n        address[] calldata vaultAddresses,\n        uint256 maxProcessCount\n    )\n        external\n        nonReentrant\n        onlyTraderAdmin\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            uint32 productId = cgs.vaults[vaultAddresses[i]].productId;\n            FCNProduct storage fcnProduct = cgs.fcnProducts[productId];\n\n            maxProcessCount -= ProductLogic.processDepositQueue(\n                cgs,\n                ProcessQueueParams({\n                    productId: productId,\n                    vaultAddress: vaultAddresses[i],\n                    depositAsset: FCNProductLogic.fcnGetProductDepositAsset(\n                        fcnProduct\n                    ),\n                    maxProcessCount: maxProcessCount,\n                    sumVaultUnderlyingAmounts: fcnProduct\n                        .sumVaultUnderlyingAmounts\n                }),\n                FCNProductLogic.fcnProcessDepositQueueHook\n            );\n\n            if (maxProcessCount == 0) {\n                return;\n            }\n        }\n    }\n\n    function fcnBulkProcessWithdrawalQueues(\n        address[] calldata vaultAddresses,\n        uint256 maxProcessCount\n    )\n        external\n        nonReentrant\n        onlyTraderAdmin\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            Vault storage vaultData = cgs.vaults[vaultAddresses[i]];\n            FCNProduct storage fcnProduct = cgs.fcnProducts[\n                vaultData.productId\n            ];\n            address settlementAsset = fcnProduct.underlyingAsset;\n\n            maxProcessCount -= ProductLogic.processWithdrawalQueue(\n                cgs,\n                treasury,\n                addressManager,\n                vaultAddresses[i],\n                maxProcessCount,\n                settlementAsset,\n                FCNProductLogic.fcnAddToWithdrawalQueueHook\n            );\n\n            if (maxProcessCount == 0) {\n                return;\n            }\n        }\n    }\n\n    function fcnBulkEndAuctions(\n        address[] calldata vaultAddresses,\n        address[] calldata auctionWinners,\n        uint40[] calldata tradeStartDates,\n        uint16[] calldata aprBps,\n        IOracleEntry.DataSource[][] calldata dataSources\n    )\n        external\n        nonReentrant\n        onlyTraderAdmin\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        require(\n            vaultAddresses.length == auctionWinners.length &&\n                vaultAddresses.length == tradeStartDates.length &&\n                vaultAddresses.length == aprBps.length &&\n                vaultAddresses.length == dataSources.length,\n            Errors.INVALID_ARRAY_LENGTH\n        );\n\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            FCNVaultLogic.endAuction(\n                cgs,\n                addressManager,\n                vaultAddresses[i],\n                auctionWinners[i],\n                tradeStartDates[i],\n                aprBps[i],\n                dataSources[i]\n            );\n        }\n    }\n\n    function fcnBulkStartTrades(\n        address[] calldata vaultAddresses\n    )\n        external\n        payable\n        nonReentrant\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n\n        MMNFTMetadata[] memory nftMetadatas = new MMNFTMetadata[](\n            vaultAddresses.length\n        );\n        uint256 totalNativeValueReceived;\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            uint256 nativeValueReceived;\n            (nativeValueReceived, nftMetadatas[i]) = FCNVaultLogic.startTrade(\n                cgs,\n                vaultAddresses[i],\n                address(0),\n                treasury,\n                addressManager\n            );\n            totalNativeValueReceived += nativeValueReceived;\n        }\n\n        uint256[] memory tokenIds = ITradeWinnerNFT(\n            addressManager.getTradeWinnerNFT()\n        ).mintBatch(msg.sender, nftMetadatas);\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            cgs.vaults[vaultAddresses[i]].auctionWinnerTokenId = tokenIds[i]\n                .toUint64();\n        }\n\n        Transfers.receiveNativeValue(totalNativeValueReceived);\n    }\n\n    function fcnBulkCheckBarriers(\n        address[] calldata vaultAddresses,\n        uint16 maxObservations\n    )\n        external\n        nonReentrant\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            (, uint16 observationsDone) = FCNVaultLogic.checkBarriers(\n                cgs,\n                addressManager,\n                vaultAddresses[i],\n                maxObservations\n            );\n            maxObservations -= observationsDone;\n            if (maxObservations == 0) {\n                return;\n            }\n        }\n    }\n\n    function fcnBulkCheckTradesExpiry(\n        address[] calldata vaultAddresses\n    )\n        external\n        nonReentrant\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            FCNVaultLogic.checkTradeExpiry(\n                cgs,\n                addressManager,\n                vaultAddresses[i]\n            );\n        }\n    }\n\n    function fcnBulkRepayBonds(\n        address[] calldata vaultAddresses,\n        uint128[] calldata amounts\n    )\n        external\n        payable\n        nonReentrant\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        require(\n            vaultAddresses.length == amounts.length,\n            Errors.INVALID_ARRAY_LENGTH\n        );\n\n        CegaGlobalStorage storage cgs = getStorage();\n        uint256 totalNativeValueReceived;\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            totalNativeValueReceived += FCNVaultLogic.repayBond(\n                cgs,\n                treasury,\n                vaultAddresses[i],\n                amounts[i]\n            );\n        }\n\n        Transfers.receiveNativeValue(totalNativeValueReceived);\n    }\n\n    function fcnBulkSettleVaults(\n        address[] calldata vaultAddresses\n    )\n        external\n        payable\n        nonReentrant\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        uint256 totalNativeValueReceived;\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            totalNativeValueReceived += FCNVaultLogic.settleVault(\n                cgs,\n                addressManager,\n                treasury,\n                vaultAddresses[i]\n            );\n        }\n\n        Transfers.receiveNativeValue(totalNativeValueReceived);\n    }\n\n    function fcnBulkCollectFees(\n        address[] calldata vaultAddresses\n    )\n        external\n        nonReentrant\n        onlyIfNotPaused\n        onlyTraderAdmin\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            FCNVaultLogic.collectVaultFees(\n                cgs,\n                treasury,\n                addressManager,\n                vaultAddresses[i]\n            );\n        }\n    }\n\n    function fcnBulkRolloverVaults(\n        address[] calldata vaultAddresses\n    )\n        external\n        nonReentrant\n        onlyTraderAdmin\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            FCNVaultLogic.rolloverVault(cgs, vaultAddresses[i]);\n        }\n    }\n\n    function fcnBulkCheckSettlementDefault(\n        address[] calldata vaultAddresses\n    )\n        external\n        nonReentrant\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            FCNVaultLogic.checkSettlementDefault(cgs, vaultAddresses[i]);\n        }\n    }\n\n    function fcnBulkCheckAuctionDefault(\n        address[] calldata vaultAddresses\n    )\n        external\n        nonReentrant\n        onlyIfNotPaused\n        onlyValidVaultsStrategy(FCN_STRATEGY_ID, vaultAddresses)\n    {\n        CegaGlobalStorage storage cgs = getStorage();\n        for (uint256 i = 0; i < vaultAddresses.length; i++) {\n            FCNVaultLogic.checkAuctionDefault(cgs, vaultAddresses[i]);\n        }\n    }\n}\n"
      },
      "contracts/cega-strategies/fcn/FCNStructs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { IOracleEntry } from \"../../oracle-entry/interfaces/IOracleEntry.sol\";\n\nstruct FCNProductCreationParams {\n    uint128 minDepositAmount;\n    uint128 minWithdrawalAmount;\n    uint128 maxUnderlyingAmountLimit;\n    address underlyingAsset;\n    uint64 leverage;\n    uint40 tenorInSeconds;\n    uint8 daysToStartLateFees;\n    uint8 daysToStartAuctionDefault;\n    uint8 daysToStartSettlementDefault;\n    uint8 disputePeriodInHours;\n    uint8 disputeGraceDelayInHours;\n    uint16 lateFeeBps;\n    string name;\n    string tradeWinnerNftImage;\n    bool isBondOption;\n    uint24 observationIntervalInSeconds;\n    FCNOptionBarrier[] optionBarriers;\n}\n\nstruct FCNProduct {\n    uint128 minDepositAmount;\n    uint128 minWithdrawalAmount;\n    uint128 maxUnderlyingAmountLimit;\n    uint128 sumVaultUnderlyingAmounts;\n    address underlyingAsset;\n    uint64 leverage;\n    uint40 tenorInSeconds;\n    uint8 daysToStartLateFees;\n    uint8 daysToStartAuctionDefault;\n    uint8 daysToStartSettlementDefault;\n    uint8 disputePeriodInHours;\n    uint8 disputeGraceDelayInHours;\n    uint16 lateFeeBps;\n    bool isDepositQueueOpen;\n    bool isBondOption;\n    uint24 observationIntervalInSeconds;\n    FCNOptionBarrier[] optionBarriers;\n    address[] vaults;\n}\n\nstruct FCNVaultCreationParams {\n    string tokenName;\n    string tokenSymbol;\n    uint16 yieldFeeBps;\n    uint16 managementFeeBps;\n}\n\nstruct FCNVaultBarrierData {\n    uint128 initialSpotPrice;\n    IOracleEntry.DataSource dataSource;\n}\n\nstruct FCNVault {\n    uint128 notional;\n    uint128 totalYield;\n    uint16 aprBps;\n    bool isKnockedIn;\n    uint16 observationsDone;\n    uint96 buffer; // buffer if we need to add any more data\n    FCNVaultBarrierData[] barrierData;\n}\n\nstruct FCNOptionBarrier {\n    uint16 barrierBps;\n    FCNOptionBarrierType barrierType;\n    address asset;\n    uint8 exponent;\n}\n\nenum FCNOptionBarrierType {\n    None,\n    KnockIn\n}\n\nenum FCNVaultStatus {\n    DepositsClosed,\n    DepositsOpen,\n    PreAuction,\n    Auctioned,\n    Traded,\n    AwaitingSettlement,\n    Settled,\n    FeesCollected,\n    WithdrawalQueueProcessed,\n    Zombie\n}\n"
      },
      "contracts/cega-strategies/fcn/interfaces/IFCNBulkActionsEntry.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport {\n    IOracleEntry\n} from \"../../../oracle-entry/interfaces/IOracleEntry.sol\";\n\ninterface IFCNBulkActionsEntry {\n    function fcnBulkProcessDepositQueues(\n        address[] calldata vaultAddresses,\n        uint256 maxProcessCount\n    ) external;\n\n    function fcnBulkProcessWithdrawalQueues(\n        address[] calldata vaultAddresses,\n        uint256 maxProcessCount\n    ) external;\n\n    function fcnBulkEndAuctions(\n        address[] calldata vaultAddresses,\n        address[] calldata auctionWinners,\n        uint40[] calldata tradeStartDates,\n        uint16[] calldata aprBps,\n        IOracleEntry.DataSource[][] calldata dataSources\n    ) external;\n\n    function fcnBulkStartTrades(\n        address[] calldata vaultAddresses\n    ) external payable;\n\n    function fcnBulkCheckBarriers(\n        address[] calldata vaultAddresses,\n        uint16 maxObservations\n    ) external;\n\n    function fcnBulkCheckTradesExpiry(\n        address[] calldata vaultAddresses\n    ) external;\n\n    function fcnBulkRepayBonds(\n        address[] calldata vaultAddresses,\n        uint128[] calldata amounts\n    ) external payable;\n\n    function fcnBulkSettleVaults(\n        address[] calldata vaultAddresses\n    ) external payable;\n\n    function fcnBulkCollectFees(address[] calldata vaultAddresses) external;\n\n    function fcnBulkRolloverVaults(address[] calldata vaultAddresses) external;\n\n    function fcnBulkCheckSettlementDefault(\n        address[] calldata vaultAddresses\n    ) external;\n\n    function fcnBulkCheckAuctionDefault(\n        address[] calldata vaultAddresses\n    ) external;\n}\n"
      },
      "contracts/cega-strategies/fcn/interfaces/IFCNEvents.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { ICommonEvents } from \"../../common/interfaces/ICommonEvents.sol\";\nimport { FCNVaultCreationParams } from \"../FCNStructs.sol\";\n\ninterface IFCNEvents is ICommonEvents {\n    event FCNProductCreated(uint32 indexed productId);\n\n    event FCNVaultCreated(\n        uint32 indexed productId,\n        address indexed vaultAddress,\n        FCNVaultCreationParams creationParams\n    );\n\n    event FCNLateFeeBpsUpdated(uint32 indexed productId, uint16 lateFeeBps);\n\n    event FCNMinDepositAmountUpdated(\n        uint32 indexed productId,\n        uint128 minDepositAmount\n    );\n\n    event FCNMinWithdrawalAmountUpdated(\n        uint32 indexed productId,\n        uint128 minWithdrawalAmount\n    );\n\n    event FCNIsDepositQueueOpenUpdated(\n        uint32 indexed productId,\n        bool isDepositQueueOpen\n    );\n\n    event FCNMaxUnderlyingAmountLimitUpdated(\n        uint32 indexed productId,\n        uint128 maxUnderlyingAmountLimit\n    );\n\n    event FCNDisputePeriodInHoursUpdated(\n        uint32 indexed productId,\n        uint8 disputePeriodInHours\n    );\n\n    event FCNDisputeGraceDelayInHoursUpdated(\n        uint32 indexed productId,\n        uint8 disputeGraceDelayInHours\n    );\n\n    event FCNDaysToStartLateFeesUpdated(\n        uint32 indexed productId,\n        uint8 daysToStartLateFees\n    );\n\n    event FCNDaysToStartAuctionDefaultUpdated(\n        uint32 indexed productId,\n        uint8 daysToStartAuctionDefault\n    );\n\n    event FCNDaysToStartSettlementDefaultUpdated(\n        uint32 indexed productId,\n        uint8 daysToStartSettlementDefault\n    );\n\n    event FCNAuctionEnded(\n        address indexed vaultAddress,\n        address indexed auctionWinner,\n        uint40 tradeStartDate,\n        uint16 aprBps,\n        uint128[] initialSpotPrices\n    );\n\n    event FCNTradeStarted(\n        address indexed vaultAddress,\n        address auctionWinner,\n        uint128 notionalAmount,\n        uint128 yieldAmount\n    );\n\n    event FCNIsKnockedInUpdated(address indexed vaultAddress, bool isKnockedIn);\n\n    event FCNLateFeePaid(address indexed vaultAddress, uint128 feeAmount);\n\n    event FCNBondRepaid(address indexed vaultAddress, uint128 amount);\n\n    event FCNVaultRolledOver(address indexed vaultAddress);\n\n    event FCNBondAllowListUpdated(address indexed receiver, bool value);\n\n    event FCNVaultFeesCollected(\n        address indexed vaultAddress,\n        uint128 totalFees,\n        uint128 managementFee,\n        uint128 yieldFee\n    );\n\n    event FCNDisputeProcessed(\n        address indexed vaultAddress,\n        bool isDisputeAccepted,\n        uint8 barrierIndex,\n        uint40 timestamp,\n        uint128 newPrice\n    );\n\n    event FCNDisputeSubmitted(\n        address indexed vaultAddress,\n        uint8 barrierIndex,\n        uint40 timestamp\n    );\n\n    event FCNProductIsBondOptionUpdated(\n        uint32 indexed productId,\n        bool isBondOption\n    );\n}\n"
      },
      "contracts/cega-strategies/fcn/lib/FCNProductLogic.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport {\n    FCNProductCreationParams,\n    FCNProduct,\n    FCNVaultCreationParams,\n    FCNOptionBarrier\n} from \"../FCNStructs.sol\";\nimport { CegaGlobalStorage, Vault } from \"../../../Structs.sol\";\nimport {\n    AddToDepositQueueParams,\n    RemoveFromDepositQueueParams\n} from \"../../common/CommonStructs.sol\";\nimport { ProductLogic } from \"../../common/lib/ProductLogic.sol\";\nimport { IAddressManager } from \"../../../aux/interfaces/IAddressManager.sol\";\nimport { ITreasury } from \"../../../treasuries/interfaces/ITreasury.sol\";\n\nlibrary FCNProductLogic {\n    /**\n     * @dev Retrieves the deposit asset for a given FCN product.\n     * @param fcnProduct The FCN product.\n     * @return The address of the deposit asset.\n     */\n    function fcnGetProductDepositAsset(\n        FCNProduct storage fcnProduct\n    ) internal view returns (address) {\n        return fcnProduct.underlyingAsset;\n    }\n\n    function fcnProcessDepositQueueHook(\n        CegaGlobalStorage storage cgs,\n        uint32 productId,\n        uint128 totalDepositsAmount\n    ) internal {\n        cgs\n            .fcnProducts[productId]\n            .sumVaultUnderlyingAmounts += totalDepositsAmount;\n    }\n\n    function fcnAddToWithdrawalQueueHook(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        uint128 assetAmount\n    ) internal {\n        cgs\n            .fcnProducts[cgs.vaults[vaultAddress].productId]\n            .sumVaultUnderlyingAmounts -= assetAmount;\n    }\n\n    function addToDepositQueue(\n        CegaGlobalStorage storage cgs,\n        address treasury,\n        uint32 productId,\n        uint128 amount,\n        address receiver\n    ) internal {\n        FCNProduct storage fcnProduct = cgs.fcnProducts[productId];\n        ProductLogic.addToDepositQueue(\n            cgs,\n            treasury,\n            AddToDepositQueueParams({\n                productId: productId,\n                amount: amount,\n                receiver: receiver,\n                depositAsset: fcnProduct.underlyingAsset,\n                isDepositQueueOpen: fcnProduct.isDepositQueueOpen,\n                minDepositAmount: fcnProduct.minDepositAmount,\n                sumVaultUnderlyingAmounts: fcnProduct.sumVaultUnderlyingAmounts,\n                maxUnderlyingAmountLimit: fcnProduct.maxUnderlyingAmountLimit\n            })\n        );\n    }\n\n    function removeFromDepositQueue(\n        CegaGlobalStorage storage cgs,\n        ITreasury treasury,\n        uint32 productId,\n        uint128 amount\n    ) internal {\n        FCNProduct storage fcnProduct = cgs.fcnProducts[productId];\n        ProductLogic.removeFromDepositQueue(\n            cgs,\n            treasury,\n            RemoveFromDepositQueueParams({\n                productId: productId,\n                amount: amount,\n                depositor: msg.sender,\n                depositAsset: fcnProduct.underlyingAsset,\n                minDepositAmount: fcnProduct.minDepositAmount\n            })\n        );\n    }\n\n    function addToWithdrawalQueue(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        ITreasury treasury,\n        address vaultAddress,\n        uint128 sharesAmount,\n        uint32 nextProductId,\n        bool useProxy\n    ) internal {\n        Vault storage vaultData = cgs.vaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vaultData.productId];\n        ProductLogic.withdrawOrAddToWithdrawalQueue(\n            cgs,\n            treasury,\n            addressManager,\n            vaultAddress,\n            sharesAmount,\n            nextProductId,\n            useProxy,\n            fcnProduct.minWithdrawalAmount,\n            fcnProduct.underlyingAsset,\n            FCNProductLogic.fcnAddToWithdrawalQueueHook\n        );\n    }\n}\n"
      },
      "contracts/cega-strategies/fcn/lib/FCNVaultLogic.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport {\n    IERC721AUpgradeable\n} from \"erc721a-upgradeable/contracts/IERC721AUpgradeable.sol\";\n\nimport { IERC721 } from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport {\n    CegaGlobalStorage,\n    Vault,\n    VaultStatus,\n    MMNFTMetadata\n} from \"../../../Structs.sol\";\nimport {\n    FCNProduct,\n    FCNVault,\n    FCNOptionBarrier,\n    FCNVaultBarrierData,\n    FCNOptionBarrierType\n} from \"../FCNStructs.sol\";\nimport { VaultLogic } from \"../../common/lib/VaultLogic.sol\";\nimport {\n    IOracleEntry\n} from \"../../../oracle-entry/interfaces/IOracleEntry.sol\";\nimport { ITreasury } from \"../../../treasuries/interfaces/ITreasury.sol\";\nimport { IAddressManager } from \"../../../aux/interfaces/IAddressManager.sol\";\nimport { ITradeWinnerNFT } from \"../../../aux/interfaces/ITradeWinnerNFT.sol\";\nimport { IFCNEvents } from \"../interfaces/IFCNEvents.sol\";\nimport { IACLManager } from \"../../../aux/interfaces/IACLManager.sol\";\nimport { Errors } from \"../../../utils/Errors.sol\";\nimport { FCNProductLogic } from \"./FCNProductLogic.sol\";\nimport { Transfers } from \"../../../utils/Transfers.sol\";\n\nlibrary FCNVaultLogic {\n    using Transfers for address;\n    using SafeCast for uint256;\n    using SafeCast for uint40;\n\n    // CONSTANTS\n\n    uint128 internal constant LARGE_CONSTANT = 1e18;\n\n    uint128 internal constant DAYS_IN_YEAR = 365;\n\n    uint128 internal constant BPS_DECIMALS = 1e4;\n\n    // FUNCTIONS\n\n    function getSpotPriceAt(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        IOracleEntry oracleEntry,\n        address asset,\n        IOracleEntry.DataSource dataSource,\n        uint40 priceTimestamp\n    ) internal view returns (uint128) {\n        uint128 priceOverride = cgs.oraclePriceOverride[vaultAddress][\n            VaultLogic.getAssetCode(asset)\n        ][priceTimestamp];\n\n        if (priceOverride > 0) {\n            return priceOverride;\n        }\n\n        return oracleEntry.getSinglePrice(asset, priceTimestamp, dataSource);\n    }\n\n    function expRatio(\n        uint256 num,\n        uint256 denom,\n        uint8 exp\n    ) internal pure returns (uint256 result) {\n        num = (num * LARGE_CONSTANT) / denom;\n        result = num;\n        for (uint8 i = 1; i < exp; i++) {\n            result = (result * num) / LARGE_CONSTANT;\n        }\n    }\n\n    function getVaultLostCapital(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress\n    ) internal view returns (uint128) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n\n        if (!fcnVault.isKnockedIn) {\n            return 0;\n        }\n\n        IOracleEntry oracleEntry = IOracleEntry(addressManager.getCegaOracle());\n\n        uint256 knockInRatio = LARGE_CONSTANT;\n        uint256 barriersLength = fcnVault.barrierData.length;\n        uint40 tradeEndDate = vault.tradeStartDate + fcnProduct.tenorInSeconds;\n\n        FCNVaultBarrierData memory barrierData;\n        FCNOptionBarrier memory optionBarrier;\n        uint256 initialSpotPrice;\n        uint256 finalSpotPrice;\n\n        for (uint256 i = 0; i < barriersLength; i++) {\n            barrierData = fcnVault.barrierData[i];\n            optionBarrier = fcnProduct.optionBarriers[i];\n\n            initialSpotPrice = barrierData.initialSpotPrice;\n            finalSpotPrice = getSpotPriceAt(\n                cgs,\n                vaultAddress,\n                oracleEntry,\n                optionBarrier.asset,\n                barrierData.dataSource,\n                tradeEndDate\n            );\n\n            if (finalSpotPrice < initialSpotPrice) {\n                uint256 currentRatio = expRatio(\n                    finalSpotPrice,\n                    initialSpotPrice,\n                    optionBarrier.exponent\n                );\n                if (currentRatio < knockInRatio) {\n                    knockInRatio = currentRatio;\n                }\n            }\n        }\n\n        uint256 principalLostRatio = Math.min(\n            (LARGE_CONSTANT - knockInRatio) * fcnProduct.leverage,\n            LARGE_CONSTANT\n        );\n        return\n            ((fcnVault.notional * principalLostRatio) / LARGE_CONSTANT)\n                .toUint128();\n    }\n\n    function calculateVaultFinalPayoff(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress\n    ) internal view returns (uint128) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n\n        VaultStatus vaultStatus = vault.vaultStatus;\n        require(\n            vaultStatus == VaultStatus.AwaitingSettlement ||\n                vaultStatus == VaultStatus.Settled,\n            Errors.INVALID_VAULT_STATUS\n        );\n\n        return\n            fcnVault.notional +\n            fcnVault.totalYield -\n            getVaultLostCapital(cgs, addressManager, vaultAddress);\n    }\n\n    function calculateRepaidBond(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal view returns (uint128) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n\n        require(fcnProduct.isBondOption, Errors.NOT_BOND_OPTION);\n\n        VaultStatus vaultStatus = vault.vaultStatus;\n        if (\n            vaultStatus == VaultStatus.Traded ||\n            vaultStatus == VaultStatus.AwaitingSettlement\n        ) {\n            return vault.totalAssets - fcnVault.totalYield;\n        } else {\n            return fcnVault.notional;\n        }\n    }\n\n    function calculateVaultSettlementAmount(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress\n    ) internal view returns (uint128) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        require(\n            vault.vaultStatus == VaultStatus.AwaitingSettlement,\n            Errors.INVALID_VAULT_STATUS\n        );\n\n        uint128 lostCapital = getVaultLostCapital(\n            cgs,\n            addressManager,\n            vaultAddress\n        );\n\n        uint128 unpaidBond;\n        if (fcnProduct.isBondOption) {\n            unpaidBond =\n                fcnVault.notional -\n                calculateRepaidBond(cgs, vaultAddress);\n        }\n\n        if (lostCapital > unpaidBond) {\n            return 0;\n        } else {\n            return unpaidBond - lostCapital;\n        }\n    }\n\n    function getVaultCouponPayment(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal view returns (uint128) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        uint128 notional;\n        if (vault.auctionWinnerTokenId != 0) {\n            notional = fcnVault.notional;\n        } else {\n            notional = vault.totalAssets;\n        }\n\n        uint40 tradeStartDate = vault.tradeStartDate;\n        uint40 tenorInSeconds = fcnProduct.tenorInSeconds;\n        return\n            VaultLogic.calculateCouponPayment(\n                notional,\n                tradeStartDate,\n                tenorInSeconds,\n                fcnVault.aprBps,\n                tradeStartDate + tenorInSeconds\n            );\n    }\n\n    function endAuction(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress,\n        address auctionWinner,\n        uint40 tradeStartDate,\n        uint16 aprBps,\n        IOracleEntry.DataSource[] calldata dataSources\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        VaultStatus vaultStatus = vault.vaultStatus;\n\n        require(\n            fcnProduct.optionBarriers.length == dataSources.length,\n            Errors.INVALID_ARRAY_LENGTH\n        );\n        require(\n            vaultStatus == VaultStatus.PreAuction ||\n                vaultStatus == VaultStatus.Auctioned,\n            Errors.INVALID_VAULT_STATUS\n        );\n\n        require(tradeStartDate != 0, Errors.VALUE_IS_ZERO);\n\n        vault.auctionWinner = auctionWinner;\n        vault.tradeStartDate = tradeStartDate;\n\n        fcnVault.aprBps = aprBps;\n        uint128[] memory initialSpotPrices = new uint128[](dataSources.length);\n\n        if (fcnVault.barrierData.length == 0) {\n            fcnVault.barrierData = new FCNVaultBarrierData[](\n                dataSources.length\n            );\n        }\n\n        for (uint256 index = 0; index < dataSources.length; index++) {\n            initialSpotPrices[index] = FCNVaultLogic.getSpotPriceAt(\n                cgs,\n                vaultAddress,\n                IOracleEntry(addressManager.getCegaOracle()),\n                fcnProduct.optionBarriers[index].asset,\n                dataSources[index],\n                tradeStartDate\n            );\n\n            fcnVault.barrierData[index] = FCNVaultBarrierData({\n                dataSource: dataSources[index],\n                initialSpotPrice: initialSpotPrices[index]\n            });\n        }\n\n        VaultLogic.setVaultStatus(cgs, vaultAddress, VaultStatus.Auctioned);\n\n        emit IFCNEvents.FCNAuctionEnded(\n            vaultAddress,\n            auctionWinner,\n            tradeStartDate,\n            aprBps,\n            initialSpotPrices\n        );\n    }\n\n    /**\n     * @dev Starts a trade for a specific vault.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     * @param tradeWinnerNFT The address of the trade winner NFT contract.\n     * @param treasury The treasury contract.\n     * @param addressManager The address manager.\n     * @return nativeValueReceived The native value received.\n     * @return nftMetadata The metadata for the minted NFT.\n     */\n    function startTrade(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        address tradeWinnerNFT,\n        ITreasury treasury,\n        IAddressManager addressManager\n    )\n        internal\n        returns (uint256 nativeValueReceived, MMNFTMetadata memory nftMetadata)\n    {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n\n        require(msg.sender == vault.auctionWinner, Errors.NOT_TRADE_WINNER);\n        require(\n            vault.vaultStatus == VaultStatus.Auctioned,\n            Errors.INVALID_VAULT_STATUS\n        );\n        require(!vault.isInDispute, Errors.VAULT_IN_DISPUTE);\n        require(\n            block.timestamp >= vault.tradeStartDate,\n            Errors.TRADE_NOT_STARTED\n        );\n\n        require(\n            !VaultLogic.getIsAuctionDefaulted(\n                cgs,\n                vaultAddress,\n                fcnProduct.daysToStartAuctionDefault\n            ),\n            Errors.TRADE_DEFAULTED\n        );\n\n        // Transfer the premium + any applicable late fee\n        uint40 tradeStartDate = vault.tradeStartDate;\n        address depositAsset = FCNProductLogic.fcnGetProductDepositAsset(\n            fcnProduct\n        );\n        uint128 totalAssets = vault.totalAssets;\n        uint16 aprBps = fcnVault.aprBps;\n        uint40 tenorInSeconds = fcnProduct.tenorInSeconds;\n\n        // prices are 0 until we modify the NFT Metadata\n        nftMetadata = MMNFTMetadata({\n            vaultAddress: vaultAddress,\n            tradeStartDate: tradeStartDate,\n            tradeEndDate: tradeStartDate + tenorInSeconds,\n            notional: totalAssets,\n            aprBps: aprBps,\n            initialSpotPrice: 0,\n            strikePrice: 0\n        });\n\n        uint128 totalYield = VaultLogic.calculateCouponPayment(\n            totalAssets,\n            tradeStartDate,\n            tenorInSeconds,\n            aprBps,\n            tradeStartDate + tenorInSeconds\n        );\n        fcnVault.totalYield = totalYield;\n        uint128 lateFee = VaultLogic.calculateLateFee(\n            totalYield,\n            tradeStartDate,\n            fcnProduct.lateFeeBps,\n            fcnProduct.daysToStartLateFees,\n            fcnProduct.daysToStartAuctionDefault\n        );\n\n        fcnVault.notional = totalAssets;\n\n        if (fcnProduct.isBondOption) {\n            require(\n                cgs.fcnBondAllowList[msg.sender],\n                Errors.UNAUTHORIZED_BOND_RECEIVER\n            );\n\n            vault.totalAssets = totalYield;\n            treasury.withdraw(depositAsset, msg.sender, totalAssets, false);\n        } else {\n            vault.totalAssets = totalAssets + totalYield;\n        }\n\n        if (lateFee > 0) {\n            nativeValueReceived = depositAsset.receiveTo(\n                addressManager.getCegaFeeReceiver(),\n                lateFee\n            );\n            emit IFCNEvents.FCNLateFeePaid(vaultAddress, lateFee);\n        }\n\n        nativeValueReceived += depositAsset.receiveTo(\n            address(treasury),\n            totalYield\n        );\n\n        fcnProduct.sumVaultUnderlyingAmounts += totalYield;\n\n        VaultLogic.setVaultStatus(cgs, vaultAddress, VaultStatus.Traded);\n\n        if (tradeWinnerNFT != address(0)) {\n            uint256 tokenId = ITradeWinnerNFT(tradeWinnerNFT).mint(\n                msg.sender,\n                nftMetadata\n            );\n            vault.auctionWinnerTokenId = tokenId.toUint64();\n        }\n\n        emit IFCNEvents.FCNTradeStarted(\n            vaultAddress,\n            msg.sender,\n            totalAssets,\n            totalYield\n        );\n    }\n\n    function checkTradeExpiry(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        VaultStatus vaultStatus = vault.vaultStatus;\n        if (\n            vaultStatus != VaultStatus.Traded &&\n            vaultStatus != VaultStatus.AwaitingSettlement\n        ) {\n            return;\n        }\n\n        uint40 tenorInSeconds = fcnProduct.tenorInSeconds;\n        uint40 tradeStartDate = vault.tradeStartDate;\n        uint256 currentTime = block.timestamp;\n        if (currentTime <= tradeStartDate + tenorInSeconds) {\n            return;\n        }\n\n        (bool isKnockedIn, ) = checkBarriers(\n            cgs,\n            addressManager,\n            vaultAddress,\n            type(uint16).max\n        );\n\n        if (\n            isKnockedIn ||\n            vault.totalAssets < fcnVault.notional + fcnVault.totalYield\n        ) {\n            VaultLogic.setVaultStatus(\n                cgs,\n                vaultAddress,\n                VaultStatus.AwaitingSettlement\n            );\n        } else {\n            VaultLogic.setVaultStatus(cgs, vaultAddress, VaultStatus.Settled);\n        }\n    }\n\n    function checkBarriers(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress,\n        uint16 maxObservations\n    ) internal returns (bool isKnockedIn, uint16 observationsCount) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n        IOracleEntry oracleEntry = IOracleEntry(addressManager.getCegaOracle());\n\n        require(\n            vault.vaultStatus == VaultStatus.Traded,\n            Errors.INVALID_VAULT_STATUS\n        );\n\n        uint40 tradeStartDate = vault.tradeStartDate;\n        uint40 tradeEndDate = tradeStartDate + fcnProduct.tenorInSeconds;\n        uint40 observationInterval = fcnProduct.observationIntervalInSeconds;\n        uint40 observationsDone = fcnVault.observationsDone;\n        uint40 observationStart = tradeStartDate +\n            (observationsDone + 1) *\n            observationInterval;\n\n        uint40 observationEnd = tradeStartDate +\n            (observationsDone + maxObservations) *\n            observationInterval;\n        if (tradeEndDate < observationEnd) {\n            observationEnd = tradeEndDate;\n        }\n        if (block.timestamp < observationEnd) {\n            observationEnd = block.timestamp.toUint40();\n        }\n\n        if (observationEnd < observationStart) {\n            return (fcnVault.isKnockedIn, 0);\n        }\n\n        observationsCount = ((observationEnd - observationStart) /\n            observationInterval +\n            1).toUint16();\n\n        uint256 barriersLength = fcnVault.barrierData.length;\n\n        FCNVaultBarrierData memory barrierData;\n        FCNOptionBarrier memory optionBarrier;\n        uint128 barrierAbsoluteValue;\n\n        for (uint256 i = 0; i < barriersLength; i++) {\n            if (\n                fcnProduct.optionBarriers[i].barrierType ==\n                FCNOptionBarrierType.KnockIn\n            ) {\n                barrierData = fcnVault.barrierData[i];\n                optionBarrier = fcnProduct.optionBarriers[i];\n                barrierAbsoluteValue =\n                    (barrierData.initialSpotPrice * optionBarrier.barrierBps) /\n                    BPS_DECIMALS;\n\n                for (\n                    uint40 observationTime = observationStart;\n                    observationTime <= observationEnd;\n                    observationTime += observationInterval\n                ) {\n                    uint128 observationSpotPrice = getSpotPriceAt(\n                        cgs,\n                        vaultAddress,\n                        oracleEntry,\n                        optionBarrier.asset,\n                        barrierData.dataSource,\n                        observationTime\n                    );\n                    if (observationSpotPrice <= barrierAbsoluteValue) {\n                        isKnockedIn = true;\n                        break;\n                    }\n                }\n                if (isKnockedIn) {\n                    break;\n                }\n            } else {\n                revert(Errors.UNKNOWN_BARRIER_TYPE);\n            }\n        }\n\n        if (isKnockedIn) {\n            fcnVault.observationsDone = type(uint16).max;\n            fcnVault.isKnockedIn = true;\n        } else {\n            fcnVault.observationsDone += observationsCount;\n        }\n\n        emit IFCNEvents.FCNIsKnockedInUpdated(vaultAddress, isKnockedIn);\n    }\n\n    /**\n     * @dev Checks for settlement default for a specific vault.\n     * @param cgs The Cega global storage.\n     * @param vaultAddress The address of the vault.\n     */\n    function checkSettlementDefault(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        if (vault.isDefaulted) {\n            return;\n        }\n\n        uint256 daysLate = VaultLogic.getDaysLate(\n            vault.tradeStartDate + fcnProduct.tenorInSeconds\n        );\n        if (\n            daysLate >= fcnProduct.daysToStartSettlementDefault &&\n            vault.vaultStatus == VaultStatus.AwaitingSettlement\n        ) {\n            VaultLogic.setIsDefaulted(cgs, vaultAddress, true);\n            if (fcnProduct.isBondOption) {\n                uint128 unpaidBond = fcnVault.notional +\n                    fcnVault.totalYield -\n                    vault.totalAssets;\n                fcnProduct.sumVaultUnderlyingAmounts -= unpaidBond;\n            }\n        }\n    }\n\n    function repayBond(\n        CegaGlobalStorage storage cgs,\n        ITreasury treasury,\n        address vaultAddress,\n        uint128 amount\n    ) internal returns (uint256 nativeValueReceived) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        require(fcnProduct.isBondOption, Errors.INVALID_VAULT);\n        require(\n            vault.vaultStatus == VaultStatus.Traded,\n            Errors.INVALID_VAULT_STATUS\n        );\n        uint128 currentAssets = vault.totalAssets;\n        require(\n            currentAssets + amount <= fcnVault.notional + fcnVault.totalYield,\n            Errors.VALUE_TOO_LARGE\n        );\n\n        vault.totalAssets = currentAssets + amount;\n        nativeValueReceived = fcnProduct.underlyingAsset.receiveTo(\n            address(treasury),\n            amount\n        );\n\n        emit IFCNEvents.FCNBondRepaid(vaultAddress, amount);\n    }\n\n    function settleVault(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        ITreasury treasury,\n        address vaultAddress\n    ) internal returns (uint256 nativeValueReceived) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        require(\n            vault.vaultStatus == VaultStatus.AwaitingSettlement,\n            Errors.INVALID_VAULT_STATUS\n        );\n        require(!vault.isInDispute, Errors.VAULT_IN_DISPUTE);\n        require(\n            block.timestamp >\n                vault.tradeStartDate +\n                    fcnProduct.tenorInSeconds +\n                    (uint256(fcnProduct.disputeGraceDelayInHours) * 1 hours),\n            Errors.VALUE_IN_DISPUTE_GRACE_DELAY\n        );\n\n        {\n            uint256 auctionWinnerTokenId = vault.auctionWinnerTokenId;\n            require(auctionWinnerTokenId != 0, Errors.TRADE_HAS_NO_WINNER);\n            require(\n                msg.sender ==\n                    IERC721AUpgradeable(addressManager.getTradeWinnerNFT())\n                        .ownerOf(auctionWinnerTokenId),\n                Errors.NOT_TRADE_WINNER\n            );\n        }\n\n        checkSettlementDefault(cgs, vaultAddress);\n        require(!vault.isDefaulted, Errors.TRADE_DEFAULTED);\n\n        uint128 bondAmount;\n        if (fcnProduct.isBondOption) {\n            bondAmount =\n                fcnVault.notional +\n                fcnVault.totalYield -\n                vault.totalAssets;\n        }\n        uint128 lostCapital = getVaultLostCapital(\n            cgs,\n            addressManager,\n            vaultAddress\n        );\n\n        fcnProduct.sumVaultUnderlyingAmounts -= lostCapital;\n\n        if (bondAmount > lostCapital) {\n            vault.totalAssets += (bondAmount - lostCapital);\n            nativeValueReceived = fcnProduct.underlyingAsset.receiveTo(\n                address(treasury),\n                bondAmount - lostCapital\n            );\n        } else {\n            vault.totalAssets -= (lostCapital - bondAmount);\n            treasury.withdraw(\n                fcnProduct.underlyingAsset,\n                msg.sender,\n                lostCapital - bondAmount,\n                false\n            );\n        }\n\n        VaultLogic.setVaultStatus(cgs, vaultAddress, VaultStatus.Settled);\n    }\n\n    function rolloverVault(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n        require(\n            vault.vaultStatus == VaultStatus.WithdrawalQueueProcessed,\n            Errors.INVALID_VAULT_STATUS\n        );\n        uint40 tradeEndDate = vault.tradeStartDate + fcnProduct.tenorInSeconds;\n\n        require(tradeEndDate != 0, Errors.INVALID_TRADE_END_DATE);\n\n        if (!vault.isDefaulted && !fcnVault.isKnockedIn) {\n            uint256 barriersLength = fcnVault.barrierData.length;\n\n            for (uint256 i = 0; i < barriersLength; i++) {\n                delete cgs.oraclePriceOverride[vaultAddress][\n                    VaultLogic.getAssetCode(fcnProduct.optionBarriers[i].asset)\n                ][tradeEndDate];\n            }\n\n            vault.tradeStartDate = 0;\n            vault.auctionWinner = address(0);\n            vault.auctionWinnerTokenId = 0;\n\n            delete fcnVault.barrierData;\n            fcnVault.aprBps = 0;\n            fcnVault.observationsDone = 0;\n            fcnVault.totalYield = 0;\n            fcnVault.notional = 0;\n\n            VaultLogic.setVaultStatus(\n                cgs,\n                vaultAddress,\n                VaultStatus.DepositsOpen\n            );\n        } else {\n            VaultLogic.setVaultStatus(cgs, vaultAddress, VaultStatus.Zombie);\n        }\n\n        emit IFCNEvents.FCNVaultRolledOver(vaultAddress);\n    }\n\n    /**\n     * @dev Collects fees from a specific vault.\n     * @param cgs The Cega global storage.\n     * @param treasury The treasury contract.\n     * @param addressManager The address manager.\n     * @param vaultAddress The address of the vault.\n     */\n    function collectVaultFees(\n        CegaGlobalStorage storage cgs,\n        ITreasury treasury,\n        IAddressManager addressManager,\n        address vaultAddress\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n\n        VaultStatus vaultStatus = vault.vaultStatus;\n\n        require(\n            vaultStatus == VaultStatus.Settled ||\n                (vaultStatus == VaultStatus.AwaitingSettlement &&\n                    vault.isDefaulted),\n            Errors.INVALID_VAULT_STATUS\n        );\n\n        require(!vault.isInDispute, Errors.VAULT_IN_DISPUTE);\n        require(\n            block.timestamp >\n                vault.tradeStartDate +\n                    fcnProduct.tenorInSeconds +\n                    (uint256(fcnProduct.disputeGraceDelayInHours) * 1 hours),\n            Errors.VALUE_IN_DISPUTE_GRACE_DELAY\n        );\n\n        uint128 totalAssets = vault.totalAssets;\n        uint128 notional = fcnVault.notional;\n        uint128 profit = totalAssets > notional ? totalAssets - notional : 0;\n\n        (\n            uint128 totalFees,\n            uint128 managementFee,\n            uint128 yieldFee\n        ) = VaultLogic.calculateFees(\n                cgs,\n                vaultAddress,\n                fcnProduct.tenorInSeconds,\n                notional,\n                profit\n            );\n        if (totalFees > totalAssets) {\n            totalFees = totalAssets;\n            managementFee = totalAssets;\n            yieldFee = 0;\n        }\n\n        VaultLogic.setVaultStatus(cgs, vaultAddress, VaultStatus.FeesCollected);\n        vault.totalAssets = totalAssets - totalFees;\n\n        treasury.withdraw(\n            FCNProductLogic.fcnGetProductDepositAsset(fcnProduct),\n            addressManager.getCegaFeeReceiver(),\n            totalFees,\n            true\n        );\n\n        fcnProduct.sumVaultUnderlyingAmounts -= uint128(totalFees);\n\n        emit IFCNEvents.FCNVaultFeesCollected(\n            vaultAddress,\n            totalFees,\n            managementFee,\n            yieldFee\n        );\n    }\n\n    function checkAuctionDefault(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress\n    ) internal {\n        uint32 productId = cgs.vaults[vaultAddress].productId;\n\n        bool isDefaulted = VaultLogic.getIsAuctionDefaulted(\n            cgs,\n            vaultAddress,\n            cgs.fcnProducts[productId].daysToStartAuctionDefault\n        );\n        if (isDefaulted) {\n            VaultLogic.setIsDefaulted(cgs, vaultAddress, true);\n        }\n    }\n\n    function checkSingleBarrier(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress,\n        uint8 barrierIndex,\n        uint40 timestamp\n    ) internal returns (bool isKnockedIn) {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage fcnProduct = cgs.fcnProducts[vault.productId];\n\n        IOracleEntry oracleEntry = IOracleEntry(addressManager.getCegaOracle());\n\n        FCNVaultBarrierData memory barrierData = fcnVault.barrierData[\n            barrierIndex\n        ];\n        FCNOptionBarrier memory optionBarrier = fcnProduct.optionBarriers[\n            barrierIndex\n        ];\n\n        if (optionBarrier.barrierType == FCNOptionBarrierType.KnockIn) {\n            uint128 barrierAbsoluteValue = (barrierData.initialSpotPrice *\n                optionBarrier.barrierBps) / BPS_DECIMALS;\n\n            uint128 observationSpotPrice = getSpotPriceAt(\n                cgs,\n                vaultAddress,\n                oracleEntry,\n                optionBarrier.asset,\n                barrierData.dataSource,\n                timestamp\n            );\n            if (observationSpotPrice <= barrierAbsoluteValue) {\n                isKnockedIn = true;\n                fcnVault.isKnockedIn = isKnockedIn;\n                emit IFCNEvents.FCNIsKnockedInUpdated(\n                    vaultAddress,\n                    isKnockedIn\n                );\n            }\n        } else {\n            revert(Errors.UNKNOWN_BARRIER_TYPE);\n        }\n    }\n\n    function disputeVault(\n        CegaGlobalStorage storage cgs,\n        address vaultAddress,\n        uint8 barrierIndex,\n        uint40 timestamp,\n        IAddressManager addressManager\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n        FCNProduct storage product = cgs.fcnProducts[vault.productId];\n\n        uint256 tradeStartDate = vault.tradeStartDate;\n        uint256 tradeEndDate = tradeStartDate + product.tenorInSeconds;\n        uint256 currentTime = block.timestamp;\n        VaultStatus vaultStatus = vault.vaultStatus;\n\n        require(!vault.isInDispute, Errors.VAULT_IN_DISPUTE);\n        if (vaultStatus == VaultStatus.Auctioned) {\n            require(\n                (msg.sender == vault.auctionWinner) ||\n                    IACLManager(addressManager.getACLManager()).isTraderAdmin(\n                        (msg.sender)\n                    ),\n                Errors.NOT_TRADE_WINNER_OR_TRADER_ADMIN\n            );\n        } else {\n            require(\n                IACLManager(addressManager.getACLManager()).isTraderAdmin(\n                    (msg.sender)\n                ) ||\n                    msg.sender ==\n                    IERC721(addressManager.getTradeWinnerNFT()).ownerOf(\n                        vault.auctionWinnerTokenId\n                    ),\n                Errors.NOT_TRADE_WINNER_OR_TRADER_ADMIN\n            );\n        }\n\n        if (currentTime < tradeEndDate) {\n            if (vaultStatus == VaultStatus.Auctioned) {\n                require(\n                    currentTime > tradeStartDate &&\n                        currentTime <\n                        tradeStartDate +\n                            (uint256(product.disputePeriodInHours) * 1 hours),\n                    Errors.OUTSIDE_DISPUTE_PERIOD\n                );\n\n                require(\n                    timestamp == tradeStartDate,\n                    Errors.OUTSIDE_DISPUTE_PERIOD\n                );\n            } else {\n                require(\n                    timestamp > tradeStartDate,\n                    Errors.OUTSIDE_DISPUTE_PERIOD\n                );\n            }\n        } else {\n            require(\n                currentTime <\n                    tradeEndDate +\n                        (uint256(product.disputePeriodInHours) * 1 hours),\n                Errors.OUTSIDE_DISPUTE_PERIOD\n            );\n\n            require(\n                timestamp > tradeStartDate && timestamp <= tradeEndDate,\n                Errors.OUTSIDE_DISPUTE_PERIOD\n            );\n\n            require(\n                vaultStatus == VaultStatus.AwaitingSettlement ||\n                    (!fcnVault.isKnockedIn &&\n                        vaultStatus == VaultStatus.Settled),\n                Errors.INVALID_VAULT_STATUS\n            );\n        }\n\n        vault.isInDispute = true;\n\n        emit IFCNEvents.FCNDisputeSubmitted(\n            vaultAddress,\n            barrierIndex,\n            timestamp\n        );\n    }\n\n    function processDispute(\n        CegaGlobalStorage storage cgs,\n        IAddressManager addressManager,\n        address vaultAddress,\n        uint8 barrierIndex,\n        uint40 timestamp,\n        uint128 newPrice\n    ) internal {\n        Vault storage vault = cgs.vaults[vaultAddress];\n        FCNProduct storage product = cgs.fcnProducts[vault.productId];\n\n        require(vault.isInDispute, Errors.VAULT_NOT_IN_DISPUTE);\n\n        if (newPrice != 0) {\n            VaultStatus vaultStatus = vault.vaultStatus;\n\n            address asset = product.optionBarriers[barrierIndex].asset;\n            VaultLogic.overrideOraclePrice(\n                cgs,\n                vaultAddress,\n                asset,\n                timestamp,\n                newPrice\n            );\n\n            if (\n                vaultStatus == VaultStatus.Settled ||\n                vaultStatus == VaultStatus.AwaitingSettlement\n            ) {\n                bool isKnockedIn = checkSingleBarrier(\n                    cgs,\n                    addressManager,\n                    vaultAddress,\n                    barrierIndex,\n                    timestamp\n                );\n\n                if (vaultStatus == VaultStatus.Settled && isKnockedIn) {\n                    VaultLogic.setVaultStatus(\n                        cgs,\n                        vaultAddress,\n                        VaultStatus.AwaitingSettlement\n                    );\n                } else if (\n                    vaultStatus == VaultStatus.AwaitingSettlement &&\n                    !isKnockedIn\n                ) {\n                    FCNVault storage fcnVault = cgs.fcnVaults[vaultAddress];\n                    // rerun all observations as we don't know which timestamp KnockedIn aside from this one.\n                    fcnVault.observationsDone = 0;\n\n                    fcnVault.isKnockedIn = false;\n                    emit IFCNEvents.FCNIsKnockedInUpdated(\n                        vaultAddress,\n                        isKnockedIn\n                    );\n\n                    // to force check expiry again\n                    VaultLogic.setVaultStatus(\n                        cgs,\n                        vaultAddress,\n                        VaultStatus.Traded\n                    );\n                }\n            }\n        }\n\n        vault.isInDispute = false;\n\n        emit IFCNEvents.FCNDisputeProcessed(\n            vaultAddress,\n            newPrice != 0,\n            barrierIndex,\n            timestamp,\n            newPrice\n        );\n    }\n}\n"
      },
      "contracts/common/EntryBase.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { CegaStorage } from \"../storage/CegaStorage.sol\";\nimport { CegaGlobalStorage } from \"../Structs.sol\";\nimport { IAddressManager } from \"../aux/interfaces/IAddressManager.sol\";\nimport { IACLManager } from \"../aux/interfaces/IACLManager.sol\";\nimport { Errors } from \"../utils/Errors.sol\";\nimport {\n    ReentrancyGuard\n} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n\nabstract contract EntryBase is ReentrancyGuard, CegaStorage {\n    // CONSTANTS & IMMUTABLE\n\n    uint256 internal constant MAX_BPS = 1e4;\n\n    IAddressManager internal immutable addressManager;\n\n    // MODIFIERS\n\n    modifier onlyCegaAdmin() {\n        require(\n            IACLManager(addressManager.getACLManager()).isCegaAdmin(msg.sender),\n            Errors.NOT_CEGA_ADMIN\n        );\n        _;\n    }\n\n    modifier onlyTraderAdmin() {\n        require(\n            IACLManager(addressManager.getACLManager()).isTraderAdmin(\n                msg.sender\n            ),\n            Errors.NOT_TRADER_ADMIN\n        );\n        _;\n    }\n\n    modifier onlyValidVault(address vaultAddress) {\n        CegaGlobalStorage storage cgs = getStorage();\n        require(cgs.vaults[vaultAddress].productId != 0, Errors.INVALID_VAULT);\n        _;\n    }\n\n    modifier onlyIfNotPaused() {\n        CegaGlobalStorage storage cgs = getStorage();\n        require(cgs.protocolPauseConfig == 0, Errors.PROTOCOL_PAUSED);\n        _;\n    }\n\n    modifier onlyValidProductStrategy(uint32 strategyId, uint32 productId) {\n        CegaGlobalStorage storage cgs = getStorage();\n        require(\n            cgs.strategyOfProduct[productId] == strategyId,\n            Errors.WRONG_STRATEGY\n        );\n        _;\n    }\n\n    modifier onlyValidVaultStrategy(uint32 strategyId, address vaultAddress) {\n        CegaGlobalStorage storage cgs = getStorage();\n\n        require(\n            cgs.strategyOfProduct[cgs.vaults[vaultAddress].productId] ==\n                strategyId,\n            Errors.INVALID_VAULT\n        );\n        _;\n    }\n\n    modifier onlyValidVaultsStrategy(\n        uint32 strategyId,\n        address[] calldata vaultAddresses\n    ) {\n        CegaGlobalStorage storage cgs = getStorage();\n\n        for (uint256 index = 0; index < vaultAddresses.length; index++) {\n            require(\n                cgs.strategyOfProduct[\n                    cgs.vaults[vaultAddresses[index]].productId\n                ] == strategyId,\n                Errors.INVALID_VAULT\n            );\n        }\n        _;\n    }\n\n    // CONSTRUCTOR\n\n    constructor(IAddressManager _addressManager) {\n        addressManager = _addressManager;\n    }\n}\n"
      },
      "contracts/oracle-entry/interfaces/IOracleEntry.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.24;\n\ninterface IOracleEntry {\n    enum DataSource {\n        None,\n        Pyth\n    }\n\n    /**\n     * @dev Emitted when a data source adapter is set.\n     * @param dataSource The data source for which the adapter is set.\n     * @param adapter The address of the adapter.\n     */\n    event DataSourceAdapterSet(DataSource dataSource, address adapter);\n\n    /**\n     * @notice Gets the price of an asset at a specific timestamp using a data source.\n     * @param asset The address of the asset.\n     * @param timestamp The timestamp for which the price is required.\n     * @param dataSource The data source to use for fetching the price.\n     * @return The price of the asset at the specified timestamp.\n     */\n    function getSinglePrice(\n        address asset,\n        uint40 timestamp,\n        DataSource dataSource\n    ) external view returns (uint128);\n\n    /**\n     * @notice Gets the price of a base asset in terms of a quote asset at a specific timestamp using a data source.\n     * @param baseAsset The address of the base asset.\n     * @param quoteAsset The address of the quote asset.\n     * @param timestamp The timestamp for which the price is required.\n     * @param dataSource The data source to use for fetching the price.\n     * @return The price of the base asset in terms of the quote asset at the specified timestamp.\n     */\n    function getPrice(\n        address baseAsset,\n        address quoteAsset,\n        uint40 timestamp,\n        DataSource dataSource\n    ) external view returns (uint128);\n\n    /**\n     * @notice Sets the adapter for a specific data source.\n     * @param dataSource The data source for which to set the adapter.\n     * @param adapter The address of the adapter.\n     */\n    function setDataSourceAdapter(\n        DataSource dataSource,\n        address adapter\n    ) external;\n\n    /**\n     * @notice Returns the target number of decimals for price values.\n     * @return The number of decimals.\n     */\n    function getTargetDecimals() external pure returns (uint8);\n}\n"
      },
      "contracts/proxies/interfaces/IWrappingProxy.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.24;\n\ninterface IWrappingProxy {\n    /**\n     * @notice Unwraps the wrapped token and transfers the underlying token to the receiver.\n     * @param receiver The address to receive the unwrapped tokens.\n     * @param amount The amount of wrapped tokens to unwrap.\n     */\n    function unwrapAndTransfer(address receiver, uint256 amount) external;\n\n    /**\n     * @notice Wraps the token and adds it to the DCS deposit queue.\n     * @param productId The product ID for the DCS deposit.\n     * @param amount The amount of tokens to wrap.\n     * @param receiver The address that will receive the deposit queue shares.\n     */\n    function wrapAndAddToDCSDepositQueue(\n        uint32 productId,\n        uint128 amount,\n        address receiver\n    ) external;\n\n    /**\n     * @notice Wraps the token and adds it to the FCN deposit queue.\n     * @param productId The product ID for the FCN deposit.\n     * @param amount The amount of tokens to wrap.\n     * @param receiver The address that will receive the deposit queue shares.\n     */\n    function wrapAndAddToFCNDepositQueue(\n        uint32 productId,\n        uint128 amount,\n        address receiver\n    ) external;\n\n    /**\n     * @notice Wraps the token and adds it to the generic deposit queue.\n     * @param productId The product ID for the deposit.\n     * @param amount The amount of tokens to wrap.\n     * @param receiver The address that will receive the deposit queue shares.\n     */\n    function wrapAndAddToDepositQueue(\n        uint32 productId,\n        uint128 amount,\n        address receiver\n    ) external;\n}\n"
      },
      "contracts/redeposits/interfaces/IRedepositManager.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { ITreasury } from \"../../treasuries/interfaces/ITreasury.sol\";\n\ninterface IRedepositManager {\n    // EVENTS\n\n    event Redeposited(\n        uint32 indexed productId,\n        address asset,\n        uint128 amount,\n        address receiver,\n        bool succeeded\n    );\n\n    // FUNCTIONS\n\n    function redeposit(\n        ITreasury treasury,\n        uint32 productId,\n        address asset,\n        uint128 amount,\n        address receiver\n    ) external;\n}\n"
      },
      "contracts/storage/CegaStorage.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { CegaGlobalStorage } from \"../Structs.sol\";\n\ncontract CegaStorage {\n    bytes32 private constant CEGA_STORAGE_POSITION =\n        bytes32(uint256(keccak256(\"cega.global.storage\")) - 1);\n\n    function getStorage() internal pure returns (CegaGlobalStorage storage ds) {\n        bytes32 position = CEGA_STORAGE_POSITION;\n        assembly {\n            ds.slot := position\n        }\n    }\n}\n"
      },
      "contracts/treasuries/interfaces/ITreasury.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.24;\n\ninterface ITreasury {\n    event Withdrawn(\n        address indexed asset,\n        address indexed receiver,\n        uint256 amount\n    );\n\n    event StuckAssetsAdded(\n        address indexed asset,\n        address indexed receiver,\n        uint256 amount\n    );\n\n    receive() external payable;\n\n    /**\n     * @dev Withdraw funds from the treasury\n     * @param asset Address of the asset (0 for native token)\n     * @param receiver Address of the withdrawal receiver\n     * @param amount The amount of funds to withdraw.\n     * @param trustedReceiver Flag if we trust that receiver won't revert withdrawal\n     */\n    function withdraw(\n        address asset,\n        address receiver,\n        uint256 amount,\n        bool trustedReceiver\n    ) external;\n\n    function withdrawStuckAssets(address asset, address receiver) external;\n}\n"
      },
      "contracts/utils/Errors.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nlibrary Errors {\n    string public constant NOT_CEGA_ENTRY = \"1\";\n    string public constant NOT_CEGA_ADMIN = \"2\";\n    string public constant NOT_TRADER_ADMIN = \"3\";\n    string public constant NOT_TRADE_WINNER = \"4\";\n    string public constant INVALID_VAULT = \"5\";\n    string public constant INVALID_VAULT_STATUS = \"6\";\n    string public constant VAULT_IN_ZOMBIE_STATE = \"7\";\n    string public constant TRADE_DEFAULTED = \"8\";\n    string public constant INVALID_SETTLEMENT_STATUS = \"9\";\n    string public constant VAULT_IN_DISPUTE = \"10\";\n    string public constant VAULT_NOT_IN_DISPUTE = \"11\";\n    string public constant OUTSIDE_DISPUTE_PERIOD = \"12\";\n    string public constant TRADE_HAS_NO_WINNER = \"13\";\n    string public constant TRADE_NOT_CONVERTED = \"14\";\n    string public constant TRADE_CONVERTED = \"15\";\n    string public constant INVALID_TRADE_END_DATE = \"16\";\n    string public constant INVALID_PRICE = \"17\";\n    string public constant VALUE_TOO_SMALL = \"18\";\n    string public constant VALUE_TOO_LARGE = \"19\";\n    string public constant VALUE_IS_ZERO = \"20\";\n    string public constant MAX_DEPOSIT_LIMIT_REACHED = \"21\";\n    string public constant DEPOSIT_QUEUE_NOT_OPEN = \"22\";\n    string public constant INVALID_QUOTE_OR_BASE_ASSETS = \"23\";\n    string public constant INVALID_MIN_DEPOSIT_AMOUNT = \"24\";\n    string public constant INVALID_MIN_WITHDRAWAL_AMOUNT = \"25\";\n    string public constant INVALID_STRIKE_PRICE = \"26\";\n    string public constant TRANSFER_FAILED = \"27\";\n    string public constant NOT_AVAILABLE_DATA_SOURCE = \"28\";\n    string public constant NO_PRICE_AVAILABLE = \"29\";\n    string public constant NO_PRICE_FEED_SET = \"30\";\n    string public constant INCOMPATIBLE_PRICE = \"31\";\n    string public constant NOT_CEGA_ENTRY_OR_REDEPOSIT_MANAGER = \"32\";\n    string public constant NO_PROXY_FOR_REDEPOSIT = \"33\";\n    string public constant NOT_TRADE_WINNER_OR_TRADER_ADMIN = \"34\";\n    string public constant TRADE_NOT_STARTED = \"35\";\n    string public constant NOT_AVAILABLE_SWAP_TYPE = \"36\";\n    string public constant NOT_AVAILABLE_SWAP_PATH = \"37\";\n    string public constant PROTOCOL_PAUSED = \"38\";\n    string public constant WRONG_STRATEGY = \"39\";\n    string public constant INVALID_ARRAY_LENGTH = \"40\";\n    string public constant UNKNOWN_BARRIER_TYPE = \"41\";\n    string public constant NOT_BOND_OPTION = \"42\";\n    string public constant UNAUTHORIZED_BOND_RECEIVER = \"43\";\n    string public constant REMAINING_VALUE_TOO_SMALL = \"44\";\n    string public constant VALUE_IN_DISPUTE_GRACE_DELAY = \"45\";\n}\n"
      },
      "contracts/utils/Transfers.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport {\n    IERC20,\n    SafeERC20\n} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Errors } from \"../utils/Errors.sol\";\n\nlibrary Transfers {\n    using SafeERC20 for IERC20;\n\n    function receiveTo(\n        address asset,\n        address to,\n        uint256 amount\n    ) internal returns (uint256 nativeValueReceived) {\n        if (asset == address(0)) {\n            require(msg.value >= amount, Errors.VALUE_TOO_SMALL);\n            (bool success, ) = to.call{ value: amount }(\"\");\n            if (!success) {\n                revert(Errors.TRANSFER_FAILED);\n            }\n            return amount;\n        } else {\n            IERC20(asset).safeTransferFrom(msg.sender, to, amount);\n            return 0;\n        }\n    }\n\n    function transfer(\n        address asset,\n        address to,\n        uint256 amount\n    ) internal returns (bool) {\n        if (asset == address(0)) {\n            (bool success, ) = payable(to).call{ value: amount }(\"\");\n            return success;\n        } else {\n            (bool success, bytes memory returndata) = asset.call(\n                abi.encodeCall(IERC20.transfer, (to, amount))\n            );\n            if (!success || asset.code.length == 0) {\n                return false;\n            }\n            return returndata.length == 0 || abi.decode(returndata, (bool));\n        }\n    }\n\n    /// @notice Adds if needed, and returns required value to pass\n    /// @param asset Asset to ensure\n    /// @param to Spender\n    /// @param amount Amount to ensure\n    /// @return Native value to pass\n    function ensureApproval(\n        address asset,\n        address to,\n        uint256 amount\n    ) internal returns (uint256) {\n        if (asset != address(0)) {\n            uint256 allowance = IERC20(asset).allowance(address(this), to);\n            if (allowance < amount) {\n                IERC20(asset).safeIncreaseAllowance(to, amount - allowance);\n            }\n            return 0;\n        } else {\n            return amount;\n        }\n    }\n\n    function receiveNativeValue(uint256 value) internal {\n        require(value <= msg.value, Errors.VALUE_TOO_SMALL);\n        uint256 excessValue = msg.value - value;\n        if (excessValue > 0) {\n            (bool success, ) = payable(msg.sender).call{ value: excessValue }(\n                \"\"\n            );\n            require(success, Errors.TRANSFER_FAILED);\n        }\n    }\n}\n"
      },
      "contracts/vaults/interfaces/ICegaVault.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.24;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface ICegaVault is IERC20 {\n    function mint(address account, uint256 amount) external;\n\n    function burn(address account, uint256 amount) external;\n}\n"
      },
      "erc721a-upgradeable/contracts/IERC721AUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// ERC721A Contracts v4.2.3\n// Creator: Chiru Labs\n\npragma solidity ^0.8.4;\n\n/**\n * @dev Interface of ERC721A.\n */\ninterface IERC721AUpgradeable {\n    /**\n     * The caller must own the token or be an approved operator.\n     */\n    error ApprovalCallerNotOwnerNorApproved();\n\n    /**\n     * The token does not exist.\n     */\n    error ApprovalQueryForNonexistentToken();\n\n    /**\n     * Cannot query the balance for the zero address.\n     */\n    error BalanceQueryForZeroAddress();\n\n    /**\n     * Cannot mint to the zero address.\n     */\n    error MintToZeroAddress();\n\n    /**\n     * The quantity of tokens minted must be more than zero.\n     */\n    error MintZeroQuantity();\n\n    /**\n     * The token does not exist.\n     */\n    error OwnerQueryForNonexistentToken();\n\n    /**\n     * The caller must own the token or be an approved operator.\n     */\n    error TransferCallerNotOwnerNorApproved();\n\n    /**\n     * The token must be owned by `from`.\n     */\n    error TransferFromIncorrectOwner();\n\n    /**\n     * Cannot safely transfer to a contract that does not implement the\n     * ERC721Receiver interface.\n     */\n    error TransferToNonERC721ReceiverImplementer();\n\n    /**\n     * Cannot transfer to the zero address.\n     */\n    error TransferToZeroAddress();\n\n    /**\n     * The token does not exist.\n     */\n    error URIQueryForNonexistentToken();\n\n    /**\n     * The `quantity` minted with ERC2309 exceeds the safety limit.\n     */\n    error MintERC2309QuantityExceedsLimit();\n\n    /**\n     * The `extraData` cannot be set on an unintialized ownership slot.\n     */\n    error OwnershipNotInitializedForExtraData();\n\n    // =============================================================\n    //                            STRUCTS\n    // =============================================================\n\n    struct TokenOwnership {\n        // The address of the owner.\n        address addr;\n        // Stores the start time of ownership with minimal overhead for tokenomics.\n        uint64 startTimestamp;\n        // Whether the token has been burned.\n        bool burned;\n        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.\n        uint24 extraData;\n    }\n\n    // =============================================================\n    //                         TOKEN COUNTERS\n    // =============================================================\n\n    /**\n     * @dev Returns the total number of tokens in existence.\n     * Burned tokens will reduce the count.\n     * To get the total number of tokens minted, please see {_totalMinted}.\n     */\n    function totalSupply() external view returns (uint256);\n\n    // =============================================================\n    //                            IERC165\n    // =============================================================\n\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n\n    // =============================================================\n    //                            IERC721\n    // =============================================================\n\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables\n     * (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in `owner`'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`,\n     * checking first that contract recipients are aware of the ERC721 protocol\n     * to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be have been allowed to move\n     * this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement\n     * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external payable;\n\n    /**\n     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external payable;\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom}\n     * whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token\n     * by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external payable;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the\n     * zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external payable;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom}\n     * for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n    // =============================================================\n    //                        IERC721Metadata\n    // =============================================================\n\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n\n    // =============================================================\n    //                           IERC2309\n    // =============================================================\n\n    /**\n     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`\n     * (inclusive) is transferred from `from` to `to`, as defined in the\n     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.\n     *\n     * See {_mintERC2309} for more details.\n     */\n    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);\n}\n"
      }
    }
  }}