From c1e1bca42ec0a61b4438073845f110a0334d5292 Mon Sep 17 00:00:00 2001 From: wwestgarth Date: Fri, 9 Aug 2024 14:01:26 +0100 Subject: [PATCH] fix: do not panic if commitment is super low in estimate-AMM bounds and fix postionfactor scaling --- core/execution/amm/estimator.go | 34 ++++++++++++++++++---------- core/execution/amm/estimator_test.go | 22 ++++++++++++++++++ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/core/execution/amm/estimator.go b/core/execution/amm/estimator.go index d6d966de11..7c076c3368 100644 --- a/core/execution/amm/estimator.go +++ b/core/execution/amm/estimator.go @@ -55,13 +55,17 @@ func EstimateBounds( lowerPriceD := lowerPrice.ToDecimal() boundPosLower := PositionAtLowerBound(riskFactorLower, balanceD, lowerPriceD, avgEntryLower, positionFactor) - lossLower := LossOnCommitment(avgEntryLower, lowerPriceD, boundPosLower) + // if the commitment is *so low* that the position at the bound is 0 then we will panic trying to calculate the rest + // and the "too wide" check below will flag it up as an invalid AMM defn + if !boundPosLower.IsZero() { + lossLower := LossOnCommitment(avgEntryLower, lowerPriceD, boundPosLower) - liquidationPriceAtLower := LiquidationPrice(balanceD, lossLower, boundPosLower, lowerPriceD, linearSlippageFactor, riskFactorLong) + liquidationPriceAtLower := LiquidationPrice(balanceD, lossLower, boundPosLower, lowerPriceD, linearSlippageFactor, riskFactorLong) - r.PositionSizeAtLower = boundPosLower - r.LiquidationPriceAtLower = liquidationPriceAtLower - r.LossOnCommitmentAtLower = lossLower + r.PositionSizeAtLower = boundPosLower.Mul(positionFactor) + r.LiquidationPriceAtLower = liquidationPriceAtLower + r.LossOnCommitmentAtLower = lossLower + } // now lets check that the lower bound is not too wide that the volume is spread too thin l := unitLower.Mul(boundPosLower).Abs() @@ -78,13 +82,19 @@ func EstimateBounds( avgEntryUpper := AverageEntryPrice(sqrter, unitUpper, upperPrice) riskFactorUpper := RiskFactor(leverageUpper, riskFactorShort, linearSlippageFactor, initialMargin) upperPriceD := upperPrice.ToDecimal() + boundPosUpper := PositionAtUpperBound(riskFactorUpper, balanceD, upperPriceD, avgEntryUpper, positionFactor) - lossUpper := LossOnCommitment(avgEntryUpper, upperPriceD, boundPosUpper) - liquidationPriceAtUpper := LiquidationPrice(balanceD, lossUpper, boundPosUpper, upperPriceD, linearSlippageFactor, riskFactorShort) - r.PositionSizeAtUpper = boundPosUpper - r.LiquidationPriceAtUpper = liquidationPriceAtUpper - r.LossOnCommitmentAtUpper = lossUpper + // if the commitment is *so low* that the position at the bound is 0 then we will panic trying to calculate the rest + // and the "too wide" check below will flag it up as an invalid AMM defn + if !boundPosUpper.IsZero() { + lossUpper := LossOnCommitment(avgEntryUpper, upperPriceD, boundPosUpper) + + liquidationPriceAtUpper := LiquidationPrice(balanceD, lossUpper, boundPosUpper, upperPriceD, linearSlippageFactor, riskFactorShort) + r.PositionSizeAtUpper = boundPosUpper.Mul(positionFactor) + r.LiquidationPriceAtUpper = liquidationPriceAtUpper + r.LossOnCommitmentAtUpper = lossUpper + } // now lets check that the lower bound is not too wide that the volume is spread too thin l := unitUpper.Mul(boundPosUpper).Abs() @@ -128,7 +138,7 @@ func PositionAtLowerBound(rf, b, pl, pa, positionFactor num.Decimal) num.Decimal pv := rf.Mul(b).Div( pl.Mul(oneSubRf).Add(rfMulPa), ) - return pv.Mul(positionFactor) + return pv } // Pvl = -rf * b / (pl * (1 + rf) - rf * pa). @@ -139,7 +149,7 @@ func PositionAtUpperBound(rf, b, pl, pa, positionFactor num.Decimal) num.Decimal pv := rf.Neg().Mul(b).Div( pl.Mul(onePlusRf).Sub(rfMulPa), ) - return pv.Mul(positionFactor) + return pv } // lc = |(pa - pb) * pB|. diff --git a/core/execution/amm/estimator_test.go b/core/execution/amm/estimator_test.go index 8fec4b8895..07d6c6115e 100644 --- a/core/execution/amm/estimator_test.go +++ b/core/execution/amm/estimator_test.go @@ -211,4 +211,26 @@ func TestEstimatePositionFactor(t *testing.T) { assert.Equal(t, expectedMetrics.PositionSizeAtLower.String(), metrics.PositionSizeAtLower.Round(3).String()) assert.False(t, metrics.TooWideLower) assert.False(t, metrics.TooWideUpper) + + // if commitment is super low then we could panic, so test that we don't + metrics = EstimateBounds( + sqrter, + lowerPrice, + basePrice, + upperPrice, + leverageLower, + leverageUpper, + num.UintOne(), + linearSlippageFactor, + initialMargin, + riskFactorShort, + riskFactorLong, + num.DecimalFromInt64(1000000000000000000), + num.DecimalOne(), + ) + + assert.Equal(t, "0", metrics.PositionSizeAtUpper.Round(3).String()) + assert.Equal(t, "0", metrics.PositionSizeAtLower.Round(3).String()) + assert.True(t, metrics.TooWideLower) + assert.True(t, metrics.TooWideUpper) }