Skip to content

Commit

Permalink
implement latestRound and getRoundData
Browse files Browse the repository at this point in the history
  • Loading branch information
rbajollari committed May 13, 2024
1 parent f7d2764 commit ce26902
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 12 deletions.
14 changes: 7 additions & 7 deletions contracts/pricefeed/CloneFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ pragma solidity ^0.8.20;
import "./PriceFeed.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";

/// @title Factory for creating PriceFeed contract clones
/// @notice This contract will create a PriceFeed clone and map its address to clone creator
/// @dev Cloning is done with OpenZeppelin's Clones contract and clones are initialized by an intitializer function instead of a constructor upon creation
/// @title Factory for creating PriceFeed contract clones.
/// @notice This contract will create a PriceFeed clone and map its address to the clone creator.
/// @dev Cloning is done with OpenZeppelin's Clones contract.
contract CloneFactory {
event PriceFeedCloneCreated(
address _priceFeedCloneAddress
Expand All @@ -15,15 +15,15 @@ contract CloneFactory {
mapping (address => address) public PriceFeedCloneAddresses;
address public implementationAddress;

/// @param _implementationAddress Address of implementation contract to be cloned
/// @param _implementationAddress Address of implementation contract to be cloned.
constructor(address _implementationAddress) {
implementationAddress = _implementationAddress;
}

/// @notice Create clone of PriceFeed contract and initialize it
/// @dev Clone method returns address of created clone
/// @notice Create clone of PriceFeed contract and initialize it.
/// @dev Clone method returns address of created clone.
/// @param _priceFeedDecimals Amount of decimals a PriceFeed is denominiated in.
/// @param _priceFeedDescription Description of PriceFeed.
/// @param _priceFeedDescription Description of PriceFeed, should be set to asset symbol ticker.
function createPriceFeed(uint8 _priceFeedDecimals, string calldata _priceFeedDescription) external {
address priceFeedCloneAddress = Clones.clone(implementationAddress);
PriceFeed(priceFeedCloneAddress).initialize(_priceFeedDecimals, _priceFeedDescription);
Expand Down
71 changes: 66 additions & 5 deletions contracts/pricefeed/PriceFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,33 @@ pragma solidity ^0.8.20;
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../IOjo.sol";
import "../OjoTypes.sol";

/// @title Contract for calling Ojo's oracle contract with chainlink's AggregatorV3Interface implemented.
/// @author Ojo Network (https://docs.ojo.network/)
contract PriceFeed is Initializable, AggregatorV3Interface {
uint8 public priceFeedDecimals;

string public priceFeedDescription;

IOjo public immutable ojo;

uint80 constant DEFAULT_ROUND = 1;

uint256 constant DEFAULT_VERSION = 1;

uint256 internal constant INT256_MAX = uint256(type(int256).max);

error GetRoundDataCanBeOnlyCalledWithLatestRound(uint80 requestedRoundId);

error UnsafeUintToIntConversion(uint256 value);

constructor(address ojo_) {
ojo = IOjo(ojo_);
}

/// @notice Initialize clone of this contract
/// @dev This function is used in place of a constructor in proxy contracts
/// @notice Initialize clone of this contract.
/// @dev This function is used in place of a constructor in proxy contracts.
/// @param _priceFeedDecimals Amount of decimals a PriceFeed is denominiated in.
/// @param _priceFeedDescription Description of PriceFeed.
function initialize(uint8 _priceFeedDecimals, string calldata _priceFeedDescription)
Expand All @@ -27,18 +40,35 @@ contract PriceFeed is Initializable, AggregatorV3Interface {
priceFeedDescription = _priceFeedDescription;
}

/// @notice Amount of decimals price is denominated in.
function decimals() external view returns (uint8) {
return priceFeedDecimals;
}

/// @notice Asset that this proxy is tracking.
/// @dev This should be set as the asset symbol ticker as it used to query the Ojo contract.
function description() external view returns (string memory) {
return priceFeedDescription;
}

/// @notice Version always returns 1.
function version() external view returns (uint256) {
return 1;
return DEFAULT_VERSION;
}

/// @dev Latest round always returns 1 since this contract does not support rounds.
function latestRound() public pure returns (uint80) {
return DEFAULT_ROUND;
}

/// @notice Fetches price data from Ojo contract from a specified round.
/// @dev Even though rounds are not utilized in this contract getRoundData is implemented for contracts
/// that still rely on it. Function will revert if specified round is not the latest round.
/// @return roundId Round ID of price data, this is always set to 1.
/// @return answer Price in USD of asset this contract is tracking.
/// @return startedAt Timestamp relating to price update.
/// @return updatedAt Timestamp relating to price update.
/// @return answeredInRound Equal to round ID.
function getRoundData(uint80 _roundId)
external
view
Expand All @@ -49,11 +79,20 @@ contract PriceFeed is Initializable, AggregatorV3Interface {
uint256 updatedAt,
uint80 answeredInRound
) {

if (_roundId != latestRound()) {
revert GetRoundDataCanBeOnlyCalledWithLatestRound(_roundId);
}
return latestRoundData();
}

/// @notice Fetches latest price data from Ojo contract.
/// @return roundId Round ID of price data, this is always set to 1.
/// @return answer Price in USD of asset this contract is tracking.
/// @return startedAt Timestamp relating to price update.
/// @return updatedAt Timestamp relating to price update.
/// @return answeredInRound Equal to round ID.
function latestRoundData()
external
public
view
returns (
uint80 roundId,
Expand All @@ -62,6 +101,28 @@ contract PriceFeed is Initializable, AggregatorV3Interface {
uint256 updatedAt,
uint80 answeredInRound
) {
roundId = latestRound();
bytes32 assetName = bytes32(bytes(priceFeedDescription));

OjoTypes.PriceData memory priceData = ojo.getPriceData(assetName);

if (priceData.price > INT256_MAX) {
revert UnsafeUintToIntConversion(priceData.price);
}

// These values are equal after chainlink’s OCR update
startedAt = priceData.resolveTime;
updatedAt = priceData.resolveTime;

// roundId is always equal to answeredInRound
answeredInRound = roundId;

return (
roundId,
int256(priceData.price),
startedAt,
updatedAt,
answeredInRound
);
}
}

0 comments on commit ce26902

Please sign in to comment.