diff --git a/test/fork/adapters/ChainlinkSourceAdapter.sol b/test/fork/adapters/ChainlinkSourceAdapter.sol index 096221f..d70ba49 100644 --- a/test/fork/adapters/ChainlinkSourceAdapter.sol +++ b/test/fork/adapters/ChainlinkSourceAdapter.sol @@ -11,7 +11,7 @@ import {IAggregatorV3Source} from "../../../src/interfaces/chainlink/IAggregator contract TestedSourceAdapter is ChainlinkSourceAdapter { constructor(IAggregatorV3Source source) ChainlinkSourceAdapter(source) {} - function internalLatestData() public view override returns (int256, uint256) {} + function internalLatestData() public view override returns (int256, uint256, uint256) {} function canUnlock(address caller, uint256 cachedLatestTimestamp) public view virtual override returns (bool) {} @@ -44,7 +44,7 @@ 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 lookBackPrice, uint256 lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 10); (, 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); @@ -52,7 +52,7 @@ contract ChainlinkSourceAdapterTest is CommonTest { // 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); + (lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 10); (, 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); @@ -61,7 +61,7 @@ contract ChainlinkSourceAdapterTest is CommonTest { // 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); + (lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 10); (, 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. @@ -72,7 +72,7 @@ contract ChainlinkSourceAdapterTest is CommonTest { // 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,) = sourceAdapter.tryLatestDataAt(targetTime, 2); (uint80 latestRound,,,,) = chainlink.latestRoundData(); (, int256 answer, uint256 startedAt,,) = chainlink.getRoundData(latestRound - 2); assertTrue(scaleChainlinkTo18(answer) == lookBackPrice); @@ -80,11 +80,11 @@ contract ChainlinkSourceAdapterTest is CommonTest { // 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,) = sourceAdapter.tryLatestDataAt(targetTime, 2); assertTrue(scaleChainlinkTo18(answer) == lookBackPrice); assertTrue(startedAt == lookBackTimestamp); targetTime = block.timestamp - 10 hours; - (lookBackPrice, lookBackTimestamp) = sourceAdapter.tryLatestDataAt(targetTime, 2); + (lookBackPrice, lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 2); assertTrue(scaleChainlinkTo18(answer) == lookBackPrice); assertTrue(startedAt == lookBackTimestamp); } @@ -94,7 +94,7 @@ contract ChainlinkSourceAdapterTest is CommonTest { (, int256 answer,, uint256 updatedAt,) = chainlink.latestRoundData(); - (int256 lookBackPrice, uint256 lookBackTimestamp) = sourceAdapter.tryLatestDataAt(targetTime, 0); + (int256 lookBackPrice, uint256 lookBackTimestamp,) = sourceAdapter.tryLatestDataAt(targetTime, 0); assertEq(lookBackPrice / 10 ** 10, answer); assertEq(lookBackTimestamp, updatedAt); } @@ -108,7 +108,7 @@ 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,) = sourceAdapter.tryLatestDataAt(block.timestamp - 2 hours, 10); (, int256 latestAnswer,, uint256 latestUpdatedAt,) = chainlink.latestRoundData(); diff --git a/test/fork/adapters/UniswapAnchoredViewSourceAdapter.sol b/test/fork/adapters/UniswapAnchoredViewSourceAdapter.sol index e1bf827..f6ba3d1 100644 --- a/test/fork/adapters/UniswapAnchoredViewSourceAdapter.sol +++ b/test/fork/adapters/UniswapAnchoredViewSourceAdapter.sol @@ -12,7 +12,7 @@ import {IUniswapAnchoredView} from "../../../src/interfaces/compound/IUniswapAnc contract TestedSourceAdapter is UniswapAnchoredViewSourceAdapter { constructor(IUniswapAnchoredView source, address cToken) UniswapAnchoredViewSourceAdapter(source, cToken) {} - function internalLatestData() public view override returns (int256, uint256) {} + function internalLatestData() public view override returns (int256, uint256, uint256) {} function canUnlock(address caller, uint256 cachedLatestTimestamp) public view virtual override returns (bool) {} function lockWindow() public view virtual override returns (uint256) {} function maxTraversal() public view virtual override returns (uint256) {} @@ -78,7 +78,7 @@ 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,) = sourceAdapter.tryLatestDataAt(targetTime, 100); assertTrue(int256(latestUniswapAnchoredViewAnswer) == lookBackPrice); assertTrue(latestAggregatorTimestamp == lookBackTimestamp); } @@ -88,18 +88,19 @@ contract UniswapAnchoredViewSourceAdapterTest is CommonTest { for (uint256 i = 0; i < snapshotAnswers.length; i++) { // Lookback at exact snapshot timestamp should return the same answer and timestamp. - (int256 lookBackPrice, uint256 lookBackTimestamp) = sourceAdapter.tryLatestDataAt(snapshotTimestamps[i], 10); + (int256 lookBackPrice, uint256 lookBackTimestamp,) = + sourceAdapter.tryLatestDataAt(snapshotTimestamps[i], 10); assertTrue(int256(snapshotAnswers[i]) == lookBackPrice); assertTrue(snapshotTimestamps[i] == lookBackTimestamp); // 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,) = sourceAdapter.tryLatestDataAt(snapshotTimestamps[i] + 1800, 10); assertTrue(int256(snapshotAnswers[i]) == lookBackPrice); assertTrue(snapshotTimestamps[i] == lookBackTimestamp); // 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,) = sourceAdapter.tryLatestDataAt(snapshotTimestamps[i] - 1800, 10); if (i > 0) { assertTrue(int256(snapshotAnswers[i - 1]) == lookBackPrice); assertTrue(snapshotTimestamps[i - 1] == lookBackTimestamp); @@ -116,7 +117,7 @@ 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,) = sourceAdapter.tryLatestDataAt(0, 1); uint256 latestUniswapAnchoredViewAnswer = uniswapAnchoredView.getUnderlyingPrice(cToken); uint256 latestAggregatorTimestamp = aggregator.latestTimestamp(); assertTrue(int256(latestUniswapAnchoredViewAnswer) == lookBackPrice); diff --git a/test/mocks/MockSnapshotSourceAdapter.sol b/test/mocks/MockSnapshotSourceAdapter.sol index 76b2413..ff8a2a7 100644 --- a/test/mocks/MockSnapshotSourceAdapter.sol +++ b/test/mocks/MockSnapshotSourceAdapter.sol @@ -25,10 +25,10 @@ abstract contract MockSnapshotSourceAdapter is SnapshotSource { view virtual override - returns (int256, uint256) + returns (int256, uint256, uint256) { SnapshotSource.Snapshot memory latestData = _tryLatestDataAt(timestamp, maxTraversal); - return (latestData.answer, latestData.timestamp); + return (latestData.answer, latestData.timestamp, 1); } function _latestSourceData() internal view returns (SourceData memory) { diff --git a/test/mocks/MockSourceAdapter.sol b/test/mocks/MockSourceAdapter.sol index 1b213a6..a73dac9 100644 --- a/test/mocks/MockSourceAdapter.sol +++ b/test/mocks/MockSourceAdapter.sol @@ -9,6 +9,7 @@ abstract contract MockSourceAdapter is DiamondRootOval { struct RoundData { int256 answer; uint256 timestamp; + uint256 roundId; // Assigned automatically, starting at 1. } RoundData[] public rounds; @@ -20,7 +21,7 @@ abstract contract MockSourceAdapter is DiamondRootOval { function snapshotData() public override {} function publishRoundData(int256 answer, uint256 timestamp) public { - rounds.push(RoundData(answer, timestamp)); + rounds.push(RoundData(answer, timestamp, rounds.length + 1)); } function tryLatestDataAt(uint256 timestamp, uint256 maxTraversal) @@ -28,10 +29,10 @@ abstract contract MockSourceAdapter is DiamondRootOval { view virtual override - returns (int256, uint256) + returns (int256, uint256, uint256) { RoundData memory latestData = _tryLatestDataAt(timestamp, maxTraversal); - return (latestData.answer, latestData.timestamp); + return (latestData.answer, latestData.timestamp, latestData.roundId); } function getLatestSourceData() public view virtual override returns (int256, uint256) { @@ -41,7 +42,7 @@ abstract contract MockSourceAdapter is DiamondRootOval { function _latestRoundData() internal view returns (RoundData memory) { if (rounds.length > 0) return rounds[rounds.length - 1]; - return RoundData(0, 0); + return RoundData(0, 0, 0); } function _tryLatestDataAt(uint256 timestamp, uint256 maxTraversal) internal view returns (RoundData memory) { @@ -57,11 +58,11 @@ abstract contract MockSourceAdapter is DiamondRootOval { function _searchDataAt(uint256 timestamp, uint256 maxTraversal) internal view returns (RoundData memory) { RoundData memory roundData; uint256 traversedRounds = 0; - uint256 roundId = rounds.length; + uint256 roundIndex = rounds.length; - while (traversedRounds < maxTraversal && roundId > 0) { - roundId--; - roundData = rounds[roundId]; + while (traversedRounds < maxTraversal && roundIndex > 0) { + roundIndex--; + roundData = rounds[roundIndex]; if (roundData.timestamp <= timestamp) return roundData; traversedRounds++; } diff --git a/test/unit/Oval.ChainlinkDestinationAdapter.sol b/test/unit/Oval.ChainlinkDestinationAdapter.sol index aa79987..f69c9f1 100644 --- a/test/unit/Oval.ChainlinkDestinationAdapter.sol +++ b/test/unit/Oval.ChainlinkDestinationAdapter.sol @@ -37,7 +37,7 @@ contract OvalChainlinkDestinationAdapter is CommonTest { } function verifyOvalMatchesOval() public { - (int256 latestAnswer, uint256 latestTimestamp) = oval.internalLatestData(); + (int256 latestAnswer, uint256 latestTimestamp,) = oval.internalLatestData(); assertTrue( latestAnswer / internalDecimalsToSourceDecimals == oval.latestAnswer() && latestTimestamp == oval.latestTimestamp() diff --git a/test/unit/Oval.UnlockLatestValue.sol b/test/unit/Oval.UnlockLatestValue.sol index 3bf4c26..c4236ae 100644 --- a/test/unit/Oval.UnlockLatestValue.sol +++ b/test/unit/Oval.UnlockLatestValue.sol @@ -32,7 +32,7 @@ contract OvalUnlockLatestValue is CommonTest { } function verifyOvalMatchesOval() public { - (int256 latestAnswer, uint256 latestTimestamp) = oval.internalLatestData(); + (int256 latestAnswer, uint256 latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == oval.latestAnswer() && latestTimestamp == oval.latestTimestamp()); } @@ -67,7 +67,7 @@ contract OvalUnlockLatestValue is CommonTest { vm.prank(permissionedUnlocker); oval.unlockLatestValue(); verifyOvalMatchesOval(); - (int256 latestAnswer, uint256 latestTimestamp) = oval.internalLatestData(); + (int256 latestAnswer, uint256 latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == newAnswer && latestTimestamp == newTimestamp); // Advance time. Add a diff to the source adapter and verify that it is applied. @@ -88,7 +88,7 @@ contract OvalUnlockLatestValue is CommonTest { vm.prank(random); oval.unlockLatestValue(); - (int256 latestAnswer, uint256 latestTimestamp) = oval.internalLatestData(); + (int256 latestAnswer, uint256 latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == initialPrice && latestTimestamp == initialTimestamp); } @@ -101,7 +101,7 @@ contract OvalUnlockLatestValue is CommonTest { oval.publishRoundData(newAnswer, beforeLockWindow); // Before updating, initial values from cache would be returned. - (int256 latestAnswer, uint256 latestTimestamp) = oval.internalLatestData(); + (int256 latestAnswer, uint256 latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == initialPrice && latestTimestamp == initialTimestamp); // After updating we should return the new values. @@ -119,14 +119,14 @@ contract OvalUnlockLatestValue is CommonTest { oval.publishRoundData(newAnswer, beforeOEVLockWindow); // Update the source. // Within original lock window (after OEV unlock), initial values from cache would be returned. - (int256 latestAnswer, uint256 latestTimestamp) = oval.internalLatestData(); + (int256 latestAnswer, uint256 latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == initialPrice && latestTimestamp == initialTimestamp, "1"); // Advancing time past the original lock window but before new lock window since source update // should not yet pass through source values. uint256 pastOEVLockWindow = beforeOEVLockWindow + 2; vm.warp(pastOEVLockWindow); - (latestAnswer, latestTimestamp) = oval.internalLatestData(); + (latestAnswer, latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == initialPrice && latestTimestamp == initialTimestamp); // Advancing time past the new lock window should pass through source values. @@ -144,7 +144,7 @@ contract OvalUnlockLatestValue is CommonTest { oval.publishRoundData(newAnswer, beforeLockWindow); // Before updating, initial values from cache would be returned. - (int256 latestAnswer, uint256 latestTimestamp) = oval.internalLatestData(); + (int256 latestAnswer, uint256 latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == initialPrice && latestTimestamp == initialTimestamp); // Sync and verify updated values. @@ -157,7 +157,7 @@ contract OvalUnlockLatestValue is CommonTest { oval.publishRoundData(nextNewAnswer, nextBeforeLockWindow); // Within lock window, values from previous update would be returned. - (latestAnswer, latestTimestamp) = oval.internalLatestData(); + (latestAnswer, latestTimestamp,) = oval.internalLatestData(); assertTrue(latestAnswer == newAnswer && latestTimestamp == beforeLockWindow); } }