Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: PriceType config #8

Merged
merged 8 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading