diff --git a/.gas-snapshot b/.gas-snapshot index 45766c3..20cd0d6 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,72 +1,72 @@ -QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 65090324, ~: 74975370) -QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 64771162, ~: 74583507) -QueryProcessorTest:testFindNearestSample_NotInitialized() (gas: 1056945756) -QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80327, ~: 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, μ: 27016, ~: 27087) -QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 70591497, ~: 80271384) -QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 69164823, ~: 77928090) -QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 69194817, ~: 77959690) -QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 64744868, ~: 74555386) -QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 64778894, ~: 74589515) -QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 64736471, ~: 74546552) -QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 64748015, ~: 74556435) -QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 102669133, ~: 112352230) -QueryProcessorTest:testGetTimeWeightedAverage_BadSecs() (gas: 10995) -ReservoirPriceOracleTest:testClearRoute() (gas: 52339) -ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 159879) -ReservoirPriceOracleTest:testDesignatePair() (gas: 29068) -ReservoirPriceOracleTest:testDesignatePair_IncorrectPair() (gas: 21155) -ReservoirPriceOracleTest:testDesignatePair_NotOwner() (gas: 17553) -ReservoirPriceOracleTest:testDesignatePair_TokenOrderReversed() (gas: 30639) -ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 34001, ~: 34118) -ReservoirPriceOracleTest:testGetQuote_AmountInTooLarge() (gas: 12963) -ReservoirPriceOracleTest:testGetQuote_BaseIsVault(uint256) (runs: 256, μ: 411282, ~: 411040) -ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10354017) -ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 36138, ~: 36254) -ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 111841) -ReservoirPriceOracleTest:testGetQuote_MultipleHops_Inverse() (gas: 112163) -ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 122567) -ReservoirPriceOracleTest:testGetQuote_NoFallbackOracle() (gas: 20820) -ReservoirPriceOracleTest:testGetQuote_PriceZero() (gas: 15958) -ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5329100, ~: 5329104) -ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10496290, ~: 10496408) -ReservoirPriceOracleTest:testGetQuote_SameBaseQuote(uint256,address) (runs: 256, μ: 8941, ~: 8941) -ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 38334) -ReservoirPriceOracleTest:testGetQuote_ZeroIn() (gas: 36975) -ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 26512, ~: 26629) -ReservoirPriceOracleTest:testPriceCache_Inverted() (gas: 22001) -ReservoirPriceOracleTest:testSetFallbackOracle_NotOwner() (gas: 10938) -ReservoirPriceOracleTest:testSetRoute() (gas: 61093) -ReservoirPriceOracleTest:testSetRoute_InvalidRewardThreshold() (gas: 37330) -ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 20154) -ReservoirPriceOracleTest:testSetRoute_InvalidRouteLength() (gas: 19294) -ReservoirPriceOracleTest:testSetRoute_MultipleHops() (gas: 201309) -ReservoirPriceOracleTest:testSetRoute_NotSorted() (gas: 13028) -ReservoirPriceOracleTest:testSetRoute_OverwriteExisting() (gas: 169666) -ReservoirPriceOracleTest:testSetRoute_SameToken() (gas: 13041) -ReservoirPriceOracleTest:testUndesignatePair() (gas: 30256) -ReservoirPriceOracleTest:testUndesignatePair_NotOwner() (gas: 15355) -ReservoirPriceOracleTest:testUpdatePrice_AboveThresholdBelowMaxReward(uint256) (runs: 256, μ: 165939, ~: 165959) -ReservoirPriceOracleTest:testUpdatePrice_BelowThreshold(uint256) (runs: 256, μ: 150797, ~: 150473) -ReservoirPriceOracleTest:testUpdatePrice_BeyondMaxReward(uint256) (runs: 256, μ: 163444, ~: 163469) -ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 154418) -ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 16111065) -ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5353482) -ReservoirPriceOracleTest:testUpdatePrice_RewardEligible_ContractNoReceive() (gas: 153582) -ReservoirPriceOracleTest:testUpdatePrice_RewardEligible_InsufficientReward(uint256) (runs: 256, μ: 212147, ~: 212363) -ReservoirPriceOracleTest:testUpdatePrice_RewardEligible_ZeroRecipient() (gas: 147250) -ReservoirPriceOracleTest:testUpdateRewardGasAmount() (gas: 19039) -ReservoirPriceOracleTest:testUpdateRewardGasAmount_NotOwner() (gas: 10940) -ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21687, ~: 21778) -ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17825, ~: 18120) -ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 30219, ~: 29977) -RoutesLibTest:testGetDecimalDifference() (gas: 3974) -RoutesLibTest:testIsCompositeRoute() (gas: 4341) -RoutesLibTest:testPackSimplePrice(int8,uint256) (runs: 256, μ: 8200, ~: 7962) -SamplesTest:testAccumulator() (gas: 3959) -SamplesTest:testAccumulator_BadVariableRequest() (gas: 3523) -SamplesTest:testInstant() (gas: 3909) -SamplesTest:testInstant_BadVariableRequest() (gas: 3566) \ No newline at end of file +QueryProcessorTest:testFindNearestSample_CanFindExactValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 65806302, ~: 74826166) +QueryProcessorTest:testFindNearestSample_CanFindIntermediateValue(uint32,uint256,uint256,uint256) (runs: 256, μ: 64996916, ~: 74226210) +QueryProcessorTest:testFindNearestSample_NotInitialized() (gas: 1056944892) +QueryProcessorTest:testFindNearestSample_OneSample(uint256) (runs: 256, μ: 80136, ~: 80169) +QueryProcessorTest:testGetInstantValue() (gas: 123891) +QueryProcessorTest:testGetInstantValue_NotInitialized(uint256) (runs: 256, μ: 19378, ~: 19378) +QueryProcessorTest:testGetInstantValue_NotInitialized_BeyondBufferSize(uint8,uint16) (runs: 256, μ: 68260435, ~: 68260368) +QueryProcessorTest:testGetPastAccumulator_BufferEmpty(uint8) (runs: 256, μ: 26902, ~: 26962) +QueryProcessorTest:testGetPastAccumulator_ExactMatch(uint32,uint256,uint256,uint16) (runs: 256, μ: 71271543, ~: 80081087) +QueryProcessorTest:testGetPastAccumulator_ExactMatch_LatestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 67118170, ~: 76073918) +QueryProcessorTest:testGetPastAccumulator_ExactMatch_OldestAccumulator(uint32,uint256,uint256) (runs: 256, μ: 67147892, ~: 76105399) +QueryProcessorTest:testGetPastAccumulator_ExtrapolatesBeyondLatest(uint32,uint256,uint256,uint256) (runs: 256, μ: 64971065, ~: 74197796) +QueryProcessorTest:testGetPastAccumulator_InterpolatesBetweenPastAccumulators(uint32,uint256,uint256,uint256) (runs: 256, μ: 65004847, ~: 74232436) +QueryProcessorTest:testGetPastAccumulator_InvalidAgo(uint32,uint256,uint256,uint256) (runs: 256, μ: 64962680, ~: 74189873) +QueryProcessorTest:testGetPastAccumulator_QueryTooOld(uint32,uint256,uint256,uint256) (runs: 256, μ: 64974173, ~: 74199723) +QueryProcessorTest:testGetTimeWeightedAverage(uint32,uint256,uint256,uint256,uint256) (runs: 256, μ: 107958222, ~: 115516665) +QueryProcessorTest:testGetTimeWeightedAverage_BadSecs() (gas: 10981) +ReservoirPriceOracleTest:testClearRoute() (gas: 52216) +ReservoirPriceOracleTest:testClearRoute_AllWordsCleared() (gas: 159654) +ReservoirPriceOracleTest:testDesignatePair() (gas: 29038) +ReservoirPriceOracleTest:testDesignatePair_IncorrectPair() (gas: 21133) +ReservoirPriceOracleTest:testDesignatePair_NotOwner() (gas: 17541) +ReservoirPriceOracleTest:testDesignatePair_TokenOrderReversed() (gas: 30605) +ReservoirPriceOracleTest:testGetQuote(uint256,uint256) (runs: 256, μ: 33681, ~: 33805) +ReservoirPriceOracleTest:testGetQuote_AmountInTooLarge() (gas: 12950) +ReservoirPriceOracleTest:testGetQuote_BaseIsVault(uint256) (runs: 256, μ: 401378, ~: 401124) +ReservoirPriceOracleTest:testGetQuote_ComplicatedDecimals() (gas: 10127860) +ReservoirPriceOracleTest:testGetQuote_Inverse(uint256,uint256) (runs: 256, μ: 35804, ~: 35867) +ReservoirPriceOracleTest:testGetQuote_MultipleHops() (gas: 111603) +ReservoirPriceOracleTest:testGetQuote_MultipleHops_Inverse() (gas: 111924) +ReservoirPriceOracleTest:testGetQuote_MultipleHops_PriceZero() (gas: 122238) +ReservoirPriceOracleTest:testGetQuote_NoFallbackOracle() (gas: 20788) +ReservoirPriceOracleTest:testGetQuote_PriceZero() (gas: 15930) +ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_1HopRoute(uint256,uint256,address,address,uint8,uint8) (runs: 256, μ: 5198032, ~: 5198035) +ReservoirPriceOracleTest:testGetQuote_RandomizeAllParam_2HopRoute(uint256,uint256,uint256,address,address,address,uint8,uint8,uint8) (runs: 256, μ: 10269567, ~: 10269655) +ReservoirPriceOracleTest:testGetQuote_SameBaseQuote(uint256,address) (runs: 256, μ: 8927, ~: 8927) +ReservoirPriceOracleTest:testGetQuote_UseFallback() (gas: 38250) +ReservoirPriceOracleTest:testGetQuote_ZeroIn() (gas: 36635) +ReservoirPriceOracleTest:testGetQuotes(uint256,uint256) (runs: 256, μ: 26203, ~: 26327) +ReservoirPriceOracleTest:testPriceCache_Inverted() (gas: 21949) +ReservoirPriceOracleTest:testSetFallbackOracle_NotOwner() (gas: 10928) +ReservoirPriceOracleTest:testSetRoute() (gas: 61014) +ReservoirPriceOracleTest:testSetRoute_InvalidRewardThreshold() (gas: 37278) +ReservoirPriceOracleTest:testSetRoute_InvalidRoute() (gas: 20106) +ReservoirPriceOracleTest:testSetRoute_InvalidRouteLength() (gas: 19253) +ReservoirPriceOracleTest:testSetRoute_MultipleHops() (gas: 201105) +ReservoirPriceOracleTest:testSetRoute_NotSorted() (gas: 13006) +ReservoirPriceOracleTest:testSetRoute_OverwriteExisting() (gas: 169491) +ReservoirPriceOracleTest:testSetRoute_SameToken() (gas: 13019) +ReservoirPriceOracleTest:testUndesignatePair() (gas: 30215) +ReservoirPriceOracleTest:testUndesignatePair_NotOwner() (gas: 15344) +ReservoirPriceOracleTest:testUpdatePrice_AboveThresholdBelowMaxReward(uint256) (runs: 256, μ: 163637, ~: 163657) +ReservoirPriceOracleTest:testUpdatePrice_BelowThreshold(uint256) (runs: 256, μ: 148532, ~: 148476) +ReservoirPriceOracleTest:testUpdatePrice_BeyondMaxReward(uint256) (runs: 256, μ: 161152, ~: 161177) +ReservoirPriceOracleTest:testUpdatePrice_FirstUpdate() (gas: 152255) +ReservoirPriceOracleTest:testUpdatePrice_IntermediateRoutes() (gas: 15927172) +ReservoirPriceOracleTest:testUpdatePrice_PriceOutOfRange() (gas: 5288225) +ReservoirPriceOracleTest:testUpdatePrice_RewardEligible_ContractNoReceive() (gas: 151436) +ReservoirPriceOracleTest:testUpdatePrice_RewardEligible_InsufficientReward(uint256) (runs: 256, μ: 209567, ~: 209771) +ReservoirPriceOracleTest:testUpdatePrice_RewardEligible_ZeroRecipient() (gas: 145106) +ReservoirPriceOracleTest:testUpdateRewardGasAmount() (gas: 19027) +ReservoirPriceOracleTest:testUpdateRewardGasAmount_NotOwner() (gas: 10930) +ReservoirPriceOracleTest:testUpdateTwapPeriod(uint256) (runs: 256, μ: 21571, ~: 21656) +ReservoirPriceOracleTest:testUpdateTwapPeriod_InvalidTwapPeriod(uint256) (runs: 256, μ: 17706, ~: 17994) +ReservoirPriceOracleTest:testWritePriceCache(uint256) (runs: 256, μ: 30061, ~: 29807) +RoutesLibTest:testGetDecimalDifference() (gas: 3966) +RoutesLibTest:testIsCompositeRoute() (gas: 4332) +RoutesLibTest:testPackSimplePrice(int8,uint256) (runs: 256, μ: 8097, ~: 7862) +SamplesTest:testAccumulator() (gas: 3952) +SamplesTest:testAccumulator_BadVariableRequest() (gas: 3355) +SamplesTest:testInstant() (gas: 3902) +SamplesTest:testInstant_BadVariableRequest() (gas: 3398) \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 870f249..49d4e58 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "lib/solady"] path = lib/solady url = https://github.com/Vectorized/solady +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/openzeppelin/openzeppelin-contracts diff --git a/README.md b/README.md index d86ed45..510d642 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,15 @@ For direct usages of the oracle, refer to [IReservoirPriceOracle.sol](src/interfaces/IReservoirPriceOracle.sol) for methods to obtain raw data from the AMM pairs. +## EVM Compatibility + +Currently the `ReservoirPriceOracle` contract makes use of the transient storage +supported since the Cancun fork via OZ's `ReentrancyGuardTransient` lib. +At the time of writing only ETH mainnet is supported. +If deployment to other chains where transient storage is not yet supported, +we can revert to using solady's `ReentrancyGuard` for the most gas efficient +implementation. + ## Usage ### Install diff --git a/foundry.toml b/foundry.toml index 2df2a55..35b800e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,5 +1,6 @@ [profile.default] -solc = "0.8.26" +solc = "0.8.28" +evm_version = "cancun" bytecode_hash = "ipfs" optimizer_runs = 1_000_000 libs = ['lib'] diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 0000000..69c8def --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 69c8def5f222ff96f2b5beff05dfba996368aa79 diff --git a/lib/solady b/lib/solady index 183a5c9..1c9927e 160000 --- a/lib/solady +++ b/lib/solady @@ -1 +1 @@ -Subproject commit 183a5c9cc3ca982492ae5fcca9e7ed6668ddb6ac +Subproject commit 1c9927e9eb0c280c44c81c943976fe8995b382ed diff --git a/package-lock.json b/package-lock.json index b02861b..57e5fd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "markdownlint": "0.34.0", "markdownlint-cli": "0.31.1", "prettier": "3.3.1", - "solhint": "5.0.1", + "solhint": "5.0.3", "ts-node": "10.8.1" } }, @@ -1402,9 +1402,9 @@ } }, "node_modules/solhint": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.1.tgz", - "integrity": "sha512-QeQLS9HGCnIiibt+xiOa/+MuP7BWz9N7C5+Mj9pLHshdkNhuo3AzCpWmjfWVZBUuwIUO3YyCRVIcYLR3YOKGfg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.3.tgz", + "integrity": "sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ==", "dev": true, "dependencies": { "@solidity-parser/parser": "^0.18.0", @@ -2745,9 +2745,9 @@ } }, "solhint": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.1.tgz", - "integrity": "sha512-QeQLS9HGCnIiibt+xiOa/+MuP7BWz9N7C5+Mj9pLHshdkNhuo3AzCpWmjfWVZBUuwIUO3YyCRVIcYLR3YOKGfg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.3.tgz", + "integrity": "sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ==", "dev": true, "requires": { "@solidity-parser/parser": "^0.18.0", diff --git a/package.json b/package.json index 6f3fa5e..59de569 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "markdownlint": "0.34.0", "markdownlint-cli": "0.31.1", "prettier": "3.3.1", - "solhint": "5.0.1", + "solhint": "5.0.3", "ts-node": "10.8.1" } } diff --git a/src/.solhint.json b/src/.solhint.json index 74001ce..d6f3959 100644 --- a/src/.solhint.json +++ b/src/.solhint.json @@ -4,6 +4,7 @@ "compiler-version": ["error", ">=0.8.0"], "func-visibility": ["error", { "ignoreConstructors": true }], "not-rely-on-time": "off", - "no-inline-assembly": "off" + "no-inline-assembly": "off", + "gas-custom-errors": "off" } } diff --git a/src/ReservoirPriceOracle.sol b/src/ReservoirPriceOracle.sol index a68a3b7..fd70bdc 100644 --- a/src/ReservoirPriceOracle.sol +++ b/src/ReservoirPriceOracle.sol @@ -10,13 +10,13 @@ import { IPriceOracle } from "src/interfaces/IPriceOracle.sol"; import { QueryProcessor, ReservoirPair, 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"; +import { ReentrancyGuardTransient } from "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol"; import { FixedPointMathLib } from "lib/amm-core/lib/solady/src/utils/FixedPointMathLib.sol"; import { LibSort } from "lib/solady/src/utils/LibSort.sol"; import { Constants } from "src/libraries/Constants.sol"; import { RoutesLib } from "src/libraries/RoutesLib.sol"; -contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuard { +contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuardTransient { using FixedPointMathLib for uint256; using LibSort for address[]; using RoutesLib for bytes32; @@ -143,7 +143,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar (address[] memory lRoute,, uint256 lPrevPrice, uint256 lRewardThreshold) = _getRouteDecimalDifferencePrice(lToken0, lToken1); - if (lRoute.length == 0) revert OracleErrors.NoPath(); + require(lRoute.length != 0, OracleErrors.NoPath()); for (uint256 i = 0; i < lRoute.length - 1; ++i) { (lToken0, lToken1) = Utils.sortTokens(lRoute[i], lRoute[i + 1]); @@ -179,11 +179,11 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar /////////////////////////////////////////////////////////////////////////////////////////////// function _validatePair(ReservoirPair aPair) private pure { - if (address(aPair) == address(0)) revert OracleErrors.NoDesignatedPair(); + require(address(aPair) != address(0), OracleErrors.NoDesignatedPair()); } function _validateTokens(address aToken0, address aToken1) private pure { - if (aToken1 <= aToken0) revert OracleErrors.InvalidTokensProvided(); + require(aToken0 < aToken1, OracleErrors.InvalidTokensProvided()); } function _getTimeWeightedAverageSingle(OracleAverageQuery memory aQuery) private view returns (uint256 rResult) { @@ -195,7 +195,8 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar } function _calculateReward(uint256 aPrevPrice, uint256 aNewPrice, uint256 aRewardThreshold) - private returns (uint256 rReward) + private + returns (uint256 rReward) { // SAFETY: this mul will not overflow as 0 < `aRewardThreshold` <= `Constants.BP_SCALE`, as checked by `setRoute` uint256 lRewardThresholdWAD; @@ -331,14 +332,14 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar } function _writePriceCache(address aToken0, address aToken1, uint256 aNewPrice) private { - if (aNewPrice == 0 || aNewPrice > Constants.MAX_SUPPORTED_PRICE) revert OracleErrors.PriceOutOfRange(aNewPrice); + require(aNewPrice != 0 && aNewPrice <= Constants.MAX_SUPPORTED_PRICE, OracleErrors.PriceOutOfRange(aNewPrice)); bytes32 lSlot = Utils.calculateSlot(aToken0, aToken1); bytes32 lData; assembly ("memory-safe") { lData := sload(lSlot) } - if (!lData.isSimplePrice()) revert OracleErrors.WriteToNonSimpleRoute(); + require(lData.isSimplePrice(), OracleErrors.WriteToNonSimpleRoute()); lData = RoutesLib.packSimplePrice(lData.getDecimalDifference(), aNewPrice, lData.getRewardThreshold()); assembly ("memory-safe") { @@ -352,7 +353,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar returns (uint256 rBidOut, uint256 rAskOut) { if (aBase == aQuote) return (aAmount, aAmount); - if (aAmount > Constants.MAX_AMOUNT_IN) revert OracleErrors.AmountInTooLarge(); + require(aAmount <= Constants.MAX_AMOUNT_IN, OracleErrors.AmountInTooLarge()); (address lToken0, address lToken1) = Utils.sortTokens(aBase, aQuote); (address[] memory lRoute, int256 lDecimalDiff, uint256 lPrice,) = @@ -372,7 +373,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar // 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(); + require(lPrice != 0, OracleErrors.PriceZero()); rBidOut = rAskOut = _calcAmtOut(aAmount, lPrice, lDecimalDiff, lRoute[0] != aBase); } // for composite route, read simple prices to derive composite price @@ -388,7 +389,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar // it is assumed that intermediate routes defined here are simple routes and not composite routes (lPrice, lDecimalDiff,) = _priceCache(lToken0, lToken1); - if (lPrice == 0) revert OracleErrors.PriceZero(); + require(lPrice != 0, OracleErrors.PriceZero()); lIntermediateAmount = _calcAmtOut(lIntermediateAmount, lPrice, lDecimalDiff, lRoute[i] != lToken0); } rBidOut = rAskOut = lIntermediateAmount; @@ -429,7 +430,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar view returns (uint256 rBidOut, uint256 rAskOut) { - if (fallbackOracle == address(0)) revert OracleErrors.NoPath(); + require(fallbackOracle != address(0), OracleErrors.NoPath()); // We do not catch errors here so the fallback oracle will revert if it doesn't support the query. if (aIsGetQuotes) (rBidOut, rAskOut) = IPriceOracle(fallbackOracle).getQuotes(aAmount, aBase, aQuote); @@ -446,9 +447,8 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar } function updateTwapPeriod(uint64 aNewPeriod) public onlyOwner { - if (aNewPeriod == 0 || aNewPeriod > Constants.MAX_TWAP_PERIOD) { - revert OracleErrors.InvalidTwapPeriod(); - } + require(aNewPeriod != 0 && aNewPeriod <= Constants.MAX_TWAP_PERIOD, OracleErrors.InvalidTwapPeriod()); + twapPeriod = aNewPeriod; emit TwapPeriod(aNewPeriod); } @@ -461,9 +461,10 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar /// @notice Sets the pair to serve as price feed for a given route. function designatePair(address aTokenA, address aTokenB, ReservoirPair aPair) external onlyOwner { (aTokenA, aTokenB) = Utils.sortTokens(aTokenA, aTokenB); - if (aTokenA != address(aPair.token0()) || aTokenB != address(aPair.token1())) { - revert OracleErrors.IncorrectTokensDesignatePair(); - } + require( + aTokenA == address(aPair.token0()) && aTokenB == address(aPair.token1()), + OracleErrors.IncorrectTokensDesignatePair() + ); pairs[aTokenA][aTokenB] = aPair; emit DesignatePair(aTokenA, aTokenB, aPair); @@ -488,9 +489,9 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar uint256 lRouteLength = aRoute.length; _validateTokens(aToken0, aToken1); - if (lRouteLength > Constants.MAX_ROUTE_LENGTH || lRouteLength < 2) revert OracleErrors.InvalidRouteLength(); - if (aRoute[0] != aToken0 || aRoute[lRouteLength - 1] != aToken1) revert OracleErrors.InvalidRoute(); - if (aRewardThresholds.length != lRouteLength - 1) revert OracleErrors.InvalidArrayLengthRewardThresholds(); + require(lRouteLength > 1 && lRouteLength <= Constants.MAX_ROUTE_LENGTH, OracleErrors.InvalidRouteLength()); + require(aRoute[0] == aToken0 && aRoute[lRouteLength - 1] == aToken1, OracleErrors.InvalidRoute()); + require(aRewardThresholds.length == lRouteLength - 1, OracleErrors.InvalidArrayLengthRewardThresholds()); bytes32 lSlot = Utils.calculateSlot(aToken0, aToken1); @@ -498,14 +499,14 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar if (lRouteLength == 2) { uint256 lToken0Decimals = IERC20(aToken0).decimals(); uint256 lToken1Decimals = IERC20(aToken1).decimals(); - if (lToken0Decimals > 18 || lToken1Decimals > 18) revert OracleErrors.UnsupportedTokenDecimals(); + require(lToken0Decimals <= 18 && lToken1Decimals <= 18, OracleErrors.UnsupportedTokenDecimals()); int256 lDiff = int256(lToken1Decimals) - int256(lToken0Decimals); uint256 lRewardThreshold = aRewardThresholds[0]; - if (lRewardThreshold > Constants.BP_SCALE || lRewardThreshold == 0) { - revert OracleErrors.InvalidRewardThreshold(); - } + require( + lRewardThreshold <= Constants.BP_SCALE && lRewardThreshold != 0, OracleErrors.InvalidRewardThreshold() + ); bytes32 lData = RoutesLib.packSimplePrice(lDiff, 0, lRewardThreshold); assembly ("memory-safe") { diff --git a/src/libraries/QueryProcessor.sol b/src/libraries/QueryProcessor.sol index 5d6dbe3..487d5c2 100644 --- a/src/libraries/QueryProcessor.sol +++ b/src/libraries/QueryProcessor.sol @@ -36,7 +36,7 @@ library QueryProcessor { */ function getInstantValue(ReservoirPair pair, PriceType priceType, uint256 index) internal view returns (uint256) { Observation memory sample = pair.observation(index); - if (sample.timestamp == 0) revert OracleErrors.OracleNotInitialized(); + require(sample.timestamp != 0, OracleErrors.OracleNotInitialized()); int256 rawInstantValue = sample.instant(priceType); return LogCompression.fromLowResLog(rawInstantValue); @@ -52,7 +52,7 @@ library QueryProcessor { uint256 ago, uint16 latestIndex ) internal view returns (uint256) { - if (secs == 0) revert OracleErrors.BadSecs(); + require(secs != 0, OracleErrors.BadSecs()); // SAFETY: // @@ -91,7 +91,7 @@ library QueryProcessor { { // solhint-disable not-rely-on-time // `ago` must not be before the epoch. - if (block.timestamp < ago) revert OracleErrors.InvalidSeconds(); + require(ago <= block.timestamp, OracleErrors.InvalidSeconds()); uint256 lookUpTime; // SAFETY: // @@ -104,7 +104,7 @@ library QueryProcessor { uint256 latestTimestamp = latestSample.timestamp; // The latest sample only has a non-zero timestamp if no data was ever processed and stored in the buffer. - if (latestTimestamp == 0) revert OracleErrors.OracleNotInitialized(); + require(latestTimestamp != 0, OracleErrors.OracleNotInitialized()); if (latestTimestamp <= lookUpTime) { // The accumulator at times ahead of the latest one are computed by extrapolating the latest data. This is @@ -143,7 +143,7 @@ library QueryProcessor { } // Finally check that the look up time is not previous to the oldest timestamp. - if (oldestTimestamp > lookUpTime) revert OracleErrors.QueryTooOld(); + require(lookUpTime >= oldestTimestamp, OracleErrors.QueryTooOld()); } // Perform binary search to find nearest samples to the desired timestamp. diff --git a/test/integration/ReservoirPriceOracle.t.sol b/test/integration/ReservoirPriceOracle.t.sol index f59222c..0a592bd 100644 --- a/test/integration/ReservoirPriceOracle.t.sol +++ b/test/integration/ReservoirPriceOracle.t.sol @@ -9,7 +9,9 @@ contract ReservoirPriceOracleIntegrationTest is Test { vm.selectFork(lForkId); } - function testBlockBaseFee() external view { + function testBlockBaseFee() external { + // skipping for now as we're targeting mainnet instead of arbitrum + vm.skip(true); // assert assertEq(block.basefee, 0.01 gwei); } diff --git a/test/unit/ReservoirPriceOracle.t.sol b/test/unit/ReservoirPriceOracle.t.sol index 8a2c2b6..0ab90b9 100644 --- a/test/unit/ReservoirPriceOracle.t.sol +++ b/test/unit/ReservoirPriceOracle.t.sol @@ -692,7 +692,7 @@ contract ReservoirPriceOracleTest is BaseTest { skip(_oracle.twapPeriod()); // act - uint256 lSwapAmt = 1_000_000; + uint256 lSwapAmt = 1_000_000; _tokenA.mint(address(lAC), lSwapAmt * 10 ** _tokenA.decimals()); lAC.swap(int256(lSwapAmt * 10 ** _tokenA.decimals()), true, address(this), "");