Skip to content

Commit

Permalink
feat: PriceType config
Browse files Browse the repository at this point in the history
* refactor: rename `Variable` into `PriceType`
* feat: make `priceType` configurable
* gas: update snapshot
* fix: mark visibility of public variable
* gas: update snapshot
* fix: read price type from storage during `updatePrice`
* gas: update snapshot
  • Loading branch information
xenide authored Jun 7, 2024
1 parent 3d403d4 commit a241b6a
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 125 deletions.
90 changes: 45 additions & 45 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,76 +1,76 @@
FlagsLibTest:testGetDecimalDifference() (gas: 3974)
FlagsLibTest:testIsCompositeRoute() (gas: 4341)
FlagsLibTest:testPackSimplePrice(int8,uint256) (runs: 256, μ: 7794, ~: 7555)
QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 67359104, ~: 75557360)
QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 72740235, ~: 82229136)
QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 69058566, ~: 77743481)
QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 72812141, ~: 81208062)
QueryProcessorTest:testFindNearestSample_NotInitialized() (gas: 8937393461068805977)
QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80321, ~: 80360)
QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80315, ~: 80360)
QueryProcessorTest:testGetInstantValue() (gas: 124248)
QueryProcessorTest:testGetInstantValue_NotInitialized(uint256) (runs: 256, μ: 19397, ~: 19397)
QueryProcessorTest:testGetInstantValue_NotInitialized_BeyondBufferSize(uint8,uint16) (runs: 256, μ: 68389639, ~: 68389599)
QueryProcessorTest:testGetPastAccumulator_BufferEmpty(uint8) (runs: 256, μ: 27031, ~: 27087)
QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 68735833, ~: 78421559)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 67855253, ~: 76188526)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 67885080, ~: 76220126)
QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 72713324, ~: 82200036)
QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 72747625, ~: 82235144)
QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 72704951, ~: 82192090)
QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 72716162, ~: 82201974)
QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 109440354, ~: 113540903)
QueryProcessorTest:testGetInstantValue_NotInitialized_BeyondBufferSize(uint8,uint16) (runs: 256, μ: 68389643, ~: 68389600)
QueryProcessorTest:testGetPastAccumulator_BufferEmpty(uint8) (runs: 256, μ: 27022, ~: 27087)
QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 69817768, ~: 78996938)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 68901555, ~: 79087570)
QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 68931370, ~: 79119170)
QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 72785052, ~: 81179346)
QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 72819515, ~: 81214070)
QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 72776690, ~: 81171057)
QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 72787880, ~: 81180941)
QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 108173406, ~: 112092926)
QueryProcessorTest:testGetTimeWeightedAverage_BadSecs() (gas: 10995)
ReservoirPriceOracleTest:testClearRoute() (gas: 52178)
ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 155206)
ReservoirPriceOracleTest:testClearRoute() (gas: 52231)
ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 155316)
ReservoirPriceOracleTest:testDesignatePair() (gas: 29135)
ReservoirPriceOracleTest:testDesignatePair_IncorrectPair() (gas: 21200)
ReservoirPriceOracleTest:testDesignatePair_NotOwner() (gas: 17531)
ReservoirPriceOracleTest:testDesignatePair_TokenOrderReversed() (gas: 30796)
ReservoirPriceOracleTest:testGasBountyAvailable(uint256) (runs: 256, μ: 9883, ~: 9881)
ReservoirPriceOracleTest:testGasBountyAvailable_Zero() (gas: 8939)
ReservoirPriceOracleTest:testGetLargestSafeQueryWindow() (gas: 8412)
ReservoirPriceOracleTest:testGetLatest(uint32) (runs: 256, μ: 92794, ~: 92731)
ReservoirPriceOracleTest:testGetLatest(uint32) (runs: 256, μ: 92782, ~: 92731)
ReservoirPriceOracleTest:testGetLatest_Inverted() (gas: 96786)
ReservoirPriceOracleTest:testGetPastAccumulators() (gas: 196383)
ReservoirPriceOracleTest:testGetPastAccumulators_Inverted() (gas: 156771)
ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 35814, ~: 35927)
ReservoirPriceOracleTest:testGetPastAccumulators_Inverted() (gas: 156794)
ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 35817, ~: 35927)
ReservoirPriceOracleTest:testGetQuote_AmountInTooLarge() (gas: 13030)
ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10353281)
ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 37970, ~: 38150)
ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 114499)
ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10353303)
ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 37978, ~: 38150)
ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 114521)
ReservoirPriceOracleTest:testGetQuote_MultipleHops_Inverse() (gas: 114821)
ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 127407)
ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 127429)
ReservoirPriceOracleTest:testGetQuote_NoFallbackOracle() (gas: 13914)
ReservoirPriceOracleTest:testGetQuote_PriceZero() (gas: 16564)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5327965, ~: 5328073)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10493988, ~: 10494081)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5327948, ~: 5328087)
ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10494021, ~: 10494095)
ReservoirPriceOracleTest:testGetQuote_SameBaseQuote(uint256,address) (runs: 256, μ: 9030, ~: 9030)
ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 35311)
ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 35304)
ReservoirPriceOracleTest:testGetQuote_ZeroIn() (gas: 39390)
ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 33347, ~: 33460)
ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 33350, ~: 33460)
ReservoirPriceOracleTest:testGetTimeWeightedAverage() (gas: 141958)
ReservoirPriceOracleTest:testGetTimeWeightedAverage_Inverted() (gas: 121129)
ReservoirPriceOracleTest:testSetFallbackOracle_NotOwner() (gas: 11003)
ReservoirPriceOracleTest:testSetRoute() (gas: 58848)
ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 17982)
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:testSetRoute() (gas: 58892)
ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 18049)
ReservoirPriceOracleTest:testSetRoute_InvalidRouteLength() (gas: 17655)
ReservoirPriceOracleTest:testSetRoute_MultipleHops() (gas: 196245)
ReservoirPriceOracleTest:testSetRoute_NotSorted() (gas: 12117)
ReservoirPriceOracleTest:testSetRoute_OverwriteExisting() (gas: 162666)
ReservoirPriceOracleTest:testSetRoute_SameToken() (gas: 12070)
ReservoirPriceOracleTest:testUndesignatePair() (gas: 30307)
ReservoirPriceOracleTest:testUndesignatePair_NotOwner() (gas: 15288)
ReservoirPriceOracleTest:testUndesignatePair_NotOwner() (gas: 15266)
ReservoirPriceOracleTest:testUpdatePriceDeviationThreshold(uint256) (runs: 256, μ: 21392, ~: 21107)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold() (gas: 216404)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_InsufficientReward(uint256) (runs: 256, μ: 205469, ~: 205672)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_ZeroRecipient() (gas: 197963)
ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 205527)
ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 15870947)
ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5355182)
ReservoirPriceOracleTest:testUpdatePrice_WithinThreshold() (gas: 206559)
ReservoirPriceOracleTest:testUpdateRewardGasAmount() (gas: 19055)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold() (gas: 216851)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_InsufficientReward(uint256) (runs: 256, μ: 205891, ~: 206097)
ReservoirPriceOracleTest:testUpdatePrice_BeyondThreshold_ZeroRecipient() (gas: 198433)
ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 205930)
ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 15872049)
ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5355607)
ReservoirPriceOracleTest:testUpdatePrice_WithinThreshold() (gas: 206962)
ReservoirPriceOracleTest:testUpdateRewardGasAmount() (gas: 19077)
ReservoirPriceOracleTest:testUpdateRewardGasAmount_NotOwner() (gas: 11006)
ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21704, ~: 21806)
ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17868, ~: 18164)
ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 29978, ~: 29777)
ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21787, ~: 21892)
ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17918, ~: 18208)
ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 29981, ~: 29777)
SamplesTest:testAccumulator() (gas: 3959)
SamplesTest:testAccumulator_BadVariableRequest() (gas: 3523)
SamplesTest:testInstant() (gas: 3909)
Expand Down
2 changes: 1 addition & 1 deletion src/Enums.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pragma solidity ^0.8.0;
// as a countermeasure to oracle manipulation attempts.
// Refer to `maxChangeRate` and `maxChangePerTrade` in `ReservoirPair` and the `Observation` struct
// Note that the price is computed *including* the tokens decimals, just like the raw price.
enum Variable {
enum PriceType {
RAW_PRICE,
CLAMPED_PRICE
}
24 changes: 18 additions & 6 deletions src/ReservoirPriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
OracleAccumulatorQuery
} from "src/interfaces/IReservoirPriceOracle.sol";
import { IPriceOracle } from "src/interfaces/IPriceOracle.sol";
import { QueryProcessor, ReservoirPair, Buffer, Variable } from "src/libraries/QueryProcessor.sol";
import { QueryProcessor, ReservoirPair, Buffer, PriceType } from "src/libraries/QueryProcessor.sol";
import { Utils } from "src/libraries/Utils.sol";
import { Owned } from "lib/amm-core/lib/solmate/src/auth/Owned.sol";
import { ReentrancyGuard } from "lib/amm-core/lib/solmate/src/utils/ReentrancyGuard.sol";
Expand All @@ -37,6 +37,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
event RewardGasAmount(uint256 newAmount);
event Route(address token0, address token1, address[] route);
event Price(address token0, address token1, uint256 price);
event SetPriceType(PriceType priceType);
event TwapPeriod(uint256 newPeriod);

///////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -47,6 +48,8 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
/// @dev If `address(0)` then there is no fallback.
address public fallbackOracle;

/// @dev the following 4 storage variables take up 1 storage slot

/// @notice percentage change greater than which, a price update may result in a reward payout of native tokens,
/// subject to availability of rewards.
/// 1e18 == 100%
Expand All @@ -59,17 +62,21 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
/// @notice TWAP period (in seconds) for querying the oracle
uint64 public twapPeriod;

/// @notice The type of price queried and stored, possibilities as defined by `PriceType`.
PriceType public priceType;

/// @notice Designated pairs to serve as price feed for a certain token0 and token1
mapping(address token0 => mapping(address token1 => ReservoirPair pair)) public pairs;

///////////////////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTOR, FALLBACKS //
///////////////////////////////////////////////////////////////////////////////////////////////

constructor(uint64 aThreshold, uint64 aTwapPeriod, uint64 aMultiplier) {
constructor(uint64 aThreshold, uint64 aTwapPeriod, uint64 aMultiplier, PriceType aType) {
updatePriceDeviationThreshold(aThreshold);
updateTwapPeriod(aTwapPeriod);
updateRewardGasAmount(aMultiplier);
setPriceType(aType);
}

/// @dev contract will hold native tokens to be distributed as gas bounty for updating the prices
Expand Down Expand Up @@ -142,7 +149,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
(lToken0, lToken1) = lRoute[i].sortTokens(lRoute[i + 1]);

lQueries[i] = OracleAverageQuery(
Variable.RAW_PRICE,
priceType,
lToken0,
lToken1,
twapPeriod,
Expand Down Expand Up @@ -188,7 +195,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
_validatePair(lPair);

(,,, uint16 lIndex) = lPair.getReserves();
uint256 lResult = lPair.getTimeWeightedAverage(lQuery.variable, lQuery.secs, lQuery.ago, lIndex);
uint256 lResult = lPair.getTimeWeightedAverage(lQuery.priceType, lQuery.secs, lQuery.ago, lIndex);
rResults[i] = lResult;
}
}
Expand All @@ -199,7 +206,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
_validatePair(lPair);

(,,, uint256 lIndex) = lPair.getReserves();
uint256 lResult = lPair.getInstantValue(aQuery.variable, lIndex);
uint256 lResult = lPair.getInstantValue(aQuery.priceType, lIndex);
return lResult;
}

Expand All @@ -218,7 +225,7 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
_validatePair(lPair);

(,,, uint16 lIndex) = lPair.getReserves();
int256 lAcc = lPair.getPastAccumulator(lQuery.variable, lIndex, lQuery.ago);
int256 lAcc = lPair.getPastAccumulator(lQuery.priceType, lIndex, lQuery.ago);
rResults[i] = lAcc;
}
}
Expand Down Expand Up @@ -493,6 +500,11 @@ contract ReservoirPriceOracle is IPriceOracle, IReservoirPriceOracle, Owned(msg.
emit DesignatePair(aToken0, aToken1, ReservoirPair(address(0)));
}

function setPriceType(PriceType aType) public onlyOwner {
priceType = aType;
emit SetPriceType(aType);
}

/// @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
12 changes: 6 additions & 6 deletions src/Structs.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import { Variable } from "src/Enums.sol";
import { PriceType } from "src/Enums.sol";

/**
* @dev Information for a Time Weighted Average query.
Expand All @@ -12,21 +12,21 @@ import { Variable } from "src/Enums.sol";
* The address of `base` is strictly less than the address of `quote`
*/
struct OracleAverageQuery {
Variable variable;
PriceType priceType;
address base;
address quote;
uint256 secs;
uint256 ago;
}

/**
* @dev Information for a query for the latest variable
* @dev Information for a query for the latest priceType
*
* Each query computes the latest instantaneous variable.
* Each query computes the latest instantaneous priceType.
* The address of `base` is strictly less than the address of `quote`
*/
struct OracleLatestQuery {
Variable variable;
PriceType priceType;
address base;
address quote;
}
Expand All @@ -38,7 +38,7 @@ struct OracleLatestQuery {
* The address of `base` is strictly less than the address of `quote`
*/
struct OracleAccumulatorQuery {
Variable variable;
PriceType priceType;
address base;
address quote;
uint256 ago;
Expand Down
4 changes: 2 additions & 2 deletions src/interfaces/IReservoirPriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ interface IReservoirPriceOracle {
returns (uint256[] memory results);

/**
* @dev Returns latest sample of `variable`. Prices are represented as 18 decimal fixed point values.
* @dev Returns latest sample of `priceType`. Prices are represented as 18 decimal fixed point values.
*/
function getLatest(OracleLatestQuery calldata variable) external view returns (uint256);
function getLatest(OracleLatestQuery calldata priceType) external view returns (uint256);

/**
* @dev Returns largest time window that can be safely queried, where 'safely' means the Oracle is guaranteed to be
Expand Down
Loading

0 comments on commit a241b6a

Please sign in to comment.