diff --git a/.gas-snapshot b/.gas-snapshot index ecbc10e..6d70ebc 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,77 +1,77 @@ FlagsLibTest:testGetDecimalDifference() (gas: 3974) FlagsLibTest:testIsCompositeRoute() (gas: 4341) FlagsLibTest:testPackSimplePrice(int8,uint256) (runs: 256, μ: 7791, ~: 7555) -QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 64954402, ~: 72638370) -QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 65183381, ~: 74353868) +QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 65310713, ~: 72822363) +QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 64244154, ~: 73315549) QueryProcessorTest:testFindNearestSample_NotInitialized() (gas: 8937393461068805977) -QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80330, ~: 80360) +QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80331, ~: 80360) QueryProcessorTest:testGetInstantValue() (gas: 124248) QueryProcessorTest:testGetInstantValue_NotInitialized(uint256) (runs: 256, μ: 19397, ~: 19397) -QueryProcessorTest:testGetInstantValue_NotInitialized_BeyondBufferSize(uint8,uint16) (runs: 256, μ: 68389670, ~: 68389600) -QueryProcessorTest:testGetPastAccumulator_BufferEmpty(uint8) (runs: 256, μ: 27026, ~: 27087) -QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 71445048, ~: 79233749) -QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 70305328, ~: 78329546) -QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 70335354, ~: 78361146) -QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 65156996, ~: 74325443) -QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 65191146, ~: 74359876) -QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 65148574, ~: 74317294) -QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 65160165, ~: 74326834) -QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 103403746, ~: 113055688) +QueryProcessorTest:testGetInstantValue_NotInitialized_BeyondBufferSize(uint8,uint16) (runs: 256, μ: 68389665, ~: 68389600) +QueryProcessorTest:testGetPastAccumulator_BufferEmpty(uint8) (runs: 256, μ: 27021, ~: 27087) +QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 70966034, ~: 79026739) +QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 69874613, ~: 79007210) +QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 69904582, ~: 79038810) +QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 64217862, ~: 73286846) +QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 64251935, ~: 73321557) +QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 64209464, ~: 73278557) +QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 64221057, ~: 73288441) +QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 103326766, ~: 109047957) QueryProcessorTest:testGetTimeWeightedAverage_BadSecs() (gas: 10995) -ReservoirPriceOracleTest:testClearRoute() (gas: 52319) -ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 155404) -ReservoirPriceOracleTest:testDesignatePair() (gas: 29102) -ReservoirPriceOracleTest:testDesignatePair_IncorrectPair() (gas: 21222) -ReservoirPriceOracleTest:testDesignatePair_NotOwner() (gas: 17553) -ReservoirPriceOracleTest:testDesignatePair_TokenOrderReversed() (gas: 30740) -ReservoirPriceOracleTest:testGasBountyAvailable(uint256) (runs: 256, μ: 9885, ~: 9881) +ReservoirPriceOracleTest:testClearRoute() (gas: 52160) +ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 155162) +ReservoirPriceOracleTest:testDesignatePair() (gas: 29119) +ReservoirPriceOracleTest:testDesignatePair_IncorrectPair() (gas: 21206) +ReservoirPriceOracleTest:testDesignatePair_NotOwner() (gas: 17531) +ReservoirPriceOracleTest:testDesignatePair_TokenOrderReversed() (gas: 30802) +ReservoirPriceOracleTest:testGasBountyAvailable(uint256) (runs: 256, μ: 9886, ~: 9882) ReservoirPriceOracleTest:testGasBountyAvailable_Zero() (gas: 8939) -ReservoirPriceOracleTest:testGetLargestSafeQueryWindow() (gas: 8412) -ReservoirPriceOracleTest:testGetLatest(uint32) (runs: 256, μ: 92856, ~: 92787) -ReservoirPriceOracleTest:testGetLatest_Inverted() (gas: 96864) -ReservoirPriceOracleTest:testGetPastAccumulators() (gas: 196417) -ReservoirPriceOracleTest:testGetPastAccumulators_Inverted() (gas: 156850) -ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 35792, ~: 35904) -ReservoirPriceOracleTest:testGetQuote_AmountInTooLarge() (gas: 12985) -ReservoirPriceOracleTest:testGetQuote_BaseIsVault(uint256) (runs: 256, μ: 445074, ~: 444837) -ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10353280) -ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 37978, ~: 38149) -ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 114609) -ReservoirPriceOracleTest:testGetQuote_MultipleHops_Inverse() (gas: 114842) -ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 127427) -ReservoirPriceOracleTest:testGetQuote_NoFallbackOracle() (gas: 16112) -ReservoirPriceOracleTest:testGetQuote_PriceZero() (gas: 16519) -ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5328074, ~: 5328117) -ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10493915, ~: 10493914) -ReservoirPriceOracleTest:testGetQuote_SameBaseQuote(uint256,address) (runs: 256, μ: 8985, ~: 8985) -ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 37825) -ReservoirPriceOracleTest:testGetQuote_ZeroIn() (gas: 39322) -ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 33348, ~: 33460) -ReservoirPriceOracleTest:testGetTimeWeightedAverage() (gas: 142014) -ReservoirPriceOracleTest:testGetTimeWeightedAverage_Inverted() (gas: 121185) +ReservoirPriceOracleTest:testGetLargestSafeQueryWindow() (gas: 8390) +ReservoirPriceOracleTest:testGetLatest(uint32) (runs: 256, μ: 92809, ~: 92738) +ReservoirPriceOracleTest:testGetLatest_Inverted() (gas: 96793) +ReservoirPriceOracleTest:testGetPastAccumulators() (gas: 196359) +ReservoirPriceOracleTest:testGetPastAccumulators_Inverted() (gas: 156800) +ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 35817, ~: 35929) +ReservoirPriceOracleTest:testGetQuote_AmountInTooLarge() (gas: 13030) +ReservoirPriceOracleTest:testGetQuote_BaseIsVault(uint256) (runs: 256, μ: 418333, ~: 418080) +ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10353271) +ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 37981, ~: 38150) +ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 114566) +ReservoirPriceOracleTest:testGetQuote_MultipleHops_Inverse() (gas: 114799) +ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 127407) +ReservoirPriceOracleTest:testGetQuote_NoFallbackOracle() (gas: 24812) +ReservoirPriceOracleTest:testGetQuote_PriceZero() (gas: 16564) +ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5328105, ~: 5328205) +ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10493972, ~: 10494009) +ReservoirPriceOracleTest:testGetQuote_SameBaseQuote(uint256,address) (runs: 256, μ: 9030, ~: 9030) +ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 38776) +ReservoirPriceOracleTest:testGetQuote_ZeroIn() (gas: 39392) +ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 33328, ~: 33440) +ReservoirPriceOracleTest:testGetTimeWeightedAverage() (gas: 141789) +ReservoirPriceOracleTest:testGetTimeWeightedAverage_Inverted() (gas: 120964) ReservoirPriceOracleTest:testSetFallbackOracle_NotOwner() (gas: 11003) -ReservoirPriceOracleTest:testSetRoute() (gas: 58936) -ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 18049) -ReservoirPriceOracleTest:testSetRoute_InvalidRouteLength() (gas: 17655) -ReservoirPriceOracleTest:testSetRoute_MultipleHops() (gas: 196333) -ReservoirPriceOracleTest:testSetRoute_NotSorted() (gas: 12117) -ReservoirPriceOracleTest:testSetRoute_OverwriteExisting() (gas: 162732) -ReservoirPriceOracleTest:testSetRoute_SameToken() (gas: 12070) -ReservoirPriceOracleTest:testUndesignatePair() (gas: 30318) -ReservoirPriceOracleTest:testUndesignatePair_NotOwner() (gas: 15288) -ReservoirPriceOracleTest:testUpdatePriceDeviationThreshold(uint256) (runs: 256, μ: 21390, ~: 21152) -ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold() (gas: 216785) -ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_InsufficientReward(uint256) (runs: 256, μ: 205829, ~: 205771) -ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_ZeroRecipient() (gas: 198455) -ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 205996) -ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 15872304) -ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5355619) -ReservoirPriceOracleTest:testUpdatePrice_WithinThreshold() (gas: 207028) -ReservoirPriceOracleTest:testUpdateRewardGasAmount() (gas: 19033) -ReservoirPriceOracleTest:testUpdateRewardGasAmount_NotOwner() (gas: 11006) -ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21815, ~: 21892) -ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17894, ~: 18208) -ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 30058, ~: 29821) +ReservoirPriceOracleTest:testSetRoute() (gas: 58848) +ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 18005) +ReservoirPriceOracleTest:testSetRoute_InvalidRouteLength() (gas: 17611) +ReservoirPriceOracleTest:testSetRoute_MultipleHops() (gas: 196135) +ReservoirPriceOracleTest:testSetRoute_NotSorted() (gas: 12095) +ReservoirPriceOracleTest:testSetRoute_OverwriteExisting() (gas: 162578) +ReservoirPriceOracleTest:testSetRoute_SameToken() (gas: 12048) +ReservoirPriceOracleTest:testUndesignatePair() (gas: 30357) +ReservoirPriceOracleTest:testUndesignatePair_NotOwner() (gas: 15332) +ReservoirPriceOracleTest:testUpdatePriceDeviationThreshold(uint256) (runs: 256, μ: 21335, ~: 21086) +ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold() (gas: 215402) +ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_InsufficientReward(uint256) (runs: 256, μ: 204438, ~: 204649) +ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_ZeroRecipient() (gas: 197028) +ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 204525) +ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 15869132) +ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5354102) +ReservoirPriceOracleTest:testUpdatePrice_WithinThreshold() (gas: 205557) +ReservoirPriceOracleTest:testUpdateRewardGasAmount() (gas: 19055) +ReservoirPriceOracleTest:testUpdateRewardGasAmount_NotOwner() (gas: 10984) +ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21794, ~: 21871) +ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17859, ~: 18165) +ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 30031, ~: 29778) SamplesTest:testAccumulator() (gas: 3959) SamplesTest:testAccumulator_BadVariableRequest() (gas: 3523) SamplesTest:testInstant() (gas: 3909) diff --git a/src/ReservoirPriceOracle.sol b/src/ReservoirPriceOracle.sol index 47b2da0..5781156 100644 --- a/src/ReservoirPriceOracle.sol +++ b/src/ReservoirPriceOracle.sol @@ -35,7 +35,6 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg. event DesignatePair(address token0, address token1, ReservoirPair pair); event FallbackOracleSet(address fallbackOracle); event PriceDeviationThreshold(uint256 newThreshold); - event ResolvedVaultSet(address vault, address asset); event RewardGasAmount(uint256 newAmount); event Route(address token0, address token1, address[] route); event TwapPeriod(uint256 newPeriod); @@ -67,10 +66,6 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg. /// @notice Designated pairs to serve as price feed for a certain token0 and token1 mapping(address token0 => mapping(address token1 => ReservoirPair pair)) public pairs; - // TODO: Why is this needed? - /// @notice ERC4626 vaults resolved using internal pricing (`convertToAssets`). - mapping(address vault => address asset) public resolvedVaults; - /////////////////////////////////////////////////////////////////////////////////////////////// // CONSTRUCTOR, FALLBACKS // /////////////////////////////////////////////////////////////////////////////////////////////// @@ -149,13 +144,15 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg. for (uint256 i = 0; i < lRoute.length - 1; ++i) { (lToken0, lToken1) = lRoute[i].sortTokens(lRoute[i + 1]); - uint256 lNewPrice = _getTimeWeightedAverageSingle(OracleAverageQuery( - PRICE_TYPE, - lToken0, - lToken1, - twapPeriod, - 0 // now - )); + uint256 lNewPrice = _getTimeWeightedAverageSingle( + OracleAverageQuery( + PRICE_TYPE, + lToken0, + lToken1, + twapPeriod, + 0 // now + ) + ); // assumed to be simple routes and therefore lPrevPrice would only be 0 for the first update // consider an optimization here for simple routes: no need to read the price cache again @@ -183,11 +180,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg. } } - function _getTimeWeightedAverageSingle(OracleAverageQuery memory aQuery) - private - view - returns (uint256 rResult) - { + function _getTimeWeightedAverageSingle(OracleAverageQuery memory aQuery) private view returns (uint256 rResult) { ReservoirPair lPair = pairs[aQuery.base][aQuery.quote]; _validatePair(lPair); @@ -388,15 +381,18 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg. (address[] memory lRoute, int256 lDecimalDiff, uint256 lPrice) = _getRouteDecimalDifferencePrice(lToken0, lToken1); - // route does not exist on our oracle, attempt querying the fallback if (lRoute.length == 0) { - address lBaseAsset = resolvedVaults[aBase]; - - if (lBaseAsset != address(0)) { + // There is one case where the behavior is a bit more unexpected, and that is when + // `aBase` is an empty contract, and the revert would not be caught at all, causing + // the entire operation to fail. But this is okay, because if `aBase` is not a contract, trying + // to use the fallbackOracle would not yield any results anyway. + // An alternative would be to use a low level `staticcall`. + try IERC4626(aBase).asset() returns (address rBaseAsset) { uint256 lResolvedAmountIn = IERC4626(aBase).convertToAssets(aAmount); - return _getQuotes(lResolvedAmountIn, lBaseAsset, aQuote, aIsGetQuotes); - } + return _getQuotes(lResolvedAmountIn, rBaseAsset, aQuote, aIsGetQuotes); + } catch { } // solhint-disable-line no-empty-blocks + // route does not exist on our oracle, attempt querying the fallback return _useFallbackOracle(aAmount, aBase, aQuote, aIsGetQuotes); } else if (lRoute.length == 2) { if (lPrice == 0) revert OracleErrors.PriceZero(); @@ -512,14 +508,6 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg. emit DesignatePair(aToken0, aToken1, ReservoirPair(address(0))); } - // TODO: What's the use case for these vaults? Is it to price wrapped tokens - // without needing a market? - function setResolvedVault(address aVault, bool aSet) external onlyOwner { - address lAsset = aSet ? IERC4626(aVault).asset() : address(0); - resolvedVaults[aVault] = lAsset; - emit ResolvedVaultSet(aVault, lAsset); - } - /// @notice Sets the price route between aToken0 and aToken1, and also intermediate routes if previously undefined /// @param aToken0 Address of the lower token /// @param aToken1 Address of the higher token diff --git a/test/unit/ReservoirPriceOracle.t.sol b/test/unit/ReservoirPriceOracle.t.sol index f85e3dc..9b2dced 100644 --- a/test/unit/ReservoirPriceOracle.t.sol +++ b/test/unit/ReservoirPriceOracle.t.sol @@ -415,7 +415,6 @@ contract ReservoirPriceOracleTest is BaseTest { // arrange uint256 lAmtIn = 5e18; StubERC4626 lVault = new StubERC4626(address(_tokenA), lRate); - _oracle.setResolvedVault(address(lVault), true); _writePriceCache(address(_tokenA), address(_tokenB), 1e18); // act @@ -1064,7 +1063,7 @@ contract ReservoirPriceOracleTest is BaseTest { function testGetQuote_NoFallbackOracle() external { // act & assert vm.expectRevert(OracleErrors.NoPath.selector); - _oracle.getQuote(123, address(123), address(456)); + _oracle.getQuote(123, address(_tokenD), address(_tokenA)); } function testGetQuote_PriceZero() external {