creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.20;\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 *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\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     * CAUTION: See Security Considerations above.\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/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\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 value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens as the allowance of `spender` over the\n     * 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 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` 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 value) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC20Permit} from \"../extensions/IERC20Permit.sol\";\nimport {Address} from \"../../../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 An operation with an ERC20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\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.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\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);\n        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\n            revert SafeERC20FailedOperation(address(token));\n        }\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 success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error AddressInsufficientBalance(address account);\n\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert AddressInsufficientBalance(address(this));\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert FailedInnerCall();\n        }\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 or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\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    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\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    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert AddressInsufficientBalance(address(this));\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n     * unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {FailedInnerCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n     */\n    function _revert(bytes memory returndata) 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 FailedInnerCall();\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\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    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\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    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\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        if (_status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\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/utils/structs/EnumerableMap.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.\n\npragma solidity ^0.8.20;\n\nimport {EnumerableSet} from \"./EnumerableSet.sol\";\n\n/**\n * @dev Library for managing an enumerable variant of Solidity's\n * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]\n * type.\n *\n * Maps have the following properties:\n *\n * - Entries are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Entries are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableMap for EnumerableMap.UintToAddressMap;\n *\n *     // Declare a set state variable\n *     EnumerableMap.UintToAddressMap private myMap;\n * }\n * ```\n *\n * The following map types are supported:\n *\n * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0\n * - `address -> uint256` (`AddressToUintMap`) since v4.6.0\n * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0\n * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0\n * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableMap.\n * ====\n */\nlibrary EnumerableMap {\n    using EnumerableSet for EnumerableSet.Bytes32Set;\n\n    // To implement this library for multiple types with as little code repetition as possible, we write it in\n    // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,\n    // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.\n    // This means that we can only create new EnumerableMaps for types that fit in bytes32.\n\n    /**\n     * @dev Query for a nonexistent map key.\n     */\n    error EnumerableMapNonexistentKey(bytes32 key);\n\n    struct Bytes32ToBytes32Map {\n        // Storage of keys\n        EnumerableSet.Bytes32Set _keys;\n        mapping(bytes32 key => bytes32) _values;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {\n        map._values[key] = value;\n        return map._keys.add(key);\n    }\n\n    /**\n     * @dev Removes a key-value pair from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {\n        delete map._values[key];\n        return map._keys.remove(key);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {\n        return map._keys.contains(key);\n    }\n\n    /**\n     * @dev Returns the number of key-value pairs in the map. O(1).\n     */\n    function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {\n        return map._keys.length();\n    }\n\n    /**\n     * @dev Returns the key-value pair stored at position `index` in the map. O(1).\n     *\n     * Note that there are no guarantees on the ordering of entries inside the\n     * array, and it may change when more entries are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {\n        bytes32 key = map._keys.at(index);\n        return (key, map._values[key]);\n    }\n\n    /**\n     * @dev Tries to returns the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {\n        bytes32 value = map._values[key];\n        if (value == bytes32(0)) {\n            return (contains(map, key), bytes32(0));\n        } else {\n            return (true, value);\n        }\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {\n        bytes32 value = map._values[key];\n        if (value == 0 && !contains(map, key)) {\n            revert EnumerableMapNonexistentKey(key);\n        }\n        return value;\n    }\n\n    /**\n     * @dev Return the an array containing all the keys\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {\n        return map._keys.values();\n    }\n\n    // UintToUintMap\n\n    struct UintToUintMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {\n        return set(map._inner, bytes32(key), bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {\n        return remove(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {\n        return contains(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(UintToUintMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {\n        (bytes32 key, bytes32 value) = at(map._inner, index);\n        return (uint256(key), uint256(value));\n    }\n\n    /**\n     * @dev Tries to returns the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {\n        (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));\n        return (success, uint256(value));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {\n        return uint256(get(map._inner, bytes32(key)));\n    }\n\n    /**\n     * @dev Return the an array containing all the keys\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintToAddressMap\n\n    struct UintToAddressMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {\n        return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {\n        return remove(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {\n        return contains(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(UintToAddressMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {\n        (bytes32 key, bytes32 value) = at(map._inner, index);\n        return (uint256(key), address(uint160(uint256(value))));\n    }\n\n    /**\n     * @dev Tries to returns the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {\n        (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));\n        return (success, address(uint160(uint256(value))));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {\n        return address(uint160(uint256(get(map._inner, bytes32(key)))));\n    }\n\n    /**\n     * @dev Return the an array containing all the keys\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressToUintMap\n\n    struct AddressToUintMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {\n        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(AddressToUintMap storage map, address key) internal returns (bool) {\n        return remove(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(AddressToUintMap storage map, address key) internal view returns (bool) {\n        return contains(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(AddressToUintMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {\n        (bytes32 key, bytes32 value) = at(map._inner, index);\n        return (address(uint160(uint256(key))), uint256(value));\n    }\n\n    /**\n     * @dev Tries to returns the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {\n        (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));\n        return (success, uint256(value));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(AddressToUintMap storage map, address key) internal view returns (uint256) {\n        return uint256(get(map._inner, bytes32(uint256(uint160(key)))));\n    }\n\n    /**\n     * @dev Return the an array containing all the keys\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(AddressToUintMap storage map) internal view returns (address[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // Bytes32ToUintMap\n\n    struct Bytes32ToUintMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {\n        return set(map._inner, key, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {\n        return remove(map._inner, key);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {\n        return contains(map._inner, key);\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(Bytes32ToUintMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {\n        (bytes32 key, bytes32 value) = at(map._inner, index);\n        return (key, uint256(value));\n    }\n\n    /**\n     * @dev Tries to returns the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {\n        (bool success, bytes32 value) = tryGet(map._inner, key);\n        return (success, uint256(value));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {\n        return uint256(get(map._inner, key));\n    }\n\n    /**\n     * @dev Return the an array containing all the keys\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position is the index of the value in the `values` array plus 1.\n        // Position 0 is used to mean a value is not in the set.\n        mapping(bytes32 value => uint256) _positions;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._positions[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We cache the value's position to prevent multiple reads from the same storage slot\n        uint256 position = set._positions[value];\n\n        if (position != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 valueIndex = position - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (valueIndex != lastIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the lastValue to the index where the value to delete is\n                set._values[valueIndex] = lastValue;\n                // Update the tracked position of the lastValue (that was just moved)\n                set._positions[lastValue] = position;\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the tracked position for the deleted slot\n            delete set._positions[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"
      },
      "src/contracts/interfaces/ITypeAI.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/// @author Raj Mazumder <rajmazumder27.08.2001@gmail.com>\n/// @title Interface of Type AI Staking Pool with fixed APY and lockup.\ninterface ITypeAI {\n    /// @notice Details of the stake holder.\n    struct StakeHolder {\n        /// @param wallet The address of the stake holder.\n        address wallet;\n        /// @param amount The total amount stake holder deposited.\n        uint256 amount;\n        /// @param claimableInterest The claimable interest of the stake holder.\n        uint256 claimableInterest;\n        /// @param realizedETH The realized ETH for the stake holder.\n        uint256 realizedETH;\n        /// @param unrealizedETH The unrealized ETH for the stake holder.\n        uint256 unrealizedETH;\n        /// @param stakedOn The timestamp when stake holder staked.\n        uint256 stakedOn;\n        /// @param aprStartedOn The timestamp when last apr started.\n        uint256 aprStartedOn;\n    }\n\n    /// READ METHODS ///\n    /**\n     * @notice Returns the no of stake holders currently staked.\n     * @return count The count of the stake holders.\n     */\n    function noOfStakeHolders() external view returns (uint256 count);\n\n    /**\n     * @notice Returns the stake holders addresses currently staked.\n     * @return holders The stake holder addresses.\n     */\n    function getStakeHolders() external view returns (address[] memory holders);\n\n    /**\n     * @notice Returns the details about the `_stakeHolder`.\n     * @param _stakeHolder address of the stake holder.\n     * @return details The details about the `_stakeHolder`.\n     */\n    function stakeHolderDetailsOf(\n        address _stakeHolder\n    ) external view returns (StakeHolder memory details);\n\n    /**\n     * @notice Returns the total amount staked by `stakeHolder`.\n     * @param stakeHolder address of the stake holder.\n     * @return stakedAmount the total amount staked.\n     */\n    function totalAmountStakedBy(\n        address stakeHolder\n    ) external view returns (uint256 stakedAmount);\n\n    /**\n     * @notice Returns the total amount locked on the contract.\n     * @return tvl the total amount of tokens locked.\n     */\n    function totalValueLocked() external view returns (uint256 tvl);\n\n    /**\n     * @notice Returns the claimable token amount as interest by the `stakeHolder`.\n     * @param stakeHolder address of the stake holder.\n     * @return claimableInterest The amount of interest gained by `stakeHolder`.\n     */\n    function claimableInterestGainedBy(\n        address stakeHolder\n    ) external view returns (uint256 claimableInterest);\n\n    /// WRITE METHODS ///\n\n    /**\n     * @notice Allows a stake holder to stake tokens.\n     * @dev Stake holder must first approve the `_amount` to stake before calling this function.\n     * @param _amount The amount to be deposited.\n     * @dev That the `amount` deposited should greater than 0.\n     */\n    function stake(uint256 _amount) external;\n\n    /**\n     * @notice Allows a user to withdraw its initial deposit.\n     * @param _amount The amount to withdraw.\n     * @dev `_amount` must be higher than `0`.\n     * @dev `_amount` must be lower or equal to the amount staked.\n     * @dev Updating the stake holder details and claim rewards if rewards to claim.\n     */\n    function unstake(uint256 _amount) external;\n\n    /**\n     * @notice Claims pending tokens gained as interest.\n     * @dev Transfers the gained tokens to the `msg.sender/caller`\n     */\n    function claimGainedInterest() external;\n\n    /**\n     * @notice Claims pending ETH reward and re lock the stake for another lock-in-period.\n     * @dev Distribute ETH reward with no compound.\n     */\n    function claimETHAndReLock() external;\n\n    /**\n     * @notice Claims pending ETH reward and convert into `token` and then re-stake for another lock-in-period.\n     * @dev Convert ETH reward to `token` and re invest.\n     * @param _minReceive The min receive from dex.\n     */\n    function compoundETHAndReLock(uint256 _minReceive) external;\n\n    /**\n     * @notice Deposit ETH rewards into contract.\n     * @dev Internally calls `_depositETHRewards`.\n     */\n    function depositETHRewards() external payable;\n\n    /**\n     * @notice Returns the realized ETH for the `_stakeHolder`\n     * @param _stakeHolder The address of the stake holder.\n     */\n    function getRealizedETH(\n        address _stakeHolder\n    ) external view returns (uint256 realizedETH);\n\n    /// EVENTS ///\n\n    /**\n     * @notice Emitted when `lockInPeriod` gets updated.\n     * @param oldPeriod The previous lock in period.\n     * @param newPeriod The new updated lock in period.\n     */\n    event LockInPeriodUpdated(uint256 indexed oldPeriod, uint256 newPeriod);\n\n    /**\n     * @notice Emitted when `fixedAPR` gets updated.\n     * @param oldAPR The previous APR.\n     * @param newAPR The new updated APR.\n     */\n    event APRUpdated(uint256 indexed oldAPR, uint256 newAPR);\n\n    /**\n     * @notice Emitted when `amount` tokens are deposited into pool contract.\n     * @param stakeHolder The stake holder address who staked.\n     * @param amount The amount stake holder staked.\n     */\n    event Deposited(address indexed stakeHolder, uint256 amount);\n\n    /**\n     * @notice Emitted when someone deposited ETH for reward distribution.\n     * @param depositor The address of the depositor.\n     * @param amount The amount of ETH deposited.\n     */\n    event DepositedETHRewards(address depositor, uint256 amount);\n\n    /**\n     * @notice Emitted when user withdraw deposited `amount`.\n     * @param stakeHolder The stake holder address who withdrawn.\n     * @param amount The amount stake holder withdrawn.\n     */\n    event Withdrawn(address indexed stakeHolder, uint256 amount);\n\n    /**\n     * @dev Emitted when `stakeHolder` claim their pending interest.\n     * @param stakeHolder The stake holder address who claimed.\n     * @param amount The amount of interest claimed.\n     */\n    event InterestClaimed(address indexed stakeHolder, uint256 amount);\n\n    /**\n     * @notice Emitted when `stakeHolder` claims ETH.\n     * @param stakeHolder The stake holder address who claimed reward.\n     * @param reward The amount of reward stakeHolder claimed.\n     */\n    event ETHRewardDistributed(address stakeHolder, uint256 reward);\n\n    /// ERRORS ///\n\n    error TypeAI__ZeroAddress(address caller);\n    error TypeAI__ZeroAPR(address caller);\n\n    /**\n     * @notice Fired when a non stake holder trying to claims interest.\n     * @param caller Address who is trying to claim.\n     */\n    error TypeAI__NotAStakeHolder(address caller);\n\n    /**\n     * @notice Fired when someone trying to deposit ETH but no stake available.\n     * @param caller Address who is trying to deposit ETH.\n     */\n    error TypeAI_NoTVLAvailable(address caller);\n\n    /**\n     * @notice Fired when stake holder claims 0 interest.\n     * @param stakeHolder Address who is trying to claim.\n     */\n    error TypeAI__NoInterestGained(address stakeHolder);\n\n    /**\n     * @notice Fired when stake holder trying to withdraw greater than his deposit.\n     * @param stakeHolder Address who is trying to withdraw.\n     */\n    error TypeAI__InsufficientDepositAmount(address stakeHolder);\n\n    /**\n     * @notice Fired when owner trying to withdraw greater than residual balance.\n     */\n    error TypeAI__InsufficientResidualBalance();\n\n    /**\n     * @notice Fired when owner trying to withdraw greater than residual balance.\n     */\n    error TypeAI__ETHTransferFailed(address receiver, uint256 amount);\n\n    /**\n     * @notice Fired when owner trying to withdraw greater than residual balance.\n     */\n    error TypeAI__InvalidETHBalance(address receiver, uint256 amount);\n    /**\n     * @notice Fired when owner trying to withdraw reward while no reward available in the contract.\n     * @param stakeHolder Address who is trying to claim.\n     * @param required The required amount.\n     */\n    error TypeAI__InsufficientRewardPresent(\n        address stakeHolder,\n        uint256 required\n    );\n\n    /**\n     * @notice Fired when stake holder trying to deposit 0 token.\n     * @param stakeHolder Address who is trying to deposit.\n     */\n    error TypeAI__AmountMustBeGreaterThanZero(address stakeHolder);\n\n    /**\n     * @notice Fired when stake holder trying to withdraw tokens before\n     * lock-in-period ends.\n     * @param stakeHolder Address who is trying to withdraw.\n     */\n    error TypeAI__UnderLockInPeriod(address stakeHolder);\n}\n"
      },
      "src/contracts/interfaces/IUniswapV2Router.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.20;\n\ninterface IUniswapV2Router01 {\n    function factory() external pure returns (address);\n\n    function WETH() external pure returns (address);\n\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint amountADesired,\n        uint amountBDesired,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB, uint liquidity);\n\n    function addLiquidityETH(\n        address token,\n        uint amountTokenDesired,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    )\n        external\n        payable\n        returns (uint amountToken, uint amountETH, uint liquidity);\n\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB);\n\n    function removeLiquidityETH(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountToken, uint amountETH);\n\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint amountA, uint amountB);\n\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint amountToken, uint amountETH);\n\n    function swapExactTokensForTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n\n    function swapTokensForExactTokens(\n        uint amountOut,\n        uint amountInMax,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n\n    function swapExactETHForTokens(\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable returns (uint[] memory amounts);\n\n    function swapTokensForExactETH(\n        uint amountOut,\n        uint amountInMax,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n\n    function swapExactTokensForETH(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n\n    function swapETHForExactTokens(\n        uint amountOut,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable returns (uint[] memory amounts);\n\n    function quote(\n        uint amountA,\n        uint reserveA,\n        uint reserveB\n    ) external pure returns (uint amountB);\n\n    function getAmountOut(\n        uint amountIn,\n        uint reserveIn,\n        uint reserveOut\n    ) external pure returns (uint amountOut);\n\n    function getAmountIn(\n        uint amountOut,\n        uint reserveIn,\n        uint reserveOut\n    ) external pure returns (uint amountIn);\n\n    function getAmountsOut(\n        uint amountIn,\n        address[] calldata path\n    ) external view returns (uint[] memory amounts);\n\n    function getAmountsIn(\n        uint amountOut,\n        address[] calldata path\n    ) external view returns (uint[] memory amounts);\n}\n\ninterface IUniswapV2Router is IUniswapV2Router01 {\n    function removeLiquidityETHSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountETH);\n\n    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint amountETH);\n\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n\n    function swapExactETHForTokensSupportingFeeOnTransferTokens(\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable;\n\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n}\n"
      },
      "src/contracts/TypeAI.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.20;\n\n/// @author Raj Mazumder <rajmazumder27.08.2001@gmail.com>\n/// @title Implementation of Type AI Staking Pool with fixed APY and lockup.\n\n/// @notice imports\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport {EnumerableMap} from \"@openzeppelin/contracts/utils/structs/EnumerableMap.sol\";\n/// Customs\nimport {ITypeAI} from \"./interfaces/ITypeAI.sol\";\nimport {IUniswapV2Router} from \"./interfaces/IUniswapV2Router.sol\";\n\ncontract TypeAI is ITypeAI, Ownable, ReentrancyGuard {\n    /// Using the libraries.\n    using SafeERC20 for IERC20;\n    using EnumerableMap for EnumerableMap.AddressToUintMap;\n\n    /// @notice STATE VARIABLES ///\n    uint256 constant MULTIPLIER = 1e36;\n\n    /// Holds the current fixed APR going on.\n    uint256 public fixedAPR;\n    /// Holds The current lock in period going on.\n    uint256 public lockInPeriod;\n    /// Holds the amount of token locked in the contract.\n    uint256 private _totalValueLocked;\n    /// Holds the total ETH deposited for reward.\n    uint256 public totalETHDeposited;\n    /// Holds the ETH amount per share as reward.\n    uint256 public ethRewardsPerShare;\n    /// Holds the total reward distributed among the stake holders.\n    uint256 public totalRewardsDistributed;\n    /// Holds the token address which is being staked.\n    IERC20 public immutable token;\n    /// Holds the dex router address.\n    IUniswapV2Router immutable _router;\n\n    /// Mapping between stakeHolder address to their details.\n    mapping(address stakeHolder => StakeHolder details)\n        private _stakeHolderDetailsOf;\n    /// Map for tacking the stake holders.\n    EnumerableMap.AddressToUintMap private _stakeHoldersMap;\n\n    /// @notice Constructor ///\n\n    /**\n     * @notice constructor contains all the parameters of the staking platform.\n     * @param _token The address of the token to be staked.\n     * @param _fixedAPR The fixed APY (in %) 10 = 10%, 50 = 50%.\n     * @param _lockInPeriod The lock in period in seconds.\n     * @param router_ The UniswapV2 router address.\n     */\n    constructor(\n        address _token,\n        uint256 _fixedAPR,\n        uint256 _lockInPeriod,\n        address router_\n    ) Ownable(_msgSender()) {\n        /// validations\n        if (_token == address(0) || (router_ == address(0)))\n            revert TypeAI__ZeroAddress(msg.sender);\n        if (_fixedAPR == 0) revert TypeAI__ZeroAPR(msg.sender);\n\n        /// Updating the state.\n        token = IERC20(_token);\n        fixedAPR = _fixedAPR;\n        lockInPeriod = _lockInPeriod;\n        _router = IUniswapV2Router(router_);\n\n        /// Emitting Events.\n        emit APRUpdated(0, _fixedAPR);\n        emit LockInPeriodUpdated(0, _lockInPeriod);\n    }\n\n    /// @notice READ METHODS ///\n\n    /**\n     * @notice Returns the no of stake holders currently staked.\n     * @return count The count of the stake holders.\n     */\n    function noOfStakeHolders() public view returns (uint256 count) {\n        return _stakeHoldersMap.length();\n    }\n\n    /**\n     * @notice Returns the details about the `stakeHolder`.\n     * @param stakeHolder address of the stake holder.\n     * @return details The details about the `stakeHolder`.\n     */\n    function stakeHolderDetailsOf(\n        address stakeHolder\n    ) public view returns (StakeHolder memory details) {\n        return _stakeHolderDetailsOf[stakeHolder];\n    }\n\n    /**\n     * @notice Returns the total amount staked by `stakeHolder`.\n     * @param stakeHolder address of the stake holder.\n     * @return stakedAmount the total amount staked by `stakeHolder`.\n     */\n    function totalAmountStakedBy(\n        address stakeHolder\n    ) public view returns (uint256 stakedAmount) {\n        return _stakeHolderDetailsOf[stakeHolder].amount;\n    }\n\n    /**\n     * @notice Returns the total amount of `token` locked in the contract.\n     * @return tvl the total amount of tokens locked.\n     */\n    function totalValueLocked() public view returns (uint256 tvl) {\n        return _totalValueLocked;\n    }\n\n    /**\n     * @notice Returns the claimable token amount as interest by the `stakeHolder`.\n     * @param stakeHolder address of the stake holder.\n     * @return claimableInterest The amount of interest gained by `stakeHolder`.\n     */\n    function claimableInterestGainedBy(\n        address stakeHolder\n    ) public view returns (uint256 claimableInterest) {\n        return _calculateInterestGainedBy(stakeHolder);\n    }\n\n    /**\n     * @notice Returns the realized ETH for the `stakeHolder`\n     * @param stakeHolder The address of the stake holder.\n     */\n    function getRealizedETH(\n        address stakeHolder\n    ) public view returns (uint256 realizedETH) {\n        /// Getting the stake holder details as memory.\n        StakeHolder memory _holderDetails = _stakeHolderDetailsOf[stakeHolder];\n        /// If stakeholder has no investment return.\n        if (_holderDetails.amount == 0) return 0;\n\n        /// Calculate and return realized ETH.\n        uint256 earnedRewards = _cumulativeETHRewards(_holderDetails.amount);\n        if (earnedRewards <= _holderDetails.unrealizedETH) return 0;\n        return earnedRewards - _holderDetails.unrealizedETH;\n    }\n\n    /**\n     * @notice Returns the stake holders addresses currently staked.\n     * @return holders The stake holder addresses.\n     */\n    function getStakeHolders() public view returns (address[] memory holders) {\n        /// Getting the no of stake holders.\n        uint256 _noOfStakeHolders = _stakeHoldersMap.length();\n        /// Adding stake holders into memory array.\n        address[] memory _stakeHolders = new address[](_noOfStakeHolders);\n        for (uint256 index; index < _noOfStakeHolders; index++) {\n            (address _stakeHolder, ) = _stakeHoldersMap.at(index);\n            _stakeHolders[index] = _stakeHolder;\n        }\n        // return _stakeHoldersMap.\n        return _stakeHolders;\n    }\n\n    /// @notice WRITE METHODS ///\n\n    /**\n     * @notice Allows the owner to set the APY\n     * @param newAPR, the new APY to be set (in %) 10 = 10%, 50 = 50\n     */\n    function updateAPR(uint8 newAPR) public onlyOwner {\n        /// Change the APR\n        uint256 _oldAPR = fixedAPR;\n        fixedAPR = newAPR;\n        /// Emitting `APRUpdated` event.\n        emit APRUpdated(_oldAPR, newAPR);\n    }\n\n    /**\n     * @notice Allows the owner to set the lock in period.\n     * @param newLockInPeriod The new lock in period in seconds.\n     */\n    function updateLockInPeriod(uint256 newLockInPeriod) public onlyOwner {\n        /// Change the Lock in period.\n        uint256 _oldLockInPeriod = lockInPeriod;\n        lockInPeriod = newLockInPeriod;\n        /// Emitting `LockInPeriodUpdated` event.\n        emit LockInPeriodUpdated(_oldLockInPeriod, newLockInPeriod);\n    }\n\n    /**\n     * @notice Allows a stake holder to stake tokens.\n     * @dev Internally calls `_stake` function.\n     * @param amount The amount to be deposited.\n     */\n    function stake(uint256 amount) public nonReentrant {\n        _stake(amount);\n    }\n\n    /**\n     * @notice Allows a user to withdraw its initial deposit.\n     * @param amount The amount to withdraw.\n     * @dev `amount` must be higher than `0`.\n     * @dev `amount` must be lower or equal to the amount staked.\n     * @dev Updating the stake holderVARIABLES claim rewards if rewards to claim.\n     */\n    function unstake(uint256 amount) public nonReentrant {\n        /// Getting the stake holder details as storage.\n        StakeHolder storage _stakeHolder = _stakeHolderDetailsOf[_msgSender()];\n\n        /// Validations\n        if (_stakeHolder.wallet == address(0))\n            revert TypeAI__NotAStakeHolder(_msgSender());\n        if ((_stakeHolder.stakedOn + lockInPeriod) >= block.timestamp)\n            revert TypeAI__UnderLockInPeriod(_stakeHolder.wallet);\n        if (amount == 0)\n            revert TypeAI__AmountMustBeGreaterThanZero(_stakeHolder.wallet);\n        if (amount > _stakeHolder.amount)\n            revert TypeAI__InsufficientDepositAmount(_stakeHolder.wallet);\n\n        /// TOKEN APR ///\n        /// Updating the claimable interest\n        _updateClaimableInterestOf(_stakeHolder.wallet);\n        /// Claim interest If any claim amount available.\n        if (_stakeHolder.claimableInterest > 0)\n            _claimGainedInterest(_stakeHolder.wallet);\n\n        /// Distribute ETH REWARDS ///\n        uint256 _realizedETH = getRealizedETH(_stakeHolder.wallet);\n        bool _otherStakersPresent = (_totalValueLocked - amount) > 0;\n        if (!_otherStakersPresent) {\n            _distributeETHRewards(_stakeHolder.wallet, false, 0);\n        }\n\n        /// Updating the TVL & stake holder balance.\n        _totalValueLocked -= amount;\n        _stakeHolder.amount -= amount;\n\n        /// Update ETH Rewards per share ///\n        _updateUnrealizedETHRewardsOf(_stakeHolder.wallet);\n        if (_otherStakersPresent && (_realizedETH > 0))\n            _depositETHRewards(_realizedETH);\n\n        /// Removing from stake holders map.\n        if (_stakeHolder.amount == 0)\n            _stakeHoldersMap.remove(_stakeHolder.wallet);\n\n        /// Transferring the tokens.\n        token.safeTransfer(_stakeHolder.wallet, amount);\n        /// Emitting `Withdrawn` event.\n        emit Withdrawn(_stakeHolder.wallet, amount);\n    }\n\n    /**\n     * @notice Claim all remaining balance on the contract\n     * Residual balance is all the remaining tokens that have not been distributed\n     * (e.g, in case the number of stakeholders is not sufficient)\n     * @dev Can only be called after the end of the staking period\n     * Cannot claim initial stakeholders deposit\n     */\n    function withdrawResidualBalance() public onlyOwner nonReentrant {\n        uint256 residualBalance = token.balanceOf(address(this)) -\n            _totalValueLocked;\n        if (residualBalance == 0) revert TypeAI__InsufficientResidualBalance();\n        /// Transfer the tokens.\n        token.safeTransfer(_msgSender(), residualBalance);\n    }\n\n    /**\n     * @notice Claims pending tokens gained as interest.\n     * @dev Transfers the gained tokens to the `msg.sender/caller`\n     */\n    function claimGainedInterest() public nonReentrant {\n        /// Validation for unknown caller.\n        if (_stakeHolderDetailsOf[_msgSender()].wallet == address(0))\n            revert TypeAI__NotAStakeHolder(_msgSender());\n        /// Claim interest.\n        _claimGainedInterest(_msgSender());\n    }\n\n    /**\n     * @notice Claims pending ETH reward and re lock the stake for another lock-in-period.\n     * @dev Distribute ETH reward with no compound.\n     */\n    function claimETHAndReLock() public nonReentrant {\n        _distributeETHRewards(_msgSender(), false, 0);\n    }\n\n    /**\n     * @notice Claims pending ETH reward and convert into `token` and then re-stake for another lock-in-period.\n     * @dev Convert ETH reward to `token` and re invest.\n     * @param _minReceive The min receive from dex.\n     */\n    function compoundETHAndReLock(uint256 _minReceive) public nonReentrant {\n        _distributeETHRewards(_msgSender(), true, _minReceive);\n    }\n\n    /**\n     * @notice Deposit ETH rewards into contract.\n     * @dev Internally calls `_depositETHRewards`.\n     */\n    function depositETHRewards() public payable nonReentrant {\n        _depositETHRewards(msg.value);\n    }\n\n    /// @notice Private Functions ///\n\n    /**\n     * @notice Returns the ETH reward amount based on `_share`.\n     * @param _share The share/deposited amount of the stake holder.\n     */\n    function _cumulativeETHRewards(\n        uint256 _share\n    ) private view returns (uint256 ethRewards) {\n        return (_share * ethRewardsPerShare) / MULTIPLIER;\n    }\n\n    /**\n     * @notice Deposit ETH for giving reward to others.\n     * @param _amountETH The amount of ETH wants to distribute.\n     */\n    function _depositETHRewards(uint256 _amountETH) private {\n        /// Validations\n        if (_amountETH == 0)\n            revert TypeAI__AmountMustBeGreaterThanZero(_msgSender());\n        if (_totalValueLocked == 0) revert TypeAI_NoTVLAvailable(_msgSender());\n\n        /// Recalculate eth per share.\n        totalETHDeposited += _amountETH;\n        ethRewardsPerShare += (MULTIPLIER * _amountETH) / _totalValueLocked;\n        /// Emit `DepositedETHRewards` event.\n        emit DepositedETHRewards(_msgSender(), _amountETH);\n    }\n\n    /**\n     * @notice Swap ETH for `token` into Uniswap and then reinvest.\n     * @param _amount The amount of ETH wanted to swap.\n     * @param _minTokensToReceive The minimum receivable `token` amount for ETH.\n     */\n    function _compoundETHRewards(\n        uint256 _amount,\n        uint256 _minTokensToReceive\n    ) private {\n        /// Setting up the swap path.\n        address[] memory path = new address[](2);\n        path[0] = _router.WETH();\n        path[1] = address(token);\n\n        /// Swap ETH for `token`\n        uint256 _tokenBalBefore = token.balanceOf(address(this));\n        _router.swapExactETHForTokensSupportingFeeOnTransferTokens{\n            value: _amount\n        }(_minTokensToReceive, path, address(this), block.timestamp);\n\n        /// Reinvest the compound amount.\n        uint256 _compoundAmount = token.balanceOf(address(this)) -\n            _tokenBalBefore;\n        _stake(_compoundAmount);\n    }\n\n    /**\n     * @notice Distribute ETH reward to `stakeHolder`.\n     * @param stakeHolder The stake holder address to whom rewards distributed.\n     * @param isReinvest If stake holder wants to reinvest ETH.\n     * @param minReceive Minimum receivable for dex if stake holder wants to reinvest.\n     */\n    function _distributeETHRewards(\n        address stakeHolder,\n        bool isReinvest,\n        uint256 minReceive\n    ) private {\n        /// Getting the stake holder details as memory.\n        StakeHolder storage _holderDetails = _stakeHolderDetailsOf[stakeHolder];\n        /// If stakeholder has no investment return.\n        if (_holderDetails.amount == 0) return;\n\n        /// Updating stake holder details.\n        uint256 _realizedETH = getRealizedETH(_holderDetails.wallet);\n        _holderDetails.realizedETH += _realizedETH;\n        _holderDetails.stakedOn = block.timestamp; /// Re lock.\n        _updateUnrealizedETHRewardsOf(_holderDetails.wallet);\n\n        if (_realizedETH > 0) {\n            /// Updating the total reward distributed.\n            totalRewardsDistributed += _realizedETH;\n\n            /// Compound and reinvest.\n            if (isReinvest)\n                _compoundETHRewards(_realizedETH, minReceive);\n                /// Claim normal ETH rewards.\n            else {\n                /// Transferring the ETH.\n                uint256 _ethBalanceBefore = address(this).balance;\n                (bool success, ) = payable(_holderDetails.wallet).call{\n                    value: _realizedETH\n                }(\"\");\n                /// Validations\n                if (!success)\n                    revert TypeAI__ETHTransferFailed(\n                        _holderDetails.wallet,\n                        _realizedETH\n                    );\n                if (address(this).balance < (_ethBalanceBefore - _realizedETH))\n                    revert TypeAI__InvalidETHBalance(\n                        _holderDetails.wallet,\n                        _realizedETH\n                    );\n            }\n\n            /// Emitting `ETHRewardDistributed` event.\n            emit ETHRewardDistributed(_holderDetails.wallet, _realizedETH);\n        }\n    }\n\n    /**\n     * @notice Allows a stake holder to stake tokens.\n     * @dev Stake holder must first approve the `_amount` to stake before calling this function.\n     * @param _amount The amount to be deposited.\n     * @dev That the `amount` deposited should greater than 0.\n     */\n    function _stake(uint256 _amount) private {\n        /// Validations\n        if (_amount == 0)\n            revert TypeAI__AmountMustBeGreaterThanZero(_msgSender());\n\n        /// Transferring the tokens.\n        token.safeTransferFrom(_msgSender(), address(this), _amount);\n\n        /// Getting the stake holder details as storage.\n        StakeHolder storage _stakeHolder = _stakeHolderDetailsOf[_msgSender()];\n\n        /// If stake holder is staking for the first time.\n        if (_stakeHolder.wallet == address(0))\n            _stakeHolder.wallet = _msgSender();\n        if (_stakeHolder.aprStartedOn == 0)\n            _stakeHolder.aprStartedOn = block.timestamp;\n\n        /// Update the interest of stake holder\n        _updateClaimableInterestOf(_stakeHolder.wallet);\n\n        // Distribute ETH Rewards.\n        if (_stakeHolder.amount > 0)\n            _distributeETHRewards(_stakeHolder.wallet, false, 0);\n\n        /// Updating the TVL, stake holder balance & address.\n        _totalValueLocked += _amount;\n        _stakeHolder.amount += _amount;\n        _stakeHolder.stakedOn = block.timestamp;\n        /// Adding into stake holders map.\n        _stakeHoldersMap.set(_stakeHolder.wallet, _amount);\n\n        /// ETH Rewards\n        _updateUnrealizedETHRewardsOf(_stakeHolder.wallet);\n\n        /// Emitting `Deposited` event.\n        emit Deposited(_stakeHolder.wallet, _amount);\n    }\n\n    /**\n     * @notice Calculate the gained interest based on the `fixedAPR`.\n     * @param _stakeHolder The address of the stake holder.\n     * @return claimableInterest amount of claimable tokens as interest of the `_stakeHolder`\n     */\n    function _calculateInterestGainedBy(\n        address _stakeHolder\n    ) private view returns (uint256 claimableInterest) {\n        /// Getting the stake holder details as memory.\n        StakeHolder memory _holderDetails = _stakeHolderDetailsOf[_stakeHolder];\n\n        /// Calculating the staking duration.\n        uint256 _stakingDuration = block.timestamp -\n            _holderDetails.aprStartedOn;\n        /// Returns the claimable interest.\n        return\n            ((_holderDetails.amount * fixedAPR * _stakingDuration) /\n                365 days /\n                100) + _holderDetails.claimableInterest;\n    }\n\n    /**\n     * @notice Claims pending interest.\n     * @dev Transfer the pending interest to the `_stakeHolder` address.\n     * @param _stakeHolder The address of the stake holder.\n     */\n    function _claimGainedInterest(address _stakeHolder) private {\n        /// Getting the stake holder details as storage.\n        StakeHolder storage _holderDetails = _stakeHolderDetailsOf[\n            _stakeHolder\n        ];\n        /// @dev Updating the claimable interest.\n        _updateClaimableInterestOf(_stakeHolder);\n\n        /// @dev Checking if any claimable amount available.\n        uint256 _claimableInterest = _holderDetails.claimableInterest;\n        if (_claimableInterest == 0)\n            revert TypeAI__NoInterestGained(_stakeHolder);\n\n        if (token.balanceOf(address(this)) < _claimableInterest)\n            revert TypeAI__InsufficientRewardPresent(\n                _stakeHolder,\n                _claimableInterest\n            );\n        if (\n            (token.balanceOf(address(this)) - _claimableInterest) <\n            _totalValueLocked\n        )\n            revert TypeAI__InsufficientRewardPresent(\n                _stakeHolder,\n                _claimableInterest\n            );\n\n        /// Removing the claimable amount.\n        delete _holderDetails.claimableInterest;\n\n        /// @dev Transfer the interest and emitting the event.\n        token.safeTransfer(_stakeHolder, _claimableInterest);\n        /// Emitting `InterestClaimed` event.\n        emit InterestClaimed(_stakeHolder, _claimableInterest);\n    }\n\n    /**\n     * @notice Updates gained interest and shift them to `rewardsToClaim`\n     * @dev Recalculate the gained amount and resetting the stake time.\n     */\n    function _updateClaimableInterestOf(address _stakeHolder) private {\n        /// Getting the stake holder details as storage.\n        StakeHolder storage _holderDetails = _stakeHolderDetailsOf[\n            _stakeHolder\n        ];\n\n        /// @dev Recalculating the claimable amount of `_stakeHolder`.\n        _holderDetails.claimableInterest = _calculateInterestGainedBy(\n            _stakeHolder\n        );\n        /// @dev Resetting the stake time.\n        _holderDetails.aprStartedOn = block.timestamp;\n    }\n\n    /**\n     * @notice Updates gained interest and shift them to `rewardsToClaim`\n     * @dev Recalculate the gained amount and resetting the stake time.\n     */\n    function _updateUnrealizedETHRewardsOf(address _stakeHolder) private {\n        /// Getting the stake holder details as storage.\n        StakeHolder storage _holderDetails = _stakeHolderDetailsOf[\n            _stakeHolder\n        ];\n\n        /// @dev Recalculating the unrealized ETH amount of `_stakeHolder`.\n        _holderDetails.unrealizedETH = _cumulativeETHRewards(\n            _holderDetails.amount\n        );\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}