Skip to content

Commit

Permalink
fix: make external call to IERC4626 to resolve vault
Browse files Browse the repository at this point in the history
  • Loading branch information
xenide committed Jun 17, 2024
1 parent 39e8ed8 commit 2c2e1d5
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 98 deletions.
130 changes: 65 additions & 65 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
50 changes: 19 additions & 31 deletions src/ReservoirPriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 //
///////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions test/unit/ReservoirPriceOracle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 2c2e1d5

Please sign in to comment.