Contract Name:
ChainlinkFeedGetter
Contract Source Code:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "../oracle/interfaces/IPrimeOracle.sol";
import "../oracle/interfaces/IPrimeOracleGetter.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../../util/CommonErrors.sol";
contract ChainlinkFeedGetter is IPrimeOracleGetter, CommonErrors {
// Map of asset price feeds (asset => priceSource)
mapping(uint256 => mapping(address => AggregatorV3Interface)) private assetFeeds;
//TODO: allow transfer of admin
address public admin;
uint8 public constant RATIO_DECIMALS = 18;
/**
* @dev Only the admin can call functions marked by this modifier.
**/
modifier onlyAdmin {
if(msg.sender != admin) revert OnlyAdmin();
_;
}
constructor() {
admin = msg.sender;
}
/// @inheritdoc IPrimeOracleGetter
function getAssetPrice(
uint256 chainId,
address asset,
address /* denomToken */
) external view override returns (uint256 price, uint8 decimals) {
AggregatorV3Interface feed = assetFeeds[chainId][asset];
if (address(feed) != address(0)) {
(
/* uint80 roundId */,
int256 answer,
/* uint256 startedAt */,
/* uint256 updatedAt */,
/* uint80 answeredInRound */
) = feed.latestRoundData();
if (answer < 0) return (0,0);
price = uint256(answer);
decimals = feed.decimals();
}
}
function getAssetRatio(
address overlyingAsset,
address underlyingAsset,
uint256 underlyingChainId
) external view override returns (uint256 ratio, uint8 decimals) {
AggregatorV3Interface numFeed = assetFeeds[block.chainid][overlyingAsset];
AggregatorV3Interface denFeed = assetFeeds[underlyingChainId][underlyingAsset];
if (address(numFeed) != address(0) && address(denFeed) != address(0)) {
(
/* uint80 roundId */,
int256 numAnswer,
/* uint256 startedAt */,
/* uint256 updatedAt */,
/* uint80 answeredInRound */
) = numFeed.latestRoundData();
(
/* uint80 roundId */,
int256 denAnswer,
/* uint256 startedAt */,
/* uint256 updatedAt */,
/* uint80 answeredInRound */
) = denFeed.latestRoundData();
if (numAnswer >= 0 && denAnswer >= 0) {
ratio = uint256(numAnswer) * 10**(denFeed.decimals() + RATIO_DECIMALS) / uint256(denAnswer) / 10**numFeed.decimals();
decimals = RATIO_DECIMALS;
}
}
}
function getPriceDecimals(uint256 chainId, address asset) external view override returns (uint256) {
if (asset == address(0)) revert AddressExpected();
AggregatorV3Interface feed = assetFeeds[chainId][asset];
if (address(feed) != address(0)) {
return feed.decimals();
}
return 0;
}
function _getAssetFeed(uint256 chainId, address asset) internal view returns (address) {
if (asset == address(0)) revert AddressExpected();
return address(assetFeeds[chainId][asset]);
}
function getAssetFeed(uint256 chainId, address asset) external view override returns (address) {
if (asset == address(0)) revert AddressExpected();
return _getAssetFeed(chainId, asset);
}
/// @inheritdoc IPrimeOracleGetter
function setAssetFeed(
uint256 chainId,
address asset,
address feed
) external override onlyAdmin() {
assetFeeds[chainId][asset] = AggregatorV3Interface(feed);
emit AssetFeedUpdated(chainId, asset, feed);
}
}
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "./IPrimeOracleGetter.sol";
import "./PrimeOracleStorage.sol";
/**
* @title IPrimeOracle
* @author Prime
* @notice The core interface for the Prime Oracle
*/
abstract contract IPrimeOracle is PrimeOracleStorage {
/**
* @dev Emitted after the price data feed of an asset is set/updated
* @param asset The address of the asset
* @param chainId The chainId of the asset
* @param feed The price feed of the asset
*/
event SetPrimaryFeed(uint256 chainId, address indexed asset, address indexed feed);
/**
* @dev Emitted after the price data feed of an asset is set/updated
* @param asset The address of the asset
* @param feed The price feed of the asset
*/
event SetSecondaryFeed(uint256 chainId, address indexed asset, address indexed feed);
/**
* @dev Emitted after the exchange rate data feed of a loan market asset is set/updated
* @param asset The address of the asset
* @param chainId The chainId of the asset
* @param feed The price feed of the asset
*/
event SetExchangRatePrimaryFeed(uint256 chainId, address indexed asset, address indexed feed);
/**
* @dev Emitted after the exchange rate data feed of a loan market asset is set/updated
* @param asset The address of the asset
* @param feed The price feed of the asset
*/
event SetExchangeRateSecondaryFeed(uint256 chainId, address indexed asset, address indexed feed);
/**
* @notice Get the underlying price of a cToken asset
* @param collateralMarketUnderlying The PToken collateral to get the sasset price of
* @param chainId the chainId to get an asset price for
* @return The underlying asset price.
* Zero means the price is unavailable.
*/
function getUnderlyingPrice(uint256 chainId, address collateralMarketUnderlying) external view virtual returns (uint256, uint8);
/**
* @notice Get the underlying borrow price of loanMarketAsset
* @return The underlying borrow price
* Zero means the price is unavailable.
*/
function getUnderlyingPriceBorrow(
uint256 chainId,
address loanMarketUnderlying
) external view virtual returns (uint256, uint8);
/**
* @notice Get the exchange rate of loanMarketAsset to basis
* @return The underlying exchange rate of loanMarketAsset to basis
* Zero means the price is unavailable.
*/
function getBorrowAssetExchangeRate(
address loanMarketOverlying,
uint256 loanMarketUnderlyingChainId,
address loanMarketUnderlying
) external view virtual returns (uint256 /* ratio */, uint8 /* decimals */);
/*** Admin Functions ***/
/**
* @notice Sets or replaces price feeds of assets
* @param asset The addresses of the assets
* @param feed The addresses of the price feeds
*/
function setPrimaryFeed(uint256 chainId, address asset, IPrimeOracleGetter feed) external virtual;
/**
* @notice Sets or replaces price feeds of assets
* @param asset The addresses of the assets
* @param feed The addresses of the price feeds
*/
function setSecondaryFeed(uint256 chainId, address asset, IPrimeOracleGetter feed) external virtual;
}
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
/**
* @title IPrimeOracleGetter
* @author Prime
* @notice Interface for the Prime price oracle.
**/
interface IPrimeOracleGetter {
/**
* @dev Emitted after the price data feed of an asset is updated
* @param asset The address of the asset
* @param feed The price feed of the asset
*/
event AssetFeedUpdated(uint256 chainId, address indexed asset, address indexed feed);
/**
* @notice Gets the price feed of an asset
* @param asset The addresses of the asset
* @return address of asset feed
*/
function getAssetFeed(uint256 chainId, address asset) external view returns (address);
/**
* @notice Sets or replaces price feeds of assets
* @param asset The addresses of the assets
* @param feed The addresses of the price feeds
*/
function setAssetFeed(uint256 chainId, address asset, address feed) external;
/**
* @notice Returns the price data in the denom currency
* @param quoteToken A token to return price data for
* @param denomToken A token to price quoteToken against
* @param price of the asset from the oracle
* @param decimals of the asset from the oracle
**/
function getAssetPrice(
uint256 chainId,
address quoteToken,
address denomToken
) external view returns (uint256 price, uint8 decimals);
function getAssetRatio(
address overlyingAsset,
address underlyingAsset,
uint256 underlyingChainId
) external view returns (uint256 ratio, uint8 decimals);
/**
* @notice Returns the price data in the denom currency
* @param quoteToken A token to return price data for
* @return return price of the asset from the oracle
**/
function getPriceDecimals(
uint256 chainId,
address quoteToken
) external view returns (uint256);
}
// 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);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
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
);
}
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
abstract contract CommonErrors {
error AccountNoAssets(address account);
error AddressExpected();
error AlreadyInitialized();
error EccMessageAlreadyProcessed();
error EccFailedToValidate();
error ExpectedMintAmount();
error ExpectedBridgeAmount();
error ExpectedBorrowAmount();
error ExpectedWithdrawAmount();
error ExpectedRepayAmount();
error ExpectedTradeAmount();
error ExpectedDepositAmount();
error ExpectedTransferAmount();
error InsufficientReserves();
error InvalidPayload();
error InvalidPrice();
error InvalidPrecision();
error InvalidSelector();
error MarketExists();
error LoanMarketIsListed(bool status);
error MarketIsPaused();
error MarketNotListed();
error MsgDataExpected();
error NameExpected();
error NothingToWithdraw();
error NotInMarket(uint256 chainId, address token);
error OnlyAdmin();
error OnlyAuth();
error OnlyGateway();
error OnlyMiddleLayer();
error OnlyMintAuth();
error OnlyRoute();
error OnlyRouter();
error OnlyMasterState();
error ParamOutOfBounds();
error RouteExists();
error Reentrancy();
error EnterLoanMarketFailed();
error EnterCollMarketFailed();
error ExitLoanMarketFailed();
error ExitCollMarketFailed();
error RepayTooMuch(uint256 repayAmount, uint256 maxAmount);
error WithdrawTooMuch();
error NotEnoughBalance(address token, address who);
error LiquidateDisallowed();
error SeizeTooMuch();
error SymbolExpected();
error RouteNotSupported(address route);
error MiddleLayerPaused();
error PairNotSupported(address loanAsset, address tradeAsset);
error TransferFailed(address from, address dest);
error TransferPaused();
error UnknownRevert();
error UnexpectedValueDelta();
error ExpectedValue();
error UnexpectedDelta();
}
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "./IPrimeOracleGetter.sol";
/**
* @title PrimeOracleStorage
* @author Prime
* @notice The core interface for the Prime Oracle storage variables
*/
abstract contract PrimeOracleStorage {
address public pusdAddress;
//TODO: allow transfer of ownership
address public admin;
// Map of asset price feeds (chainasset => priceSource)
mapping(uint256 => mapping(address => IPrimeOracleGetter)) public primaryFeeds;
mapping(uint256 => mapping(address => IPrimeOracleGetter)) public secondaryFeeds;
mapping(uint256 => mapping(address => IPrimeOracleGetter)) public exchangeRatePrimaryFeeds;
mapping(uint256 => mapping(address => IPrimeOracleGetter)) public exchangeRateSecondaryFeeds;
}