diff --git a/src/ReservoirPriceOracle.sol b/src/ReservoirPriceOracle.sol index 9bde4aa..cf8aead 100644 --- a/src/ReservoirPriceOracle.sol +++ b/src/ReservoirPriceOracle.sol @@ -207,21 +207,15 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar view returns (uint256 rReward) { - // SAFETY: this mul will not overflow as 0 < `aRewardThreshold` <= `Constants.BP_SCALE`, as checked by `setRoute` - uint256 lRewardThresholdWAD; - unchecked { - lRewardThresholdWAD = aRewardThreshold * Constants.WAD / Constants.BP_SCALE; - } - uint256 lPercentDiff = aPrevPrice.calcPercentageDiff(aNewPrice); // SAFETY: this mul will not overflow even in extreme cases of `block.basefee`. unchecked { - if (lPercentDiff < lRewardThresholdWAD) { + if (lPercentDiff < aRewardThreshold) { return 0; } // payout max reward - else if (lPercentDiff >= lRewardThresholdWAD * MAX_REWARD_MULTIPLIER) { + else if (lPercentDiff >= aRewardThreshold * MAX_REWARD_MULTIPLIER) { // N.B. Revisit this whenever deployment on a new chain is needed // // we use `block.basefee` instead of `ArbGasInfo::getMinimumGasPrice()` @@ -230,7 +224,8 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar // congestion rReward = block.basefee * rewardGasAmount * MAX_REWARD_MULTIPLIER; } else { - rReward = block.basefee * rewardGasAmount * lPercentDiff / lRewardThresholdWAD; // denominator is never 0 + // denominator is never 0 as checked by `setRoute` + rReward = block.basefee * rewardGasAmount * lPercentDiff / aRewardThreshold; } } } @@ -300,7 +295,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar // Calculate the storage slot for this intermediate segment and read it to see if there is an existing // route. If there isn't an existing route, we create one as well. - function _checkAndPopulateIntermediateRoute(address aTokenA, address aTokenB, uint16 aBpMaxReward) private { + function _checkAndPopulateIntermediateRoute(address aTokenA, address aTokenB, uint64 aBpMaxReward) private { (address lToken0, address lToken1) = Utils.sortTokens(aTokenA, aTokenB); bytes32 lSlot = Utils.calculateSlot(lToken0, lToken1); @@ -312,9 +307,9 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar address[] memory lIntermediateRoute = new address[](2); lIntermediateRoute[0] = lToken0; lIntermediateRoute[1] = lToken1; - uint16[] memory asd = new uint16[](1); - asd[0] = aBpMaxReward; - setRoute(lToken0, lToken1, lIntermediateRoute, asd); + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = aBpMaxReward; + setRoute(lToken0, lToken1, lIntermediateRoute, lRewardThreshold); } } @@ -488,7 +483,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar /// @param aToken1 Address of the higher token. /// @param aRoute Path with which the price between aToken0 and aToken1 should be derived. /// @param aRewardThresholds Array of basis points at and beyond which a reward is applicable for a price update. - function setRoute(address aToken0, address aToken1, address[] memory aRoute, uint16[] memory aRewardThresholds) + function setRoute(address aToken0, address aToken1, address[] memory aRoute, uint64[] memory aRewardThresholds) public onlyOwner { @@ -511,7 +506,7 @@ contract ReservoirPriceOracle is IPriceOracle, Owned(msg.sender), ReentrancyGuar uint256 lRewardThreshold = aRewardThresholds[0]; require( - lRewardThreshold <= Constants.BP_SCALE && lRewardThreshold != 0, OracleErrors.InvalidRewardThreshold() + lRewardThreshold <= Constants.WAD && lRewardThreshold != 0, OracleErrors.InvalidRewardThreshold() ); bytes32 lData = RoutesLib.packSimplePrice(lDiff, 0, lRewardThreshold); diff --git a/src/libraries/Constants.sol b/src/libraries/Constants.sol index f88e93c..d4bee05 100644 --- a/src/libraries/Constants.sol +++ b/src/libraries/Constants.sol @@ -6,10 +6,9 @@ library Constants { // CONSTANTS // /////////////////////////////////////////////////////////////////////////////////////////////// + uint64 public constant WAD = 1e18; uint256 public constant MAX_TWAP_PERIOD = 1 hours; uint256 public constant MAX_ROUTE_LENGTH = 4; - uint256 public constant WAD = 1e18; uint256 public constant MAX_SUPPORTED_PRICE = type(uint128).max; uint256 public constant MAX_AMOUNT_IN = type(uint128).max; - uint16 public constant BP_SCALE = 1e4; } diff --git a/src/libraries/RoutesLib.sol b/src/libraries/RoutesLib.sol index 6daa8fe..956c95c 100644 --- a/src/libraries/RoutesLib.sol +++ b/src/libraries/RoutesLib.sol @@ -29,14 +29,14 @@ library RoutesLib { // Assumes that aDecimalDifference is between -18 and 18 // Assumes that aPrice is between 1 and `Constants.MAX_SUPPORTED_PRICE` - // Assumes that aRewardThreshold is <= `Constants.BP_SCALE` + // Assumes that aRewardThreshold is between 1 and `Constants.WAD` function packSimplePrice(int256 aDecimalDifference, uint256 aPrice, uint256 aRewardThreshold) internal pure returns (bytes32 rPacked) { bytes32 lDecimalDifferenceRaw = bytes1(uint8(int8(aDecimalDifference))); - bytes32 lRewardThreshold = bytes2(uint16(aRewardThreshold)); + bytes32 lRewardThreshold = bytes8(uint64(aRewardThreshold)); rPacked = FLAG_SIMPLE_PRICE | lDecimalDifferenceRaw >> 8 | lRewardThreshold >> 16 | bytes32(aPrice); } @@ -61,12 +61,12 @@ library RoutesLib { } function getPrice(bytes32 aData) internal pure returns (uint256 rPrice) { - rPrice = uint256(aData & 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + rPrice = uint256(aData & 0x00000000000000000000ffffffffffffffffffffffffffffffffffffffffffff); } - function getRewardThreshold(bytes32 aData) internal pure returns (uint16 rRewardThreshold) { + function getRewardThreshold(bytes32 aData) internal pure returns (uint64 rRewardThreshold) { rRewardThreshold = - uint16(uint256((aData & 0x0000ffff00000000000000000000000000000000000000000000000000000000) >> 224)); + uint64(uint256((aData & 0x0000ffffffffffffffff00000000000000000000000000000000000000000000) >> 176)); } function getTokenFirstWord(bytes32 aData) internal pure returns (address rToken) { diff --git a/src/libraries/Utils.sol b/src/libraries/Utils.sol index f7ec76a..88f28fb 100644 --- a/src/libraries/Utils.sol +++ b/src/libraries/Utils.sol @@ -14,6 +14,7 @@ library Utils { /// @dev Assumes that `aOriginal` and `aNew` is less than or equal to /// `Constants.MAX_SUPPORTED_PRICE`. So multiplication by 1e18 will not overflow. + /// 1e18 indicates a 100% difference. i.e. a doubling in price function calcPercentageDiff(uint256 aOriginal, uint256 aNew) internal pure returns (uint256) { unchecked { if (aOriginal == 0) return 0; diff --git a/test/large/ReservoirPriceOracleLarge.t.sol b/test/large/ReservoirPriceOracleLarge.t.sol index b0dd10f..df10a89 100644 --- a/test/large/ReservoirPriceOracleLarge.t.sol +++ b/test/large/ReservoirPriceOracleLarge.t.sol @@ -78,8 +78,8 @@ contract ReservoirPriceOracleLargeTest is ReservoirPriceOracleTest { lRoute[3] = aTokenAAddress; } - uint16[] memory lRewardThresholds = new uint16[](3); - lRewardThresholds[0] = lRewardThresholds[1] = lRewardThresholds[2] = Constants.BP_SCALE; + uint64[] memory lRewardThresholds = new uint64[](3); + lRewardThresholds[0] = lRewardThresholds[1] = lRewardThresholds[2] = Constants.WAD; _oracle.setRoute(lRoute[0], lRoute[3], lRoute, lRewardThresholds); _writePriceCache( diff --git a/test/unit/ReservoirPriceOracle.t.sol b/test/unit/ReservoirPriceOracle.t.sol index e35a22c..0836d6e 100644 --- a/test/unit/ReservoirPriceOracle.t.sol +++ b/test/unit/ReservoirPriceOracle.t.sol @@ -56,7 +56,7 @@ contract ReservoirPriceOracleTest is BaseTest { lDecimalDiff = lDecimalDiff == 0 ? int256(uint256(IERC20(aToken1).decimals())) - int256(uint256(IERC20(aToken0).decimals())) : lDecimalDiff; - bytes32 lData = lDecimalDiff.packSimplePrice(aPrice, uint16(lRewardThreshold)); + bytes32 lData = lDecimalDiff.packSimplePrice(aPrice, lRewardThreshold); require(lData.isSimplePrice(), "flag incorrect"); require(lData.getDecimalDifference() == lDecimalDiff, "decimal diff incorrect"); require(lData.getRewardThreshold() == lRewardThreshold, "reward threshold incorrect"); @@ -88,7 +88,7 @@ contract ReservoirPriceOracleTest is BaseTest { function setUp() external { // define route address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](1); + uint64[] memory lRewardThreshold = new uint64[](1); lRoute[0] = address(_tokenA); lRoute[1] = address(_tokenB); lRewardThreshold[0] = 200; // 2% @@ -160,8 +160,8 @@ contract ReservoirPriceOracleTest is BaseTest { _writePriceCache(address(_tokenC), address(_tokenD), lPriceCD); address[] memory lRoute = new address[](4); - uint16[] memory lRewardThreshold = new uint16[](3); - lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](3); + lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.WAD; lRoute[0] = address(_tokenA); lRoute[1] = address(_tokenB); @@ -190,8 +190,8 @@ contract ReservoirPriceOracleTest is BaseTest { _writePriceCache(address(_tokenC), address(_tokenD), lPriceCD); address[] memory lRoute = new address[](4); - uint16[] memory lRewardThreshold = new uint16[](3); - lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](3); + lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.WAD; lRoute[0] = address(_tokenA); lRoute[1] = address(_tokenB); lRoute[2] = address(_tokenC); @@ -233,8 +233,8 @@ contract ReservoirPriceOracleTest is BaseTest { lRoute[2] = address(lTokenC); { - uint16[] memory lRewardThreshold = new uint16[](2); - lRewardThreshold[0] = lRewardThreshold[1] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](2); + lRewardThreshold[0] = lRewardThreshold[1] = Constants.WAD; _oracle.setRoute(address(lTokenA), address(lTokenC), lRoute, lRewardThreshold); _writePriceCache(address(lTokenA), address(lTokenB), 1e18); _writePriceCache(address(lTokenC), address(lTokenB), 1e18); @@ -277,8 +277,8 @@ contract ReservoirPriceOracleTest is BaseTest { _oracle.designatePair(address(lTokenA), address(lTokenB), lPair); address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; (lRoute[0], lRoute[1]) = lTokenA < lTokenB ? (address(lTokenA), address(lTokenB)) : (address(lTokenB), address(lTokenA)); _oracle.setRoute(lRoute[0], lRoute[1], lRoute, lRewardThreshold); @@ -339,8 +339,8 @@ contract ReservoirPriceOracleTest is BaseTest { lTokenA < lTokenC ? (address(lTokenA), address(lTokenC)) : (address(lTokenC), address(lTokenA)); lRoute[1] = address(lTokenB); - uint16[] memory lRewardThreshold = new uint16[](2); - lRewardThreshold[0] = lRewardThreshold[1] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](2); + lRewardThreshold[0] = lRewardThreshold[1] = Constants.WAD; _oracle.setRoute(lRoute[0], lRoute[2], lRoute, lRewardThreshold); _writePriceCache( address(lTokenA) < address(lTokenB) ? address(lTokenA) : address(lTokenB), @@ -493,7 +493,7 @@ contract ReservoirPriceOracleTest is BaseTest { function testUpdatePrice_BelowThreshold(uint256 aPercentDiff) external { // assume (,, uint256 lRewardThreshold) = _oracle.priceCache(address(_tokenA), address(_tokenB)); - uint256 lPercentDiff = bound(aPercentDiff, 0, (lRewardThreshold - 1) * WAD / Constants.BP_SCALE); + uint256 lPercentDiff = bound(aPercentDiff, 0, (lRewardThreshold - 1)); // arrange - we fuzz test by varying the starting price instead of the new price uint256 lCurrentPrice = 98_918_868_099_219_913_512; @@ -518,11 +518,10 @@ contract ReservoirPriceOracleTest is BaseTest { function testUpdatePrice_AboveThresholdBelowMaxReward(uint256 aPercentDiff) external { // assume (,, uint256 lRewardThreshold) = _oracle.priceCache(address(_tokenA), address(_tokenB)); - uint256 lRewardThresholdWAD = lRewardThreshold * WAD / Constants.BP_SCALE; uint256 lPercentDiff = bound( aPercentDiff, - lRewardThresholdWAD, - _oracle.MAX_REWARD_MULTIPLIER() * lRewardThreshold * WAD / Constants.BP_SCALE + lRewardThreshold, + _oracle.MAX_REWARD_MULTIPLIER() * lRewardThreshold ); // arrange @@ -541,7 +540,7 @@ contract ReservoirPriceOracleTest is BaseTest { // assert (uint256 lPrice,,) = _oracle.priceCache(address(_tokenA), address(_tokenB)); assertEq(lPrice, lCurrentPrice); - uint256 lExpectedRewardReceived = block.basefee * _oracle.rewardGasAmount() * lPercentDiff / lRewardThresholdWAD; + uint256 lExpectedRewardReceived = block.basefee * _oracle.rewardGasAmount() * lPercentDiff / lRewardThreshold; assertGe(lExpectedRewardReceived, block.basefee * _oracle.rewardGasAmount()); assertLe(lExpectedRewardReceived, block.basefee * _oracle.rewardGasAmount() * _oracle.MAX_REWARD_MULTIPLIER()); assertEq(address(this).balance, lExpectedRewardReceived); // some reward received but is less than max possible reward @@ -553,7 +552,7 @@ contract ReservoirPriceOracleTest is BaseTest { (,, uint256 lRewardThreshold) = _oracle.priceCache(address(_tokenA), address(_tokenB)); uint256 lPercentDiff = bound( aPercentDiff, - _oracle.MAX_REWARD_MULTIPLIER() * lRewardThreshold * WAD / Constants.BP_SCALE, + _oracle.MAX_REWARD_MULTIPLIER() * lRewardThreshold, WAD // 100% ); @@ -649,7 +648,7 @@ contract ReservoirPriceOracleTest is BaseTest { address lIntermediate2 = address(_tokenD); address lEnd = address(_tokenB); address[] memory lRoute = new address[](4); - uint16[] memory lRewardThreshold = new uint16[](3); + uint64[] memory lRewardThreshold = new uint64[](3); lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = 3; // 3bp lRoute[0] = lStart; lRoute[1] = lIntermediate1; @@ -717,8 +716,8 @@ contract ReservoirPriceOracleTest is BaseTest { address lToken0 = address(_tokenB); address lToken1 = address(_tokenC); address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; lRoute[0] = lToken0; lRoute[1] = lToken1; @@ -741,8 +740,8 @@ contract ReservoirPriceOracleTest is BaseTest { address lToken0 = address(_tokenB); address lToken1 = address(_tokenC); address[] memory lRoute = new address[](4); - uint16[] memory lRewardThreshold = new uint16[](3); - lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](3); + lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.WAD; lRoute[0] = lToken0; lRoute[1] = address(_tokenA); lRoute[2] = address(_tokenD); @@ -782,8 +781,8 @@ contract ReservoirPriceOracleTest is BaseTest { lIntermediateRoute3[0] = lIntermediate2; lIntermediateRoute3[1] = lEnd; - uint16[] memory lRewardThreshold = new uint16[](3); - lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](3); + lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.WAD; // act vm.expectEmit(false, false, false, true); @@ -810,8 +809,8 @@ contract ReservoirPriceOracleTest is BaseTest { address lToken0 = address(_tokenB); address lToken1 = address(_tokenC); address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; lRoute[0] = lToken0; lRoute[1] = lToken1; _oracle.setRoute(lToken0, lToken1, lRoute, lRewardThreshold); @@ -834,8 +833,8 @@ contract ReservoirPriceOracleTest is BaseTest { function testClearRoute_AllWordsCleared() external { // arrange address[] memory lRoute = new address[](4); - uint16[] memory lRewardThreshold = new uint16[](3); - lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](3); + lRewardThreshold[0] = lRewardThreshold[1] = lRewardThreshold[2] = Constants.WAD; lRoute[0] = address(_tokenA); lRoute[1] = address(_tokenC); lRoute[2] = address(_tokenB); @@ -961,8 +960,8 @@ contract ReservoirPriceOracleTest is BaseTest { lPair.sync(); address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; lRoute[0] = address(_tokenB); lRoute[1] = address(_tokenC); @@ -981,7 +980,7 @@ contract ReservoirPriceOracleTest is BaseTest { function testUpdatePrice_WriteToNonSimpleRoute() external { // arrange - uint16[] memory lRewardThresholds = new uint16[](2); + uint64[] memory lRewardThresholds = new uint64[](2); lRewardThresholds[0] = lRewardThresholds[1] = 1; address[] memory lRoute = new address[](3); lRoute[0] = address(_tokenA); @@ -1021,8 +1020,8 @@ contract ReservoirPriceOracleTest is BaseTest { address lToken0 = address(0x1); address lToken1 = address(0x1); address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; lRoute[0] = lToken0; lRoute[1] = lToken1; @@ -1036,8 +1035,8 @@ contract ReservoirPriceOracleTest is BaseTest { address lToken0 = address(0x21); address lToken1 = address(0x2); address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; lRoute[0] = lToken0; lRoute[1] = lToken1; @@ -1051,8 +1050,8 @@ contract ReservoirPriceOracleTest is BaseTest { address lToken0 = address(0x1); address lToken1 = address(0x2); address[] memory lTooLong = new address[](5); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; lTooLong[0] = lToken0; lTooLong[1] = address(0); lTooLong[2] = address(0); @@ -1084,8 +1083,8 @@ contract ReservoirPriceOracleTest is BaseTest { lInvalidRoute2[1] = address(54); lInvalidRoute2[2] = lToken1; - uint16[] memory lRewardThreshold = new uint16[](2); - lRewardThreshold[0] = lRewardThreshold[1] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](2); + lRewardThreshold[0] = lRewardThreshold[1] = Constants.WAD; // act & assert vm.expectRevert(OracleErrors.InvalidRoute.selector); @@ -1097,8 +1096,8 @@ contract ReservoirPriceOracleTest is BaseTest { function testSetRoute_InvalidRewardThreshold() external { // arrange address[] memory lRoute = new address[](2); - uint16[] memory lInvalidRewardThreshold = new uint16[](1); - lInvalidRewardThreshold[0] = Constants.BP_SCALE + 1; + uint64[] memory lInvalidRewardThreshold = new uint64[](1); + lInvalidRewardThreshold[0] = Constants.WAD + 1; lRoute[0] = address(_tokenC); lRoute[1] = address(_tokenD); @@ -1113,8 +1112,8 @@ contract ReservoirPriceOracleTest is BaseTest { function testSetRoute_InvalidRewardThresholdLength() external { address[] memory lRoute = new address[](2); - uint16[] memory lRewardThreshold = new uint16[](2); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](2); + lRewardThreshold[0] = Constants.WAD; lRoute[0] = address(_tokenC); lRoute[1] = address(_tokenD); @@ -1129,8 +1128,8 @@ contract ReservoirPriceOracleTest is BaseTest { address[] memory lRoute = new address[](2); lRoute[0] = address(lToken) < address(_tokenA) ? address(lToken) : address(_tokenA); lRoute[1] = address(lToken) < address(_tokenA) ? address(_tokenA) : address(lToken); - uint16[] memory lRewardThreshold = new uint16[](1); - lRewardThreshold[0] = Constants.BP_SCALE; + uint64[] memory lRewardThreshold = new uint64[](1); + lRewardThreshold[0] = Constants.WAD; // act & assert vm.expectRevert(OracleErrors.UnsupportedTokenDecimals.selector); diff --git a/test/unit/libraries/RoutesLib.t.sol b/test/unit/libraries/RoutesLib.t.sol index 05a6e32..f764738 100644 --- a/test/unit/libraries/RoutesLib.t.sol +++ b/test/unit/libraries/RoutesLib.t.sol @@ -36,17 +36,17 @@ contract RoutesLibTest is Test { assertEq(lZero.getDecimalDifference(), 0); } - function testPackSimplePrice(int8 aDiff, uint256 aPrice) external pure { + function testPackSimplePrice(int8 aDiff, uint64 aRewardThreshold, uint256 aPrice) external pure { // assume uint256 lPrice = bound(aPrice, 1, Constants.MAX_SUPPORTED_PRICE); // act - bytes32 lResult = int256(aDiff).packSimplePrice(lPrice, Constants.BP_SCALE); + bytes32 lResult = int256(aDiff).packSimplePrice(lPrice, aRewardThreshold); // assert assertEq(lResult[0], RoutesLib.FLAG_SIMPLE_PRICE); assertEq(lResult[1], bytes1(uint8(aDiff))); - assertEq(lResult.getRewardThreshold(), Constants.BP_SCALE); + assertEq(lResult.getRewardThreshold(), aRewardThreshold); assertEq(lResult.getPrice(), lPrice); } } diff --git a/test/unit/libraries/Utils.t.sol b/test/unit/libraries/Utils.t.sol new file mode 100644 index 0000000..6142824 --- /dev/null +++ b/test/unit/libraries/Utils.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +import { Test, console2, stdError } from "forge-std/Test.sol"; + +import { Utils } from "src/libraries/Utils.sol"; +import { Constants } from "src/libraries/Constants.sol"; + +contract UtilsTest is Test{ + using Utils for uint256; + + function testCalcPercentageDiff_Double(uint256 aOriginal) external pure { + // assume + uint256 lOriginal = bound(aOriginal, 1, Constants.MAX_SUPPORTED_PRICE / 2); + + // act + uint256 lDiff = lOriginal.calcPercentageDiff( lOriginal * 2); + + // assert + assertEq(lDiff, 1e18); + } + + function testCalcPercentageDiff_Half(uint256 aOriginal) external pure { + // assume - when numbers get too small the error becomes too large + uint256 lOriginal = bound(aOriginal, 1e6, Constants.MAX_SUPPORTED_PRICE); + + // act + uint256 lDiff = lOriginal.calcPercentageDiff( lOriginal / 2); + + // assert + assertApproxEqRel(lDiff, 0.5e18, 0.00001e18); + } + + function testCalcPercentageDiff_NoDiff(uint256 aOriginal) external pure { + // assume + uint256 lOriginal = bound(aOriginal, 1, Constants.MAX_SUPPORTED_PRICE); + + // act + uint256 lDiff = lOriginal.calcPercentageDiff(lOriginal); + + // assert + assertEq(lDiff, 0); + } +}