pragma solidity >=0.8.4; import "./PriceOracle.sol"; import "./SafeMath.sol"; import "./StringUtils.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; interface AggregatorInterface { function latestAnswer() external view returns (int256); } // StablePriceOracle sets a price in USD, based on an oracle. contract StablePriceOracle is Ownable, PriceOracle { using SafeMath for *; using StringUtils for *; // Rent in base price units by length. Element 0 is for 1-length names, and so on. uint256[] public rentPrices; // Oracle address AggregatorInterface public immutable usdOracle; event OracleChanged(address oracle); event RentPriceChanged(uint256[] prices); bytes4 private constant INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)")); bytes4 private constant ORACLE_ID = bytes4( keccak256("price(string,uint256,uint256)") ^ keccak256("premium(string,uint256,uint256)") ); constructor(AggregatorInterface _usdOracle, uint256[] memory _rentPrices) public { usdOracle = _usdOracle; setPrices(_rentPrices); } function price( string calldata name, uint256 expires, uint256 duration ) external view override returns (uint256) { uint256 len = name.strlen(); if (len > rentPrices.length) { len = rentPrices.length; } require(len > 0); uint256 basePrice = rentPrices[len - 1].mul(duration); basePrice = basePrice.add(_premium(name, expires, duration)); return attoUSDToWei(basePrice); } /** * @dev Sets rent prices. * @param _rentPrices The price array. Each element corresponds to a specific * name length; names longer than the length of the array * default to the price of the last element. Values are * in base price units, equal to one attodollar (1e-18 * dollar) each. */ function setPrices(uint256[] memory _rentPrices) public onlyOwner { rentPrices = _rentPrices; emit RentPriceChanged(_rentPrices); } /** * @dev Returns the pricing premium in wei. */ function premium( string calldata name, uint256 expires, uint256 duration ) external view returns (uint256) { uint256 weiPrice = attoUSDToWei(_premium(name, expires, duration)); return weiPrice; } /** * @dev Returns the pricing premium in internal base units. */ function _premium( string memory name, uint256 expires, uint256 duration ) internal view virtual returns (uint256) { return 0; } function attoUSDToWei(uint256 amount) internal view returns (uint256) { uint256 ethPrice = uint256(usdOracle.latestAnswer()); //2 return amount.mul(1e8).div(ethPrice); } function weiToAttoUSD(uint256 amount) internal view returns (uint256) { uint256 ethPrice = uint256(usdOracle.latestAnswer()); return amount.mul(ethPrice).div(1e8); } function supportsInterface(bytes4 interfaceID) public view virtual returns (bool) { return interfaceID == INTERFACE_META_ID || interfaceID == ORACLE_ID; } }