creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/price-getters/susde/sUSDePriceProviderBUniCatch.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.6.6;\n\nimport {FullMath} from '../uniswap-v2/libraries/FullMath.sol';\nimport {IPriceGetter} from '../uniswap-v2/interfaces/IPriceGetter.sol';\nimport {IERC20Metadata} from '../uniswap-v2/interfaces/IERC20Metadata.sol';\n\ninterface ICurvePoolWithOracle {\n  function price_oracle(uint256 i) external view returns (uint256);\n\n  function get_p(uint256 i) external view returns (uint256);\n}\n\ninterface IUwUOracle {\n  function getAssetPrice(address asset) external view returns (uint256);\n}\n\ncontract sUSDePriceProviderBUniCatch is IPriceGetter {\n  address public constant FRAX = 0x853d955aCEf822Db058eb8505911ED77F175b99e;\n  address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n  address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n  address public constant CRVUSD = 0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E;\n  address public constant GHO = 0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f;\n  ICurvePoolWithOracle public constant FRAX_POOL =\n    ICurvePoolWithOracle(0x5dc1BF6f1e983C0b21EfB003c105133736fA0743);\n  ICurvePoolWithOracle public constant DAI_POOL =\n    ICurvePoolWithOracle(0xF36a4BA50C603204c3FC6d2dA8b78A7b69CBC67d);\n  ICurvePoolWithOracle public constant USDC_POOL =\n    ICurvePoolWithOracle(0x02950460E2b9529D0E00284A5fA2d7bDF3fA4d72);\n  ICurvePoolWithOracle public constant CRVUSD_POOL =\n    ICurvePoolWithOracle(0xF55B0f6F2Da5ffDDb104b58a60F2862745960442);\n  ICurvePoolWithOracle public constant GHO_POOL =\n    ICurvePoolWithOracle(0x670a72e6D22b0956C0D2573288F82DCc5d6E3a61);\n  IUwUOracle public constant uwuOracle = IUwUOracle(0xAC4A2aC76D639E10f2C05a41274c1aF85B772598);\n  IPriceGetter public immutable UNI_V3_TWAP_USDT_ORACLE;\n\n  uint256 public sUSDeScalingFactor = 1047;\n  address public owner;\n\n  constructor(address _usdeUsdtOracle) public {\n    owner = msg.sender;\n    UNI_V3_TWAP_USDT_ORACLE = IPriceGetter(_usdeUsdtOracle);\n  }\n\n  /******* VIEW *******/\n\n  function getPrice() external view override returns (uint256) {\n    (uint256[] memory prices, bool uniFail) = _getPrices(true);\n\n    uint256 median = uniFail ? (prices[5] + prices[6]) / 2 : prices[5];\n\n    require(median > 0, 'Median is zero');\n\n    return FullMath.mulDiv(median, sUSDeScalingFactor, 1e3);\n  }\n\n  function getPrices(bool sorted) external view returns (uint256[] memory, bool) {\n    return _getPrices(sorted);\n  }\n\n  function getMedianUsdePriceInUSD() external view returns (uint256) {\n    (uint256[] memory prices, bool uniFail) = _getPrices(true);\n\n    return uniFail ? (prices[5] + prices[6]) / 2 : prices[5];\n  }\n\n  function getUSDeFraxEMAInUSD() external view returns (uint256, uint256) {\n    return _getUSDeFraxEMAInUSD();\n  }\n\n  function getUSDeUSDCEMAInUSD() external view returns (uint256, uint256) {\n    return _getUSDeUsdcEMAInUSD();\n  }\n\n  function getUSDeDAIEMAInUSD() external view returns (uint256, uint256) {\n    return _getUSDeDaiEMAInUSD();\n  }\n\n  function getUSDeCrvUsdEMAInUSD() external view returns (uint256, uint256) {\n    return _getCrvUsdUSDeEMAInUSD();\n  }\n\n  function getUSDeGhoEMAInUSD() external view returns (uint256, uint256) {\n    return _getUSDeGhoEMAInUSD();\n  }\n\n  function getUSDeUsdtTWAPInUSD() external view returns (uint256) {\n    try UNI_V3_TWAP_USDT_ORACLE.getPrice() returns (uint256 price) {\n      return price;\n    } catch {\n      return 0;\n    }\n  }\n\n  /******* OWNER *******/\n\n  function changeScalingFactor(uint256 _newScalingFactor) external {\n    require(msg.sender == owner, 'Only Owner');\n    require(_newScalingFactor >= 1000, 'Factor cannot be lower than 1000');\n    sUSDeScalingFactor = _newScalingFactor;\n  }\n\n  function transferOwnership(address _newOwner) external {\n    require(msg.sender == owner, 'Only Owner');\n    owner = _newOwner;\n  }\n\n  /******* INTERNAL *******/\n\n  function _getPrices(bool sorted) internal view returns (uint256[] memory, bool uniFail) {\n    uint256[] memory prices = new uint256[](11);\n    (prices[0], prices[1]) = _getUSDeFraxEMAInUSD();\n    (prices[2], prices[3]) = _getUSDeUsdcEMAInUSD();\n    (prices[4], prices[5]) = _getUSDeDaiEMAInUSD();\n    (prices[6], prices[7]) = _getCrvUsdUSDeEMAInUSD();\n    (prices[8], prices[9]) = _getUSDeGhoEMAInUSD();\n    try UNI_V3_TWAP_USDT_ORACLE.getPrice() returns (uint256 price) {\n      prices[10] = price;\n    } catch {\n      uniFail = true;\n    }\n\n    if (sorted) {\n      _bubbleSort(prices);\n    }\n\n    return (prices, uniFail);\n  }\n\n  function _getUSDeFraxEMAInUSD() internal view returns (uint256, uint256) {\n    uint256 price = uwuOracle.getAssetPrice(FRAX);\n    // (USDe/FRAX * FRAX/USD) / 1e18\n    return (\n      FullMath.mulDiv(FRAX_POOL.price_oracle(0), price, 1e18),\n      FullMath.mulDiv(FRAX_POOL.get_p(0), price, 1e18)\n    );\n  }\n\n  function _getUSDeUsdcEMAInUSD() internal view returns (uint256, uint256) {\n    uint256 price = uwuOracle.getAssetPrice(USDC);\n    // (USDC/USD * 1e18) / USDC/USDe\n    return (\n      FullMath.mulDiv(price, 1e18, USDC_POOL.price_oracle(0)),\n      FullMath.mulDiv(price, 1e18, USDC_POOL.get_p(0))\n    );\n  }\n\n  function _getUSDeDaiEMAInUSD() internal view returns (uint256, uint256) {\n    uint256 price = uwuOracle.getAssetPrice(DAI);\n    // (DAI/USD * 1e18) / DAI/USDe\n    return (\n      FullMath.mulDiv(price, 1e18, DAI_POOL.price_oracle(0)),\n      FullMath.mulDiv(price, 1e18, DAI_POOL.get_p(0))\n    );\n  }\n\n  function _getCrvUsdUSDeEMAInUSD() internal view returns (uint256, uint256) {\n    uint256 price = uwuOracle.getAssetPrice(CRVUSD);\n    // (CRVUSD/USD * 1e18) / CRVUSD/USDe\n    return (\n      FullMath.mulDiv(price, 1e18, CRVUSD_POOL.price_oracle(0)),\n      FullMath.mulDiv(price, 1e18, CRVUSD_POOL.get_p(0))\n    );\n  }\n\n  function _getUSDeGhoEMAInUSD() internal view returns (uint256, uint256) {\n    uint256 price = uwuOracle.getAssetPrice(GHO);\n    // (USDe/GHO * GHO/USD) / 1e18\n    return (\n      FullMath.mulDiv(GHO_POOL.price_oracle(0), price, 1e18),\n      FullMath.mulDiv(GHO_POOL.get_p(0), price, 1e18)\n    );\n  }\n\n  function _bubbleSort(uint[] memory arr) internal pure returns (uint[] memory) {\n    uint256 n = arr.length;\n    for (uint256 i = 0; i < n - 1; i++) {\n      for (uint256 j = 0; j < n - i - 1; j++) {\n        if (arr[j] > arr[j + 1]) {\n          (arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);\n        }\n      }\n    }\n    return arr;\n  }\n}\n"
      },
      "contracts/price-getters/uniswap-v2/interfaces/IERC20Metadata.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity 0.6.6;\n\ninterface IERC20Metadata {\n  function decimals() external view returns (uint8);\n}\n"
      },
      "contracts/price-getters/uniswap-v2/interfaces/IPriceGetter.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity 0.6.6;\n\ninterface IPriceGetter {\n  function getPrice() external view returns (uint256 price);\n}\n"
      },
      "contracts/price-getters/uniswap-v2/libraries/FullMath.sol": {
        "content": "// SPDX-License-Identifier: CC-BY-4.0\npragma solidity 0.6.6;\n\n// taken from https://medium.com/coinmonks/math-in-solidity-part-3-percents-and-proportions-4db014e080b1\n// license is CC-BY-4.0\nlibrary FullMath {\n  function fullMul(uint256 x, uint256 y) internal pure returns (uint256 l, uint256 h) {\n    uint256 mm = mulmod(x, y, uint256(-1));\n    l = x * y;\n    h = mm - l;\n    if (mm < l) h -= 1;\n  }\n\n  function fullDiv(uint256 l, uint256 h, uint256 d) private pure returns (uint256) {\n    uint256 pow2 = d & -d;\n    d /= pow2;\n    l /= pow2;\n    l += h * ((-pow2) / pow2 + 1);\n    uint256 r = 1;\n    r *= 2 - d * r;\n    r *= 2 - d * r;\n    r *= 2 - d * r;\n    r *= 2 - d * r;\n    r *= 2 - d * r;\n    r *= 2 - d * r;\n    r *= 2 - d * r;\n    r *= 2 - d * r;\n    return l * r;\n  }\n\n  function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256) {\n    (uint256 l, uint256 h) = fullMul(x, y);\n\n    uint256 mm = mulmod(x, y, d);\n    if (mm > l) h -= 1;\n    l -= mm;\n\n    if (h == 0) return l / d;\n\n    require(h < d, 'FullMath: FULLDIV_OVERFLOW');\n    return fullDiv(l, h, d);\n  }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "evmVersion": "istanbul",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}