Skip to content

Commit

Permalink
fix: composite eth price feed renamed for better compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
Van0k committed Dec 1, 2022
1 parent 5f8f702 commit 614d5a7
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,24 @@ import { PriceFeedType, IPriceFeedType } from "../interfaces/IPriceFeedType.sol"
// EXCEPTIONS
import { NotImplementedException } from "../interfaces/IErrors.sol";

/// @title Price feed that composes an ETH price feed with a USD one
/// @notice Used to avoid price feed discrepancies for ETH-correlated assets, such as stETH
contract CompositeETHPriceFeed is
/// @title Price feed that composes an base asset-denominated price feed with a USD one
/// @notice Used for better price tracking for correlated assets (such as stETH or WBTC) or on networks where
/// only feeds for the native tokens exist
contract CompositePriceFeed is
PriceFeedChecker,
AggregatorV3Interface,
IPriceFeedType
{
/// @dev Chainlink ETH price feed for the target asset
AggregatorV3Interface public immutable targetEthPriceFeed;
/// @dev Chainlink base asset price feed for the target asset
AggregatorV3Interface public immutable targetToBasePriceFeed;

/// @dev Chainlink ETH/USD price feed
AggregatorV3Interface public immutable ethUsdPriceFeed;
/// @dev Chainlink Base asset / USD price feed
AggregatorV3Interface public immutable baseToUsdPriceFeed;

/// @dev Decimals of the returned result.
uint8 public immutable override decimals;

/// @dev 10 ^ Decimals of Target / ETH price feed, to divide the product of answers
/// @dev 10 ^ Decimals of Target / Base price feed, to divide the product of answers
int256 public immutable answerDenominator;

/// @dev Price feed description
Expand All @@ -41,19 +42,19 @@ contract CompositeETHPriceFeed is
bool public constant override skipPriceCheck = true;

/// @dev Constructor
/// @param _targetEthPriceFeed ETH price feed for target asset
/// @param _ethUsdPriceFeed USD price feed for ETH
constructor(address _targetEthPriceFeed, address _ethUsdPriceFeed) {
targetEthPriceFeed = AggregatorV3Interface(_targetEthPriceFeed);
ethUsdPriceFeed = AggregatorV3Interface(_ethUsdPriceFeed);
/// @param _targetToBasePriceFeed Base asset price feed for target asset
/// @param _baseToUsdPriceFeed USD price feed for base asset
constructor(address _targetToBasePriceFeed, address _baseToUsdPriceFeed) {
targetToBasePriceFeed = AggregatorV3Interface(_targetToBasePriceFeed);
baseToUsdPriceFeed = AggregatorV3Interface(_baseToUsdPriceFeed);
description = string(
abi.encodePacked(
targetEthPriceFeed.description(),
" ETH/USD Composite"
targetToBasePriceFeed.description(),
" to USD Composite"
)
);
decimals = ethUsdPriceFeed.decimals();
answerDenominator = int256(10**targetEthPriceFeed.decimals());
decimals = baseToUsdPriceFeed.decimals();
answerDenominator = int256(10**targetToBasePriceFeed.decimals());
}

/// @dev Implemented for compatibility, but reverts since Gearbox's price feeds
Expand All @@ -71,7 +72,7 @@ contract CompositeETHPriceFeed is
uint80 // answeredInRound
)
{
revert NotImplementedException(); // F:[LPF-2]
revert NotImplementedException();
}

/// @dev Returns the composite USD-denominated price of the asset, computed as (Target / ETH rate * ETH / USD rate)
Expand All @@ -93,7 +94,7 @@ contract CompositeETHPriceFeed is
uint256 startedAt0,
uint256 updatedAt0,
uint80 answeredInRound0
) = targetEthPriceFeed.latestRoundData();
) = targetToBasePriceFeed.latestRoundData();

_checkAnswer(roundId0, answer0, updatedAt0, answeredInRound0);

Expand All @@ -103,7 +104,7 @@ contract CompositeETHPriceFeed is
startedAt,
updatedAt,
answeredInRound
) = ethUsdPriceFeed.latestRoundData();
) = baseToUsdPriceFeed.latestRoundData();

_checkAnswer(roundId, answer, updatedAt, answeredInRound);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;

import { CompositeETHPriceFeed } from "../../oracles/CompositeETHPriceFeed.sol";
import { CompositePriceFeed } from "../../oracles/CompositePriceFeed.sol";
import { PriceFeedMock } from "../mocks/oracles/PriceFeedMock.sol";
import { IPriceOracleV2Exceptions } from "../../interfaces/IPriceOracle.sol";

Expand All @@ -17,21 +17,21 @@ import { TokensTestSuite } from "../suites/TokensTestSuite.sol";
// EXCEPTIONS
import { NotImplementedException, CallerNotConfiguratorException } from "../../interfaces/IErrors.sol";

/// @title CompositeETHPriceFeedTest
/// @title CompositePriceFeedTest
/// @notice Designed for unit test purposes only
contract CompositeETHPriceFeedTest is DSTest, IPriceOracleV2Exceptions {
contract CompositePriceFeedTest is DSTest, IPriceOracleV2Exceptions {
CheatCodes evm = CheatCodes(HEVM_ADDRESS);

PriceFeedMock public targetPf;
PriceFeedMock public ethUsdPf;
CompositeETHPriceFeed public pf;
PriceFeedMock public baseUsdPf;
CompositePriceFeed public pf;

TokensTestSuite tokenTestSuite;

function setUp() public {
targetPf = new PriceFeedMock(99 * 10**16, 18);
ethUsdPf = new PriceFeedMock(1000 * 10**8, 8);
pf = new CompositeETHPriceFeed(address(targetPf), address(ethUsdPf));
baseUsdPf = new PriceFeedMock(1000 * 10**8, 8);
pf = new CompositePriceFeed(address(targetPf), address(baseUsdPf));
}

///
Expand All @@ -40,11 +40,11 @@ contract CompositeETHPriceFeedTest is DSTest, IPriceOracleV2Exceptions {
///
///

/// @dev [CEPF-1]: constructor sets correct values
function test_CEPF_01_constructor_sets_correct_values() public {
/// @dev [CPF-1]: constructor sets correct values
function test_CPF_01_constructor_sets_correct_values() public {
assertEq(
pf.description(),
"price oracle ETH/USD Composite",
"price oracle to USD Composite",
"Incorrect description"
);

Expand All @@ -59,15 +59,15 @@ contract CompositeETHPriceFeedTest is DSTest, IPriceOracleV2Exceptions {
assertTrue(pf.skipPriceCheck(), "Incorrect skipPriceCheck");
}

/// @dev [CEPF-2]: getRoundData reverts
function test_CEPF_02_getRoundData_reverts() public {
/// @dev [CPF-2]: getRoundData reverts
function test_CPF_02_getRoundData_reverts() public {
evm.expectRevert(NotImplementedException.selector);

pf.getRoundData(1);
}

/// @dev [CEPF-3]: latestRoundData works correctly
function test_CEPF_03_latestRoundData_works_correctly(
/// @dev [CPF-3]: latestRoundData works correctly
function test_CPF_03_latestRoundData_works_correctly(
int256 answer1,
int256 answer2
) public {
Expand All @@ -77,7 +77,7 @@ contract CompositeETHPriceFeedTest is DSTest, IPriceOracleV2Exceptions {
evm.assume(answer2 < int256(RAY));

targetPf.setPrice(answer1);
ethUsdPf.setPrice(answer2);
baseUsdPf.setPrice(answer2);

(
uint80 roundId,
Expand All @@ -88,24 +88,24 @@ contract CompositeETHPriceFeedTest is DSTest, IPriceOracleV2Exceptions {
) = pf.latestRoundData();
(, int256 answerTarget, , , ) = targetPf.latestRoundData();
(
uint80 roundIdEth,
int256 answerEth,
uint256 startedAtEth,
uint256 updatedAtEth,
uint80 answeredInRoundEth
) = ethUsdPf.latestRoundData();

assertEq(roundId, roundIdEth, "Incorrect round Id #1");
uint80 roundIdBase,
int256 answerBase,
uint256 startedAtBase,
uint256 updatedAtBase,
uint80 answeredInRoundBase
) = baseUsdPf.latestRoundData();

assertEq(roundId, roundIdBase, "Incorrect round Id #1");
assertEq(
answer,
(answerTarget * answerEth) / int256(10**targetPf.decimals()),
(answerTarget * answerBase) / int256(10**targetPf.decimals()),
"Incorrect answer #1"
);
assertEq(startedAt, startedAtEth, "Incorrect startedAt #1");
assertEq(updatedAt, updatedAtEth, "Incorrect updatedAt #1");
assertEq(startedAt, startedAtBase, "Incorrect startedAt #1");
assertEq(updatedAt, updatedAtBase, "Incorrect updatedAt #1");
assertEq(
answeredInRound,
answeredInRoundEth,
answeredInRoundBase,
"Incorrect answeredInRound #1"
);
}
Expand Down Expand Up @@ -141,22 +141,22 @@ contract CompositeETHPriceFeedTest is DSTest, IPriceOracleV2Exceptions {

targetPf.setPrice(99 * 10**16);

(roundId, answer, startedAt, updatedAt, answeredInRound) = ethUsdPf
(roundId, answer, startedAt, updatedAt, answeredInRound) = baseUsdPf
.latestRoundData();

ethUsdPf.setParams(roundId, startedAt, 0, answeredInRound);
baseUsdPf.setParams(roundId, startedAt, 0, answeredInRound);

evm.expectRevert(ChainPriceStaleException.selector);
pf.latestRoundData();

ethUsdPf.setParams(roundId, startedAt, updatedAt, roundId - 1);
baseUsdPf.setParams(roundId, startedAt, updatedAt, roundId - 1);

evm.expectRevert(ChainPriceStaleException.selector);
pf.latestRoundData();

ethUsdPf.setParams(roundId, startedAt, updatedAt, answeredInRound);
baseUsdPf.setParams(roundId, startedAt, updatedAt, answeredInRound);

ethUsdPf.setPrice(0);
baseUsdPf.setPrice(0);

evm.expectRevert(ZeroPriceException.selector);
pf.latestRoundData();
Expand Down

0 comments on commit 614d5a7

Please sign in to comment.