diff --git a/tests/Contracts/MockAggregator.sol b/tests/Contracts/MockAggregator.sol index b3c953e19..fe664239e 100644 --- a/tests/Contracts/MockAggregator.sol +++ b/tests/Contracts/MockAggregator.sol @@ -42,6 +42,7 @@ contract MockAggregator { uint8 public decimals = 18; int256 public answer; + uint256 public blockTimestamp; constructor(int256 _answer) public { answer = _answer; @@ -61,7 +62,7 @@ contract MockAggregator { // Shh _roundId; - return (roundId, answer, block.timestamp, block.timestamp, roundId); + return (roundId, answer, blockTimestamp, blockTimestamp, roundId); } function latestRoundData() @@ -75,7 +76,7 @@ contract MockAggregator { uint80 ) { - return (roundId, answer, block.timestamp, block.timestamp, roundId); + return (roundId, answer, blockTimestamp, blockTimestamp, roundId); } function setAnswer(int256 _answer) external { @@ -85,6 +86,10 @@ contract MockAggregator { function setDecimals(uint8 _decimals) external { decimals = _decimals; } + + function setBlockTimestamp(uint256 newBlockTimestamp) external { + blockTimestamp = newBlockTimestamp; + } } contract MockRegistry is FeedRegistryInterface { @@ -93,6 +98,7 @@ contract MockRegistry is FeedRegistryInterface { mapping(address => mapping(address => int256)) private answer; bool public getFeedFailed; bool public feedDisabled; + uint256 public blockTimestamp; function getRoundData( address base, @@ -109,7 +115,7 @@ contract MockRegistry is FeedRegistryInterface { uint80 ) { - return (roundId, answer[base][quote], block.timestamp, block.timestamp, _roundId); + return (roundId, answer[base][quote], blockTimestamp, blockTimestamp, _roundId); } function latestRoundData(address base, address quote) @@ -123,7 +129,7 @@ contract MockRegistry is FeedRegistryInterface { uint80 ) { - return (roundId, answer[base][quote], block.timestamp, block.timestamp, roundId); + return (roundId, answer[base][quote], blockTimestamp, blockTimestamp, roundId); } function decimals(address base, address quote) external view returns (uint8) { @@ -183,4 +189,8 @@ contract MockRegistry is FeedRegistryInterface { ) external { answer[base][quote] = _answer; } + + function setBlockTimestamp(uint256 newBlockTimestamp) external { + blockTimestamp = newBlockTimestamp; + } } diff --git a/tests/Contracts/PriceOracleProxyHarness.sol b/tests/Contracts/PriceOracleProxyHarness.sol new file mode 100644 index 000000000..98e83d688 --- /dev/null +++ b/tests/Contracts/PriceOracleProxyHarness.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.5.16; + +import "../../contracts/PriceOracle/PriceOracleProxy.sol"; + +contract PriceOracleProxyHarness is PriceOracleProxy { + uint256 public blockTimestamp = 100000; + + constructor( + address admin_, + address v1PriceOracle_, + address cEthAddress_, + address registry_ + ) public PriceOracleProxy(admin_, v1PriceOracle_, cEthAddress_, registry_) {} + + function getBlockTimestamp() internal view returns (uint256) { + return blockTimestamp; + } + + function setBlockTimestamp(uint256 newBlockTimestamp) public { + blockTimestamp = newBlockTimestamp; + } +} diff --git a/tests/PriceOracleProxyTest.js b/tests/PriceOracleProxyTest.js index 23d58ca1e..5854f1c84 100644 --- a/tests/PriceOracleProxyTest.js +++ b/tests/PriceOracleProxyTest.js @@ -47,7 +47,7 @@ describe('PriceOracleProxy', () => { cYv2CrvLP = await makeCToken({comptroller: cEth.comptroller, supportMarket: true, underlying: yv2CrvLP}); backingOracle = await makePriceOracle(); - oracle = await deploy('PriceOracleProxy', + oracle = await deploy('PriceOracleProxyHarness', [ root, backingOracle._address, @@ -196,6 +196,31 @@ describe('PriceOracleProxy', () => { let proxyPrice = await call(oracle, "getUnderlyingPrice", [cOther._address]); expect(Number(proxyPrice)).toEqual(0.0005 * 1e18); }); + + it("fallbacks to v1 if the price from chainlink is invalid", async () => { + const v1Price = 10; + const oraclePrice = '0'; + + await setAndVerifyBackingPrice(cOther, v1Price); + await setPrice(cOther.underlying._address, cOther.underlying._address, ethAddress, oraclePrice); + await readAndVerifyProxyPrice(cOther, v1Price); + }); + + it("fallbacks to v1 if the price from chainlink is stale", async () => { + const v1Price = 10; + const oraclePrice = '2'; + + const timestamp1 = 10000; + const timestamp2 = 96500; // greater than timestamp1 + 86400 (1 day) + + await setAndVerifyBackingPrice(cOther, v1Price); + await setPrice(cOther.underlying._address, cOther.underlying._address, ethAddress, oraclePrice); + + await call(mockAggregator, "setBlockTimestamp", [timestamp1]); + await call(oracle, "setBlockTimestamp", [timestamp2]); + + await readAndVerifyProxyPrice(cOther, v1Price); + }); }); describe("_setAdmin", () => {