PriceConsumer.sol 4.19 KB
Newer Older
John Doe's avatar
John Doe committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "./interfaces/IPriceConsumer.sol";

contract PriceConsumer is IPriceConsumer {
	/**
	 * Network: Rinkeby
	 * Aggregators: ETH/USD, BTC/USD, XAU/USD, XFT/USD
	 */

	enum Assets {
		XFT,
		USD,
		BTC,
		ETH,
		XAU
	}

	uint8 internal constant _decimalmax = 18;

	constructor() {}

	/**
	 * @dev Returns required input amount of the asset given an output amount of other asset.
	 * @param exchAggr aggregator of input asset.
	 * @param quoteAggr aggregator of output asset.
	 * @param exchAmount output amount.
	 * @return input amount and decimals.
	 */
	function exchangeAssets(
		uint8 exchAggr,
		uint8 quoteAggr,
		uint256 exchAmount
	) external view override returns (uint256, uint8) {
		require(exchAggr != quoteAggr, "Aggregator names are the same");
		(uint256 _quotePrice, uint8 _quoteDecimal) = getDerivedPrice(exchAggr, quoteAggr);

		return (uint256(exchAmount * _quotePrice) / (uint256(10**_quoteDecimal)), _quoteDecimal);
	}

	/**
	 * @dev Returns output amount of the asset given other asset.
 	 * @param baseAggr input asset agregator.
	 * @param quoteAggr output asset agregator.
	 * @return amount and decimals.
	 */
	function getDerivedPrice(uint8 baseAggr, uint8 quoteAggr)
		public
		view
		returns (uint256, uint8)
	{
		(int256 _basePrice, uint8 _baseDecimals) = getLatestPrice(baseAggr);
		(int256 _quotePrice, uint8 _quoteDecimals) = getLatestPrice(quoteAggr);

		(_basePrice, _baseDecimals) = _scalePrice(_basePrice, _baseDecimals, _decimalmax);
		(_quotePrice, _quoteDecimals) = _scalePrice(_quotePrice, _quoteDecimals, _decimalmax);

		return (
			uint256((_basePrice * (int256(10**uint256(_baseDecimals)))) / _quotePrice),
			_quoteDecimals
		);
	}

	/**
	 * @dev Returns the latest price.
	 * @param aggregator Token name by number in Assets enum.
	 * @return price and decimals
	 */
	function getLatestPrice(uint8 aggregator) public view returns (int256, uint8) {
		if (aggregator == uint8(Assets.USD)) {
			return (int256(10**8), 8);
		}
		address _addrAggr = _getAddrAggregator(aggregator);
		require(_addrAggr != address(0), "Adress aggregator cannot be zero.");
		(, int256 _price, , , ) = AggregatorV3Interface(_addrAggr).latestRoundData();
		uint8 _decimals = AggregatorV3Interface(_addrAggr).decimals();
		return (_price, _decimals);
	}

	/**
	 * @dev Returns the aggregator address.
	 * @param _aggregator Token name by number in Assets enum.
	 * @return address.
	 */
	function _getAddrAggregator(uint8 _aggregator) internal pure returns (address) {
		address _addrAggregator;

		if (_aggregator == uint8(Assets.BTC))
			_addrAggregator = 0xECe365B379E1dD183B20fc5f022230C044d51404;

		if (_aggregator == uint8(Assets.ETH))
			_addrAggregator = 0x8A753747A1Fa494EC906cE90E9f37563A8AF630e;

		if (_aggregator == uint8(Assets.XAU))
			_addrAggregator = 0x81570059A0cb83888f1459Ec66Aad1Ac16730243;

		if (_aggregator == uint8(Assets.XFT))
			_addrAggregator = 0xab4a352ac35dFE83221220D967Db41ee61A0DeFa;

		return _addrAggregator;
	}

	/**
	 * @dev Convert the price to the set decimals.
	 * @param _price Token name by number in Assets enum.
	 * @param _priceDecimals Token name by number in Assets enum.
	 * @param _decimals Token name by number in Assets enum.
	 * @return price and decimals.
	 */
	function _scalePrice(
		int256 _price,
		uint8 _priceDecimals,
		uint8 _decimals
	) internal pure returns (int256, uint8) {
		if (_priceDecimals < _decimals) {
			return (_price * int256(10**uint256(_decimals - _priceDecimals)), _decimals);
		} else if (_priceDecimals > _decimals) {
			return (_price / int256(10**uint256(_priceDecimals - _decimals)), _priceDecimals);
		}
		return (_price, _priceDecimals);
	}

	/**
	 * @dev Function for check aggregators equality.
	 * @param _aggr Token name by number in Assets enum.
	 * @param _name Token name by number in Assets enum.
	 * @return result of the equality check.
	 */
	function _isEqualAggr(string memory _aggr, string memory _name) internal pure returns (bool) {
		bool _isEq = bytes(_aggr).length == bytes(_name).length;
		for (uint8 i = 0; i < bytes(_aggr).length; i++) {
			_isEq = _isEq && (bytes(_aggr)[i] == bytes(_name)[i]);
		}
		return _isEq;
	}
}