// File: contracts/PriceOracles.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract PriceOracles {

    error Invalid_chainlink_price();
    
// 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"); _;}

// setup of chainlink addresses
    AggregatorV3Interface public ETH_USD;
    AggregatorV3Interface public Gold_USD;
    AggregatorV3Interface public Silver_USD;
    AggregatorV3Interface public EUR_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 setEURAddress(address _addr) external onlyOwner {EUR_USD = AggregatorV3Interface(_addr);}
    function setBTCAddress(address _addr) external onlyOwner {BTC_ETH = AggregatorV3Interface(_addr);}

//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 and Fiat 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 _getEURPrice() internal view returns (uint256) {(, int price, , , ) = EUR_USD.latestRoundData(); unchecked {if (price == 0 || price >= 10**60) {revert Invalid_chainlink_price();} uint8 _decimals = EUR_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 EuroDollar_ETHprice() external view returns (uint256) {return ((_getEURPrice() + 1000000000000000)/(2*_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;}}
}
// 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
    );
}