Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions contracts/dependencies/PriceConverter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,42 @@ pragma solidity 0.8.9;

import '@openzeppelin/contracts/access/Ownable.sol';

interface AggregatorInterface {
function latestAnswer() external view returns (int256);
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
);
}

contract PriceConverter is Ownable {
/// Oracle feed pricing
AggregatorInterface public priceFeedContract;
AggregatorV3Interface public priceFeedContract;

constructor(address _priceAggregator) {
priceFeedContract = AggregatorInterface(_priceAggregator);
priceFeedContract = AggregatorV3Interface(_priceAggregator);
}

/**
Expand All @@ -37,15 +63,24 @@ contract PriceConverter is Ownable {
* @dev Returns the latest price
*/
function getEtherPriceInUSD() public view returns (uint256) {
int256 answer = priceFeedContract.latestAnswer();
// Chainlink returns 8 decimal places so we convert to wei
return uint256(answer * 1e10);
(uint80 roundID, int256 answer, , uint256 updatedAt, uint80 answeredInRound) = priceFeedContract.latestRoundData();

// check that answer is indeed from the last known round
require(answeredInRound == roundID, 'Stale price');
// check that answer is within an allowed margin of freshness by checking updated at was updated less than an hour ago
require(updatedAt > block.timestamp - 3600, 'Answer is not from last known round');
// check returned answer is not zero
require(answer > 0, 'Negative price');

// safe to cast answer into uint256 as we require it to be greater than 0 or above and decimals returns a uint8
// this also assumes that aggregator decimals won't surpass 18 as it will revert with a panic error also solidity doesn't support negative exponents yet
return uint256(answer) * (10**(18 - priceFeedContract.decimals()));
}

/**
* @dev changes the price aggregator
*/
function changeAggregator(AggregatorInterface _priceFeedContract) external onlyOwner {
function changeAggregator(AggregatorV3Interface _priceFeedContract) external onlyOwner {
priceFeedContract = _priceFeedContract;
}
}
81 changes: 76 additions & 5 deletions contracts/mocks/DummyPriceOracle.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;

interface AggregatorInterface {
function latestAnswer() external view returns (int256);
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
);
}

contract DummyPriceOracle is AggregatorInterface {
contract DummyPriceOracle is AggregatorV3Interface {
int256 value;
uint8 _decimals = 8;
string _description = '';
uint256 _version = 3;

constructor(int256 _value) {
set(_value);
Expand All @@ -16,7 +45,49 @@ contract DummyPriceOracle is AggregatorInterface {
value = _value;
}

function latestAnswer() external view returns (int256) {
return value;
function setDecimals(uint8 __decimals) external {
_decimals = __decimals;
}

function decimals() external view returns (uint8) {
return _decimals;
}

function description() external view returns (string memory) {
return _description;
}

function version() external view returns (uint256) {
return _version;
}

function getRoundData(
uint80 /** _roundId */
)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return (1, value, block.timestamp, block.timestamp, 1);
}

function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return (1, value, block.timestamp, block.timestamp, 1);
}
}