Skip to content

Commit

Permalink
Add digit to nSigma so it's more governable (#153)
Browse files Browse the repository at this point in the history
  • Loading branch information
haydenshively authored Sep 11, 2023
1 parent 42e99e0 commit 1793b06
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 67 deletions.
26 changes: 13 additions & 13 deletions core/.gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
BorrowerGasTest:test_addMargin() (gas: 16203)
BorrowerGasTest:test_borrow() (gas: 110565)
BorrowerGasTest:test_borrow() (gas: 110577)
BorrowerGasTest:test_getUniswapPositions() (gas: 5219)
BorrowerGasTest:test_modify() (gas: 82162)
BorrowerGasTest:test_modifyWithAnte() (gas: 88617)
BorrowerGasTest:test_repay() (gas: 111924)
BorrowerGasTest:test_uniswapDepositInBorrower() (gas: 257777)
BorrowerGasTest:test_modify() (gas: 82174)
BorrowerGasTest:test_modifyWithAnte() (gas: 88629)
BorrowerGasTest:test_repay() (gas: 111936)
BorrowerGasTest:test_uniswapDepositInBorrower() (gas: 257789)
BorrowerGasTest:test_uniswapDepositStandard() (gas: 167558)
BorrowerGasTest:test_uniswapWithdraw() (gas: 147664)
BorrowerGasTest:test_withdraw() (gas: 105682)
BorrowerGasTest:test_uniswapWithdraw() (gas: 147673)
BorrowerGasTest:test_withdraw() (gas: 105694)
FactoryGasTest:test_createBorrower() (gas: 156519)
FactoryGasTest:test_createMarket() (gas: 3903606)
FactoryGasTest:test_createMarket() (gas: 3904606)
LenderGasTest:test_accrueInterest() (gas: 46070)
LenderGasTest:test_borrow() (gas: 40834)
LenderGasTest:test_deposit() (gas: 53422)
LenderGasTest:test_depositWithCourier() (gas: 53568)
LenderGasTest:test_redeem() (gas: 53114)
LenderGasTest:test_redeemWithCourier() (gas: 83506)
LenderGasTest:test_repay() (gas: 44774)
LiquidatorGasTest:test_noCallbackOneAsset() (gas: 51093)
LiquidatorGasTest:test_noCallbackTwoAssets() (gas: 59274)
LiquidatorGasTest:test_noCallbackTwoAssetsAndUniswapPosition() (gas: 95674)
LiquidatorGasTest:test_warn() (gas: 35077)
LiquidatorGasTest:test_withCallbackAndSwap() (gas: 130258)
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)
VolatilityGasTest:test_consult() (gas: 43075)
VolatilityGasTest:test_updateNoBinarySearch() (gas: 145902)
2 changes: 1 addition & 1 deletion core/src/libraries/BalanceSheet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ library BalanceSheet {
uint56 metric
) internal pure returns (uint160 a, uint160 b, bool isSus) {
unchecked {
iv = SoladyMath.clamp(nSigma * iv, PROBE_PERCENT_MIN, PROBE_PERCENT_MAX);
iv = SoladyMath.clamp((nSigma * iv) / 10, PROBE_PERCENT_MIN, PROBE_PERCENT_MAX);
isSus = metric > _manipulationThreshold(_effectiveCollateralFactor(iv));

a = uint160((sqrtMeanPriceX96 * SoladyMath.sqrt(1e12 - iv)) / 1e6);
Expand Down
1 change: 1 addition & 0 deletions core/src/libraries/Volatility.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ library Volatility {

/**
* @notice Estimates implied volatility using [this math](https://lambert-guillaume.medium.com/on-chain-volatility-and-uniswap-v3-d031b98143d1).
* @dev The return value can fit in uint128 if necessary
* @param metadata The pool's metadata (may be cached)
* @param data A summary of the pool's state from `pool.slot0` `pool.observe` and `pool.liquidity`
* @param a The pool's cumulative feeGrowthGlobals some time in the past
Expand Down
16 changes: 9 additions & 7 deletions core/src/libraries/constants/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ uint256 constant MAX_RATE = 706354;
uint216 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.
uint8 constant DEFAULT_N_SIGMA = 5;
/// 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 The default portion of interest that will accrue to a `Lender`'s `RESERVE` address.
/// Expressed as a reciprocal, e.g. 16 → 6.25%
Expand All @@ -43,11 +43,13 @@ uint8 constant DEFAULT_RESERVE_FACTOR = 16;
GOVERNANCE CONSTRAINTS
//////////////////////////////////////////////////////////////*/

/// @dev The lowest number of standard deviations of price movement allowed for determining `Borrower` probe prices
uint8 constant CONSTRAINT_N_SIGMA_MIN = 4;
/// @dev The lowest number of standard deviations of price movement allowed for determining `Borrower` probe prices.
/// Expressed x10, e.g. 40 → 4σ
uint8 constant CONSTRAINT_N_SIGMA_MIN = 40;

/// @dev The highest number of standard deviations of price movement allowed for determining `Borrower` probe prices
uint8 constant CONSTRAINT_N_SIGMA_MAX = 5;
/// @dev The highest number of standard deviations of price movement allowed for determining `Borrower` probe prices.
/// Expressed x10, e.g. 80 → 8σ
uint8 constant CONSTRAINT_N_SIGMA_MAX = 80;

/// @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;
Expand Down Expand Up @@ -108,7 +110,7 @@ uint32 constant IV_SCALE = 24 hours;
/// @dev The initial value of implied volatility, used when `VolatilityOracle.prepare` is called for a new pool.
/// Expressed as a 1e12 percentage at `IV_SCALE`, e.g. {0.20e12, 24 hours} → 20% daily → 382% annual. Error on the
/// side of making this too large (resulting in low LTV).
uint128 constant IV_COLD_START = uint128(PROBE_PERCENT_MAX / DEFAULT_N_SIGMA);
uint128 constant IV_COLD_START = uint128((PROBE_PERCENT_MAX * 10) / CONSTRAINT_N_SIGMA_MIN);

/// @dev The maximum rate at which (reported) implied volatility can change. Raw samples in `VolatilityOracle.update`
/// are clamped (before being stored) so as not to exceed this rate.
Expand Down
96 changes: 50 additions & 46 deletions core/test/libraries/BalanceSheet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,109 +23,109 @@ contract BalanceSheetTest is Test {
function test_spec_computeProbePrices() public {
bool isSus;

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.00e12, 5, 87);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 87);
assertFalse(isSus, "0.00 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.00e12, 5, 88);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.00e12, 50, 88);
assertTrue(isSus, "0.00 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.01e12, 5, 87);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 87);
assertFalse(isSus, "0.01 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.01e12, 5, 88);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.01e12, 50, 88);
assertTrue(isSus, "0.01 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.02e12, 5, 132);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 132);
assertFalse(isSus, "0.02 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.02e12, 5, 133);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.02e12, 50, 133);
assertTrue(isSus, "0.02 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.03e12, 5, 180);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 180);
assertFalse(isSus, "0.03 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.03e12, 5, 181);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.03e12, 50, 181);
assertTrue(isSus, "0.03 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.04e12, 5, 230);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 230);
assertFalse(isSus, "0.04 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.04e12, 5, 231);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.04e12, 50, 231);
assertTrue(isSus, "0.04 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.05e12, 5, 284);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 284);
assertFalse(isSus, "0.05 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.05e12, 5, 285);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.05e12, 50, 285);
assertTrue(isSus, "0.05 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.06e12, 5, 341);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 341);
assertFalse(isSus, "0.06 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.06e12, 5, 342);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.06e12, 50, 342);
assertTrue(isSus, "0.06 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.07e12, 5, 403);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 403);
assertFalse(isSus, "0.07 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.07e12, 5, 404);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.07e12, 50, 404);
assertTrue(isSus, "0.07 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.08e12, 5, 470);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 470);
assertFalse(isSus, "0.08 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.08e12, 5, 471);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.08e12, 50, 471);
assertTrue(isSus, "0.08 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.09e12, 5, 542);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 542);
assertFalse(isSus, "0.09 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.09e12, 5, 543);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.09e12, 50, 543);
assertTrue(isSus, "0.09 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.10e12, 5, 622);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 622);
assertFalse(isSus, "0.10 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.10e12, 5, 623);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.10e12, 50, 623);
assertTrue(isSus, "0.10 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.11e12, 5, 710);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 710);
assertFalse(isSus, "0.11 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.11e12, 5, 711);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.11e12, 50, 711);
assertTrue(isSus, "0.11 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.12e12, 5, 808);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 808);
assertFalse(isSus, "0.12 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.12e12, 5, 809);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.12e12, 50, 809);
assertTrue(isSus, "0.12 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.13e12, 5, 919);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 919);
assertFalse(isSus, "0.13 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.13e12, 5, 920);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.13e12, 50, 920);
assertTrue(isSus, "0.13 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.14e12, 5, 1048);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1048);
assertFalse(isSus, "0.14 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.14e12, 5, 1049);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.14e12, 50, 1049);
assertTrue(isSus, "0.14 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.15e12, 5, 1199);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1199);
assertFalse(isSus, "0.15 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.15e12, 5, 1200);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.15e12, 50, 1200);
assertTrue(isSus, "0.15 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.16e12, 5, 1385);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1385);
assertFalse(isSus, "0.16 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.16e12, 5, 1386);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.16e12, 50, 1386);
assertTrue(isSus, "0.16 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.17e12, 5, 1625);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1625);
assertFalse(isSus, "0.17 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.17e12, 5, 1626);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.17e12, 50, 1626);
assertTrue(isSus, "0.17 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.18e12, 5, 1918);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1918);
assertFalse(isSus, "0.18 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.18e12, 5, 1919);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.18e12, 50, 1919);
assertTrue(isSus, "0.18 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, 0.19e12, 5, 1918);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1918);
assertFalse(isSus, "0.19 false");
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.19e12, 5, 1919);
(, , isSus) = BalanceSheet.computeProbePrices(0, 0.19e12, 50, 1919);
assertTrue(isSus, "0.19 true");

(, , isSus) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 5, 1918);
(, , isSus) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1918);
assertFalse(isSus, "cold start false");
(, , isSus) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 5, 1919);
(, , isSus) = BalanceSheet.computeProbePrices(0, IV_COLD_START, 50, 1919);
assertTrue(isSus, "cold start true");
}

Expand All @@ -147,18 +147,22 @@ contract BalanceSheetTest is Test {
a = square(uint160(a));
b = square(uint160(b));

if (iv < PROBE_PERCENT_MIN / nSigma) iv = PROBE_PERCENT_MIN / nSigma;
else if (iv > PROBE_PERCENT_MAX / nSigma) iv = PROBE_PERCENT_MAX / 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, 1e12), 0.0001e18);
assertApproxEqRel(b, SoladyMath.fullMulDiv(price, 1e12 + nSigma * iv, 1e12), 0.0001e18);
assertApproxEqRel(a, SoladyMath.fullMulDiv(price, 1e12 - (nSigma * iv) / 10, 1e12), 0.0001e18);
assertApproxEqRel(b, SoladyMath.fullMulDiv(price, 1e12 + (nSigma * iv) / 10, 1e12), 0.0001e18);
}

function test_constants() public {
// Just checking that things are reasonable
assertEqDecimal(PROBE_PERCENT_MIN, 50500000000, 12);
assertEqDecimal(PROBE_PERCENT_MAX, 894500000000, 12);

// Necessary for iv scaling not to overflow
assertLt(PROBE_PERCENT_MIN, 1 << 128);
assertLt(PROBE_PERCENT_MAX, 1 << 128);

// Necessary for collateral factor computation to work
assertGt(LTV_MIN, TickMath.MIN_SQRT_RATIO);
}
Expand Down

0 comments on commit 1793b06

Please sign in to comment.