From f58a4f809f0dc791646d9d962e0eaac41e25ef1e Mon Sep 17 00:00:00 2001 From: Hayden Shively <17186559+haydenshively@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:03:25 -0500 Subject: [PATCH 1/2] Fix pausing functionality --- core/.gas-snapshot | 26 +-- core/src/Borrower.sol | 33 ++-- core/src/Factory.sol | 6 +- core/src/libraries/BalanceSheet.sol | 4 +- core/test/Liquidator.t.sol | 14 +- core/test/Utils.sol | 5 - core/test/libraries/BalanceSheet.t.sol | 254 ++++++++++++++----------- 7 files changed, 189 insertions(+), 153 deletions(-) diff --git a/core/.gas-snapshot b/core/.gas-snapshot index 9cf0f826..72d0a3e5 100644 --- a/core/.gas-snapshot +++ b/core/.gas-snapshot @@ -1,15 +1,15 @@ BorrowerGasTest:test_addMargin() (gas: 16203) -BorrowerGasTest:test_borrow() (gas: 110577) +BorrowerGasTest:test_borrow() (gas: 110553) BorrowerGasTest:test_getUniswapPositions() (gas: 5219) -BorrowerGasTest:test_modify() (gas: 82174) -BorrowerGasTest:test_modifyWithAnte() (gas: 88629) -BorrowerGasTest:test_repay() (gas: 111936) -BorrowerGasTest:test_uniswapDepositInBorrower() (gas: 257789) +BorrowerGasTest:test_modify() (gas: 82150) +BorrowerGasTest:test_modifyWithAnte() (gas: 88605) +BorrowerGasTest:test_repay() (gas: 65205) +BorrowerGasTest:test_uniswapDepositInBorrower() (gas: 257762) BorrowerGasTest:test_uniswapDepositStandard() (gas: 167558) -BorrowerGasTest:test_uniswapWithdraw() (gas: 147673) -BorrowerGasTest:test_withdraw() (gas: 105694) +BorrowerGasTest:test_uniswapWithdraw() (gas: 147654) +BorrowerGasTest:test_withdraw() (gas: 105670) FactoryGasTest:test_createBorrower() (gas: 156519) -FactoryGasTest:test_createMarket() (gas: 3904606) +FactoryGasTest:test_createMarket() (gas: 3879742) 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: 51105) -LiquidatorGasTest:test_noCallbackTwoAssets() (gas: 59286) -LiquidatorGasTest:test_noCallbackTwoAssetsAndUniswapPosition() (gas: 95684) -LiquidatorGasTest:test_warn() (gas: 35089) -LiquidatorGasTest:test_withCallbackAndSwap() (gas: 130270) +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) 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 09a190d6..8a838e2f 100644 --- a/core/src/Borrower.sol +++ b/core/src/Borrower.sol @@ -149,7 +149,7 @@ contract Borrower is IUniswapV3MintCallback { { // Fetch prices from oracle - Prices memory prices = getPrices(oracleSeed); + (Prices memory prices, ) = getPrices(oracleSeed); // Tally assets without actually withdrawing Uniswap positions Assets memory assets = _getAssets(positions.read(), prices, false); // Fetch liabilities from lenders @@ -188,7 +188,7 @@ contract Borrower is IUniswapV3MintCallback { _saveSlot0(slot0_, _formatted(State.Locked)); // Fetch prices from oracle - Prices memory prices = getPrices(oracleSeed); + (Prices memory prices, ) = getPrices(oracleSeed); uint256 liabilities0; uint256 liabilities1; @@ -295,21 +295,21 @@ contract Borrower is IUniswapV3MintCallback { int24[] memory positions_ = positions.write(callee.callback(data, msg.sender)); _saveSlot0(uint160(msg.sender), _formatted(State.Ready)); - (uint256 ante, uint256 nSigma, uint256 pausedUntilTime) = FACTORY.getParameters(UNISWAP_POOL); - - (Prices memory prices, bool isSus) = _getPrices(nSigma, oracleSeed); - Assets memory assets = _getAssets(positions_, prices, false); (uint256 liabilities0, uint256 liabilities1) = _getLiabilities(); - - require(BalanceSheet.isHealthy(prices, assets, liabilities0, liabilities1), "Aloe: unhealthy"); unchecked { - if (liabilities0 + liabilities1 > 0) + if (liabilities0 + liabilities1 > 0) { + (uint256 ante, uint256 nSigma, uint256 pausedUntilTime) = FACTORY.getParameters(UNISWAP_POOL); + (Prices memory prices, bool seemsLegit) = _getPrices(oracleSeed, nSigma); + require( - address(this).balance > ante && !isSus && block.timestamp > pausedUntilTime, + seemsLegit && (block.timestamp > pausedUntilTime) && (address(this).balance >= ante), "Aloe: missing ante / sus price" ); + + Assets memory assets = _getAssets(positions_, prices, false); + require(BalanceSheet.isHealthy(prices, assets, liabilities0, liabilities1), "Aloe: unhealthy"); + } } - if (isSus) FACTORY.pause(UNISWAP_POOL); } /*////////////////////////////////////////////////////////////// @@ -439,18 +439,21 @@ contract Borrower is IUniswapV3MintCallback { return positions.read(); } - function getPrices(uint40 oracleSeed) public view returns (Prices memory prices) { + function getPrices(uint40 oracleSeed) public view returns (Prices memory prices, bool seemsLegit) { (, uint256 nSigma, ) = FACTORY.getParameters(UNISWAP_POOL); - (prices, ) = _getPrices(nSigma, oracleSeed); + (prices, seemsLegit) = _getPrices(oracleSeed, nSigma); } - function _getPrices(uint256 nSigma, uint40 oracleSeed) private view returns (Prices memory prices, bool isSus) { + function _getPrices( + uint40 oracleSeed, + uint256 nSigma + ) 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, isSus) = BalanceSheet.computeProbePrices(prices.c, iv, nSigma, metric); + (prices.a, prices.b, seemsLegit) = BalanceSheet.computeProbePrices(prices.c, iv, nSigma, metric); } function _getAssets( diff --git a/core/src/Factory.sol b/core/src/Factory.sol index a74c266a..15b35f38 100644 --- a/core/src/Factory.sol +++ b/core/src/Factory.sol @@ -103,8 +103,10 @@ contract Factory { DEFAULT_RATE_MODEL = defaultRateModel; } - function pause(IUniswapV3Pool pool) external { - require(isBorrower[msg.sender]); + function pause(IUniswapV3Pool pool, uint40 oracleSeed) external { + (, bool seemsLegit) = getMarket[pool].borrowerImplementation.getPrices(oracleSeed); + if (seemsLegit) return; + unchecked { getParameters[pool].pausedUntilTime = uint32(block.timestamp) + UNISWAP_AVG_WINDOW; } diff --git a/core/src/libraries/BalanceSheet.sol b/core/src/libraries/BalanceSheet.sol index 2005cd42..ac4826d5 100644 --- a/core/src/libraries/BalanceSheet.sol +++ b/core/src/libraries/BalanceSheet.sol @@ -85,10 +85,10 @@ library BalanceSheet { uint256 iv, uint256 nSigma, uint56 metric - ) internal pure returns (uint160 a, uint160 b, bool isSus) { + ) internal pure returns (uint160 a, uint160 b, bool seemsLegit) { unchecked { iv = SoladyMath.clamp((nSigma * iv) / 10, PROBE_PERCENT_MIN, PROBE_PERCENT_MAX); - isSus = metric > _manipulationThreshold(_effectiveCollateralFactor(iv)); + seemsLegit = metric < _manipulationThreshold(_effectiveCollateralFactor(iv)); a = uint160((sqrtMeanPriceX96 * SoladyMath.sqrt(1e12 - iv)) / 1e6); b = uint160(SoladyMath.min((sqrtMeanPriceX96 * SoladyMath.sqrt(1e12 + iv)) / 1e6, type(uint160).max)); diff --git a/core/test/Liquidator.t.sol b/core/test/Liquidator.t.sol index 3847454f..33dbb5b9 100644 --- a/core/test/Liquidator.t.sol +++ b/core/test/Liquidator.t.sol @@ -262,7 +262,7 @@ contract LiquidatorTest is Test, IManager, ILiquidator { vm.expectRevert(); account.liquidate(this, bytes(""), 0, (1 << 32)); - Prices memory prices = account.getPrices((1 << 32)); + (Prices memory prices, ) = account.getPrices(1 << 32); uint256 price = Math.mulDiv(prices.c, prices.c, Q96); uint256 incentive1 = Math.mulDiv(debt / LIQUIDATION_INCENTIVE, price, Q96); uint256 assets1 = Math.mulDiv(debt / strain, price, Q96) + incentive1 / strain; @@ -299,7 +299,7 @@ contract LiquidatorTest is Test, IManager, ILiquidator { uint160(address(this)) + (1 << 160) ))); - Prices memory prices = account.getPrices((1 << 32)); + (Prices memory prices, ) = account.getPrices(1 << 32); uint256 price = Math.mulDiv(prices.c, prices.c, Q96); uint256 incentive1 = Math.mulDiv(debt / LIQUIDATION_INCENTIVE, price, Q96); uint256 assets1 = Math.mulDiv(debt / strain, price, Q96) + incentive1 / strain; @@ -317,7 +317,7 @@ contract LiquidatorTest is Test, IManager, ILiquidator { // These tests are forked, so we don't want to spam the RPC with too many fuzzing values strain = (strain % 8) + 1; - Prices memory prices = account.getPrices((1 << 32)); + (Prices memory prices,) = account.getPrices(1 << 32); uint256 borrow1 = 1e18 * ((scale % 4) + 1); // Same concern here { uint256 effectiveLiabilities1 = borrow1 + borrow1 / 200 + borrow1 / 20; @@ -369,7 +369,7 @@ contract LiquidatorTest is Test, IManager, ILiquidator { function test_spec_priceTriggerRepayDAIUsingSwap() public { uint256 strain = 1; - Prices memory prices = account.getPrices((1 << 32)); + (Prices memory prices, ) = account.getPrices(1 << 32); uint256 borrow0 = 1000e18; { uint256 effectiveLiabilities0 = borrow0 + borrow0 / 200; @@ -418,7 +418,7 @@ contract LiquidatorTest is Test, IManager, ILiquidator { uint160(address(this)) + (1 << 160) ))); - prices = account.getPrices((1 << 32)); + (prices, ) = account.getPrices(1 << 32); uint256 price = Math.mulDiv(prices.c, prices.c, Q96); uint256 assets1 = Math.mulDiv(borrow0 / strain, price, Q96); @@ -435,7 +435,7 @@ contract LiquidatorTest is Test, IManager, ILiquidator { function test_warnDoesProtect() public { uint256 strain = 1; - Prices memory prices = account.getPrices((1 << 32)); + (Prices memory prices, ) = account.getPrices(1 << 32); uint256 borrow0 = 1000e18; { uint256 effectiveLiabilities0 = borrow0 + borrow0 / 200; @@ -489,7 +489,7 @@ contract LiquidatorTest is Test, IManager, ILiquidator { skip(1); - prices = account.getPrices((1 << 32)); + (prices, ) = account.getPrices(1 << 32); uint256 price = Math.mulDiv(prices.c, prices.c, Q96); uint256 assets1 = Math.mulDiv(borrow0 / strain, price, Q96); diff --git a/core/test/Utils.sol b/core/test/Utils.sol index 7342f6dc..7b15b945 100644 --- a/core/test/Utils.sol +++ b/core/test/Utils.sol @@ -14,11 +14,6 @@ import {Lender} from "src/Lender.sol"; import {RateModel} from "src/RateModel.sol"; import {VolatilityOracle} from "src/VolatilityOracle.sol"; -function deploySingleBorrower(IUniswapV3Pool pool, Lender lender0, Lender lender1) returns (Borrower) { - address oracleMock = address(new VolatilityOracleMock()); - return new Borrower(VolatilityOracle(oracleMock), pool, lender0, lender1); -} - contract FactoryForLenderTests is Factory { constructor( RateModel rateModel, diff --git a/core/test/libraries/BalanceSheet.t.sol b/core/test/libraries/BalanceSheet.t.sol index 75631244..01761853 100644 --- a/core/test/libraries/BalanceSheet.t.sol +++ b/core/test/libraries/BalanceSheet.t.sol @@ -12,121 +12,155 @@ import { PROBE_PERCENT_MAX, IV_COLD_START } from "src/libraries/constants/Constants.sol"; -import {BalanceSheet, TickMath, square} from "src/libraries/BalanceSheet.sol"; +import {BalanceSheet, Assets, Prices, TickMath, square} from "src/libraries/BalanceSheet.sol"; import {FixedPointMathLib as SoladyMath} from "solady/utils/FixedPointMathLib.sol"; +contract LibraryWrapper { + function isHealthy( + Prices memory prices, + Assets memory mem, + uint256 liabilities0, + uint256 liabilities1 + ) external pure returns (bool) { + return BalanceSheet.isHealthy(prices, mem, liabilities0, liabilities1); + } +} + contract BalanceSheetTest is Test { function setUp() public {} + function test_alwaysHealthyWhenLiabilitiesAre0( + uint128 fixed0, + uint128 fixed1, + uint128 fluid1A, + uint128 fluid1B, + uint128 fluid0C, + uint128 fluid1C, + uint160 a, + uint160 b, + uint160 c + ) public { + Assets memory assets = Assets(fixed0, fixed1, fluid1A, fluid1B, fluid0C, fluid1C); + Prices memory prices = Prices(a, b, c); + + LibraryWrapper wrapper = new LibraryWrapper(); + try wrapper.isHealthy(prices, assets, 0, 0) returns (bool isHealthy) { + assertTrue(isHealthy); + } 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 isSus; - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 87); - assertFalse(isSus, "0.00 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 88); - assertTrue(isSus, "0.00 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 87); - assertFalse(isSus, "0.01 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 88); - assertTrue(isSus, "0.01 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 132); - assertFalse(isSus, "0.02 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 133); - assertTrue(isSus, "0.02 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 180); - assertFalse(isSus, "0.03 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 181); - assertTrue(isSus, "0.03 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 230); - assertFalse(isSus, "0.04 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 231); - assertTrue(isSus, "0.04 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 284); - assertFalse(isSus, "0.05 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 285); - assertTrue(isSus, "0.05 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 341); - assertFalse(isSus, "0.06 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 342); - assertTrue(isSus, "0.06 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 403); - assertFalse(isSus, "0.07 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 404); - assertTrue(isSus, "0.07 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 470); - assertFalse(isSus, "0.08 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 471); - assertTrue(isSus, "0.08 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 542); - assertFalse(isSus, "0.09 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 543); - assertTrue(isSus, "0.09 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 622); - assertFalse(isSus, "0.10 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 623); - assertTrue(isSus, "0.10 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 710); - assertFalse(isSus, "0.11 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 711); - assertTrue(isSus, "0.11 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 808); - assertFalse(isSus, "0.12 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 809); - assertTrue(isSus, "0.12 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 919); - assertFalse(isSus, "0.13 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 920); - assertTrue(isSus, "0.13 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1048); - assertFalse(isSus, "0.14 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1049); - assertTrue(isSus, "0.14 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1199); - assertFalse(isSus, "0.15 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1200); - assertTrue(isSus, "0.15 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1385); - assertFalse(isSus, "0.16 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1386); - assertTrue(isSus, "0.16 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1625); - assertFalse(isSus, "0.17 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1626); - assertTrue(isSus, "0.17 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1918); - assertFalse(isSus, "0.18 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1919); - assertTrue(isSus, "0.18 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1918); - assertFalse(isSus, "0.19 false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1919); - assertTrue(isSus, "0.19 true"); - - (, , isSus) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1918); - assertFalse(isSus, "cold start false"); - (, , isSus) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1919); - assertTrue(isSus, "cold start true"); + bool seemsLegit; + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 86); + assertTrue(seemsLegit, "0.00 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 87); + assertFalse(seemsLegit, "0.00 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 86); + assertTrue(seemsLegit, "0.01 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 87); + assertFalse(seemsLegit, "0.01 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 131); + assertTrue(seemsLegit, "0.02 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 132); + assertFalse(seemsLegit, "0.02 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 179); + assertTrue(seemsLegit, "0.03 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 180); + assertFalse(seemsLegit, "0.03 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 229); + assertTrue(seemsLegit, "0.04 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 230); + assertFalse(seemsLegit, "0.04 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 283); + assertTrue(seemsLegit, "0.05 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 284); + assertFalse(seemsLegit, "0.05 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 340); + assertTrue(seemsLegit, "0.06 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 341); + assertFalse(seemsLegit, "0.06 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 402); + assertTrue(seemsLegit, "0.07 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 403); + assertFalse(seemsLegit, "0.07 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 469); + assertTrue(seemsLegit, "0.08 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 470); + assertFalse(seemsLegit, "0.08 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 541); + assertTrue(seemsLegit, "0.09 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 542); + assertFalse(seemsLegit, "0.09 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 621); + assertTrue(seemsLegit, "0.10 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 622); + assertFalse(seemsLegit, "0.10 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 709); + assertTrue(seemsLegit, "0.11 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 710); + assertFalse(seemsLegit, "0.11 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 807); + assertTrue(seemsLegit, "0.12 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 808); + assertFalse(seemsLegit, "0.12 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 918); + assertTrue(seemsLegit, "0.13 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 919); + assertFalse(seemsLegit, "0.13 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1047); + assertTrue(seemsLegit, "0.14 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1048); + assertFalse(seemsLegit, "0.14 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1198); + assertTrue(seemsLegit, "0.15 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1199); + assertFalse(seemsLegit, "0.15 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1384); + assertTrue(seemsLegit, "0.16 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1385); + assertFalse(seemsLegit, "0.16 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1624); + assertTrue(seemsLegit, "0.17 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1625); + assertFalse(seemsLegit, "0.17 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1917); + assertTrue(seemsLegit, "0.18 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1918); + assertFalse(seemsLegit, "0.18 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1917); + assertTrue(seemsLegit, "0.19 true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1918); + assertFalse(seemsLegit, "0.19 false"); + + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1917); + assertTrue(seemsLegit, "cold true"); + (, , seemsLegit) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1918); + assertFalse(seemsLegit, "cold false"); } function test_computeProbePrices(uint160 sqrtMeanPriceX96, uint256 iv, uint256 nSigma) public { @@ -139,6 +173,8 @@ contract BalanceSheetTest is Test { sqrtMeanPriceX96 = uint160( bound(sqrtMeanPriceX96, (1 << 40), (uint256(TickMath.MAX_SQRT_RATIO) * 1e6) / 1376408) ); + // 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)); (uint256 a, uint256 b, ) = BalanceSheet.computeProbePrices(sqrtMeanPriceX96, iv, nSigma, 0); @@ -147,8 +183,8 @@ contract BalanceSheetTest is Test { a = square(uint160(a)); b = square(uint160(b)); - if (iv < PROBE_PERCENT_MIN * 10 / nSigma) iv = PROBE_PERCENT_MIN * 10 / nSigma; - else if (iv > PROBE_PERCENT_MAX * 10 / nSigma) iv = PROBE_PERCENT_MAX * 10 / nSigma; + if (iv < (PROBE_PERCENT_MIN * 10) / nSigma) iv = (PROBE_PERCENT_MIN * 10) / nSigma; + else if (iv > (PROBE_PERCENT_MAX * 10) / nSigma) iv = (PROBE_PERCENT_MAX * 10) / nSigma; assertApproxEqRel(a, SoladyMath.fullMulDiv(price, 1e12 - (nSigma * iv) / 10, 1e12), 0.0001e18); assertApproxEqRel(b, SoladyMath.fullMulDiv(price, 1e12 + (nSigma * iv) / 10, 1e12), 0.0001e18); From 37333e5bab43db4512330181b965b678d893fc89 Mon Sep 17 00:00:00 2001 From: Hayden Shively <17186559+haydenshively@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:31:26 -0500 Subject: [PATCH 2/2] More conservative conditional --- core/src/Borrower.sol | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/core/src/Borrower.sol b/core/src/Borrower.sol index 8a838e2f..a8d4c544 100644 --- a/core/src/Borrower.sol +++ b/core/src/Borrower.sol @@ -296,19 +296,17 @@ contract Borrower is IUniswapV3MintCallback { _saveSlot0(uint160(msg.sender), _formatted(State.Ready)); (uint256 liabilities0, uint256 liabilities1) = _getLiabilities(); - unchecked { - if (liabilities0 + liabilities1 > 0) { - (uint256 ante, uint256 nSigma, uint256 pausedUntilTime) = FACTORY.getParameters(UNISWAP_POOL); - (Prices memory prices, bool seemsLegit) = _getPrices(oracleSeed, nSigma); + if (liabilities0 > 0 || liabilities1 > 0) { + (uint256 ante, uint256 nSigma, uint256 pausedUntilTime) = FACTORY.getParameters(UNISWAP_POOL); + (Prices memory prices, bool seemsLegit) = _getPrices(oracleSeed, nSigma); - require( - seemsLegit && (block.timestamp > pausedUntilTime) && (address(this).balance >= ante), - "Aloe: missing ante / sus price" - ); + require( + seemsLegit && (block.timestamp > pausedUntilTime) && (address(this).balance >= ante), + "Aloe: missing ante / sus price" + ); - Assets memory assets = _getAssets(positions_, prices, false); - require(BalanceSheet.isHealthy(prices, assets, liabilities0, liabilities1), "Aloe: unhealthy"); - } + Assets memory assets = _getAssets(positions_, prices, false); + require(BalanceSheet.isHealthy(prices, assets, liabilities0, liabilities1), "Aloe: unhealthy"); } }