Skip to content

Commit

Permalink
test: check round id
Browse files Browse the repository at this point in the history
Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
  • Loading branch information
Reinis-FRP committed May 9, 2024
1 parent 0c6aae5 commit f2d0ff3
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 21 deletions.
38 changes: 25 additions & 13 deletions test/fork/adapters/ChainlinkSourceAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,59 +44,69 @@ contract ChainlinkSourceAdapterTest is CommonTest {
// hour ago is simply the previous round (there was only one update in that interval due to chainlink heartbeat)
uint256 targetTime = block.timestamp - 1 hours;
(uint80 latestRound,,,,) = chainlink.latestRoundData();
(int256 lookBackPrice, uint256 lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 10);
(, int256 answer, uint256 startedAt,,) = chainlink.getRoundData(latestRound - 1);
(int256 lookBackPrice, uint256 lookBackTimestamp, uint256 lookBackRoundId) =
sourceAdapter.tryLatestDataAt(targetTime, 10);
(uint80 roundId, int256 answer, uint256 startedAt,,) = chainlink.getRoundData(latestRound - 1);
assertTrue(startedAt <= targetTime); // The time from the chainlink source is at least 1 hours old.
assertTrue(scaleChainlinkTo18(answer) == lookBackPrice);
assertTrue(startedAt == lookBackTimestamp);
assertTrue(uint256(roundId) == lookBackRoundId);

// Next, try looking back 2 hours. Equally, we should get the price from 2 rounds ago.
targetTime = block.timestamp - 2 hours;
(lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 10);
(, answer, startedAt,,) = chainlink.getRoundData(latestRound - 2);
(lookBackPrice, lookBackTimestamp, lookBackRoundId) = sourceAdapter.tryLatestDataAt(targetTime, 10);
(roundId, answer, startedAt,,) = chainlink.getRoundData(latestRound - 2);
assertTrue(startedAt <= targetTime); // The time from the chainlink source is at least 2 hours old.
assertTrue(scaleChainlinkTo18(answer) == lookBackPrice);
assertTrue(startedAt == lookBackTimestamp);
assertTrue(uint256(roundId) == lookBackRoundId);

// Now, try 3 hours old. again, The value should be at least 3 hours old. However, for this lookback the chainlink
// souce was updated 2x in the interval. Therefore, we should get the price from 4 rounds ago.
targetTime = block.timestamp - 3 hours;
(lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 10);
(, answer, startedAt,,) = chainlink.getRoundData(latestRound - 4);
(lookBackPrice, lookBackTimestamp, lookBackRoundId) = sourceAdapter.tryLatestDataAt(targetTime, 10);
(roundId, answer, startedAt,,) = chainlink.getRoundData(latestRound - 4);
assertTrue(startedAt <= block.timestamp - 3 hours); // The time from the chainlink source is at least 3 hours old.
assertTrue(startedAt > block.timestamp - 4 hours); // Time from chainlink source is at not more than 4 hours.
assertTrue(uint256(roundId) == lookBackRoundId);
}

function testCorrectlyBoundsMaxLookBack() public {
// If we limit how far we can lookback the source should correctly return the oldest data it can find, up to
// that limit. From the previous tests we showed that looking back 2 hours should return the price from round 2.
// If we try look back longer than this we should get the price from round 2, no matter how far we look back.
uint256 targetTime = block.timestamp - 2 hours;
(int256 lookBackPrice, uint256 lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 2);
(int256 lookBackPrice, uint256 lookBackTimestamp, uint256 lookBackRoundId) =
sourceAdapter.tryLatestDataAt(targetTime, 2);
(uint80 latestRound,,,,) = chainlink.latestRoundData();
(, int256 answer, uint256 startedAt,,) = chainlink.getRoundData(latestRound - 2);
(uint80 roundId, int256 answer, uint256 startedAt,,) = chainlink.getRoundData(latestRound - 2);
assertTrue(scaleChainlinkTo18(answer) == lookBackPrice);
assertTrue(startedAt == lookBackTimestamp);
assertTrue(uint256(roundId) == lookBackRoundId);

// Now, lookback longer than 2 hours. should get the same value as before.
targetTime = block.timestamp - 3 hours;
(lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 2);
(lookBackPrice, lookBackTimestamp, lookBackRoundId) = sourceAdapter.tryLatestDataAt(targetTime, 2);
assertTrue(scaleChainlinkTo18(answer) == lookBackPrice);
assertTrue(startedAt == lookBackTimestamp);
assertTrue(uint256(roundId) == lookBackRoundId);
targetTime = block.timestamp - 10 hours;
(lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 2);
(lookBackPrice, lookBackTimestamp, lookBackRoundId) = sourceAdapter.tryLatestDataAt(targetTime, 2);
assertTrue(scaleChainlinkTo18(answer) == lookBackPrice);
assertTrue(startedAt == lookBackTimestamp);
assertTrue(uint256(roundId) == lookBackRoundId);
}

function testNonHistoricalData() public {
uint256 targetTime = block.timestamp - 1 hours;

(, int256 answer,, uint256 updatedAt,) = chainlink.latestRoundData();
(uint80 roundId, int256 answer,, uint256 updatedAt,) = chainlink.latestRoundData();

(int256 lookBackPrice, uint256 lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 0);
(int256 lookBackPrice, uint256 lookBackTimestamp, uint256 lookBackRoundId) =
sourceAdapter.tryLatestDataAt(targetTime, 0);
assertEq(lookBackPrice / 10 ** 10, answer);
assertEq(lookBackTimestamp, updatedAt);
assertEq(uint256(roundId), lookBackRoundId);
}

function testMismatchedRoundId() public {
Expand All @@ -108,13 +118,15 @@ contract ChainlinkSourceAdapterTest is CommonTest {
abi.encode(latestRound, 1000, block.timestamp - 5 days, block.timestamp, latestRound)
);

(int256 resultPrice, uint256 resultTimestamp,) = sourceAdapter.tryLatestDataAt(block.timestamp - 2 hours, 10);
(int256 resultPrice, uint256 resultTimestamp, uint256 lookBackRoundId) =
sourceAdapter.tryLatestDataAt(block.timestamp - 2 hours, 10);

(, int256 latestAnswer,, uint256 latestUpdatedAt,) = chainlink.latestRoundData();

// Check if the return value matches the latest round data, given the fallback logic in _tryLatestRoundDataAt
assertTrue(resultPrice == DecimalLib.convertDecimals(latestAnswer, 8, 18));
assertTrue(resultTimestamp == latestUpdatedAt);
assertTrue(uint256(latestRound) == lookBackRoundId);
}

function scaleChainlinkTo18(int256 input) public pure returns (int256) {
Expand Down
18 changes: 13 additions & 5 deletions test/fork/adapters/UniswapAnchoredViewSourceAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,29 +78,36 @@ contract UniswapAnchoredViewSourceAdapterTest is CommonTest {
assertTrue(latestAggregatorTimestamp > targetTime);

// UniswapAnchoredView does not support historical lookups so this should still return latest data without snapshotting.
(int256 lookBackPrice, uint256 lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 100);
(int256 lookBackPrice, uint256 lookBackTimestamp, uint256 lookBackRoundId) =
sourceAdapter.tryLatestDataAt(targetTime, 100);
assertTrue(int256(latestUniswapAnchoredViewAnswer) == lookBackPrice);
assertTrue(latestAggregatorTimestamp == lookBackTimestamp);
assertTrue(lookBackRoundId == 1); // roundId not supported, hardcoded to 1.
}

function testCorrectlyLooksBackThroughSnapshots() public {
(uint256[] memory snapshotAnswers, uint256[] memory snapshotTimestamps) = _snapshotOnTransmissionBlocks();

for (uint256 i = 0; i < snapshotAnswers.length; i++) {
// Lookback at exact snapshot timestamp should return the same answer and timestamp.
(int256 lookBackPrice, uint256 lookBackTimestamp,) =
(int256 lookBackPrice, uint256 lookBackTimestamp, uint256 lookBackRoundId) =
sourceAdapter.tryLatestDataAt(snapshotTimestamps[i], 10);
assertTrue(int256(snapshotAnswers[i]) == lookBackPrice);
assertTrue(snapshotTimestamps[i] == lookBackTimestamp);
assertTrue(lookBackRoundId == 1); // roundId not supported, hardcoded to 1.

// Source updates were more than 30 minutes apart, so lookback 30 minutes later should return the same answer.
(lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(snapshotTimestamps[i] + 1800, 10);
(lookBackPrice, lookBackTimestamp, lookBackRoundId) =
sourceAdapter.tryLatestDataAt(snapshotTimestamps[i] + 1800, 10);
assertTrue(int256(snapshotAnswers[i]) == lookBackPrice);
assertTrue(snapshotTimestamps[i] == lookBackTimestamp);
assertTrue(lookBackRoundId == 1); // roundId not supported, hardcoded to 1.

// Source updates were more than 30 minutes apart, so lookback 30 minutes earlier should return the previous answer,
// except for the first snapshot which should return the same answer as it does not have earlier data.
(lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(snapshotTimestamps[i] - 1800, 10);
(lookBackPrice, lookBackTimestamp, lookBackRoundId) =
sourceAdapter.tryLatestDataAt(snapshotTimestamps[i] - 1800, 10);
assertTrue(lookBackRoundId == 1); // roundId not supported, hardcoded to 1.
if (i > 0) {
assertTrue(int256(snapshotAnswers[i - 1]) == lookBackPrice);
assertTrue(snapshotTimestamps[i - 1] == lookBackTimestamp);
Expand All @@ -117,11 +124,12 @@ contract UniswapAnchoredViewSourceAdapterTest is CommonTest {
// If we limit how far we can lookback the source adapter snapshot should correctly return the oldest data it
// can find, up to that limit. When searching for the earliest possible snapshot while limiting maximum snapshot
// traversal to 1 we should still get the latest data.
(int256 lookBackPrice, uint256 lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(0, 1);
(int256 lookBackPrice, uint256 lookBackTimestamp, uint256 lookBackRoundId) = sourceAdapter.tryLatestDataAt(0, 1);
uint256 latestUniswapAnchoredViewAnswer = uniswapAnchoredView.getUnderlyingPrice(cToken);
uint256 latestAggregatorTimestamp = aggregator.latestTimestamp();
assertTrue(int256(latestUniswapAnchoredViewAnswer) == lookBackPrice);
assertTrue(latestAggregatorTimestamp == lookBackTimestamp);
assertTrue(lookBackRoundId == 1); // roundId not supported, hardcoded to 1.
}

function testUpgradeAggregator() public {
Expand Down
4 changes: 2 additions & 2 deletions test/unit/Oval.ChainlinkDestinationAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ contract OvalChainlinkDestinationAdapter is CommonTest {
oval.latestRoundData();

// Check that Oval return the correct values scaled to the source oracle decimals.
assertTrue(roundId == 2);
assertTrue(roundId == 2); // We published twice and roundId starts at 1.
assertTrue(answer == newAnswer / internalDecimalsToSourceDecimals);
assertTrue(startedAt == newTimestamp);
assertTrue(updatedAt == newTimestamp);
assertTrue(answeredInRound == 2);
assertTrue(answeredInRound == 2); // We published twice and roundId starts at 1.
}
}
3 changes: 2 additions & 1 deletion test/unit/Oval.UniswapAnchoredViewDestinationAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {CommonTest} from "../Common.sol";
contract OvalUniswapAnchoredViewDestinationAdapter is CommonTest {
int256 newAnswer = 1900 * 1e18;
uint256 newTimestamp = 1690000000;
uint256 roundId = 1; // UniswapAnchoredView does not support roundId and has it hardcoded to 1.

int256 internalDecimalsToSourceDecimals = 1e10;

Expand Down Expand Up @@ -75,7 +76,7 @@ contract OvalUniswapAnchoredViewDestinationAdapter is CommonTest {
vm.mockCall(
OvalAddress,
abi.encodeWithSelector(IOval.internalLatestData.selector),
abi.encode(newAnswer, newTimestamp, 1)
abi.encode(newAnswer, newTimestamp, roundId)
);
uint256 underlyingPrice = destinationAdapter.getUnderlyingPrice(cTokenAddress);

Expand Down

0 comments on commit f2d0ff3

Please sign in to comment.