Skip to content

Commit

Permalink
support oracles reporting feeds with different decimal format (#1321)
Browse files Browse the repository at this point in the history
* support oracles reporting feeds with different decimal format

* lint

* gas optimisation
  • Loading branch information
sparrowDom authored Apr 14, 2023
1 parent 6afa1c3 commit abde155
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 10 deletions.
49 changes: 40 additions & 9 deletions contracts/contracts/oracle/OracleRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ pragma solidity ^0.8.0;
import "../interfaces/chainlink/AggregatorV3Interface.sol";
import { IOracle } from "../interfaces/IOracle.sol";
import { Helpers } from "../utils/Helpers.sol";
import { StableMath } from "../utils/StableMath.sol";

abstract contract OracleRouterBase is IOracle {
uint256 constant MIN_DRIFT = uint256(70000000);
uint256 constant MAX_DRIFT = uint256(130000000);
using StableMath for uint256;

uint256 constant MIN_DRIFT = 0.7e18;
uint256 constant MAX_DRIFT = 1.3e18;
address constant FIXED_PRICE = 0x0000000000000000000000000000000000000001;
mapping(address => uint8) internal decimalsCache;

/**
* @dev The price feed contract to use for a particular asset.
Expand All @@ -18,9 +22,9 @@ abstract contract OracleRouterBase is IOracle {
function feed(address asset) internal view virtual returns (address);

/**
* @notice Returns the total price in 8 digit USD for a given asset.
* @notice Returns the total price in 18 digit unit for a given asset.
* @param asset address of the asset
* @return uint256 USD price of 1 of the asset, in 8 decimal fixed
* @return uint256 unit price for 1 asset unit, in 18 decimal fixed
*/
function price(address asset)
external
Expand All @@ -34,14 +38,36 @@ abstract contract OracleRouterBase is IOracle {
require(_feed != FIXED_PRICE, "Fixed price feeds not supported");
(, int256 _iprice, , , ) = AggregatorV3Interface(_feed)
.latestRoundData();
uint256 _price = uint256(_iprice);
uint8 decimals = getDecimals(asset);

uint256 _price = uint256(_iprice).scaleBy(18, decimals);
if (isStablecoin(asset)) {
require(_price <= MAX_DRIFT, "Oracle: Price exceeds max");
require(_price >= MIN_DRIFT, "Oracle: Price under min");
}
return uint256(_price);
}

function getDecimals(address _asset)
internal
view
returns (uint8)
{
uint8 decimals = decimalsCache[_asset];
require(decimals > 0, "Oracle: Decimals not cached");
return decimals;
}

function cacheDecimals(address _asset) external returns (uint8) {
address _feed = feed(_asset);
require(_feed != address(0), "Asset not available");
require(_feed != FIXED_PRICE, "Fixed price feeds not supported");

uint8 decimals = AggregatorV3Interface(_feed).decimals();
decimalsCache[_asset] = decimals;
return decimals;
}

function isStablecoin(address _asset) internal view returns (bool) {
string memory symbol = Helpers.getSymbol(_asset);
bytes32 symbolHash = keccak256(abi.encodePacked(symbol));
Expand Down Expand Up @@ -101,12 +127,14 @@ contract OracleRouter is OracleRouterBase {
}

contract OETHOracleRouter is OracleRouter {
using StableMath for uint256;

/**
* @notice Returns the total price in 8 digit USD for a given asset.
* @notice Returns the total price in 18 digit units for a given asset.
* This implementation does not (!) do range checks as the
* parent OracleRouter does.
* @param asset address of the asset
* @return uint256 USD price of 1 of the asset, in 8 decimal fixed
* @return uint256 unit price for 1 asset unit, in 18 decimal fixed
*/
function price(address asset)
external
Expand All @@ -117,12 +145,15 @@ contract OETHOracleRouter is OracleRouter {
{
address _feed = feed(asset);
if (_feed == FIXED_PRICE) {
return 1e8;
return 1e18;
}
require(_feed != address(0), "Asset not available");
(, int256 _iprice, , , ) = AggregatorV3Interface(_feed)
.latestRoundData();
return uint256(_iprice);

uint8 decimals = getDecimals(asset);
uint256 _price = uint256(_iprice).scaleBy(18, decimals);
return _price;
}
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/vault/VaultCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ contract VaultCore is VaultStorage {
returns (uint256 price)
{
UnitConversion conversion = assets[_asset].unitConversion;
price = IOracle(priceProvider).price(_asset) * 1e10;
price = IOracle(priceProvider).price(_asset);

if (conversion == UnitConversion.GETEXCHANGERATE) {
uint256 exchangeRate = IGetExchangeRateToken(_asset)
Expand Down
28 changes: 28 additions & 0 deletions contracts/deploy/052_decimal_cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,18 @@ module.exports = deploymentWithGovernanceProposal(
// Current contracts
const cVaultProxy = await ethers.getContract("VaultProxy");
const dVaultAdmin = await deployWithConfirmation("VaultAdmin");
const dOracleRouter = await deployWithConfirmation("OracleRouter");

const cVault = await ethers.getContractAt("Vault", cVaultProxy.address);
const cOracleRouter = await ethers.getContract("OracleRouter");
await cOracleRouter.cacheDecimals(addresses.mainnet.rETH);
await cOracleRouter.cacheDecimals(addresses.mainnet.DAI);
await cOracleRouter.cacheDecimals(addresses.mainnet.USDC);
await cOracleRouter.cacheDecimals(addresses.mainnet.USDT);
await cOracleRouter.cacheDecimals(addresses.mainnet.COMP);
await cOracleRouter.cacheDecimals(addresses.mainnet.Aave);
await cOracleRouter.cacheDecimals(addresses.mainnet.CRV);
await cOracleRouter.cacheDecimals(addresses.mainnet.CVX);

const cVaultAdmin = new ethers.Contract(cVaultProxy.address, [
{
Expand All @@ -38,6 +48,19 @@ module.exports = deploymentWithGovernanceProposal(
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "_priceProvider",
type: "address",
},
],
name: "setPriceProvider",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
]);

// Governance Actions
Expand All @@ -55,6 +78,11 @@ module.exports = deploymentWithGovernanceProposal(
signature: "cacheDecimals(address)",
args: [assetAddresses.DAI],
},
{
contract: cVaultAdmin,
signature: "setPriceProvider(address)",
args: [dOracleRouter.address],
},
{
contract: cVaultAdmin,
signature: "cacheDecimals(address)",
Expand Down
4 changes: 4 additions & 0 deletions contracts/deploy/053_oeth.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ const deployCore = async ({

await withConfirmation(cVault.connect(sDeployer).unpauseCapital());

await withConfirmation(
cOETHOracleRouter.cacheDecimals(addresses.mainnet.rETH)
);

await withConfirmation(
// 0 stands for DECIMAL unit conversion
cVault.connect(sDeployer).supportAsset(addresses.mainnet.frxETH, 0)
Expand Down

0 comments on commit abde155

Please sign in to comment.