// File: contracts/PriceOracles.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

// extra simplified interface IUniswapV2Pair without any unused functions
interface IUniswapV2Pair {
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function getPair(address tokenA, address tokenB) external view returns (address pair);
    }

contract PriceOracles {

// simplified version of ownable (to save gas)
    address private _owner;
    constructor() {_owner = msg.sender;}
    modifier onlyOwner() {require(_owner == msg.sender, "Ownable: caller is not the owner"); _;}

// CHAINLINK PART
    AggregatorV3Interface public ETH_USD;
    AggregatorV3Interface public Gold_USD;
    AggregatorV3Interface public Silver_USD;
    AggregatorV3Interface public Oil_USD;
    AggregatorV3Interface public BTC_ETH;
    function setETHaddress(address _addr) external onlyOwner {ETH_USD = AggregatorV3Interface(_addr);}
    function setGoldAddress(address _addr) external onlyOwner {Gold_USD = AggregatorV3Interface(_addr);}
    function setSilverAddress(address _addr) external onlyOwner {Silver_USD = AggregatorV3Interface(_addr);}
    function setOilAddress(address _addr) external onlyOwner {Oil_USD = AggregatorV3Interface(_addr);}
    function setBTCAddress(address _addr) external onlyOwner {BTC_ETH = AggregatorV3Interface(_addr);}
    error Invalid_chainlink_price();
//calculations of Normalized price can be unchecked, price is capped by if statement with revert so it can't overflow when multiplying
    // price of ETH in USD with 3 decimals
    function _getETHprice() internal view returns (uint256) {(, int price, , , ) = ETH_USD.latestRoundData(); unchecked {if (price == 0 || price >= 10**72) {revert Invalid_chainlink_price();} uint8 _decimals = ETH_USD.decimals(); uint256 Normalized = (uint256 (price * 1000) / (10 ** _decimals)); return Normalized;}}
    // price of Commodities in USD with 15 decimals
    function _getGoldPrice() internal view returns (uint256) {(, int price, , , ) = Gold_USD.latestRoundData(); unchecked {if (price == 0 || price >= 10**60) {revert Invalid_chainlink_price();} uint8 _decimals = Gold_USD.decimals(); uint256 Normalized = (uint256 (price * 1000000000000000) / (10 ** _decimals)); return Normalized;}}
    function _getSilverPrice() internal view returns (uint256) {(, int price, , , ) = Silver_USD.latestRoundData(); unchecked {if (price == 0 || price >= 10**60) {revert Invalid_chainlink_price();} uint8 _decimals = Silver_USD.decimals(); uint256 Normalized = (uint256 (price * 1000000000000000) / (10 ** _decimals)); return Normalized;}}
    function _getOilPrice() internal view returns (uint256) {(, int price, , , ) = Oil_USD.latestRoundData(); unchecked {if (price == 0 || price >= 10**60) {revert Invalid_chainlink_price();} uint8 _decimals = Oil_USD.decimals(); uint256 Normalized = (uint256 (price * 1000000000000000) / (10 ** _decimals)); return Normalized;}}
    // output prices in ETH with 12 decimals
    function Gold_ETHprice() external view returns (uint256) {return (_getGoldPrice()/_getETHprice());}
    function Silver_ETHprice() external view returns (uint256) {return (_getSilverPrice()/_getETHprice());}
    function Oil_ETHprice() external view returns (uint256) {return (_getOilPrice()/_getETHprice());}
    function BTC_ETHprice() external view returns (uint256) {(, int price, , , ) = BTC_ETH.latestRoundData(); unchecked {if (price == 0 || price >= 10**63) {revert Invalid_chainlink_price();} uint8 _decimals = BTC_ETH.decimals(); uint256 Normalized = (uint256 (price * 1000000000000) / (10 ** _decimals)); return Normalized;}}

// UNISWAP PART
    IUniswapV2Pair public EQT_ETHpool;
    IUniswapV2Pair public UniswapContract = IUniswapV2Pair(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
    function correctUniswapV2Address(address _addr) external onlyOwner {UniswapContract = IUniswapV2Pair(_addr);}
    function setEQT_ETHpool(address _addr) external onlyOwner {EQT_ETHpool = IUniswapV2Pair(_addr);}
    function getEQT_ETHpool(address EQT, address ETH) external view returns(address) {address addr = UniswapContract.getPair(EQT, ETH); return addr;}
//calculation can be unchecked, Res0 originally comes as uint112, it can't overflow uint256 by adding 18 decimals
    function getEQT_ETHprice() external view returns(uint256) {(uint Res0, uint Res1,) = EQT_ETHpool.getReserves(); unchecked {return((Res1*10**18)/Res0);}}
}
// File: @chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol



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

interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function getRoundData(uint80 _roundId)
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
}