diff --git a/core/.gas-snapshot b/core/.gas-snapshot index 72d0a3e5..2a0f6bbe 100644 --- a/core/.gas-snapshot +++ b/core/.gas-snapshot @@ -1,15 +1,15 @@ BorrowerGasTest:test_addMargin() (gas: 16203) -BorrowerGasTest:test_borrow() (gas: 110553) +BorrowerGasTest:test_borrow() (gas: 110758) BorrowerGasTest:test_getUniswapPositions() (gas: 5219) -BorrowerGasTest:test_modify() (gas: 82150) -BorrowerGasTest:test_modifyWithAnte() (gas: 88605) -BorrowerGasTest:test_repay() (gas: 65205) -BorrowerGasTest:test_uniswapDepositInBorrower() (gas: 257762) +BorrowerGasTest:test_modify() (gas: 82355) +BorrowerGasTest:test_modifyWithAnte() (gas: 88810) +BorrowerGasTest:test_repay() (gas: 65245) +BorrowerGasTest:test_uniswapDepositInBorrower() (gas: 257967) BorrowerGasTest:test_uniswapDepositStandard() (gas: 167558) -BorrowerGasTest:test_uniswapWithdraw() (gas: 147654) -BorrowerGasTest:test_withdraw() (gas: 105670) +BorrowerGasTest:test_uniswapWithdraw() (gas: 147818) +BorrowerGasTest:test_withdraw() (gas: 105875) FactoryGasTest:test_createBorrower() (gas: 156519) -FactoryGasTest:test_createMarket() (gas: 3879742) +FactoryGasTest:test_createMarket() (gas: 3889605) LenderGasTest:test_accrueInterest() (gas: 46070) LenderGasTest:test_borrow() (gas: 40834) LenderGasTest:test_deposit() (gas: 53422) @@ -17,10 +17,10 @@ LenderGasTest:test_depositWithCourier() (gas: 53568) LenderGasTest:test_redeem() (gas: 53114) LenderGasTest:test_redeemWithCourier() (gas: 83506) LenderGasTest:test_repay() (gas: 44774) -LiquidatorGasTest:test_noCallbackOneAsset() (gas: 51108) -LiquidatorGasTest:test_noCallbackTwoAssets() (gas: 59289) -LiquidatorGasTest:test_noCallbackTwoAssetsAndUniswapPosition() (gas: 95669) -LiquidatorGasTest:test_warn() (gas: 35092) -LiquidatorGasTest:test_withCallbackAndSwap() (gas: 130273) +LiquidatorGasTest:test_noCallbackOneAsset() (gas: 51278) +LiquidatorGasTest:test_noCallbackTwoAssets() (gas: 59459) +LiquidatorGasTest:test_noCallbackTwoAssetsAndUniswapPosition() (gas: 95805) +LiquidatorGasTest:test_warn() (gas: 35262) +LiquidatorGasTest:test_withCallbackAndSwap() (gas: 130443) VolatilityGasTest:test_consult() (gas: 43075) VolatilityGasTest:test_updateNoBinarySearch() (gas: 145902) \ No newline at end of file diff --git a/core/src/Borrower.sol b/core/src/Borrower.sol index a8d4c544..88f3e930 100644 --- a/core/src/Borrower.sol +++ b/core/src/Borrower.sol @@ -297,8 +297,8 @@ contract Borrower is IUniswapV3MintCallback { (uint256 liabilities0, uint256 liabilities1) = _getLiabilities(); if (liabilities0 > 0 || liabilities1 > 0) { - (uint256 ante, uint256 nSigma, uint256 pausedUntilTime) = FACTORY.getParameters(UNISWAP_POOL); - (Prices memory prices, bool seemsLegit) = _getPrices(oracleSeed, nSigma); + (uint208 ante, uint8 nSigma, uint8 mtd, uint32 pausedUntilTime) = FACTORY.getParameters(UNISWAP_POOL); + (Prices memory prices, bool seemsLegit) = _getPrices(oracleSeed, nSigma, mtd); require( seemsLegit && (block.timestamp > pausedUntilTime) && (address(this).balance >= ante), @@ -438,20 +438,27 @@ contract Borrower is IUniswapV3MintCallback { } function getPrices(uint40 oracleSeed) public view returns (Prices memory prices, bool seemsLegit) { - (, uint256 nSigma, ) = FACTORY.getParameters(UNISWAP_POOL); - (prices, seemsLegit) = _getPrices(oracleSeed, nSigma); + (, uint8 nSigma, uint8 manipulationThresholdDivisor, ) = FACTORY.getParameters(UNISWAP_POOL); + (prices, seemsLegit) = _getPrices(oracleSeed, nSigma, manipulationThresholdDivisor); } function _getPrices( uint40 oracleSeed, - uint256 nSigma + uint8 nSigma, + uint8 manipulationThresholdDivisor ) private view returns (Prices memory prices, bool seemsLegit) { uint56 metric; uint256 iv; // compute current price and volatility (metric, prices.c, iv) = ORACLE.consult(UNISWAP_POOL, oracleSeed); // compute prices at which solvency will be checked - (prices.a, prices.b, seemsLegit) = BalanceSheet.computeProbePrices(prices.c, iv, nSigma, metric); + (prices.a, prices.b, seemsLegit) = BalanceSheet.computeProbePrices( + metric, + prices.c, + iv, + nSigma, + manipulationThresholdDivisor + ); } function _getAssets( diff --git a/core/src/Factory.sol b/core/src/Factory.sol index 15b35f38..c00f6e34 100644 --- a/core/src/Factory.sol +++ b/core/src/Factory.sol @@ -9,9 +9,12 @@ import {IUniswapV3Pool} from "v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import { DEFAULT_ANTE, DEFAULT_N_SIGMA, + DEFAULT_MANIPULATION_THRESHOLD_DIVISOR, DEFAULT_RESERVE_FACTOR, CONSTRAINT_N_SIGMA_MIN, CONSTRAINT_N_SIGMA_MAX, + CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MIN, + CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MAX, CONSTRAINT_RESERVE_FACTOR_MIN, CONSTRAINT_RESERVE_FACTOR_MAX, CONSTRAINT_ANTE_MAX, @@ -44,8 +47,9 @@ contract Factory { } struct Parameters { - uint216 ante; + uint208 ante; uint8 nSigma; + uint8 manipulationThresholdDivisor; uint32 pausedUntilTime; } @@ -139,7 +143,7 @@ contract Factory { _setMarketConfig( pool, MarketConfig( - Parameters(DEFAULT_ANTE, DEFAULT_N_SIGMA, 0), + Parameters(DEFAULT_ANTE, DEFAULT_N_SIGMA, DEFAULT_MANIPULATION_THRESHOLD_DIVISOR, 0), DEFAULT_RATE_MODEL, DEFAULT_RATE_MODEL, DEFAULT_RESERVE_FACTOR, @@ -228,11 +232,16 @@ contract Factory { require(msg.sender == GOVERNOR); require( - // nSigma: min, max - (CONSTRAINT_N_SIGMA_MIN <= marketConfig.parameters.nSigma && - marketConfig.parameters.nSigma <= CONSTRAINT_N_SIGMA_MAX) && - // ante: max - (marketConfig.parameters.ante <= CONSTRAINT_ANTE_MAX) && + // ante: max + (marketConfig.parameters.ante <= CONSTRAINT_ANTE_MAX) && + // nSigma: min, max + (CONSTRAINT_N_SIGMA_MIN <= marketConfig.parameters.nSigma && + marketConfig.parameters.nSigma <= CONSTRAINT_N_SIGMA_MAX) && + // manipulationThresholdDivisor: min, max + (CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MIN <= + marketConfig.parameters.manipulationThresholdDivisor && + marketConfig.parameters.manipulationThresholdDivisor <= + CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MAX) && // pauseUntilTime: max (marketConfig.parameters.pausedUntilTime <= block.timestamp + CONSTRAINT_PAUSE_INTERVAL_MAX) && // reserveFactor0: min, max diff --git a/core/src/libraries/BalanceSheet.sol b/core/src/libraries/BalanceSheet.sol index ac4826d5..5dbe2c35 100644 --- a/core/src/libraries/BalanceSheet.sol +++ b/core/src/libraries/BalanceSheet.sol @@ -3,13 +3,7 @@ pragma solidity 0.8.17; import {FixedPointMathLib as SoladyMath} from "solady/utils/FixedPointMathLib.sol"; -import { - MAX_LEVERAGE, - LIQUIDATION_INCENTIVE, - PROBE_PERCENT_MIN, - PROBE_PERCENT_MAX, - MANIPULATION_THRESHOLD_DIVISOR -} from "./constants/Constants.sol"; +import {MAX_LEVERAGE, LIQUIDATION_INCENTIVE, PROBE_PERCENT_MIN, PROBE_PERCENT_MAX} from "./constants/Constants.sol"; import {square, mulDiv128} from "./MulDiv.sol"; import {TickMath} from "./TickMath.sol"; @@ -81,14 +75,15 @@ library BalanceSheet { } function computeProbePrices( + uint56 metric, uint160 sqrtMeanPriceX96, uint256 iv, - uint256 nSigma, - uint56 metric + uint8 nSigma, + uint8 manipulationThresholdDivisor ) internal pure returns (uint160 a, uint160 b, bool seemsLegit) { unchecked { iv = SoladyMath.clamp((nSigma * iv) / 10, PROBE_PERCENT_MIN, PROBE_PERCENT_MAX); - seemsLegit = metric < _manipulationThreshold(_effectiveCollateralFactor(iv)); + seemsLegit = metric < _manipulationThreshold(_effectiveCollateralFactor(iv), manipulationThresholdDivisor); a = uint160((sqrtMeanPriceX96 * SoladyMath.sqrt(1e12 - iv)) / 1e6); b = uint160(SoladyMath.min((sqrtMeanPriceX96 * SoladyMath.sqrt(1e12 + iv)) / 1e6, type(uint160).max)); @@ -124,8 +119,8 @@ library BalanceSheet { } /// @dev Equivalent to \\( \frac{log_{1.0001} \left( \frac{10^{12}}{cf} \right)}{\text{MANIPULATION_THRESHOLD_DIVISOR}} \\) - function _manipulationThreshold(uint256 cf) private pure returns (uint24) { - return uint24(-TickMath.getTickAtSqrtRatio(uint160(cf)) - 778261) / (2 * MANIPULATION_THRESHOLD_DIVISOR); + function _manipulationThreshold(uint256 cf, uint256 manipulationThresholdDivisor) private pure returns (uint24) { + return uint24(-TickMath.getTickAtSqrtRatio(uint160(cf)) - 778261) / uint24(2 * manipulationThresholdDivisor); } /// @dev Equivalent to \\( \frac{1 - σ}{1 + \frac{1}{liquidationIncentive} + \frac{1}{maxLeverage}} \\) where diff --git a/core/src/libraries/constants/Constants.sol b/core/src/libraries/constants/Constants.sol index 6ed74f72..dad4fced 100644 --- a/core/src/libraries/constants/Constants.sol +++ b/core/src/libraries/constants/Constants.sol @@ -29,12 +29,22 @@ uint256 constant MAX_RATE = 706354; /// @dev The default amount of Ether required to take on debt in a `Borrower`. The `Factory` can override this value /// on a per-market basis. -uint216 constant DEFAULT_ANTE = 0.01 ether; +uint208 constant DEFAULT_ANTE = 0.01 ether; /// @dev The default number of standard deviations of price movement used to determine probe prices for `Borrower` /// solvency. The `Factory` can override this value on a per-market basis. Expressed x10, e.g. 50 → 5σ uint8 constant DEFAULT_N_SIGMA = 50; +/// @dev Assume someone is manipulating the Uniswap TWAP oracle. To steal money from the protocol and create bad debt, +/// they would need to change the TWAP by a factor of (1 / collateralFactor), where the collateralFactor is a function +/// of volatility. We have a manipulation metric that increases as an attacker tries to change the TWAP. If this metric +/// rises above a certain threshold, certain functionality will be paused, e.g. no new debt can be created. The +/// threshold is calculated as follows: +/// +/// \\( \text{manipulationThreshold} = +/// \frac{log_{1.0001}\left( \frac{1}{\text{collateralFactor}} \right)}{\text{MANIPULATION_THRESHOLD_DIVISOR}} \\) +uint8 constant DEFAULT_MANIPULATION_THRESHOLD_DIVISOR = 12; + /// @dev The default portion of interest that will accrue to a `Lender`'s `RESERVE` address. /// Expressed as a reciprocal, e.g. 16 → 6.25% uint8 constant DEFAULT_RESERVE_FACTOR = 16; @@ -51,6 +61,10 @@ uint8 constant CONSTRAINT_N_SIGMA_MIN = 40; /// Expressed x10, e.g. 80 → 8σ uint8 constant CONSTRAINT_N_SIGMA_MAX = 80; +uint8 constant CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MIN = 12; + +uint8 constant CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MAX = 20; + /// @dev The lower bound on what any `Lender`'s reserve factor can be. Expressed as reciprocal, e.g. 4 → 25% uint8 constant CONSTRAINT_RESERVE_FACTOR_MIN = 4; @@ -136,13 +150,3 @@ uint256 constant FEE_GROWTH_SAMPLE_PERIOD = 15 minutes; /// from `UNISWAP_AVG_WINDOW` seconds ago. Larger values make the resulting price/liquidity values harder to /// manipulate, but also make the oracle slower to respond to changes. uint32 constant UNISWAP_AVG_WINDOW = 30 minutes; - -/// @dev Assume someone is manipulating the Uniswap TWAP oracle. To steal money from the protocol and create bad debt, -/// they would need to change the TWAP by a factor of (1 / collateralFactor), where the collateralFactor is a function -/// of volatility. We have a manipulation metric that increases as an attacker tries to change the TWAP. If this metric -/// rises above a certain threshold, certain functionality will be paused, e.g. no new debt can be created. The -/// threshold is calculated as follows: -/// -/// \\( \text{manipulationThreshold} = -/// \frac{log_{1.0001}\left( \frac{1}{\text{collateralFactor}} \right)}{\text{MANIPULATION_THRESHOLD_DIVISOR}} \\) -uint24 constant MANIPULATION_THRESHOLD_DIVISOR = 12; diff --git a/core/test/libraries/BalanceSheet.t.sol b/core/test/libraries/BalanceSheet.t.sol index 01761853..d6e26733 100644 --- a/core/test/libraries/BalanceSheet.t.sol +++ b/core/test/libraries/BalanceSheet.t.sol @@ -7,6 +7,8 @@ import { DEFAULT_N_SIGMA, CONSTRAINT_N_SIGMA_MIN, CONSTRAINT_N_SIGMA_MAX, + CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MIN, + CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MAX, LTV_MIN, PROBE_PERCENT_MIN, PROBE_PERCENT_MAX, @@ -50,120 +52,120 @@ contract BalanceSheetTest is Test { } catch { vm.expectRevert(stdError.arithmeticError); wrapper.isHealthy(prices, assets, 0, 0); - } + } } /// @dev See https://www.desmos.com/calculator/hrrpjqy4t1 function test_spec_computeProbePrices() public { bool seemsLegit; - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 86); + (, , seemsLegit) = BalanceSheet.computeProbePrices(86, 0, 0.00e12, 50, 12); assertTrue(seemsLegit, "0.00 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 87); + (, , seemsLegit) = BalanceSheet.computeProbePrices(87, 0, 0.00e12, 50, 12); assertFalse(seemsLegit, "0.00 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 86); + (, , seemsLegit) = BalanceSheet.computeProbePrices(86, 0, 0.01e12, 50, 12); assertTrue(seemsLegit, "0.01 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 87); + (, , seemsLegit) = BalanceSheet.computeProbePrices(87, 0, 0.01e12, 50, 12); assertFalse(seemsLegit, "0.01 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 131); + (, , seemsLegit) = BalanceSheet.computeProbePrices(131, 0, 0.02e12, 50, 12); assertTrue(seemsLegit, "0.02 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 132); + (, , seemsLegit) = BalanceSheet.computeProbePrices(132, 0, 0.02e12, 50, 12); assertFalse(seemsLegit, "0.02 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 179); + (, , seemsLegit) = BalanceSheet.computeProbePrices(179, 0, 0.03e12, 50, 12); assertTrue(seemsLegit, "0.03 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 180); + (, , seemsLegit) = BalanceSheet.computeProbePrices(180, 0, 0.03e12, 50, 12); assertFalse(seemsLegit, "0.03 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 229); + (, , seemsLegit) = BalanceSheet.computeProbePrices(229, 0, 0.04e12, 50, 12); assertTrue(seemsLegit, "0.04 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 230); + (, , seemsLegit) = BalanceSheet.computeProbePrices(230, 0, 0.04e12, 50, 12); assertFalse(seemsLegit, "0.04 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 283); + (, , seemsLegit) = BalanceSheet.computeProbePrices(283, 0, 0.05e12, 50, 12); assertTrue(seemsLegit, "0.05 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 284); + (, , seemsLegit) = BalanceSheet.computeProbePrices(284, 0, 0.05e12, 50, 12); assertFalse(seemsLegit, "0.05 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 340); + (, , seemsLegit) = BalanceSheet.computeProbePrices(340, 0, 0.06e12, 50, 12); assertTrue(seemsLegit, "0.06 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 341); + (, , seemsLegit) = BalanceSheet.computeProbePrices(341, 0, 0.06e12, 50, 12); assertFalse(seemsLegit, "0.06 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 402); + (, , seemsLegit) = BalanceSheet.computeProbePrices(402, 0, 0.07e12, 50, 12); assertTrue(seemsLegit, "0.07 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 403); + (, , seemsLegit) = BalanceSheet.computeProbePrices(403, 0, 0.07e12, 50, 12); assertFalse(seemsLegit, "0.07 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 469); + (, , seemsLegit) = BalanceSheet.computeProbePrices(469, 0, 0.08e12, 50, 12); assertTrue(seemsLegit, "0.08 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 470); + (, , seemsLegit) = BalanceSheet.computeProbePrices(470, 0, 0.08e12, 50, 12); assertFalse(seemsLegit, "0.08 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 541); + (, , seemsLegit) = BalanceSheet.computeProbePrices(541, 0, 0.09e12, 50, 12); assertTrue(seemsLegit, "0.09 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 542); + (, , seemsLegit) = BalanceSheet.computeProbePrices(542, 0, 0.09e12, 50, 12); assertFalse(seemsLegit, "0.09 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 621); + (, , seemsLegit) = BalanceSheet.computeProbePrices(621, 0, 0.10e12, 50, 12); assertTrue(seemsLegit, "0.10 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 622); + (, , seemsLegit) = BalanceSheet.computeProbePrices(622, 0, 0.10e12, 50, 12); assertFalse(seemsLegit, "0.10 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 709); + (, , seemsLegit) = BalanceSheet.computeProbePrices(709, 0, 0.11e12, 50, 12); assertTrue(seemsLegit, "0.11 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 710); + (, , seemsLegit) = BalanceSheet.computeProbePrices(710, 0, 0.11e12, 50, 12); assertFalse(seemsLegit, "0.11 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 807); + (, , seemsLegit) = BalanceSheet.computeProbePrices(807, 0, 0.12e12, 50, 12); assertTrue(seemsLegit, "0.12 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 808); + (, , seemsLegit) = BalanceSheet.computeProbePrices(808, 0, 0.12e12, 50, 12); assertFalse(seemsLegit, "0.12 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 918); + (, , seemsLegit) = BalanceSheet.computeProbePrices(918, 0, 0.13e12, 50, 12); assertTrue(seemsLegit, "0.13 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 919); + (, , seemsLegit) = BalanceSheet.computeProbePrices(919, 0, 0.13e12, 50, 12); assertFalse(seemsLegit, "0.13 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1047); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1047, 0, 0.14e12, 50, 12); assertTrue(seemsLegit, "0.14 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1048); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1048, 0, 0.14e12, 50, 12); assertFalse(seemsLegit, "0.14 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1198); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1198, 0, 0.15e12, 50, 12); assertTrue(seemsLegit, "0.15 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1199); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1199, 0, 0.15e12, 50, 12); assertFalse(seemsLegit, "0.15 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1384); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1384, 0, 0.16e12, 50, 12); assertTrue(seemsLegit, "0.16 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1385); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1385, 0, 0.16e12, 50, 12); assertFalse(seemsLegit, "0.16 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1624); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1624, 0, 0.17e12, 50, 12); assertTrue(seemsLegit, "0.17 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1625); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1625, 0, 0.17e12, 50, 12); assertFalse(seemsLegit, "0.17 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1917); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1917, 0, 0.18e12, 50, 12); assertTrue(seemsLegit, "0.18 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1918); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1918, 0, 0.18e12, 50, 12); assertFalse(seemsLegit, "0.18 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1917); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1917, 0, 0.19e12, 50, 12); assertTrue(seemsLegit, "0.19 true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1918); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1918, 0, 0.19e12, 50, 12); assertFalse(seemsLegit, "0.19 false"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1917); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1917, 0, IV_COLD_START, 50, 12); assertTrue(seemsLegit, "cold true"); - (, , seemsLegit) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1918); + (, , seemsLegit) = BalanceSheet.computeProbePrices(1918, 0, IV_COLD_START, 50, 12); assertFalse(seemsLegit, "cold false"); } - function test_computeProbePrices(uint160 sqrtMeanPriceX96, uint256 iv, uint256 nSigma) public { + function test_computeProbePrices(uint160 sqrtMeanPriceX96, uint256 iv, uint8 nSigma, uint8 mtd) public { // The lower bound is related to how precise our assertion is. For prices to be correct within 0.01%, // the sqrtPrice must be >= 2^40 (approximately). Calculations for that are here: // https://www.desmos.com/calculator/gfbkcnt0vs @@ -175,9 +177,12 @@ contract BalanceSheetTest is Test { ); // This is valid because of the sqrt in `Volatility` library iv = bound(iv, 0, type(uint128).max); - nSigma = uint160(bound(nSigma, CONSTRAINT_N_SIGMA_MIN, CONSTRAINT_N_SIGMA_MAX)); + nSigma = uint8(bound(nSigma, CONSTRAINT_N_SIGMA_MIN, CONSTRAINT_N_SIGMA_MAX)); + mtd = uint8( + bound(mtd, CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MIN, CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MAX) + ); - (uint256 a, uint256 b, ) = BalanceSheet.computeProbePrices(sqrtMeanPriceX96, iv, nSigma, 0); + (uint256 a, uint256 b, ) = BalanceSheet.computeProbePrices(0, sqrtMeanPriceX96, iv, nSigma, mtd); uint256 price = square(sqrtMeanPriceX96); a = square(uint160(a));