creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "/contracts/RewardFarmers.sol": {
        "content": "// contracts/RewardFarmers.sol\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.12;\n\nimport \"./Oracle.sol\";\nimport \"./libraries/ERC20Helpers.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n\n\n/**\n *  \n *   .d8888b.  d8b                        888           .d8888b.                  d8b                                       \n *  d88P  Y88b Y8P                        888          d88P  Y88b                 Y8P                                       \n *  Y88b.                                 888          888    888                                                           \n *   \"Y888b.   888 88888b.d88b.  88888b.  888  .d88b.  888        888d888 8888b.  888 88888b.       .d88b.  888d888 .d88b.  \n *      \"Y88b. 888 888 \"888 \"88b 888 \"88b 888 d8P  Y8b 888  88888 888P\"      \"88b 888 888 \"88b     d88\"\"88b 888P\"  d88P\"88b \n *        \"888 888 888  888  888 888  888 888 88888888 888    888 888    .d888888 888 888  888     888  888 888    888  888 \n *  Y88b  d88P 888 888  888  888 888 d88P 888 Y8b.     Y88b  d88P 888    888  888 888 888  888 d8b Y88..88P 888    Y88b 888 \n *   \"Y8888P\"  888 888  888  888 88888P\"  888  \"Y8888   \"Y8888P88 888    \"Y888888 888 888  888 Y8P  \"Y88P\"  888     \"Y88888 \n *                               888                                                                                    888 \n *                               888                                                                               Y8b d88P \n *                               888                                                                                \"Y88P\"  \n */\n\n\n/// @title RewardFarmers\n/// @notice A contract that allows users to stake a specific ERC20 token and earn rewards in other ERC20 tokens. Forked from shibalaunch\ncontract RewardFarmers is \n  Context, Ownable,\n  ReentrancyGuard\n{\n\n  struct RewardInfo {\n    uint256 id;\n    string name;\n    address token;\n    string symbol;\n    bool hasClaimed;\n    uint256 decimals;\n    uint256 canClaim;\n    uint256 ethPerToken;\n    uint256 totalRewards;\n    uint256 distributionId;\n  }\n\n  struct UncommonReward {\n    mapping(address => bool) hasClaimed;\n    uint256 distributionId;\n    uint256 perDeposit;\n    uint256 amount;\n    ERC20 token;\n    uint256 id;\n  }\n\n  ERC20 public immutable Stakeable;\n  address[] public commonRewardTokens;\n  UncommonReward[] public uncommonRewards;\n  Oracle public oracle;\n\n  uint256 public totalStaked;\n  mapping(address => uint256) public deposits;\n  mapping(address => uint256) public lockedUntil;\n  mapping(address => bool) public isCommonReward;\n  mapping(address => mapping(address => uint256)) public nullifiedRewards;\n\n\n  mapping(address => uint256) public userWithdrewEverythingAt;\n  mapping(address => uint256) public rewardsPerDeposit;\n  mapping(address => uint256) public totalRewarded;\n\n  // depositForReward[uncommonRewardId][user] => depositAmount each\n  // each time an uncommon reward is added, uncommonRewardId is increased.\n  // This is a mapping from that index, to the deposits for a specific user.\n  // If the deposit amount is type(uint256).max, that repesents have a 0 deposit for\n  // the specified reward. If the deposit amount is 0, then it represents not\n  // having any change in state while the uncommon rewardID is in the value specified.\n  mapping(uint256 => mapping(address => uint256)) public depositForReward;\n\n  mapping(address => bool) public isRewarder;\n  bool public canChangeRewarder = true;\n  uint256 public precision = 10 ** 22;\n  uint256 public lockTime;\n\n  /// @notice Initializes the contract with the stakeable token, lock time, and initial reward tokens.\n  /// @param _stakeable The token that users can stake.\n  /// @param _lockTime The time that users must wait after unlocking their stake before they can withdraw it.\n  /// @param _rewardTokens An array of tokens that users can earn as rewards.\n  constructor(Oracle _oracle, address _stakeable, uint256 _lockTime, address[] memory _rewardTokens) {\n    Stakeable = ERC20(_stakeable);\n    lockTime = _lockTime;\n    oracle = _oracle;\n\n    ensureRewardToken(address(0));\n    for (uint16 i=0; i < _rewardTokens.length; i++)\n      ensureRewardToken(_rewardTokens[i]);\n\n    // making a call to common claimable to ensure that it can be called\n    // and all of the chosen tokens exist. \n    commonClaimable(address(0));\n  }\n\n  // @notice Revoke ability to change the rewarder address\n  function revokeSettingRewarder() public onlyOwner() {\n    canChangeRewarder = false;\n  }\n\n  /// @notice Set a new rewarder for adding rewards\n  /// @param _rewarderAddress The new rewarder contract address.\n  /// @param _isRewarder boolean value correlated to if rewarder or not\n  function setRewarderAddress(address _rewarderAddress, bool _isRewarder) public onlyOwner() {\n    require(canChangeRewarder, 'Can not change rewarder address');\n    isRewarder[_rewarderAddress] = _isRewarder;\n  }\n\n  /// @notice Set a new oracle for fetching token price data.\n  /// @param _oracle The new oracle contract address.\n  function setOracle(Oracle _oracle) external onlyOwner() {\n    oracle = _oracle;\n  }\n\n  /// @notice Deposit stakeable tokens into the contract to start earning rewards.\n  /// @param amount The amount of the stakeable token to deposit.\n  function deposit(uint256 amount) external nonReentrant {\n    require(!unlockInitiated(msg.sender), \"you must wait until you withdraw your tokens\");\n    require(amount > 0, \"you can not deposit 0 tokens\");\n\n    // Stakeable.transferFrom(msg.sender, address(this), amount);\n    ERC20Helpers.safeTransferFrom(address(Stakeable), msg.sender, address(this), amount);\n\n    // Claims all rewards before updating the user's stake.\n    claimAllCommon(commonRewardTokens);\n\n    totalStaked += amount;\n    deposits[msg.sender] += amount;\n    depositForReward[uncommonRewards.length][msg.sender] = deposits[msg.sender];\n\n    userWithdrewEverythingAt[msg.sender] = 0;\n  }\n\n  /// @notice Withdraw all stakeable tokens from the contract.\n  function withdrawAll() external {\n    withdraw(deposits[msg.sender]);\n  }\n\n  /// @notice Withdraw a specific amount of stakeable tokens from the contract.\n  /// @param amount The amount of stakeable tokens to withdraw.\n  function withdraw(uint256 amount) public nonReentrant {\n    require(unlockInitiated(msg.sender), \"you must unlock your staked tokens first\");\n    require(isUnlocked(msg.sender), \"your staked tokens are still locked\");\n\n    deposits[msg.sender] -= amount;\n    totalStaked += deposits[msg.sender];\n\n    ERC20Helpers.safeTransfer(address(Stakeable), msg.sender, amount);\n\n    if (deposits[msg.sender] == 0) {\n      depositForReward[uncommonRewards.length][msg.sender] = type(uint256).max;\n      userWithdrewEverythingAt[msg.sender] = uncommonRewards.length + 1; // using \n    } else depositForReward[uncommonRewards.length][msg.sender] = deposits[msg.sender];\n\n    lockedUntil[msg.sender] = 0;\n  }\n\n  /// @notice Initiates the process for unlocking the staked tokens.\n  function unlock() external nonReentrant {\n    require(!unlockInitiated(msg.sender), \"Unlock is already pending\");\n\n    // Claims all rewards before updating the user's stake.\n    claimAllCommon(commonRewardTokens);\n\n    totalStaked -= deposits[msg.sender];\n    lockedUntil[msg.sender] = block.timestamp + lockTime;\n    depositForReward[uncommonRewards.length][msg.sender] = type(uint256).max;\n  }\n\n  /// @notice Internal function to nullify the rewards for a specific token.\n  /// @param token The address of the token for which to nullify rewards.\n  function nullifyRewardsForToken(address token) internal {\n    nullifiedRewards[token][msg.sender] = rewardsPerDeposit[token];\n  }\n\n  /// @notice Get the number of uncommon rewards available.\n  /// @return The count of uncommon rewards.\n  function uncommonRewardCount() public view returns (uint256) {\n    return uncommonRewards.length;\n  }\n\n  /// @notice Add rewards to the contract which can be claimed by stakers.\n  /// @param distributionId The identifier for the reward distribution.\n  /// @param token The address of the token in which rewards are being added.\n  /// @param amount The amount of rewards to add.\n  function addRewards(uint256 distributionId, address token, uint256 amount) external payable nonReentrant {\n    require(isRewarder[msg.sender], \"Can only be called from a rewarder address\");\n    require(totalStaked > 0, \"can not add rewards if there are no stakers\");\n\n    if (token != address(0))\n      ERC20Helpers.safeTransferFrom(token, msg.sender, address(this), amount);\n    else amount = msg.value;\n\n    if (isCommonReward[token]) {\n      rewardsPerDeposit[token] += precision * amount / totalStaked;\n      totalRewarded[token] += amount;\n    } else {\n      uncommonRewards.push();\n\n      // Calculate the index of the new UncommonReward\n      uint256 newIndex = uncommonRewards.length - 1;\n\n      // Now, set the values for the new UncommonReward directly in storage.\n      UncommonReward storage reward = uncommonRewards[newIndex];\n      reward.perDeposit = precision * amount / totalStaked;\n      reward.distributionId = distributionId;\n      reward.id = newIndex; // Assuming ID is meant to be the index in the array\n      reward.token = ERC20(token);\n      reward.amount = amount;\n    }\n  }\n\n  /// @notice Get general information about the contract's state and a user's stake.\n  /// @param user The address of the user to retrieve information for.\n  /// @return Total staked, user's deposit, lock status, and related token information.\n  function getInfo(address user) external view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256) {\n    return (\n      totalStaked,\n      deposits[user],\n      lockedUntil[user],\n      Stakeable.decimals(),\n      Stakeable.balanceOf(user),\n      ethPerToken(address(Stakeable)),\n      Stakeable.allowance(user, address(this))\n    );\n  }\n\n  /// @notice Get claimable uncommon rewards information for a user.\n  /// @param user The address of the user to retrieve information for.\n  /// @param page The page of the reward listing.\n  /// @param pageSize The number of reward items per page.\n  /// @return An array of RewardInfo structures containing reward details.\n  function uncommonClaimable(address user, uint page, uint pageSize) external view returns (RewardInfo[] memory) {\n    uint256 totalRewards = uncommonRewards.length;\n    uint256 start = totalRewards > page * pageSize ? totalRewards - page * pageSize : 0;\n    uint256 end = start + pageSize > totalRewards ? totalRewards : start + pageSize;\n    uint256 count = end > start ? end - start : 0;\n\n    RewardInfo[] memory rewards = new RewardInfo[](count);\n\n    for (uint256 i = start; i < end; i++) {\n      UncommonReward storage reward = uncommonRewards[i];\n      ERC20 token = reward.token;\n      rewards[i - start] = RewardInfo({\n        id: reward.id,\n        token: address(token),\n        totalRewards: reward.amount,\n        canClaim: rewardAmount(i, user),\n        name: ERC20Helpers.tryName(token),\n        hasClaimed: reward.hasClaimed[user],\n        symbol: ERC20Helpers.trySymbol(token),\n        distributionId: reward.distributionId,\n        ethPerToken: ethPerToken(address(token)),\n        decimals: ERC20Helpers.tryDecimals(token)\n      });\n    }\n\n    return rewards;\n  }\n\n  /// @notice Get claimable common rewards information for a user.\n  /// @param user The address of the user to retrieve information for.\n  /// @return An array of RewardInfo structures containing reward details.\n  function commonClaimable(address user) public view returns (RewardInfo[] memory) {\n    address[] memory tokens = commonRewardTokens;\n    RewardInfo[] memory rewards = new RewardInfo[](tokens.length);\n\n    for (uint256 i = 0; i < tokens.length; i++) {\n      uint256 decimals;\n      string memory name;\n      string memory symbol;\n      if (tokens[i] == address(0)) {\n        name = \"Ethereum\";\n        symbol = \"ETH\";\n        decimals = 18;\n      } else {\n        ERC20 token = ERC20(tokens[i]);\n\n        name = ERC20Helpers.tryName(token);\n        symbol = ERC20Helpers.trySymbol(token);\n        decimals = ERC20Helpers.tryDecimals(token);\n      }\n\n      rewards[i] = RewardInfo({\n        id: i,\n        name: name,\n        symbol: symbol,\n        token: tokens[i],\n        hasClaimed: false,\n        distributionId: 0,\n        decimals: decimals,\n        canClaim: claimable(tokens[i], user),\n        totalRewards: totalRewarded[tokens[i]],\n        ethPerToken: ethPerToken(tokens[i])\n      });\n    }\n\n    return rewards;\n  }\n\n\n  /// @notice Calculate the amount of a specific token that a user can claim as rewards.\n  /// @param token The token to calculate claimable rewards for.\n  /// @param user The user to calculate rewards for.\n  /// @return The amount of the token that can be claimed.\n  function claimable(address token, address user) public view returns (uint256){\n    if (unlockInitiated(user)) return 0;\n\n    return deposits[user] * (rewardsPerDeposit[token] - nullifiedRewards[token][user]) / precision;\n  }\n\n  /// @notice Calculate the amount of an uncommon reward that belongs to a user.\n  /// @param uncommonRewardId The identifier for the uncommon reward.\n  /// @param user The user for whom to calculate the reward amount.\n  /// @return The amount of the reward that can be claimed.\n  function rewardAmount(uint256 uncommonRewardId, address user) public view returns (uint256){\n    UncommonReward storage reward = uncommonRewards[uncommonRewardId];\n    uint256 deposited = userDepositAtTimeOfUncommonReward(uncommonRewardId, user);\n    return deposited * reward.perDeposit / precision;\n  }\n\n  /// @notice Calculate the user's deposit amount at the time of an uncommon reward.\n  /// @param uncommonRewardId The identifier for the uncommon reward.\n  /// @param user The user for whom to calculate the deposit amount.\n  /// @return The deposit amount at the time of the uncommon reward.\n  function userDepositAtTimeOfUncommonReward(uint256 uncommonRewardId, address user) public view returns (uint256) {\n    if (userWithdrewEverythingAt[user] == 0 && deposits[user] == 0)\n      return 0; // User never deposited\n\n    if (userWithdrewEverythingAt[user] != 0 && userWithdrewEverythingAt[user] <= uncommonRewardId + 1)\n      return 0; // User withdrew everything before reward was added\n\n    for (uint256 index = 0; index <= uncommonRewardId; index++)\n      if (depositForReward[uncommonRewardId - index][user] > 0) {\n        uint256 deposited = depositForReward[uncommonRewardId - index][user];\n        if (deposited == type(uint256).max) return 0;\n        else return deposited;\n      }\n\n    return 0; // user never deposited\n  }\n\n  /// @notice Internal function to allow a user to claim a specific uncommon reward.\n  /// @param rewardId The identifier for the uncommon reward to claim.\n  function claimUncommonReward(uint256 rewardId) internal {\n    UncommonReward storage reward = uncommonRewards[rewardId];\n    if (!reward.hasClaimed[msg.sender]) {\n      reward.hasClaimed[msg.sender] = true;\n      uint256 willClaim = rewardAmount(rewardId, msg.sender);\n\n      if (willClaim > 0)\n        ERC20Helpers.safeTransfer(address(reward.token), msg.sender, willClaim);\n    }\n  }\n\n  /// @notice Internal function to allow a user to claim rewards in a specific token.\n  /// @param token The token in which to claim rewards.\n  function claim(address token) internal {\n    uint256 willClaim = claimable(token, msg.sender);\n    nullifyRewardsForToken(token);\n\n    if (willClaim > 0) {\n      if (token == address(0))\n        payable(msg.sender).transfer(willClaim);\n      else ERC20Helpers.safeTransfer(token, msg.sender, willClaim);\n    }\n  }\n\n\t/// @notice Internal function to claim all common rewards for a user.\n\t/// @param rewards An array of token addresses to claim rewards in.\n  function claimAllCommon(address[] memory rewards) internal {\n    for (uint16 i=0; i < rewards.length; i++)\n      claim(rewards[i]);\n  }\n\n\t/// @notice Allows the user to claim all their rewards in specified tokens.\n\t/// @param rewards An array of token addresses to claim rewards in.\n\t/// @param uncommonRewardIds An array of reward identifiers for uncommon rewards to claim.\n  function claimAll(address[] memory rewards, uint256[] memory uncommonRewardIds) external nonReentrant {\n    claimAllCommon(rewards);\n\n    for (uint16 i=0; i < uncommonRewardIds.length; i++)\n      claimUncommonReward(uncommonRewardIds[i]);\n  }\n\n\t/// @notice Check if a user has initiated the unlock process.\n\t/// @param user The user to check the unlock status for.\n\t/// @return True if the user has initiated unlock, false otherwise.\n  function unlockInitiated(address user) public view returns (bool) {\n    return lockedUntil[user] > 0;\n  }\n\n\t/// @notice Check if a user's stake is currently unlocked.\n\t/// @param user The user to check the lock status for.\n\t/// @return True if the user's stake is unlocked, false otherwise.\n  function isUnlocked(address user) public view returns (bool) {\n    return lockedUntil[user] < block.timestamp;\n  }\n\n\t/// @notice Check the amount of RICE staked for a user\n\t/// @param user The user to check the lock status for.\n\t/// @return uint256 amount staked.\n  function balanceOf(address user) public view returns (uint256) {\n    return deposits[user];\n  }\n\n\t/// @notice Internal function to add a new common reward token.\n\t/// @param token The token to add as a common reward.\n\tfunction ensureRewardToken(address token) internal {\n\t\tif (!isCommonReward[token]) {\n\t\t\tcommonRewardTokens.push(token);\n\t\t\tisCommonReward[token] = true;\n\t\t}\n\t}\n\n\t/// @notice Get the exchange rate of ETH per token from the oracle.\n\t/// @param token The token to get the exchange rate for.\n\t/// @return The amount of ETH per token.\n  function ethPerToken(address token) public view returns (uint256) {\n    try oracle.ethPerToken(token) returns (uint256 result) {\n      return result;\n    } catch {\n      return 0;\n    }\n  }\n\n}\n\n"
      },
      "/contracts/libraries/ERC20Helpers.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\nimport \"@openzeppelin/contracts/interfaces/IERC20Metadata.sol\";\n\npragma solidity >=0.6.0;\n\n// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false\nlibrary ERC20Helpers {\n  function safeApprove(\n    address token,\n    address to,\n    uint256 value\n  ) internal {\n    // bytes4(keccak256(bytes('approve(address,uint256)')));\n    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\n    require(\n      success && (data.length == 0 || abi.decode(data, (bool))),\n      'ERC20Helpers::safeApprove: approve failed'\n    );\n  }\n\n  function safeTransfer(\n    address token,\n    address to,\n    uint256 value\n  ) internal {\n    // bytes4(keccak256(bytes('transfer(address,uint256)')));\n    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\n    require(\n      success && (data.length == 0 || abi.decode(data, (bool))),\n      'ERC20Helpers::safeTransfer: transfer failed'\n    );\n  }\n\n  function safeTransferFrom(\n    address token,\n    address from,\n    address to,\n    uint256 value\n  ) internal {\n    // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));\n    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\n    require(\n      success && (data.length == 0 || abi.decode(data, (bool))),\n      'ERC20Helpers::transferFrom: transferFrom failed'\n    );\n  }\n\n  function safeTransferETH(address to, uint256 value) internal {\n    (bool success, ) = to.call{value: value}(new bytes(0));\n    require(success, 'ERC20Helpers::safeTransferETH: ETH transfer failed');\n  }\n\n  /**\n  * @dev Tries to fetch the decimals of the given token, defaults to 0 if undefined.\n  * @param token The token contract to retrieve decimals from.\n  * @return The number of decimals of the token.\n  */\n  function tryDecimals(IERC20Metadata token) internal view returns (uint8) {\n    try token.decimals{gas: 20000}() returns (uint8 value) {\n      return value;\n    } catch {\n      return 18; // Default value\n    }\n  }\n\n  /**\n  * @dev Tries to fetch the symbol of the given token, defaults to \"UNKNOWN\" if undefined.\n  * @param token The token contract to retrieve the symbol from.\n  * @return The symbol of the token.\n  */\n  function trySymbol(IERC20Metadata token) internal view returns (string memory) {\n    try token.symbol{gas: 20000}() returns (string memory value) {\n      return value;\n    } catch {\n      return \"UNKNOWN\"; // Default value\n    }\n  }\n\n  /**\n  * @dev Tries to fetch the name of the given token, defaults to \"Unknown Token\" if undefined.\n  * @param token The token contract to retrieve the name from.\n  * @return The name of the token.\n  */\n  function tryName(IERC20Metadata token) internal view returns (string memory) {\n    try token.name{gas: 20000}() returns (string memory value) {\n      return value;\n    } catch {\n      return \"Unknown Token\"; // Default value\n    }\n  }\n\n}\n\n\n"
      },
      "/contracts/Oracle.sol": {
        "content": "// contracts/Oracle.sol\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';\n\ninterface IV2Factory {\n  function getPair(address tokenA, address tokenB) external view returns (address pair);\n}\n\ninterface IUniswapV3Factory {\n  function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);\n}\n\ninterface IUniswapV3Pool {\n  function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked);\n  function liquidity() external view returns (uint128);\n}\n\ncontract Oracle {\n\n  address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n  uint256 public constant PRECISION = 10**18;\n\n  function v3EthPerToken(address token) public view returns (uint256) {\n    IUniswapV3Factory factory = IUniswapV3Factory(0x1F98431c8aD98523631AE4a59f267346ea31F984);\n\n    uint16[3] memory feeTiers = [500, 3000, 10000];\n    for (uint i = 0; i < feeTiers.length; i++) {\n      IUniswapV3Pool poolV3 = IUniswapV3Pool(factory.getPool(token, WETH, feeTiers[i]));\n      if (address(poolV3) != address(0)) {\n        // uint128 liquidity = poolV3.liquidity();\n        if (IERC20(WETH).balanceOf(address(poolV3)) > 2 ether) { // Check for sufficient liquidity\n          (uint160 sqrtPriceX96,,,,,,) = poolV3.slot0();\n          // Calculate price per token, adjust for sufficient liquidity\n          uint pricePerToken = (((uint(sqrtPriceX96) * 10**9) / (2 ** 96)) ** 2);\n          return pricePerToken;\n        }\n      }\n    }\n    return 0;\n  }\n\n  function v2EthPerToken(address token) public view returns (uint256) {\n    IV2Factory uniswapV2Factory = IV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);\n    address pairV2 = uniswapV2Factory.getPair(token, WETH);\n\n    IUniswapV2Router02 uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);\n\n    uint256 amountIn = 0.1 ether;\n    address[] memory path = new address[](2);\n    path[0] = WETH;\n    path[1] = token;\n\n    uint256[] memory amountsOut = uniswapV2Router.getAmountsOut(amountIn, path);\n\n    // If there is less than 2 eth in the reserve, then\n    // assume there is not enough liquidity to detmine a price\n    if (IERC20(WETH).balanceOf(pairV2) > 2 ether)\n      return (PRECISION * PRECISION / (10 * amountsOut[1]));\n\n    return 0;\n  }\n\n  function ethPerToken(address token) public view returns (uint) {\n    if (token == address(0)) return 1 ether;\n\n    // Check Uniswap V2\n    uint256 price = v2EthPerToken(token);\n    if (price > 0) return price;\n\n    // Uniswap V3 fee tiers\n    return v3EthPerToken(token);\n  }\n}\n"
      },
      "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol": {
        "content": "pragma solidity >=0.6.2;\n\nimport './IUniswapV2Router01.sol';\n\ninterface IUniswapV2Router02 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    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, 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    function swapExactETHForTokensSupportingFeeOnTransferTokens(\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable;\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n}\n"
      },
      "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol": {
        "content": "pragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n    function factory() external pure returns (address);\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    function addLiquidityETH(\n        address token,\n        uint amountTokenDesired,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);\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    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    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, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountToken, uint amountETH);\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    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    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n\n    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);\n    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);\n    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);\n    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);\n    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"
      },
      "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n}\n"
      },
      "@openzeppelin/contracts/interfaces/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/extensions/IERC20Metadata.sol\";\n"
      },
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../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 * By default, the owner account will be the one that deploys the contract. This\n * can 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    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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"
      }
    },
    "settings": {
      "remappings": [],
      "optimizer": {
        "enabled": false,
        "runs": 200
      },
      "evmVersion": "london",
      "libraries": {},
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    }
  }}