diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aac3d649f5..7829fb907c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#5983](https://github.com/osmosis-labs/osmosis/pull/5983) refactor(CL): 6 return values in CL CreatePosition with a struct * [#6004](https://github.com/osmosis-labs/osmosis/pull/6004) reduce number of returns for creating full range position * [#6018](https://github.com/osmosis-labs/osmosis/pull/6018) golangci: add unused parameters linter +* [#6033](https://github.com/osmosis-labs/osmosis/pull/6033) change tick API from sdk.Dec to osmomath.BigDec ### Features diff --git a/tests/cl-genesis-positions/convert.go b/tests/cl-genesis-positions/convert.go index 3e3cdb7e862..911b45430d6 100644 --- a/tests/cl-genesis-positions/convert.go +++ b/tests/cl-genesis-positions/convert.go @@ -138,7 +138,7 @@ func ConvertSubgraphToOsmosisGenesis(positionCreatorAddresses []sdk.AccAddress, if err != nil { panic(err) } - lowerTickOsmosis, err := math.SqrtPriceToTickRoundDownSpacing(sqrtPriceLower, pool.GetTickSpacing()) + lowerTickOsmosis, err := math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrtPriceLower), pool.GetTickSpacing()) if err != nil { panic(err) } @@ -147,7 +147,7 @@ func ConvertSubgraphToOsmosisGenesis(positionCreatorAddresses []sdk.AccAddress, if err != nil { panic(err) } - upperTickOsmosis, err := math.SqrtPriceToTickRoundDownSpacing(sqrtPriceUpper, pool.GetTickSpacing()) + upperTickOsmosis, err := math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrtPriceUpper), pool.GetTickSpacing()) if err != nil { panic(err) } diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 9a72774afe4..ceed8f16514 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -491,8 +491,8 @@ func (s *IntegrationTestSuite) ConcentratedLiquidity() { s.Require().NoError(err) _, sqrtPriceAtNextInitializedTick, err := clmath.TickToSqrtPrice(nextInitTick) s.Require().NoError(err) - sqrtPriceAfterNextInitializedTickBigDec := osmomath.BigDecFromSDKDec(sqrtPriceAfterNextInitializedTick) - sqrtPriceAtNextInitializedTickBigDec := osmomath.BigDecFromSDKDec(sqrtPriceAtNextInitializedTick) + sqrtPriceAfterNextInitializedTickBigDec := sqrtPriceAfterNextInitializedTick + sqrtPriceAtNextInitializedTickBigDec := sqrtPriceAtNextInitializedTick // Calculate Δ(sqrtPrice): // deltaSqrtPriceAfterNextInitializedTick = ΔsqrtP(40300) - ΔsqrtP(40000) @@ -635,7 +635,7 @@ func (s *IntegrationTestSuite) ConcentratedLiquidity() { s.Require().NoError(err) _, sqrtPriceAtNextInitializedTick, err = clmath.TickToSqrtPrice(nextInitTick) s.Require().NoError(err) - sqrtPriceAtNextInitializedTickBigDec = osmomath.BigDecFromSDKDec(sqrtPriceAtNextInitializedTick) + sqrtPriceAtNextInitializedTickBigDec = sqrtPriceAtNextInitializedTick // Calculate numerators numeratorBelowNextInitializedTick := sqrtPriceAtNextInitializedTick.Sub(sqrtPricebBelowNextInitializedTick) @@ -650,7 +650,7 @@ func (s *IntegrationTestSuite) ConcentratedLiquidity() { fractionAtNextInitializedTick := numeratorNextInitializedTick.Quo(denominatorNextInitializedTick) // Calculate amounts of uionIn needed - amountInToGetToTickBelowInitialized := liquidityBeforeSwap.Add(positionsAddress1[0].Position.Liquidity).Mul(fractionBelowNextInitializedTick) + amountInToGetToTickBelowInitialized := liquidityBeforeSwap.Add(positionsAddress1[0].Position.Liquidity).Mul(fractionBelowNextInitializedTick.SDKDec()) amountInToGetToNextInitTick = liquidityBeforeSwap.Mul(fractionAtNextInitializedTick.SDKDec()) var ( diff --git a/x/concentrated-liquidity/export_test.go b/x/concentrated-liquidity/export_test.go index 882d734f129..c757fc02c37 100644 --- a/x/concentrated-liquidity/export_test.go +++ b/x/concentrated-liquidity/export_test.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils/accum" "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/model" "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/swapstrategy" @@ -170,7 +171,7 @@ func (k Keeper) SetPositionIdToLock(ctx sdk.Context, positionId, underlyingLockI k.setPositionIdToLock(ctx, positionId, underlyingLockId) } -func RoundTickToCanonicalPriceTick(lowerTick, upperTick int64, priceTickLower, priceTickUpper sdk.Dec, tickSpacing uint64) (int64, int64, error) { +func RoundTickToCanonicalPriceTick(lowerTick, upperTick int64, priceTickLower, priceTickUpper osmomath.BigDec, tickSpacing uint64) (int64, int64, error) { return roundTickToCanonicalPriceTick(lowerTick, upperTick, priceTickLower, priceTickUpper, tickSpacing) } @@ -336,7 +337,7 @@ func (k Keeper) GetLargestSupportedUptimeDuration(ctx sdk.Context) time.Duration func (k Keeper) SetupSwapStrategy(ctx sdk.Context, p types.ConcentratedPoolExtension, spreadFactor sdk.Dec, tokenInDenom string, - priceLimit sdk.Dec) (strategy swapstrategy.SwapStrategy, sqrtPriceLimit sdk.Dec, err error) { + priceLimit sdk.Dec) (strategy swapstrategy.SwapStrategy, sqrtPriceLimit osmomath.BigDec, err error) { return k.setupSwapStrategy(p, spreadFactor, tokenInDenom, priceLimit) } diff --git a/x/concentrated-liquidity/fuzz_test.go b/x/concentrated-liquidity/fuzz_test.go index 3aadfc58d4b..163624400ae 100644 --- a/x/concentrated-liquidity/fuzz_test.go +++ b/x/concentrated-liquidity/fuzz_test.go @@ -204,7 +204,7 @@ func (s *KeeperTestSuite) swapNearNextTickBoundary(r *rand.Rand, pool types.Conc func (s *KeeperTestSuite) swapNearInitializedTickBoundary(r *rand.Rand, pool types.ConcentratedPoolExtension, zfo bool) (didSwap bool, fatalErr bool) { fmt.Println("swap type: near initialized tick boundary") - ss := swapstrategy.New(zfo, sdk.ZeroDec(), s.App.GetKey(types.ModuleName), sdk.ZeroDec()) + ss := swapstrategy.New(zfo, osmomath.ZeroDec(), s.App.GetKey(types.ModuleName), sdk.ZeroDec()) iter := ss.InitializeNextTickIterator(s.Ctx, pool.GetId(), pool.GetCurrentTick()) defer iter.Close() diff --git a/x/concentrated-liquidity/incentives.go b/x/concentrated-liquidity/incentives.go index c5868b9d868..73bdc111e4b 100644 --- a/x/concentrated-liquidity/incentives.go +++ b/x/concentrated-liquidity/incentives.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "golang.org/x/exp/slices" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/osmoutils/accum" "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/math" @@ -200,7 +201,7 @@ func (k Keeper) prepareBalancerPoolAsFullRange(ctx sdk.Context, clPoolId uint64, // Calculate the amount of liquidity the Balancer amounts qualify in the CL pool. Note that since we use the CL spot price, this is // safe against prices drifting apart between the two pools (we take the lower bound on the qualifying liquidity in this case). // The `sqrtPriceLowerTick` and `sqrtPriceUpperTick` fields are set to the appropriate values for a full range position. - qualifyingFullRangeSharesPreDiscount := math.GetLiquidityFromAmounts(clPool.GetCurrentSqrtPrice(), types.MinSqrtPrice, types.MaxSqrtPrice, asset0Amount, asset1Amount) + qualifyingFullRangeSharesPreDiscount := math.GetLiquidityFromAmounts(clPool.GetCurrentSqrtPrice(), osmomath.BigDecFromSDKDec(types.MinSqrtPrice), osmomath.BigDecFromSDKDec(types.MaxSqrtPrice), asset0Amount, asset1Amount) // Get discount ratio from governance-set discount rate. // Note that discount rate is the amount that is being discounted by (e.g. 0.05 for a 5% discount), while discount ratio is what diff --git a/x/concentrated-liquidity/incentives_test.go b/x/concentrated-liquidity/incentives_test.go index 5b9ab6b911f..f9d63da3a8c 100644 --- a/x/concentrated-liquidity/incentives_test.go +++ b/x/concentrated-liquidity/incentives_test.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils/accum" cl "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity" "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/math" @@ -1056,7 +1057,7 @@ func (s *KeeperTestSuite) TestUpdateUptimeAccumulatorsToNow() { clPool, err = clKeeper.GetPoolById(s.Ctx, clPool.GetId()) s.Require().NoError(err) if tc.canonicalBalancerPoolAssets != nil { - qualifyingBalancerLiquidityPreDiscount := math.GetLiquidityFromAmounts(clPool.GetCurrentSqrtPrice(), types.MinSqrtPrice, types.MaxSqrtPrice, tc.canonicalBalancerPoolAssets[0].Token.Amount, tc.canonicalBalancerPoolAssets[1].Token.Amount) + qualifyingBalancerLiquidityPreDiscount := math.GetLiquidityFromAmounts(clPool.GetCurrentSqrtPrice(), osmomath.BigDecFromSDKDec(types.MinSqrtPrice), osmomath.BigDecFromSDKDec(types.MaxSqrtPrice), tc.canonicalBalancerPoolAssets[0].Token.Amount, tc.canonicalBalancerPoolAssets[1].Token.Amount) qualifyingBalancerLiquidity = (sdk.OneDec().Sub(types.DefaultBalancerSharesDiscount)).Mul(qualifyingBalancerLiquidityPreDiscount) qualifyingLiquidity = qualifyingLiquidity.Add(qualifyingBalancerLiquidity) @@ -3591,7 +3592,7 @@ func (s *KeeperTestSuite) TestPrepareBalancerPoolAsFullRange() { s.Require().NoError(err) asset0BalancerAmount := tc.balancerPoolAssets[0].Token.Amount.ToDec().Mul(tc.portionOfSharesBonded).TruncateInt() asset1BalancerAmount := tc.balancerPoolAssets[1].Token.Amount.ToDec().Mul(tc.portionOfSharesBonded).TruncateInt() - qualifyingSharesPreDiscount := math.GetLiquidityFromAmounts(updatedClPool.GetCurrentSqrtPrice(), types.MinSqrtPrice, types.MaxSqrtPrice, asset1BalancerAmount, asset0BalancerAmount) + qualifyingSharesPreDiscount := math.GetLiquidityFromAmounts(updatedClPool.GetCurrentSqrtPrice(), osmomath.BigDecFromSDKDec(types.MinSqrtPrice), osmomath.BigDecFromSDKDec(types.MaxSqrtPrice), asset1BalancerAmount, asset0BalancerAmount) qualifyingShares := (sdk.OneDec().Sub(types.DefaultBalancerSharesDiscount)).Mul(qualifyingSharesPreDiscount) // TODO: clean this check up (will likely require refactoring the whole test) diff --git a/x/concentrated-liquidity/keeper_test.go b/x/concentrated-liquidity/keeper_test.go index b43cb85a5a0..763f9e62391 100644 --- a/x/concentrated-liquidity/keeper_test.go +++ b/x/concentrated-liquidity/keeper_test.go @@ -65,10 +65,10 @@ var ( sqrt4999 = sdk.MustNewDecFromStr("70.703606697254136613") sqrt5500 = sdk.MustNewDecFromStr("74.161984870956629488") sqrt6250 = sdk.MustNewDecFromStr("79.056941504209483300") - DefaultExponentConsecutivePositionLowerTick, _ = math.SqrtPriceToTickRoundDownSpacing(sqrt5500, DefaultTickSpacing) - DefaultExponentConsecutivePositionUpperTick, _ = math.SqrtPriceToTickRoundDownSpacing(sqrt6250, DefaultTickSpacing) - DefaultExponentOverlappingPositionLowerTick, _ = math.SqrtPriceToTickRoundDownSpacing(sqrt4000, DefaultTickSpacing) - DefaultExponentOverlappingPositionUpperTick, _ = math.SqrtPriceToTickRoundDownSpacing(sqrt4999, DefaultTickSpacing) + DefaultExponentConsecutivePositionLowerTick, _ = math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrt5500), DefaultTickSpacing) + DefaultExponentConsecutivePositionUpperTick, _ = math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrt6250), DefaultTickSpacing) + DefaultExponentOverlappingPositionLowerTick, _ = math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrt4000), DefaultTickSpacing) + DefaultExponentOverlappingPositionUpperTick, _ = math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrt4999), DefaultTickSpacing) BAR = "bar" FOO = "foo" InsufficientFundsError = fmt.Errorf("insufficient funds") @@ -82,7 +82,7 @@ func TestConstants(t *testing.T) { lowerSqrtPrice, _ := osmomath.MonotonicSqrt(DefaultLowerPrice) upperSqrtPrice, _ := osmomath.MonotonicSqrt(DefaultUpperPrice) liq := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, - lowerSqrtPrice, upperSqrtPrice, DefaultAmt0, DefaultAmt1) + osmomath.BigDecFromSDKDec(lowerSqrtPrice), osmomath.BigDecFromSDKDec(upperSqrtPrice), DefaultAmt0, DefaultAmt1) require.Equal(t, DefaultLiquidityAmt, liq) } diff --git a/x/concentrated-liquidity/lp.go b/x/concentrated-liquidity/lp.go index e918b2d6cc8..5fb17458741 100644 --- a/x/concentrated-liquidity/lp.go +++ b/x/concentrated-liquidity/lp.go @@ -521,7 +521,7 @@ func (k Keeper) initializeInitialPositionForPool(ctx sdk.Context, pool types.Con // Calculate the initial tick from the initial spot price // We round down here so that the tick is rounded to // the nearest possible value given the tick spacing. - initialTick, err := math.SqrtPriceToTickRoundDownSpacing(initialCurSqrtPrice, pool.GetTickSpacing()) + initialTick, err := math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(initialCurSqrtPrice), pool.GetTickSpacing()) if err != nil { return err } diff --git a/x/concentrated-liquidity/math/math.go b/x/concentrated-liquidity/math/math.go index d4f210afe0f..3bf2aca1fff 100644 --- a/x/concentrated-liquidity/math/math.go +++ b/x/concentrated-liquidity/math/math.go @@ -173,28 +173,25 @@ func GetNextSqrtPriceFromAmount1OutRoundingDown(sqrtPriceCurrent, liquidity, amo // GetLiquidityFromAmounts takes the current sqrtPrice and the sqrtPrice for the upper and lower ticks as well as the amounts of asset0 and asset1 // and returns the resulting liquidity from these inputs. -func GetLiquidityFromAmounts(sqrtPrice osmomath.BigDec, sqrtPriceA, sqrtPriceB sdk.Dec, amount0, amount1 sdk.Int) (liquidity sdk.Dec) { - sqrtPriceABigDec := osmomath.BigDecFromSDKDec(sqrtPriceA) - sqrtPriceBBigDec := osmomath.BigDecFromSDKDec(sqrtPriceB) - +func GetLiquidityFromAmounts(sqrtPrice osmomath.BigDec, sqrtPriceA, sqrtPriceB osmomath.BigDec, amount0, amount1 sdk.Int) (liquidity sdk.Dec) { // Reorder the prices so that sqrtPriceA is the smaller of the two. // todo: Remove this. - if sqrtPriceABigDec.GT(sqrtPriceBBigDec) { - sqrtPriceABigDec, sqrtPriceBBigDec = sqrtPriceBBigDec, sqrtPriceABigDec + if sqrtPriceA.GT(sqrtPriceB) { + sqrtPriceA, sqrtPriceB = sqrtPriceB, sqrtPriceA } - if sqrtPrice.LTE(sqrtPriceABigDec) { + if sqrtPrice.LTE(sqrtPriceA) { // If the current price is less than or equal to the lower tick, then we use the liquidity0 formula. - liquidity = Liquidity0(amount0, sqrtPriceABigDec, sqrtPriceBBigDec) - } else if sqrtPrice.LT(sqrtPriceBBigDec) { + liquidity = Liquidity0(amount0, sqrtPriceA, sqrtPriceB) + } else if sqrtPrice.LT(sqrtPriceB) { // If the current price is between the lower and upper ticks (exclusive of both the lower and upper ticks, // as both would trigger a division by zero), then we use the minimum of the liquidity0 and liquidity1 formulas. - liquidity0 := Liquidity0(amount0, sqrtPrice, sqrtPriceBBigDec) - liquidity1 := Liquidity1(amount1, sqrtPrice, sqrtPriceABigDec) + liquidity0 := Liquidity0(amount0, sqrtPrice, sqrtPriceB) + liquidity1 := Liquidity1(amount1, sqrtPrice, sqrtPriceA) liquidity = sdk.MinDec(liquidity0, liquidity1) } else { // If the current price is greater than the upper tick, then we use the liquidity1 formula. - liquidity = Liquidity1(amount1, sqrtPriceBBigDec, sqrtPriceABigDec) + liquidity = Liquidity1(amount1, sqrtPriceB, sqrtPriceA) } return liquidity diff --git a/x/concentrated-liquidity/math/math_test.go b/x/concentrated-liquidity/math/math_test.go index 388c6e6d413..84ad2f1f5b3 100644 --- a/x/concentrated-liquidity/math/math_test.go +++ b/x/concentrated-liquidity/math/math_test.go @@ -268,8 +268,8 @@ func TestGetLiquidityFromAmounts(t *testing.T) { testCases := map[string]struct { currentSqrtP osmomath.BigDec - sqrtPHigh sdk.Dec - sqrtPLow sdk.Dec + sqrtPHigh osmomath.BigDec + sqrtPLow osmomath.BigDec // the amount of token0 that will need to be sold to move the price from P_cur to P_low amount0Desired sdk.Int // the amount of token 1 that will need to be sold to move the price from P_cur to P_high. @@ -283,40 +283,40 @@ func TestGetLiquidityFromAmounts(t *testing.T) { }{ "happy path (case A)": { currentSqrtP: osmomath.MustNewDecFromStr("67"), // 4489 - sqrtPHigh: sqrt5500, // 5500 - sqrtPLow: sqrt4545, // 4545 + sqrtPHigh: sqrt5500BigDec, // 5500 + sqrtPLow: sqrt4545BigDec, // 4545 amount0Desired: sdk.NewInt(1000000), amount1Desired: sdk.ZeroInt(), expectedLiquidity: "741212151.448720111852782017", }, "happy path (case A, but with sqrtPriceA greater than sqrtPriceB)": { currentSqrtP: osmomath.MustNewDecFromStr("67"), // 4489 - sqrtPHigh: sqrt4545, // 4545 - sqrtPLow: sqrt5500, // 5500 + sqrtPHigh: sqrt4545BigDec, // 4545 + sqrtPLow: sqrt5500BigDec, // 5500 amount0Desired: sdk.NewInt(1000000), amount1Desired: sdk.ZeroInt(), expectedLiquidity: "741212151.448720111852782017", }, "happy path (case B)": { currentSqrtP: sqrt5000BigDec, // 5000 - sqrtPHigh: sqrt5500, // 5500 - sqrtPLow: sqrt4545, // 4545 + sqrtPHigh: sqrt5500BigDec, // 5500 + sqrtPLow: sqrt4545BigDec, // 4545 amount0Desired: sdk.NewInt(1000000), amount1Desired: sdk.NewInt(5000000000), expectedLiquidity: "1517882343.751510418088349649", }, "happy path (case C)": { currentSqrtP: osmomath.MustNewDecFromStr("75"), // 5625 - sqrtPHigh: sqrt5500, // 5500 - sqrtPLow: sqrt4545, // 4545 + sqrtPHigh: sqrt5500BigDec, // 5500 + sqrtPLow: sqrt4545BigDec, // 4545 amount0Desired: sdk.ZeroInt(), amount1Desired: sdk.NewInt(5000000000), expectedLiquidity: "741249214.836069764856625637", }, "full range, price proportional to amounts, equal liquidities (some rounding error) price of 4": { currentSqrtP: sqrt(sdk.NewDec(4)), - sqrtPHigh: cltypes.MaxSqrtPrice, - sqrtPLow: cltypes.MinSqrtPrice, + sqrtPHigh: osmomath.BigDecFromSDKDec(cltypes.MaxSqrtPrice), + sqrtPLow: osmomath.BigDecFromSDKDec(cltypes.MinSqrtPrice), amount0Desired: sdk.NewInt(4), amount1Desired: sdk.NewInt(16), @@ -326,8 +326,8 @@ func TestGetLiquidityFromAmounts(t *testing.T) { }, "full range, price proportional to amounts, equal liquidities (some rounding error) price of 2": { currentSqrtP: sqrt(sdk.NewDec(2)), - sqrtPHigh: cltypes.MaxSqrtPrice, - sqrtPLow: cltypes.MinSqrtPrice, + sqrtPHigh: osmomath.BigDecFromSDKDec(cltypes.MaxSqrtPrice), + sqrtPLow: osmomath.BigDecFromSDKDec(cltypes.MinSqrtPrice), amount0Desired: sdk.NewInt(1), amount1Desired: sdk.NewInt(2), @@ -337,8 +337,8 @@ func TestGetLiquidityFromAmounts(t *testing.T) { }, "not full range, price proportional to amounts, non equal liquidities": { currentSqrtP: sqrt(sdk.NewDec(2)), - sqrtPHigh: sqrt(sdk.NewDec(3)).SDKDec(), - sqrtPLow: sqrt(sdk.NewDec(1)).SDKDec(), + sqrtPHigh: sqrt(sdk.NewDec(3)), + sqrtPLow: sqrt(sdk.NewDec(1)), amount0Desired: sdk.NewInt(1), amount1Desired: sdk.NewInt(2), @@ -348,8 +348,8 @@ func TestGetLiquidityFromAmounts(t *testing.T) { }, "current sqrt price on upper bound": { currentSqrtP: sqrt5500BigDec, - sqrtPHigh: sqrt5500, - sqrtPLow: sqrt4545, + sqrtPHigh: sqrt5500BigDec, + sqrtPLow: sqrt4545BigDec, amount0Desired: sdk.ZeroInt(), amount1Desired: sdk.NewInt(1000000), // Liquidity1 = amount1 / (sqrtPriceB - sqrtPriceA) diff --git a/x/concentrated-liquidity/math/tick.go b/x/concentrated-liquidity/math/tick.go index 5310608cd84..07a9d971d4b 100644 --- a/x/concentrated-liquidity/math/tick.go +++ b/x/concentrated-liquidity/math/tick.go @@ -13,17 +13,17 @@ import ( // TicksToSqrtPrice returns the sqrtPrice for the lower and upper ticks by // individually calling `TickToSqrtPrice` method. // Returns error if fails to calculate price. -func TicksToSqrtPrice(lowerTick, upperTick int64) (sdk.Dec, sdk.Dec, error) { +func TicksToSqrtPrice(lowerTick, upperTick int64) (osmomath.BigDec, osmomath.BigDec, error) { if lowerTick >= upperTick { - return sdk.Dec{}, sdk.Dec{}, types.InvalidLowerUpperTickError{LowerTick: lowerTick, UpperTick: upperTick} + return osmomath.BigDec{}, osmomath.BigDec{}, types.InvalidLowerUpperTickError{LowerTick: lowerTick, UpperTick: upperTick} } _, sqrtPriceUpperTick, err := TickToSqrtPrice(upperTick) if err != nil { - return sdk.Dec{}, sdk.Dec{}, err + return osmomath.BigDec{}, osmomath.BigDec{}, err } _, sqrtPriceLowerTick, err := TickToSqrtPrice(lowerTick) if err != nil { - return sdk.Dec{}, sdk.Dec{}, err + return osmomath.BigDec{}, osmomath.BigDec{}, err } return sqrtPriceLowerTick, sqrtPriceUpperTick, nil } @@ -31,41 +31,29 @@ func TicksToSqrtPrice(lowerTick, upperTick int64) (sdk.Dec, sdk.Dec, error) { // TickToSqrtPrice returns the sqrtPrice given a tickIndex // If tickIndex is zero, the function returns sdk.OneDec(). // It is the combination of calling TickToPrice followed by Sqrt. -func TickToSqrtPrice(tickIndex int64) (sdk.Dec, sdk.Dec, error) { - price, err := TickToPrice(tickIndex) +func TickToSqrtPrice(tickIndex int64) (osmomath.BigDec, osmomath.BigDec, error) { + priceBigDec, err := TickToPrice(tickIndex) if err != nil { - return sdk.Dec{}, sdk.Dec{}, err + return osmomath.BigDec{}, osmomath.BigDec{}, err } - // Determine the sqrtPrice from the price - sqrtPrice, err := osmomath.MonotonicSqrt(price) - if err != nil { - return sdk.Dec{}, sdk.Dec{}, err - } - return price, sqrtPrice, nil -} - -// TickToSqrtPriceBigDec returns the sqrtPrice given a tickIndex -// as a BigDec. -func TickToSqrtPriceBigDec(tickIndex int64) (osmomath.BigDec, error) { - price, err := TickToPrice(tickIndex) - if err != nil { - return osmomath.BigDec{}, err - } + // It is acceptable to truncate here as TickToPrice() function converts + // from sdk.Dec to osmomath.BigDec before returning. + price := priceBigDec.SDKDec() // Determine the sqrtPrice from the price sqrtPrice, err := osmomath.MonotonicSqrt(price) if err != nil { - return osmomath.BigDec{}, err + return osmomath.BigDec{}, osmomath.BigDec{}, err } - return osmomath.BigDecFromSDKDec(sqrtPrice), nil + return osmomath.BigDecFromSDKDec(price), osmomath.BigDecFromSDKDec(sqrtPrice), nil } // TickToPrice returns the price given a tickIndex // If tickIndex is zero, the function returns sdk.OneDec(). -func TickToPrice(tickIndex int64) (price sdk.Dec, err error) { +func TickToPrice(tickIndex int64) (osmomath.BigDec, error) { if tickIndex == 0 { - return sdk.OneDec(), nil + return osmomath.OneDec(), nil } // The formula is as follows: geometricExponentIncrementDistanceInTicks = 9 * 10**(-exponentAtPriceOne) @@ -75,10 +63,10 @@ func TickToPrice(tickIndex int64) (price sdk.Dec, err error) { // Check that the tick index is between min and max value if tickIndex < types.MinCurrentTick { - return sdk.Dec{}, types.TickIndexMinimumError{MinTick: types.MinCurrentTick} + return osmomath.BigDec{}, types.TickIndexMinimumError{MinTick: types.MinCurrentTick} } if tickIndex > types.MaxTick { - return sdk.Dec{}, types.TickIndexMaximumError{MaxTick: types.MaxTick} + return osmomath.BigDec{}, types.TickIndexMaximumError{MaxTick: types.MaxTick} } // Use floor division to determine what the geometricExponent is now (the delta) @@ -100,14 +88,14 @@ func TickToPrice(tickIndex int64) (price sdk.Dec, err error) { numAdditiveTicks := tickIndex - (geometricExponentDelta * geometricExponentIncrementDistanceInTicks) // Finally, we can calculate the price - price = PowTenInternal(geometricExponentDelta).Add(osmomath.NewBigDec(numAdditiveTicks).Mul(currentAdditiveIncrementInTicks).SDKDec()) + price := PowTenInternal(geometricExponentDelta).Add(osmomath.NewBigDec(numAdditiveTicks).Mul(currentAdditiveIncrementInTicks).SDKDec()) // defense in depth, this logic would not be reached due to use having checked if given tick is in between // min tick and max tick. if price.GT(types.MaxSpotPrice) || price.LT(types.MinSpotPrice) { - return sdk.Dec{}, types.PriceBoundError{ProvidedPrice: price, MinSpotPrice: types.MinSpotPrice, MaxSpotPrice: types.MaxSpotPrice} + return osmomath.BigDec{}, types.PriceBoundError{ProvidedPrice: price, MinSpotPrice: types.MinSpotPrice, MaxSpotPrice: types.MaxSpotPrice} } - return price, nil + return osmomath.BigDecFromSDKDec(price), nil } // RoundDownTickToSpacing rounds the tick index down to the nearest tick spacing if the tickIndex is in between authorized tick values @@ -139,8 +127,8 @@ func RoundDownTickToSpacing(tickIndex int64, tickSpacing int64) (int64, error) { // SqrtPriceToTickRoundDown converts the given sqrt price to its corresponding tick rounded down // to the nearest tick spacing. -func SqrtPriceToTickRoundDownSpacing(sqrtPrice sdk.Dec, tickSpacing uint64) (int64, error) { - tickIndex, err := CalculateSqrtPriceToTick(osmomath.BigDecFromSDKDec(sqrtPrice)) +func SqrtPriceToTickRoundDownSpacing(sqrtPrice osmomath.BigDec, tickSpacing uint64) (int64, error) { + tickIndex, err := CalculateSqrtPriceToTick(sqrtPrice) if err != nil { return 0, err } @@ -169,7 +157,11 @@ func powTenBigDec(exponent int64) osmomath.BigDec { return bigNegPowersOfTen[-exponent] } -func CalculatePriceToTickDec(price sdk.Dec) (tickIndex sdk.Dec, err error) { +func CalculatePriceToTickDec(priceBigDec osmomath.BigDec) (tickIndex sdk.Dec, err error) { + // It is acceptable to truncate price as the minimum we support is + // 10**-12 which is above the smallest value of sdk.Dec. + price := priceBigDec.SDKDec() + if price.IsNegative() { return sdk.ZeroDec(), fmt.Errorf("price must be greater than zero") } @@ -225,11 +217,7 @@ func CalculateSqrtPriceToTick(sqrtPrice osmomath.BigDec) (tickIndex int64, err e // and move it in a +/- 1 tick range based on the sqrt price those ticks would imply. price := sqrtPrice.Mul(sqrtPrice) - // It is acceptable to truncate price as the minimum we support is - // 10**-12 which is above the smallest value of sdk.Dec. - priceDec := price.SDKDec() - - tick, err := CalculatePriceToTickDec(priceDec) + tick, err := CalculatePriceToTickDec(price) if err != nil { return 0, err } @@ -257,10 +245,10 @@ func CalculateSqrtPriceToTick(sqrtPrice osmomath.BigDec) (tickIndex int64, err e outOfBounds = true } - sqrtPriceTmin1, errM1 := TickToSqrtPriceBigDec(truncatedTick - 1) - sqrtPriceT, errT := TickToSqrtPriceBigDec(truncatedTick) - sqrtPriceTplus1, errP1 := TickToSqrtPriceBigDec(truncatedTick + 1) - sqrtPriceTplus2, errP2 := TickToSqrtPriceBigDec(truncatedTick + 2) + _, sqrtPriceTmin1, errM1 := TickToSqrtPrice(truncatedTick - 1) + _, sqrtPriceT, errT := TickToSqrtPrice(truncatedTick) + _, sqrtPriceTplus1, errP1 := TickToSqrtPrice(truncatedTick + 1) + _, sqrtPriceTplus2, errP2 := TickToSqrtPrice(truncatedTick + 2) if errM1 != nil || errT != nil || errP1 != nil || errP2 != nil { return 0, errors.New("internal error in computing square roots within CalculateSqrtPriceToTick") } diff --git a/x/concentrated-liquidity/math/tick_test.go b/x/concentrated-liquidity/math/tick_test.go index 82c7f6e2c88..e20c837fa72 100644 --- a/x/concentrated-liquidity/math/tick_test.go +++ b/x/concentrated-liquidity/math/tick_test.go @@ -25,7 +25,7 @@ var ( ) // testing helper for price to tick, state machine only implements sqrt price to tick. -func PriceToTick(price sdk.Dec) (int64, error) { +func PriceToTick(price osmomath.BigDec) (int64, error) { tickDec, err := math.CalculatePriceToTickDec(price) tickIndex := tickDec.TruncateInt64() return tickIndex, err @@ -33,7 +33,7 @@ func PriceToTick(price sdk.Dec) (int64, error) { // testing helper for price to tick round down spacing, // state machine only implements sqrt price to tick round dow spacing. -func PriceToTickRoundDownSpacing(price sdk.Dec, tickSpacing uint64) (int64, error) { +func PriceToTickRoundDownSpacing(price osmomath.BigDec, tickSpacing uint64) (int64, error) { tickIndex, err := PriceToTick(price) if err != nil { return 0, err @@ -219,8 +219,8 @@ func TestTickToSqrtPrice(t *testing.T) { expectedSqrtPrice, err := osmomath.MonotonicSqrt(tc.expectedPrice) require.NoError(t, err) - require.Equal(t, tc.expectedPrice.String(), price.String()) - require.Equal(t, expectedSqrtPrice.String(), sqrtPrice.String()) + require.Equal(t, osmomath.BigDecFromSDKDec(tc.expectedPrice).String(), price.String()) + require.Equal(t, osmomath.BigDecFromSDKDec(expectedSqrtPrice).String(), sqrtPrice.String()) }) } } @@ -297,8 +297,8 @@ func TestTicksToSqrtPrice(t *testing.T) { expectedUpperSqrtPrice, err := osmomath.MonotonicSqrt(tc.expectedUpperPrice) require.NoError(t, err) - require.Equal(t, expectedLowerSqrtPrice.String(), lowerSqrtPrice.String()) - require.Equal(t, expectedUpperSqrtPrice.String(), upperSqrtPrice.String()) + require.Equal(t, osmomath.BigDecFromSDKDec(expectedLowerSqrtPrice).String(), lowerSqrtPrice.String()) + require.Equal(t, osmomath.BigDecFromSDKDec(expectedUpperSqrtPrice).String(), upperSqrtPrice.String()) }) } } @@ -309,88 +309,88 @@ func TestPriceToTick(t *testing.T) { ) testCases := map[string]struct { - price sdk.Dec + price osmomath.BigDec tickExpected int64 expectedError error }{ "BTC <> USD, tick 38035200 -> price 30352": { - price: sdk.MustNewDecFromStr("30352"), + price: osmomath.MustNewDecFromStr("30352"), tickExpected: 38035200, }, "BTC <> USD, tick 38035300 + 100 -> price 30353": { - price: sdk.MustNewDecFromStr("30353"), + price: osmomath.MustNewDecFromStr("30353"), tickExpected: 38035300, }, "SHIB <> USD, tick -44821000 -> price 0.000011790": { - price: sdk.MustNewDecFromStr("0.000011790"), + price: osmomath.MustNewDecFromStr("0.000011790"), tickExpected: -44821000, }, "SHIB <> USD, tick -44820900 -> price 0.000011791": { - price: sdk.MustNewDecFromStr("0.000011791"), + price: osmomath.MustNewDecFromStr("0.000011791"), tickExpected: -44820900, }, "ETH <> BTC, tick -12104000 -> price 0.068960": { - price: sdk.MustNewDecFromStr("0.068960"), + price: osmomath.MustNewDecFromStr("0.068960"), tickExpected: -12104000, }, "ETH <> BTC, tick -12104000 + 100 -> price 0.068961": { - price: sdk.MustNewDecFromStr("0.068961"), + price: osmomath.MustNewDecFromStr("0.068961"), tickExpected: -12103900, }, "max sqrt price -1, max neg tick six - 100 -> max tick neg six - 100": { - price: sdk.MustNewDecFromStr("99999000000000000000000000000000000000"), + price: osmomath.MustNewDecFromStr("99999000000000000000000000000000000000"), tickExpected: types.MaxTick - 100, }, "max sqrt price, max tick neg six -> max spot price": { - price: types.MaxSqrtPrice.Power(2), + price: osmomath.BigDecFromSDKDec(types.MaxSqrtPrice.Power(2)), tickExpected: types.MaxTick, }, "Gyen <> USD, tick -20594000 -> price 0.0074060": { - price: sdk.MustNewDecFromStr("0.007406"), + price: osmomath.MustNewDecFromStr("0.007406"), tickExpected: -20594000, }, "Gyen <> USD, tick -20594000 + 100 -> price 0.0074061": { - price: sdk.MustNewDecFromStr("0.0074061"), + price: osmomath.MustNewDecFromStr("0.0074061"), tickExpected: -20593900, }, "Spell <> USD, tick -29204000 -> price 0.00077960": { - price: sdk.MustNewDecFromStr("0.0007796"), + price: osmomath.MustNewDecFromStr("0.0007796"), tickExpected: -29204000, }, "Spell <> USD, tick -29204000 + 100 -> price 0.00077961": { - price: sdk.MustNewDecFromStr("0.00077961"), + price: osmomath.MustNewDecFromStr("0.00077961"), tickExpected: -29203900, }, "Atom <> Osmo, tick -12150000 -> price 0.068500": { - price: sdk.MustNewDecFromStr("0.0685"), + price: osmomath.MustNewDecFromStr("0.0685"), tickExpected: -12150000, }, "Atom <> Osmo, tick -12150000 + 100 -> price 0.068501": { - price: sdk.MustNewDecFromStr("0.068501"), + price: osmomath.MustNewDecFromStr("0.068501"), tickExpected: -12149900, }, "Boot <> Osmo, tick 64576000 -> price 25760000": { - price: sdk.MustNewDecFromStr("25760000"), + price: osmomath.MustNewDecFromStr("25760000"), tickExpected: 64576000, }, "Boot <> Osmo, tick 64576000 + 100 -> price 25761000": { - price: sdk.MustNewDecFromStr("25761000"), + price: osmomath.MustNewDecFromStr("25761000"), tickExpected: 64576100, }, "price is one Dec": { - price: sdk.OneDec(), + price: osmomath.OneDec(), tickExpected: 0, }, "price is negative decimal": { - price: sdk.OneDec().Neg(), + price: osmomath.OneDec().Neg(), expectedError: fmt.Errorf("price must be greater than zero"), }, "price is greater than max spot price": { - price: types.MaxSpotPrice.Add(sdk.OneDec()), + price: osmomath.BigDecFromSDKDec(types.MaxSpotPrice.Add(sdk.OneDec())), expectedError: types.PriceBoundError{ProvidedPrice: types.MaxSpotPrice.Add(sdk.OneDec()), MinSpotPrice: types.MinSpotPrice, MaxSpotPrice: types.MaxSpotPrice}, }, "price is smaller than min spot price": { - price: types.MinSpotPrice.Quo(sdk.NewDec(10)), + price: osmomath.BigDecFromSDKDec(types.MinSpotPrice.Quo(sdk.NewDec(10))), expectedError: types.PriceBoundError{ProvidedPrice: types.MinSpotPrice.Quo(sdk.NewDec(10)), MinSpotPrice: types.MinSpotPrice, MaxSpotPrice: types.MaxSpotPrice}, }, } @@ -417,64 +417,64 @@ func TestPriceToTick(t *testing.T) { func TestPriceToTickRoundDown(t *testing.T) { testCases := map[string]struct { - price sdk.Dec + price osmomath.BigDec tickSpacing uint64 tickExpected int64 }{ "tick spacing 100, price of 1": { - price: sdk.OneDec(), + price: osmomath.OneDec(), tickSpacing: defaultTickSpacing, tickExpected: 0, }, "tick spacing 100, price of 1.000030, tick 30 -> 0": { - price: sdk.MustNewDecFromStr("1.000030"), + price: osmomath.MustNewDecFromStr("1.000030"), tickSpacing: defaultTickSpacing, tickExpected: 0, }, "tick spacing 100, price of 0.9999970, tick -30 -> -100": { - price: sdk.MustNewDecFromStr("0.9999970"), + price: osmomath.MustNewDecFromStr("0.9999970"), tickSpacing: defaultTickSpacing, tickExpected: -100, }, "tick spacing 50, price of 0.9999730, tick -270 -> -300": { - price: sdk.MustNewDecFromStr("0.9999730"), + price: osmomath.MustNewDecFromStr("0.9999730"), tickSpacing: 50, tickExpected: -300, }, "tick spacing 100, MinSpotPrice, MinTick": { - price: types.MinSpotPrice, + price: osmomath.BigDecFromSDKDec(types.MinSpotPrice), tickSpacing: defaultTickSpacing, tickExpected: types.MinInitializedTick, }, "tick spacing 100, Spot price one tick above min, one tick above min -> MinTick": { - price: types.MinSpotPrice.Add(sdk.SmallestDec()), + price: osmomath.BigDecFromSDKDec(types.MinSpotPrice.Add(sdk.SmallestDec())), tickSpacing: defaultTickSpacing, // Since the tick should always be the closest tick below (and `smallestDec` isn't sufficient // to push us into the next tick), we expect MinTick to be returned here. tickExpected: types.MinInitializedTick, }, "tick spacing 100, Spot price one tick below max, one tick below max -> MaxTick - 1": { - price: closestPriceBelowMaxPriceDefaultTickSpacing, + price: osmomath.BigDecFromSDKDec(closestPriceBelowMaxPriceDefaultTickSpacing), tickSpacing: defaultTickSpacing, tickExpected: types.MaxTick - 100, }, "tick spacing 100, Spot price 100_000_050 -> 72000000": { - price: sdk.NewDec(100_000_050), + price: osmomath.NewBigDec(100_000_050), tickSpacing: defaultTickSpacing, tickExpected: 72000000, }, "tick spacing 100, Spot price 100_000_051 -> 72000100 (rounded up to tick spacing)": { - price: sdk.NewDec(100_000_051), + price: osmomath.NewBigDec(100_000_051), tickSpacing: defaultTickSpacing, tickExpected: 72000000, }, "tick spacing 1, Spot price 100_000_051 -> 72000000 no tick spacing rounding": { - price: sdk.NewDec(100_000_051), + price: osmomath.NewBigDec(100_000_051), tickSpacing: 1, tickExpected: 72000000, }, "tick spacing 1, Spot price 100_000_101 -> 72000001 no tick spacing rounding": { - price: sdk.NewDec(100_000_101), + price: osmomath.NewBigDec(100_000_101), tickSpacing: 1, tickExpected: 72000001, }, @@ -496,90 +496,90 @@ func TestPriceToTickRoundDown(t *testing.T) { // TODO: Revisit this test, under the lens of bucket index. func TestTickToSqrtPricePriceToTick_InverseRelationship(t *testing.T) { type testcase struct { - price sdk.Dec - truncatedPrice sdk.Dec + price osmomath.BigDec + truncatedPrice osmomath.BigDec tickExpected int64 } testCases := map[string]testcase{ "50000 to tick": { - price: sdk.MustNewDecFromStr("50000"), + price: osmomath.MustNewDecFromStr("50000"), tickExpected: 40000000, }, "5.01 to tick": { - price: sdk.MustNewDecFromStr("5.01"), + price: osmomath.MustNewDecFromStr("5.01"), tickExpected: 4010000, }, "50000.01 to tick": { - price: sdk.MustNewDecFromStr("50000.01"), + price: osmomath.MustNewDecFromStr("50000.01"), tickExpected: 40000001, }, "0.090001 to tick": { - price: sdk.MustNewDecFromStr("0.090001"), + price: osmomath.MustNewDecFromStr("0.090001"), tickExpected: -9999900, }, "0.9998 to tick": { - price: sdk.MustNewDecFromStr("0.9998"), + price: osmomath.MustNewDecFromStr("0.9998"), tickExpected: -2000, }, "53030 to tick": { - price: sdk.MustNewDecFromStr("53030"), + price: osmomath.MustNewDecFromStr("53030"), tickExpected: 40303000, }, "max spot price": { - price: types.MaxSpotPrice, + price: osmomath.BigDecFromSDKDec(types.MaxSpotPrice), tickExpected: types.MaxTick, }, "max spot price - smallest price delta given exponent at price one of -6": { // 37 - 6 is calculated by counting the exponent of max spot price and subtracting exponent at price one - price: types.MaxSpotPrice.Sub(sdk.NewDec(10).PowerMut(37 - 6)), + price: osmomath.BigDecFromSDKDec(types.MaxSpotPrice.Sub(sdk.NewDec(10).PowerMut(37 - 6))), tickExpected: types.MaxTick - 1, // still max }, "min spot price": { - price: types.MinSpotPrice, + price: osmomath.BigDecFromSDKDec(types.MinSpotPrice), tickExpected: types.MinInitializedTick, }, "smallest + min price + tick": { - price: sdk.MustNewDecFromStr("0.000000000001000001"), + price: osmomath.MustNewDecFromStr("0.000000000001000001"), tickExpected: types.MinInitializedTick + 1, }, "at price level of 0.01 - odd": { - price: sdk.MustNewDecFromStr("0.012345670000000000"), + price: osmomath.MustNewDecFromStr("0.012345670000000000"), tickExpected: -17765433, }, "at price level of 0.01 - even": { - price: sdk.MustNewDecFromStr("0.01234568000000000"), + price: osmomath.MustNewDecFromStr("0.01234568000000000"), tickExpected: -17765432, }, "at min price level of 0.01 - odd": { - price: sdk.MustNewDecFromStr("0.000000000001234567"), + price: osmomath.MustNewDecFromStr("0.000000000001234567"), tickExpected: -107765433, }, "at min price level of 0.01 - even": { - price: sdk.MustNewDecFromStr("0.000000000001234568"), + price: osmomath.MustNewDecFromStr("0.000000000001234568"), tickExpected: -107765432, }, "at price level of 1_000_000_000 - odd end": { - price: sdk.MustNewDecFromStr("1234567000"), + price: osmomath.MustNewDecFromStr("1234567000"), tickExpected: 81234567, }, "at price level of 1_000_000_000 - in-between supported": { - price: sdk.MustNewDecFromStr("1234567500"), + price: osmomath.MustNewDecFromStr("1234567500"), tickExpected: 81234567, - truncatedPrice: sdk.MustNewDecFromStr("1234567000"), + truncatedPrice: osmomath.MustNewDecFromStr("1234567000"), }, "at price level of 1_000_000_000 - even end": { - price: sdk.MustNewDecFromStr("1234568000"), + price: osmomath.MustNewDecFromStr("1234568000"), tickExpected: 81234568, }, "inverse testing with 1": { - price: sdk.OneDec(), + price: osmomath.OneDec(), tickExpected: 0, }, } var powTen int64 = 10 for i := 1; i < 13; i++ { testCases[fmt.Sprintf("min spot price * 10^%d", i)] = testcase{ - price: types.MinSpotPrice.MulInt64(powTen), + price: osmomath.BigDecFromSDKDec(types.MinSpotPrice.MulInt64(powTen)), tickExpected: types.MinInitializedTick + (int64(i) * 9e6), } powTen *= 10 @@ -618,7 +618,7 @@ func TestTickToSqrtPricePriceToTick_InverseRelationship(t *testing.T) { // require.Equal(t, expectedPrice.String(), priceFromSqrtPrice.String()) // 5. Compute tick from sqrt price from the original tick. - inverseTickFromSqrtPrice, err := math.CalculateSqrtPriceToTick(osmomath.BigDecFromSDKDec(sqrtPrice)) + inverseTickFromSqrtPrice, err := math.CalculateSqrtPriceToTick(sqrtPrice) require.NoError(t, err) require.Equal(t, tickFromPrice, inverseTickFromSqrtPrice, "expected: %s, actual: %s", tickFromPrice, inverseTickFromSqrtPrice) @@ -628,16 +628,16 @@ func TestTickToSqrtPricePriceToTick_InverseRelationship(t *testing.T) { func TestPriceToTick_ErrorCases(t *testing.T) { testCases := map[string]struct { - price sdk.Dec + price osmomath.BigDec }{ "use negative price": { - price: sdk.OneDec().Neg(), + price: osmomath.OneDec().Neg(), }, "price is greater than max spot price": { - price: types.MaxSpotPrice.Add(sdk.OneDec()), + price: osmomath.BigDecFromSDKDec(types.MaxSpotPrice.Add(sdk.OneDec())), }, "price is less than min spot price": { - price: types.MinSpotPrice.Sub(sdk.OneDec()), + price: osmomath.BigDecFromSDKDec(types.MinSpotPrice.Sub(sdk.OneDec())), }, } for name, tc := range testCases { @@ -673,31 +673,31 @@ func TestTickToPrice_ErrorCases(t *testing.T) { func TestCalculatePriceToTick(t *testing.T) { testCases := map[string]struct { - price sdk.Dec + price osmomath.BigDec expectedTickIndex int64 }{ "Price greater than 1": { - price: sdk.MustNewDecFromStr("9.78"), + price: osmomath.MustNewDecFromStr("9.78"), expectedTickIndex: 8780000, }, "Price less than 1": { - price: sdk.MustNewDecFromStr("0.71"), + price: osmomath.MustNewDecFromStr("0.71"), expectedTickIndex: -2900000, }, "100_000_000 -> 72000000": { - price: sdk.NewDec(100_000_000), + price: osmomath.NewBigDec(100_000_000), expectedTickIndex: 72000000, }, "100_000_050 -> 72000000": { - price: sdk.NewDec(100_000_050), + price: osmomath.NewBigDec(100_000_050), expectedTickIndex: 72000000, }, "100_000_051 -> 72000000": { - price: sdk.NewDec(100_000_051), + price: osmomath.NewBigDec(100_000_051), expectedTickIndex: 72000000, }, "100_000_100 -> 72000001": { - price: sdk.NewDec(100_000_100), + price: osmomath.NewBigDec(100_000_100), expectedTickIndex: 72000001, }, } @@ -736,6 +736,8 @@ func TestPowTenInternal(t *testing.T) { } func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { + sdkULP := osmomath.BigDecFromSDKDec(sdk.SmallestDec()) + // Compute reference values that need to be satisfied _, sqp1, err := math.TickToSqrtPrice(1) require.NoError(t, err) @@ -755,12 +757,12 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { require.NoError(t, err) testCases := map[string]struct { - sqrtPrice sdk.Dec + sqrtPrice osmomath.BigDec tickSpacing uint64 tickExpected int64 }{ "sqrt price of 1 (tick spacing 1)": { - sqrtPrice: sdk.OneDec(), + sqrtPrice: osmomath.OneDec(), tickSpacing: 1, tickExpected: 0, }, @@ -770,7 +772,7 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { tickExpected: 1, }, "sqrt price one ULP below boundary of next tick (tick spacing 1)": { - sqrtPrice: sqp1.Sub(sdk.SmallestDec()), + sqrtPrice: sqp1.Sub(sdkULP), tickSpacing: 1, tickExpected: 0, }, @@ -785,7 +787,7 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { tickExpected: 100, }, "sqrt price one ULP below bucket 100 (tick spacing 100)": { - sqrtPrice: sqp100.Sub(sdk.SmallestDec()), + sqrtPrice: sqp100.Sub(sdkULP), tickSpacing: defaultTickSpacing, tickExpected: 0, }, @@ -795,7 +797,7 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { tickExpected: -100, }, "sqrt price one ULP below bucket -100 (tick spacing 100)": { - sqrtPrice: sqpn100.Sub(sdk.SmallestDec()), + sqrtPrice: sqpn100.Sub(sdkULP), tickSpacing: defaultTickSpacing, tickExpected: -200, }, @@ -805,17 +807,17 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { tickExpected: -200, }, "sqrt price exactly equal to max sqrt price": { - sqrtPrice: types.MaxSqrtPrice, + sqrtPrice: osmomath.BigDecFromSDKDec(types.MaxSqrtPrice), tickSpacing: defaultTickSpacing, tickExpected: types.MaxTick, }, "sqrt price exactly equal to min sqrt price": { - sqrtPrice: types.MinSqrtPrice, + sqrtPrice: osmomath.BigDecFromSDKDec(types.MinSqrtPrice), tickSpacing: defaultTickSpacing, tickExpected: types.MinInitializedTick, }, "sqrt price equal to max sqrt price minus one ULP": { - sqrtPrice: types.MaxSqrtPrice.Sub(sdk.SmallestDec()), + sqrtPrice: osmomath.BigDecFromSDKDec(types.MaxSqrtPrice).Sub(sdkULP), tickSpacing: defaultTickSpacing, tickExpected: types.MaxTick - defaultTickSpacing, }, @@ -825,12 +827,12 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { tickExpected: types.MaxTick - 1, }, "sqrt price one ULP below max tick - 1 (tick spacing 1)": { - sqrtPrice: sqpMaxTickSubOne.Sub(sdk.SmallestDec()), + sqrtPrice: sqpMaxTickSubOne.Sub(sdkULP), tickSpacing: 1, tickExpected: types.MaxTick - 2, }, "sqrt price one ULP below max tick - 1 (tick spacing 100)": { - sqrtPrice: sqpMaxTickSubOne.Sub(sdk.SmallestDec()), + sqrtPrice: sqpMaxTickSubOne.Sub(sdkULP), tickSpacing: defaultTickSpacing, tickExpected: types.MaxTick - defaultTickSpacing, }, @@ -841,13 +843,13 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { }, "sqrt price corresponds exactly to min tick + 1 minus 1 ULP (tick spacing 1)": { // Calculated using TickToSqrtPrice(types.MinInitializedTick + 1) - 1 ULP - sqrtPrice: sqpMinTickPlusOne.Sub(sdk.SmallestDec()), + sqrtPrice: sqpMinTickPlusOne.Sub(sdkULP), tickSpacing: 1, tickExpected: types.MinInitializedTick, }, "sqrt price corresponds exactly to min tick + 1 plus 1 ULP (tick spacing 1)": { // Calculated using TickToSqrtPrice(types.MinInitializedTick + 1) + 1 ULP - sqrtPrice: sqpMinTickPlusOne.Add(sdk.SmallestDec()), + sqrtPrice: sqpMinTickPlusOne.Add(sdkULP), tickSpacing: 1, tickExpected: types.MinInitializedTick + 1, }, @@ -858,13 +860,13 @@ func TestSqrtPriceToTickRoundDownSpacing(t *testing.T) { }, "sqrt price corresponds exactly to min tick + 2 plus 1 ULP (tick spacing 1)": { // Calculated using TickToSqrtPrice(types.MinInitializedTick + 2) + 1 ULP - sqrtPrice: sqpMinTickPlusTwo.Add(sdk.SmallestDec()), + sqrtPrice: sqpMinTickPlusTwo.Add(sdkULP), tickSpacing: 1, tickExpected: types.MinInitializedTick + 2, }, "sqrt price corresponds exactly to min tick + 2 minus 1 ULP (tick spacing 1)": { // Calculated using TickToSqrtPrice(types.MinInitializedTick + 2) - 1 ULP - sqrtPrice: sqpMinTickPlusTwo.Sub(sdk.SmallestDec()), + sqrtPrice: sqpMinTickPlusTwo.Sub(sdkULP), tickSpacing: 1, tickExpected: types.MinInitializedTick + 1, }, diff --git a/x/concentrated-liquidity/model/pool.go b/x/concentrated-liquidity/model/pool.go index f9f57aea86f..93a488112ee 100644 --- a/x/concentrated-liquidity/model/pool.go +++ b/x/concentrated-liquidity/model/pool.go @@ -242,9 +242,7 @@ func (p Pool) CalcActualAmounts(ctx sdk.Context, lowerTick, upperTick int64, liq roundUp := liquidityDelta.IsPositive() var ( - liquidityDeltaBigDec = osmomath.BigDecFromSDKDec(liquidityDelta) - sqrtPriceLowerTickBigDec = osmomath.BigDecFromSDKDec(sqrtPriceLowerTick) - sqrtPriceUpperTickBigDec = osmomath.BigDecFromSDKDec(sqrtPriceUpperTick) + liquidityDeltaBigDec = osmomath.BigDecFromSDKDec(liquidityDelta) actualAmountDenom0 osmomath.BigDec actualAmountDenom1 osmomath.BigDec @@ -255,18 +253,18 @@ func (p Pool) CalcActualAmounts(ctx sdk.Context, lowerTick, upperTick int64, liq // if this is the case, we attempt to provide liquidity evenly between asset0 and asset1 // we also update the pool liquidity since the virtual liquidity is modified by this position's creation currentSqrtPrice := p.CurrentSqrtPrice - actualAmountDenom0 = math.CalcAmount0Delta(liquidityDeltaBigDec, currentSqrtPrice, sqrtPriceUpperTickBigDec, roundUp) - actualAmountDenom1 = math.CalcAmount1Delta(liquidityDeltaBigDec, currentSqrtPrice, sqrtPriceLowerTickBigDec, roundUp) + actualAmountDenom0 = math.CalcAmount0Delta(liquidityDeltaBigDec, currentSqrtPrice, sqrtPriceUpperTick, roundUp) + actualAmountDenom1 = math.CalcAmount1Delta(liquidityDeltaBigDec, currentSqrtPrice, sqrtPriceLowerTick, roundUp) } else if p.CurrentTick < lowerTick { // outcome two: position is below current price // this means position is solely made up of asset0 actualAmountDenom1 = osmomath.ZeroDec() - actualAmountDenom0 = math.CalcAmount0Delta(liquidityDeltaBigDec, sqrtPriceLowerTickBigDec, sqrtPriceUpperTickBigDec, roundUp) + actualAmountDenom0 = math.CalcAmount0Delta(liquidityDeltaBigDec, sqrtPriceLowerTick, sqrtPriceUpperTick, roundUp) } else { // outcome three: position is above current price // this means position is solely made up of asset1 actualAmountDenom0 = osmomath.ZeroDec() - actualAmountDenom1 = math.CalcAmount1Delta(liquidityDeltaBigDec, sqrtPriceLowerTickBigDec, sqrtPriceUpperTickBigDec, roundUp) + actualAmountDenom1 = math.CalcAmount1Delta(liquidityDeltaBigDec, sqrtPriceLowerTick, sqrtPriceUpperTick, roundUp) } if roundUp { diff --git a/x/concentrated-liquidity/model/pool_test.go b/x/concentrated-liquidity/model/pool_test.go index 1bbab8baf51..75e9c0274d1 100644 --- a/x/concentrated-liquidity/model/pool_test.go +++ b/x/concentrated-liquidity/model/pool_test.go @@ -566,7 +566,7 @@ func (s *ConcentratedPoolTestSuite) TestNewConcentratedLiquidityPool() { func (suite *ConcentratedPoolTestSuite) TestCalcActualAmounts() { var ( - tickToSqrtPrice = func(tick int64) sdk.Dec { + tickToSqrtPrice = func(tick int64) osmomath.BigDec { _, sqrtPrice, err := clmath.TickToSqrtPrice(tick) suite.Require().NoError(err) return sqrtPrice @@ -576,13 +576,13 @@ func (suite *ConcentratedPoolTestSuite) TestCalcActualAmounts() { defaultLiquidityDeltaBigDec = osmomath.NewBigDec(1000) lowerTick = int64(-99) - lowerSqrtPriceBigDec = osmomath.BigDecFromSDKDec(tickToSqrtPrice(lowerTick)) + lowerSqrtPriceBigDec = tickToSqrtPrice(lowerTick) midtick = int64(2) - midSqrtPriceBigDec = osmomath.BigDecFromSDKDec(tickToSqrtPrice(midtick)) + midSqrtPriceBigDec = tickToSqrtPrice(midtick) uppertick = int64(74) - upperSqrtPriceBigDec = osmomath.BigDecFromSDKDec(tickToSqrtPrice(uppertick)) + upperSqrtPriceBigDec = tickToSqrtPrice(uppertick) ) tests := map[string]struct { @@ -696,7 +696,7 @@ func (suite *ConcentratedPoolTestSuite) TestCalcActualAmounts() { CurrentTick: tc.currentTick, } _, currenTicktSqrtPrice, _ := clmath.TickToSqrtPrice(pool.CurrentTick) - pool.CurrentSqrtPrice = osmomath.BigDecFromSDKDec(currenTicktSqrtPrice) + pool.CurrentSqrtPrice = currenTicktSqrtPrice actualAmount0, actualAmount1, err := pool.CalcActualAmounts(suite.Ctx, tc.lowerTick, tc.upperTick, tc.liquidityDelta) @@ -791,7 +791,7 @@ func (suite *ConcentratedPoolTestSuite) TestUpdateLiquidityIfActivePosition() { CurrentTickLiquidity: defaultLiquidityAmt, } _, currenTicktSqrtPrice, _ := clmath.TickToSqrtPrice(pool.CurrentTick) - pool.CurrentSqrtPrice = osmomath.BigDecFromSDKDec(currenTicktSqrtPrice) + pool.CurrentSqrtPrice = currenTicktSqrtPrice wasUpdated := pool.UpdateLiquidityIfActivePosition(suite.Ctx, tc.lowerTick, tc.upperTick, tc.liquidityDelta) if tc.lowerTick <= tc.currentTick && tc.currentTick <= tc.upperTick { diff --git a/x/concentrated-liquidity/position_test.go b/x/concentrated-liquidity/position_test.go index 1d8f115afe1..1e1590a28f8 100644 --- a/x/concentrated-liquidity/position_test.go +++ b/x/concentrated-liquidity/position_test.go @@ -2673,7 +2673,7 @@ func (s *KeeperTestSuite) TestNegativeTickRange_SpreadFactor() { s.Require().True(toTick < pool.GetCurrentTick()) - amountZeroIn := math.CalcAmount0Delta(osmomath.BigDecFromSDKDec(pool.GetLiquidity()), pool.GetCurrentSqrtPrice(), osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(toTick)), true) + amountZeroIn := math.CalcAmount0Delta(osmomath.BigDecFromSDKDec(pool.GetLiquidity()), pool.GetCurrentSqrtPrice(), s.tickToSqrtPrice(toTick), true) coinZeroIn := sdk.NewCoin(denom0, amountZeroIn.SDKDec().TruncateInt()) return coinZeroIn @@ -2689,7 +2689,7 @@ func (s *KeeperTestSuite) TestNegativeTickRange_SpreadFactor() { s.Require().True(toTick > pool.GetCurrentTick()) - amountOneIn := math.CalcAmount1Delta(osmomath.BigDecFromSDKDec(pool.GetLiquidity()), pool.GetCurrentSqrtPrice(), osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(toTick)), true) + amountOneIn := math.CalcAmount1Delta(osmomath.BigDecFromSDKDec(pool.GetLiquidity()), pool.GetCurrentSqrtPrice(), s.tickToSqrtPrice(toTick), true) coinOneIn := sdk.NewCoin(denom1, amountOneIn.SDKDec().TruncateInt()) return coinOneIn diff --git a/x/concentrated-liquidity/query.go b/x/concentrated-liquidity/query.go index 5db18358839..cf547dabc46 100644 --- a/x/concentrated-liquidity/query.go +++ b/x/concentrated-liquidity/query.go @@ -23,7 +23,7 @@ import ( func (k Keeper) GetTickLiquidityForFullRange(ctx sdk.Context, poolId uint64) ([]queryproto.LiquidityDepthWithRange, error) { // use false for zeroForOne since we're going from lower tick -> upper tick zeroForOne := false - swapStrategy := swapstrategy.New(zeroForOne, sdk.ZeroDec(), k.storeKey, sdk.ZeroDec()) + swapStrategy := swapstrategy.New(zeroForOne, osmomath.ZeroDec(), k.storeKey, sdk.ZeroDec()) // set current tick to min tick, and find the first initialized tick starting from min tick -1. // we do -1 to make min tick inclusive. @@ -149,7 +149,7 @@ func (k Keeper) GetTickLiquidityNetInDirection(ctx sdk.Context, poolId uint64, t } liquidityDepths := []queryproto.TickLiquidityNet{} - swapStrategy := swapstrategy.New(zeroForOne, sdk.ZeroDec(), k.storeKey, sdk.ZeroDec()) + swapStrategy := swapstrategy.New(zeroForOne, osmomath.ZeroDec(), k.storeKey, sdk.ZeroDec()) currentTick := p.GetCurrentTick() _, currentTickSqrtPrice, err := math.TickToSqrtPrice(currentTick) @@ -168,7 +168,7 @@ func (k Keeper) GetTickLiquidityNetInDirection(ctx sdk.Context, poolId uint64, t } ctx.Logger().Debug(fmt.Sprintf("validateTick %s; validate sqrtPrice %s\n", validateTick.String(), validateSqrtPrice.String())) - if err := swapStrategy.ValidateSqrtPrice(validateSqrtPrice, osmomath.BigDecFromSDKDec(currentTickSqrtPrice)); err != nil { + if err := swapStrategy.ValidateSqrtPrice(validateSqrtPrice, currentTickSqrtPrice); err != nil { return err } diff --git a/x/concentrated-liquidity/query_test.go b/x/concentrated-liquidity/query_test.go index a592e0ec3af..70e3aed8edc 100644 --- a/x/concentrated-liquidity/query_test.go +++ b/x/concentrated-liquidity/query_test.go @@ -572,7 +572,7 @@ func (s *KeeperTestSuite) TestGetTickLiquidityNetInDirection() { s.Require().NoError(err) curTick = test.currentPoolTick - curSqrtPrice = osmomath.BigDecFromSDKDec(sqrtPrice) + curSqrtPrice = sqrtPrice } pool.SetCurrentSqrtPrice(curSqrtPrice) pool.SetCurrentTick(curTick) diff --git a/x/concentrated-liquidity/range_test.go b/x/concentrated-liquidity/range_test.go index e722315c7d0..2277b87a09a 100644 --- a/x/concentrated-liquidity/range_test.go +++ b/x/concentrated-liquidity/range_test.go @@ -439,7 +439,7 @@ func (s *KeeperTestSuite) getInitialPositionAssets(pool types.ConcentratedPoolEx // Calculate asset amounts that would be required to get the required spot price (rounding up on asset1 to ensure we stay in the intended tick) asset0Amount := sdk.NewInt(100000000000000) - asset1Amount := sdk.NewDecFromInt(asset0Amount).Mul(requiredPrice).Ceil().TruncateInt() + asset1Amount := sdk.NewDecFromInt(asset0Amount).Mul(requiredPrice.SDKDec()).Ceil().TruncateInt() assetCoins := sdk.NewCoins( sdk.NewCoin(pool.GetToken0(), asset0Amount), diff --git a/x/concentrated-liquidity/spread_rewards_test.go b/x/concentrated-liquidity/spread_rewards_test.go index de29d2af471..93e529f8b80 100644 --- a/x/concentrated-liquidity/spread_rewards_test.go +++ b/x/concentrated-liquidity/spread_rewards_test.go @@ -505,7 +505,7 @@ func (s *KeeperTestSuite) TestGetInitialSpreadRewardGrowthOppositeDirectionOfLas func (s *KeeperTestSuite) TestGetInitialSpreadRewardGrowthOppositeDirectionOfLastTraversalForTick() { sqrtPrice := osmomath.MustMonotonicSqrt(DefaultAmt1.ToDec().Quo(DefaultAmt0.ToDec())) - initialPoolTick, err := clmath.SqrtPriceToTickRoundDownSpacing(sqrtPrice, DefaultTickSpacing) + initialPoolTick, err := clmath.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrtPrice), DefaultTickSpacing) s.Require().NoError(err) initialGlobalSpreadRewardGrowth := oneEth diff --git a/x/concentrated-liquidity/swaps.go b/x/concentrated-liquidity/swaps.go index fb5f0a3a3ae..7997a7a407b 100644 --- a/x/concentrated-liquidity/swaps.go +++ b/x/concentrated-liquidity/swaps.go @@ -306,10 +306,10 @@ func (k Keeper) swapSetup(ctx sdk.Context, // returns next initialized tick, next initialized tick sqrt price, implied sqrt price target, and error // the next initialized tick sqrt price return arg is unfortunately there due to some bigdec situations. // poolId as an argument is for debug info and should be removed in the future -func iteratorToNextInitializedTickSqrtPriceTarget(nextInitTickIter db.Iterator, _poolId uint64, swapstrat swapstrategy.SwapStrategy) (int64, sdk.Dec, sdk.Dec, error) { +func iteratorToNextInitializedTickSqrtPriceTarget(nextInitTickIter db.Iterator, _poolId uint64, swapstrat swapstrategy.SwapStrategy) (int64, osmomath.BigDec, osmomath.BigDec, error) { // Iterator must be valid to be able to retrieve the next tick from it below. if !nextInitTickIter.Valid() { - return 0, sdk.Dec{}, sdk.Dec{}, types.RanOutOfTicksForPoolError{PoolId: _poolId} + return 0, osmomath.BigDec{}, osmomath.BigDec{}, types.RanOutOfTicksForPoolError{PoolId: _poolId} } // We first check to see what the position of the nearest initialized tick is // if zeroForOneStrategy, we look to the left of the tick the current sqrt price is at @@ -317,13 +317,13 @@ func iteratorToNextInitializedTickSqrtPriceTarget(nextInitTickIter db.Iterator, // if no ticks are initialized (no users have created liquidity positions) then we return an error nextInitializedTick, err := types.TickIndexFromBytes(nextInitTickIter.Key()) if err != nil { - return 0, sdk.Dec{}, sdk.Dec{}, err + return 0, osmomath.BigDec{}, osmomath.BigDec{}, err } // Utilizing the next initialized tick, we find the corresponding nextInitializedTickSqrtPrice (the target sqrt price). _, nextInitializedTickSqrtPrice, err := math.TickToSqrtPrice(nextInitializedTick) if err != nil { - return 0, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextInitializedTick) + return 0, osmomath.BigDec{}, osmomath.BigDec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextInitializedTick) } // If nextInitializedTickSqrtPrice exceeds the given price limit, we set the sqrtPriceTarget to the price limit. @@ -366,7 +366,7 @@ func (k Keeper) computeOutAmtGivenIn( // TODO: for now, we check if amountSpecifiedRemaining is GT 0.0000001. This is because there are times when the remaining // amount may be extremely small, and that small amount cannot generate and amountIn/amountOut and we are therefore left // in an infinite loop. - for swapState.amountSpecifiedRemaining.GT(smallestDec) && !swapState.sqrtPrice.Equal(osmomath.BigDecFromSDKDec(sqrtPriceLimit)) { + for swapState.amountSpecifiedRemaining.GT(smallestDec) && !swapState.sqrtPrice.Equal(sqrtPriceLimit) { // Log the sqrtPrice we start the iteration with sqrtPriceStart := swapState.sqrtPrice @@ -402,21 +402,19 @@ func (k Keeper) computeOutAmtGivenIn( // We add the amount of tokens we received (amountOut) from the ComputeSwapWithinBucketOutGivenIn(...) above to the amountCalculated accumulator swapState.amountCalculated.AddMut(amountOut) - nextInitializedTickSqrtPriceBigDec := osmomath.BigDecFromSDKDec(nextInitializedTickSqrtPrice) - // If ComputeSwapWithinBucketOutGivenIn(...) calculated a computedSqrtPrice that is equal to the nextInitializedTickSqrtPrice, this means all liquidity in the current // bucket has been consumed and we must move on to the next bucket to complete the swap - if nextInitializedTickSqrtPriceBigDec.Equal(computedSqrtPrice) { + if nextInitializedTickSqrtPrice.Equal(computedSqrtPrice) { swapState, err = k.swapCrossTickLogic(ctx, swapState, swapStrategy, nextInitializedTick, nextInitTickIter, p, spreadRewardAccumulator, uptimeAccums, tokenInMin.Denom) if err != nil { return sdk.Coin{}, sdk.Coin{}, PoolUpdates{}, sdk.Dec{}, err } - } else if edgeCaseInequalityBasedOnSwapStrategy(swapStrategy.ZeroForOne(), nextInitializedTickSqrtPriceBigDec, computedSqrtPrice) { + } else if edgeCaseInequalityBasedOnSwapStrategy(swapStrategy.ZeroForOne(), nextInitializedTickSqrtPrice, computedSqrtPrice) { // If, based on the swap strategy, the computedSqrtPrice matches the edge case inequality, we return an error. // This is an edge case that occurs when swapping at/near tick boundaries that will be fixed in the next release. // For now, we return an error and ask the user to try again with a different swap amount. - return sdk.Coin{}, sdk.Coin{}, PoolUpdates{}, sdk.Dec{}, types.ComputedSqrtPriceInequalityError{IsZeroForOne: swapStrategy.ZeroForOne(), ComputedSqrtPrice: computedSqrtPrice, NextInitializedTickSqrtPrice: nextInitializedTickSqrtPriceBigDec} + return sdk.Coin{}, sdk.Coin{}, PoolUpdates{}, sdk.Dec{}, types.ComputedSqrtPriceInequalityError{IsZeroForOne: swapStrategy.ZeroForOne(), ComputedSqrtPrice: computedSqrtPrice, NextInitializedTickSqrtPrice: nextInitializedTickSqrtPrice} } else if !sqrtPriceStart.Equal(computedSqrtPrice) { // Otherwise if the sqrtPrice calculated from ComputeSwapWithinBucketOutGivenIn(...) does not equal the sqrtPriceStart we started with at the // beginning of this iteration, we set the swapState tick to the corresponding tick of the computedSqrtPrice calculated from ComputeSwapWithinBucketOutGivenIn(...) @@ -494,7 +492,7 @@ func (k Keeper) computeInAmtGivenOut( // TODO: for now, we check if amountSpecifiedRemaining is GT 10^-18. This is because there are times when the remaining // amount may be extremely small, and that small amount cannot generate and amountIn/amountOut and we are therefore left // in an infinite loop. - for swapState.amountSpecifiedRemaining.GT(smallestDec) && !swapState.sqrtPrice.Equal(osmomath.BigDecFromSDKDec(sqrtPriceLimit)) { + for swapState.amountSpecifiedRemaining.GT(smallestDec) && !swapState.sqrtPrice.Equal(sqrtPriceLimit) { // log the sqrtPrice we start the iteration with sqrtPriceStart := swapState.sqrtPrice @@ -526,21 +524,19 @@ func (k Keeper) computeInAmtGivenOut( swapState.amountSpecifiedRemaining.SubMut(amountOut) swapState.amountCalculated.AddMut(amountIn.Add(spreadRewardChargeTotal)) - nextInitializedTickSqrtPriceBigDec := osmomath.BigDecFromSDKDec(nextInitializedTickSqrtPrice) - // If the ComputeSwapWithinBucketInGivenOut(...) calculated a computedSqrtPrice that is equal to the nextInitializedTickSqrtPrice, this means all liquidity in the current // bucket has been consumed and we must move on to the next bucket by crossing a tick to complete the swap - if nextInitializedTickSqrtPriceBigDec.Equal(computedSqrtPrice) { + if nextInitializedTickSqrtPrice.Equal(computedSqrtPrice) { swapState, err = k.swapCrossTickLogic(ctx, swapState, swapStrategy, nextInitializedTick, nextInitTickIter, p, spreadRewardAccumulator, uptimeAccums, tokenInDenom) if err != nil { return sdk.Coin{}, sdk.Coin{}, PoolUpdates{}, sdk.Dec{}, err } - } else if edgeCaseInequalityBasedOnSwapStrategy(swapStrategy.ZeroForOne(), nextInitializedTickSqrtPriceBigDec, computedSqrtPrice) { + } else if edgeCaseInequalityBasedOnSwapStrategy(swapStrategy.ZeroForOne(), nextInitializedTickSqrtPrice, computedSqrtPrice) { // If, based on the swap strategy, the computedSqrtPrice matches the edge case inequality, we return an error. // This is an edge case that occurs when swapping at/near tick boundaries that will be fixed in the next release. // For now, we return an error and ask the user to try again with a different swap amount. - return sdk.Coin{}, sdk.Coin{}, PoolUpdates{}, sdk.Dec{}, types.ComputedSqrtPriceInequalityError{IsZeroForOne: swapStrategy.ZeroForOne(), ComputedSqrtPrice: computedSqrtPrice, NextInitializedTickSqrtPrice: nextInitializedTickSqrtPriceBigDec} + return sdk.Coin{}, sdk.Coin{}, PoolUpdates{}, sdk.Dec{}, types.ComputedSqrtPriceInequalityError{IsZeroForOne: swapStrategy.ZeroForOne(), ComputedSqrtPrice: computedSqrtPrice, NextInitializedTickSqrtPrice: nextInitializedTickSqrtPrice} } else if !sqrtPriceStart.Equal(computedSqrtPrice) { // Otherwise, if the computedSqrtPrice calculated from ComputeSwapWithinBucketInGivenOut(...) does not equal the sqrtPriceStart we started with at the // beginning of this iteration, we set the swapState tick to the corresponding tick of the computedSqrtPrice calculated from ComputeSwapWithinBucketInGivenOut(...) @@ -724,13 +720,13 @@ func checkDenomValidity(inDenom, outDenom, asset0, asset1 string) error { return nil } -func (k Keeper) setupSwapStrategy(p types.ConcentratedPoolExtension, spreadFactor sdk.Dec, tokenInDenom string, priceLimit sdk.Dec) (strategy swapstrategy.SwapStrategy, sqrtPriceLimit sdk.Dec, err error) { +func (k Keeper) setupSwapStrategy(p types.ConcentratedPoolExtension, spreadFactor sdk.Dec, tokenInDenom string, priceLimit sdk.Dec) (strategy swapstrategy.SwapStrategy, sqrtPriceLimit osmomath.BigDec, err error) { zeroForOne := getZeroForOne(tokenInDenom, p.GetToken0()) // take provided price limit and turn this into a sqrt price limit since formulas use sqrtPrice sqrtPriceLimit, err = swapstrategy.GetSqrtPriceLimit(priceLimit, zeroForOne) if err != nil { - return strategy, sdk.Dec{}, types.SqrtRootCalculationError{SqrtPriceLimit: sqrtPriceLimit} + return strategy, osmomath.BigDec{}, types.SqrtRootCalculationError{SqrtPriceLimit: sqrtPriceLimit} } // set the swap strategy @@ -739,7 +735,7 @@ func (k Keeper) setupSwapStrategy(p types.ConcentratedPoolExtension, spreadFacto // get current sqrt price from pool curSqrtPrice := p.GetCurrentSqrtPrice() if err := swapStrategy.ValidateSqrtPrice(sqrtPriceLimit, curSqrtPrice); err != nil { - return strategy, sdk.Dec{}, err + return strategy, osmomath.BigDec{}, err } return swapStrategy, sqrtPriceLimit, nil @@ -870,10 +866,8 @@ func (k Keeper) ComputeMaxInAmtGivenMaxTicksCrossed( totalTokenOut = totalTokenOut.Add(amountOut) // Check if the tick needs to be updated - nextInitializedTickSqrtPriceBigDec := osmomath.BigDecFromSDKDec(nextInitializedTickSqrtPrice) - // We do not need to track spread rewards or uptime accums here since we are not actually swapping. - if nextInitializedTickSqrtPriceBigDec.Equal(computedSqrtPrice) { + if nextInitializedTickSqrtPrice.Equal(computedSqrtPrice) { nextInitializedTickInfo, err := ParseTickFromBz(nextInitTickIter.Value()) if err != nil { return sdk.Coin{}, sdk.Coin{}, err @@ -886,11 +880,11 @@ func (k Keeper) ComputeMaxInAmtGivenMaxTicksCrossed( swapState.liquidity.AddMut(liquidityNet) swapState.tick = swapStrategy.UpdateTickAfterCrossing(nextInitializedTick) - } else if edgeCaseInequalityBasedOnSwapStrategy(swapStrategy.ZeroForOne(), nextInitializedTickSqrtPriceBigDec, computedSqrtPrice) { + } else if edgeCaseInequalityBasedOnSwapStrategy(swapStrategy.ZeroForOne(), nextInitializedTickSqrtPrice, computedSqrtPrice) { return sdk.Coin{}, sdk.Coin{}, types.ComputedSqrtPriceInequalityError{ IsZeroForOne: swapStrategy.ZeroForOne(), ComputedSqrtPrice: computedSqrtPrice, - NextInitializedTickSqrtPrice: nextInitializedTickSqrtPriceBigDec, + NextInitializedTickSqrtPrice: nextInitializedTickSqrtPrice, } } else if !swapState.sqrtPrice.Equal(computedSqrtPrice) { newTick, err := math.CalculateSqrtPriceToTick(computedSqrtPrice) diff --git a/x/concentrated-liquidity/swaps_test.go b/x/concentrated-liquidity/swaps_test.go index 668030b9616..85423cb75f6 100644 --- a/x/concentrated-liquidity/swaps_test.go +++ b/x/concentrated-liquidity/swaps_test.go @@ -758,7 +758,7 @@ var ( expectedTokenIn: sdk.NewCoin("eth", sdk.NewInt(12892)), expectedTokenOut: sdk.NewCoin("usdc", sdk.NewInt(64417624)), expectedTick: func() int64 { - tick, _ := math.SqrtPriceToTickRoundDownSpacing(sqrt4994, DefaultTickSpacing) + tick, _ := math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrt4994), DefaultTickSpacing) return tick }(), // Since the next sqrt price is based on the price limit, we can calculate this directly. @@ -896,7 +896,7 @@ var ( expectedTokenOut: sdk.NewCoin("usdc", sdk.NewInt(64417624)), expectedSpreadRewardGrowthAccumulatorValue: sdk.MustNewDecFromStr("0.000000085792039652"), expectedTick: func() int64 { - tick, _ := math.SqrtPriceToTickRoundDownSpacing(sqrt4994, DefaultTickSpacing) + tick, _ := math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(sqrt4994), DefaultTickSpacing) return tick }(), expectedSqrtPrice: osmomath.MustNewDecFromStr("70.668238976219012614"), @@ -2043,10 +2043,10 @@ func (s *KeeperTestSuite) getExpectedLiquidity(test SwapTest, pool types.Concent func (s *KeeperTestSuite) lowerUpperPricesToTick(lowerPrice, upperPrice sdk.Dec, tickSpacing uint64) (int64, int64) { lowerSqrtPrice := osmomath.MustMonotonicSqrt(lowerPrice) - newLowerTick, err := clmath.SqrtPriceToTickRoundDownSpacing(lowerSqrtPrice, tickSpacing) + newLowerTick, err := clmath.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(lowerSqrtPrice), tickSpacing) s.Require().NoError(err) upperSqrtPrice := osmomath.MustMonotonicSqrt(upperPrice) - newUpperTick, err := clmath.SqrtPriceToTickRoundDownSpacing(upperSqrtPrice, tickSpacing) + newUpperTick, err := clmath.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromSDKDec(upperSqrtPrice), tickSpacing) s.Require().NoError(err) return newLowerTick, newUpperTick } diff --git a/x/concentrated-liquidity/swaps_tick_cross_test.go b/x/concentrated-liquidity/swaps_tick_cross_test.go index 0a6274d379d..193c63496ef 100644 --- a/x/concentrated-liquidity/swaps_tick_cross_test.go +++ b/x/concentrated-liquidity/swaps_tick_cross_test.go @@ -62,7 +62,7 @@ func (s *KeeperTestSuite) CreatePositionTickSpacingsFromCurrentTick(poolId uint6 } // tickToSqrtPrice a helper to convert a tick to a sqrt price. -func (s *KeeperTestSuite) tickToSqrtPrice(tick int64) sdk.Dec { +func (s *KeeperTestSuite) tickToSqrtPrice(tick int64) osmomath.BigDec { _, sqrtPrice, err := math.TickToSqrtPrice(tick) s.Require().NoError(err) return sqrtPrice @@ -93,7 +93,7 @@ func (s *KeeperTestSuite) validateIteratorRightOneForZero(poolId uint64, expecte s.Require().NoError(err) // Setup swap strategy directly as it would fail validation if constructed via SetupSwapStrategy(...) - oneForZeroSwapStrategy := swapstrategy.New(false, types.MaxSqrtPrice, s.App.GetKey(types.ModuleName), sdk.ZeroDec()) + oneForZeroSwapStrategy := swapstrategy.New(false, osmomath.BigDecFromSDKDec(types.MaxSqrtPrice), s.App.GetKey(types.ModuleName), sdk.ZeroDec()) s.Require().NoError(err) initializedTickValue := pool.GetCurrentTick() iter := oneForZeroSwapStrategy.InitializeNextTickIterator(s.Ctx, pool.GetId(), initializedTickValue) @@ -276,7 +276,7 @@ func (s *KeeperTestSuite) computeSwapAmounts(poolId uint64, curSqrtPrice osmomat currentTick := originalCurrentTick // compute current sqrt price if not provided if curSqrtPrice.IsNil() { - curSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(currentTick)) + curSqrtPrice = s.tickToSqrtPrice(currentTick) } // Start from current pool liquidity and zero amount in. @@ -286,7 +286,7 @@ func (s *KeeperTestSuite) computeSwapAmounts(poolId uint64, curSqrtPrice osmomat for i, liquidityNetEntry := range liquidityNetAmounts { // Initialize the next initialized tick and its sqrt price. nextInitializedTick := liquidityNetEntry.TickIndex - nextInitTickSqrtPrice := osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nextInitializedTick)) + nextInitTickSqrtPrice := s.tickToSqrtPrice(nextInitializedTick) // Handle swap depending on the direction. // Left (zero for one) or right (one for zero) @@ -302,7 +302,7 @@ func (s *KeeperTestSuite) computeSwapAmounts(poolId uint64, curSqrtPrice osmomat shouldCrossTick := currentTick > expectedTickToSwapTo && !shouldStayWithinTheSameBucket if shouldCrossTick { // Runs regular tick crossing logic. - curSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nextInitializedTick)) + curSqrtPrice = s.tickToSqrtPrice(nextInitializedTick) currentLiquidity = currentLiquidity.Sub(liquidityNetEntry.LiquidityNet) currentTick = nextInitializedTick - 1 } @@ -313,7 +313,7 @@ func (s *KeeperTestSuite) computeSwapAmounts(poolId uint64, curSqrtPrice osmomat // This in an edge case when going left in second swap after previously going right // and indetending to stay within the same bucket. if amountIn.IsZero() && isWithinDesiredBucketAfterSwap { - nextInitTickSqrtPrice := osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(liquidityNetAmounts[i+1].TickIndex)) + nextInitTickSqrtPrice := s.tickToSqrtPrice(liquidityNetAmounts[i+1].TickIndex) // We discount by half so that we do no cross any tick and remain in the same bucket. curAmountIn := math.CalcAmount0Delta(osmomath.BigDecFromSDKDec(currentLiquidity), curSqrtPrice, nextInitTickSqrtPrice, true).QuoInt64(2).SDKDecRoundUp() @@ -329,7 +329,7 @@ func (s *KeeperTestSuite) computeSwapAmounts(poolId uint64, curSqrtPrice osmomat shouldCrossTick := currentTick <= expectedTickToSwapTo && !shouldStayWithinTheSameBucket if shouldCrossTick { // Runs regular tick crossing logic. - curSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nextInitializedTick)) + curSqrtPrice = s.tickToSqrtPrice(nextInitializedTick) currentLiquidity = currentLiquidity.Add(liquidityNetEntry.LiquidityNet) currentTick = nextInitializedTick } @@ -364,7 +364,7 @@ func (s *KeeperTestSuite) computeSwapAmountsInGivenOut(poolId uint64, curSqrtPri currentTick := originalCurrentTick // compute current sqrt price if not provided if curSqrtPrice.IsNil() { - curSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(currentTick)) + curSqrtPrice = s.tickToSqrtPrice(currentTick) } // Start from current pool liquidity and zero amount in. @@ -374,7 +374,7 @@ func (s *KeeperTestSuite) computeSwapAmountsInGivenOut(poolId uint64, curSqrtPri for i, liquidityNetEntry := range liquidityNetAmounts { // Initialize the next initialized tick and its sqrt price. nextInitializedTick := liquidityNetEntry.TickIndex - nextInitTickSqrtPrice := osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nextInitializedTick)) + nextInitTickSqrtPrice := s.tickToSqrtPrice(nextInitializedTick) // Handle swap depending on the direction. // Left (zero for one) or right (one for zero) @@ -390,7 +390,7 @@ func (s *KeeperTestSuite) computeSwapAmountsInGivenOut(poolId uint64, curSqrtPri shouldCrossTick := currentTick > expectedTickToSwapTo && !shouldStayWithinTheSameBucket if shouldCrossTick { // Runs regular tick crossing logic. - curSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nextInitializedTick)) + curSqrtPrice = s.tickToSqrtPrice(nextInitializedTick) currentLiquidity = currentLiquidity.Sub(osmomath.BigDecFromSDKDec(liquidityNetEntry.LiquidityNet)) currentTick = nextInitializedTick - 1 } @@ -401,7 +401,7 @@ func (s *KeeperTestSuite) computeSwapAmountsInGivenOut(poolId uint64, curSqrtPri // This in an edge case when going left in second swap after previously going right // and indetending to stay within the same bucket. if amountOut.IsZero() && isWithinDesiredBucketAfterSwap { - nextInitTickSqrtPrice := osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(liquidityNetAmounts[i+1].TickIndex)) + nextInitTickSqrtPrice := s.tickToSqrtPrice(liquidityNetAmounts[i+1].TickIndex) // We discound by two so that we do no cross any tick and remain in the same bucket. curAmountIn := math.CalcAmount1Delta(currentLiquidity, curSqrtPrice, nextInitTickSqrtPrice, false).QuoInt64(2) @@ -417,7 +417,7 @@ func (s *KeeperTestSuite) computeSwapAmountsInGivenOut(poolId uint64, curSqrtPri shouldCrossTick := currentTick <= expectedTickToSwapTo && !shouldStayWithinTheSameBucket if shouldCrossTick { // Runs regular tick crossing logic. - curSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nextInitializedTick)) + curSqrtPrice = s.tickToSqrtPrice(nextInitializedTick) currentLiquidity = currentLiquidity.Add(osmomath.BigDecFromSDKDec(liquidityNetEntry.LiquidityNet)) currentTick = nextInitializedTick } @@ -627,7 +627,7 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_Tick_Initialization_And_Crossing() // Compute the sqrt price corresponding to the lower tick // of the narrow range position. - sqrtPriceTarget := osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(tickToSwapTo)) + sqrtPriceTarget := s.tickToSqrtPrice(tickToSwapTo) // Check that narrow range position is considered in range isNarrowInRange := pool.IsCurrentTickInRange(nr1Position.lowerTick, nr1Position.upperTick) @@ -641,7 +641,7 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_Tick_Initialization_And_Crossing() ) if tickToSwapTo < nr1Position.lowerTick { - sqrtPriceLowerTickOne := osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nr1Position.lowerTick)) + sqrtPriceLowerTickOne := s.tickToSqrtPrice(nr1Position.lowerTick) amountZeroIn = math.CalcAmount0Delta(osmomath.BigDecFromSDKDec(liquidity), sqrtPriceLowerTickOne, sqrtPriceStart, true).SDKDec() @@ -732,7 +732,7 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_Tick_Initialization_And_Crossing() ) if tickToSwapTo >= nr1Position.upperTick { - sqrtPriceUpperOne := osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(nr1Position.upperTick)) + sqrtPriceUpperOne := s.tickToSqrtPrice(nr1Position.upperTick) amountOneIn = math.CalcAmount1Delta(osmomath.BigDecFromSDKDec(liquidity), sqrtPriceUpperOne, sqrtPriceStart, true).SDKDecRoundUp() @@ -743,7 +743,7 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_Tick_Initialization_And_Crossing() // This is the total amount necessary to cross the lower tick of narrow position. // Note it is rounded up to ensure that the tick is crossed. - amountOneIn = math.CalcAmount1Delta(osmomath.BigDecFromSDKDec(liquidity), osmomath.BigDecFromSDKDec(sqrtPriceTarget), sqrtPriceStart, true).SDKDecRoundUp().Add(amountOneIn) + amountOneIn = math.CalcAmount1Delta(osmomath.BigDecFromSDKDec(liquidity), sqrtPriceTarget, sqrtPriceStart, true).SDKDecRoundUp().Add(amountOneIn) tokenOneIn := sdk.NewCoin(pool.GetToken1(), amountOneIn.Ceil().TruncateInt()) @@ -1418,15 +1418,15 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_GetLiquidityFromAmountsPositionBoun positionThreeTS = positions[1] positionThreeTSLowerTick = positionThreeTS.lowerTick positionThreeTSUpperTick = positionThreeTS.upperTick - positionThreeTSLowerSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(positionThreeTSLowerTick)) - positionThreeTSUpperSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(positionThreeTSUpperTick)) + positionThreeTSLowerSqrtPrice = s.tickToSqrtPrice(positionThreeTSLowerTick) + positionThreeTSUpperSqrtPrice = s.tickToSqrtPrice(positionThreeTSUpperTick) // 2 tick spacings away [30999998, 31000002) (2TS) from the original current tick (31000000) positionTwoTS = positions[2] positionTwoTSLowerTick = positionTwoTS.lowerTick positionTwoTSUpperTick = positionTwoTS.upperTick - positionTwoTSLowerSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(positionTwoTSLowerTick)) - positionTwoTSUpperSqrtPrice = osmomath.BigDecFromSDKDec(s.tickToSqrtPrice(positionTwoTSUpperTick)) + positionTwoTSLowerSqrtPrice = s.tickToSqrtPrice(positionTwoTSLowerTick) + positionTwoTSUpperSqrtPrice = s.tickToSqrtPrice(positionTwoTSUpperTick) ) // Assert that the liquidity computed from amounts utilized the "in-range" option. @@ -1434,7 +1434,7 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_GetLiquidityFromAmountsPositionBoun liquidity0 := math.Liquidity0(DefaultAmt0, currentSqrtPrice, upperTickSqrtPrice) liquidity1 := math.Liquidity1(DefaultAmt1, currentSqrtPrice, lowerTickSqrtPrice) expectedLiquidity := sdk.MinDec(liquidity0, liquidity1) - actualLiquidity := math.GetLiquidityFromAmounts(currentSqrtPrice, lowerTickSqrtPrice.SDKDec(), upperTickSqrtPrice.SDKDec(), DefaultAmt0, DefaultAmt1) + actualLiquidity := math.GetLiquidityFromAmounts(currentSqrtPrice, lowerTickSqrtPrice, upperTickSqrtPrice, DefaultAmt0, DefaultAmt1) s.Require().Equal(expectedLiquidity, actualLiquidity) } @@ -1495,7 +1495,7 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_GetLiquidityFromAmountsPositionBoun // 2TS position should consist of token zero only as it is to the right of the active range. liquidity02TS := math.Liquidity0(DefaultAmt0, currentSqrtPrice, positionTwoTSUpperSqrtPrice) - actualLiquidity2Ts := math.GetLiquidityFromAmounts(pool.GetCurrentSqrtPrice(), positionTwoTSLowerSqrtPrice.SDKDec(), s.tickToSqrtPrice(positionTwoTS.upperTick), DefaultAmt0, DefaultAmt1) + actualLiquidity2Ts := math.GetLiquidityFromAmounts(pool.GetCurrentSqrtPrice(), positionTwoTSLowerSqrtPrice, s.tickToSqrtPrice(positionTwoTS.upperTick), DefaultAmt0, DefaultAmt1) s.Require().Equal(liquidity02TS, actualLiquidity2Ts) // Reset suite context @@ -1544,7 +1544,7 @@ func (s *KeeperTestSuite) TestSwapOutGivenIn_GetLiquidityFromAmountsPositionBoun // 2TS should consist of token one only as it is to the right of the active range. liquidity1Pos3 := math.Liquidity1(DefaultAmt1, currentSqrtPrice, positionTwoTSLowerSqrtPrice) - actualLiquidityPos3 := math.GetLiquidityFromAmounts(pool.GetCurrentSqrtPrice(), positionTwoTSLowerSqrtPrice.SDKDec(), positionTwoTSUpperSqrtPrice.SDKDec(), DefaultAmt0, DefaultAmt1) + actualLiquidityPos3 := math.GetLiquidityFromAmounts(pool.GetCurrentSqrtPrice(), positionTwoTSLowerSqrtPrice, positionTwoTSUpperSqrtPrice, DefaultAmt0, DefaultAmt1) s.Require().Equal(liquidity1Pos3, actualLiquidityPos3) // Reset suite context diff --git a/x/concentrated-liquidity/swapstrategy/one_for_zero.go b/x/concentrated-liquidity/swapstrategy/one_for_zero.go index c6ada4347eb..6fe8109c3ac 100644 --- a/x/concentrated-liquidity/swapstrategy/one_for_zero.go +++ b/x/concentrated-liquidity/swapstrategy/one_for_zero.go @@ -19,7 +19,7 @@ import ( // With this strategy, we are moving to the right of the current // tick index and square root price. type oneForZeroStrategy struct { - sqrtPriceLimit sdk.Dec + sqrtPriceLimit osmomath.BigDec storeKey sdk.StoreKey spreadFactor sdk.Dec } @@ -31,7 +31,7 @@ func (s oneForZeroStrategy) ZeroForOne() bool { return false } // GetSqrtTargetPrice returns the target square root price given the next tick square root price. // If the given nextTickSqrtPrice is greater than the sqrt price limit, the sqrt price limit is returned. // Otherwise, the input nextTickSqrtPrice is returned. -func (s oneForZeroStrategy) GetSqrtTargetPrice(nextTickSqrtPrice sdk.Dec) sdk.Dec { +func (s oneForZeroStrategy) GetSqrtTargetPrice(nextTickSqrtPrice osmomath.BigDec) osmomath.BigDec { if nextTickSqrtPrice.GT(s.sqrtPriceLimit) { return s.sqrtPriceLimit } @@ -57,13 +57,12 @@ func (s oneForZeroStrategy) GetSqrtTargetPrice(nextTickSqrtPrice sdk.Dec) sdk.De // // OneForZero details: // - oneForZeroStrategy assumes moving to the right of the current square root price. -func (s oneForZeroStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent osmomath.BigDec, sqrtPriceTarget, liquidity, amountOneInRemaining sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { - sqrtPriceTargetBigDec := osmomath.BigDecFromSDKDec(sqrtPriceTarget) +func (s oneForZeroStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent, sqrtPriceTarget osmomath.BigDec, liquidity, amountOneInRemaining sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { liquidityBigDec := osmomath.BigDecFromSDKDec(liquidity) amountOneInRemainingBigDec := osmomath.BigDecFromSDKDec(amountOneInRemaining) // Estimate the amount of token one needed until the target sqrt price is reached. - amountOneIn := math.CalcAmount1Delta(liquidityBigDec, sqrtPriceTargetBigDec, sqrtPriceCurrent, true) + amountOneIn := math.CalcAmount1Delta(liquidityBigDec, sqrtPriceTarget, sqrtPriceCurrent, true) // Calculate sqrtPriceNext on the amount of token remaining after spread reward. amountOneInRemainingLessSpreadReward := amountOneInRemainingBigDec.MulTruncate(oneBigDec.Sub(osmomath.BigDecFromSDKDec(s.spreadFactor))) @@ -72,13 +71,13 @@ func (s oneForZeroStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent o // If have more of the amount remaining after spread reward than estimated until target, // bound the next sqrtPriceNext by the target sqrt price. if amountOneInRemainingLessSpreadReward.GTE(amountOneIn) { - sqrtPriceNext = sqrtPriceTargetBigDec + sqrtPriceNext = sqrtPriceTarget } else { // Otherwise, compute the next sqrt price based on the amount remaining after spread reward. sqrtPriceNext = math.GetNextSqrtPriceFromAmount1InRoundingDown(sqrtPriceCurrent, liquidityBigDec, amountOneInRemainingLessSpreadReward) } - hasReachedTarget := sqrtPriceTargetBigDec.Equal(sqrtPriceNext) + hasReachedTarget := sqrtPriceTarget.Equal(sqrtPriceNext) // If the sqrt price target was not reached, recalculate how much of the amount remaining after spread reward was needed // to complete the swap step. This implies that some of the amount remaining after spread reward is left over after the @@ -121,14 +120,13 @@ func (s oneForZeroStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent o // // OneForZero details: // - oneForZeroStrategy assumes moving to the right of the current square root price. -func (s oneForZeroStrategy) ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent osmomath.BigDec, sqrtPriceTarget, liquidity, amountZeroRemainingOut sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { +func (s oneForZeroStrategy) ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent, sqrtPriceTarget osmomath.BigDec, liquidity, amountZeroRemainingOut sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { liquidityBigDec := osmomath.BigDecFromSDKDec(liquidity) - sqrtPriceTargetBigDec := osmomath.BigDecFromSDKDec(sqrtPriceTarget) amountZeroRemainingOutBigDec := osmomath.BigDecFromSDKDec(amountZeroRemainingOut) // Estimate the amount of token zero needed until the target sqrt price is reached. // N.B.: contrary to out given in, we do not round up because we do not want to exceed the initial amount out at the end. - amountZeroOut := math.CalcAmount0Delta(liquidityBigDec, sqrtPriceTargetBigDec, sqrtPriceCurrent, false) + amountZeroOut := math.CalcAmount0Delta(liquidityBigDec, sqrtPriceTarget, sqrtPriceCurrent, false) // Calculate sqrtPriceNext on the amount of token remaining. Note that the // spread reward is not charged as amountRemaining is amountOut, and we only charge spread reward on @@ -137,13 +135,13 @@ func (s oneForZeroStrategy) ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent o // If have more of the amount remaining after spread reward than estimated until target, // bound the next sqrtPriceNext by the target sqrt price. if amountZeroRemainingOutBigDec.GTE(amountZeroOut) { - sqrtPriceNext = sqrtPriceTargetBigDec + sqrtPriceNext = sqrtPriceTarget } else { // Otherwise, compute the next sqrt price based on the amount remaining after spread reward. sqrtPriceNext = math.GetNextSqrtPriceFromAmount0OutRoundingUp(sqrtPriceCurrent, liquidityBigDec, amountZeroRemainingOutBigDec) } - hasReachedTarget := sqrtPriceTargetBigDec.Equal(sqrtPriceNext) + hasReachedTarget := sqrtPriceTarget.Equal(sqrtPriceNext) // If the sqrt price target was not reached, recalculate how much of the amount remaining after spread reward was needed // to complete the swap step. This implies that some of the amount remaining after spread reward is left over after the @@ -254,12 +252,10 @@ func (s oneForZeroStrategy) UpdateTickAfterCrossing(nextTick int64) int64 { // oneForZeroStrategy assumes moving to the right of the current square root price. // Therefore, the following invariant must hold: // current square root price <= sqrtPrice <= types.MaxSqrtRatio -func (s oneForZeroStrategy) ValidateSqrtPrice(sqrtPrice sdk.Dec, currentSqrtPrice osmomath.BigDec) error { - sqrtPriceBigDec := osmomath.BigDecFromSDKDec(sqrtPrice) - +func (s oneForZeroStrategy) ValidateSqrtPrice(sqrtPrice osmomath.BigDec, currentSqrtPrice osmomath.BigDec) error { // check that the price limit is above the current sqrt price but lower than the maximum sqrt price since we are swapping asset1 for asset0 - if sqrtPriceBigDec.LT(currentSqrtPrice) || sqrtPriceBigDec.GT(types.MaxSqrtPriceBigDec) { - return types.SqrtPriceValidationError{SqrtPriceLimit: sqrtPriceBigDec, LowerBound: currentSqrtPrice, UpperBound: types.MaxSqrtPriceBigDec} + if sqrtPrice.LT(currentSqrtPrice) || sqrtPrice.GT(types.MaxSqrtPriceBigDec) { + return types.SqrtPriceValidationError{SqrtPriceLimit: sqrtPrice, LowerBound: currentSqrtPrice, UpperBound: types.MaxSqrtPriceBigDec} } return nil } diff --git a/x/concentrated-liquidity/swapstrategy/one_for_zero_test.go b/x/concentrated-liquidity/swapstrategy/one_for_zero_test.go index 02cf0b829ba..8bcec2ae16f 100644 --- a/x/concentrated-liquidity/swapstrategy/one_for_zero_test.go +++ b/x/concentrated-liquidity/swapstrategy/one_for_zero_test.go @@ -11,7 +11,7 @@ import ( func (suite *StrategyTestSuite) setupNewOneForZeroSwapStrategy(sqrtPriceLimit sdk.Dec, spread sdk.Dec) swapstrategy.SwapStrategy { suite.SetupTest() - return swapstrategy.New(false, sqrtPriceLimit, suite.App.GetKey(types.ModuleName), spread) + return swapstrategy.New(false, osmomath.BigDecFromSDKDec(sqrtPriceLimit), suite.App.GetKey(types.ModuleName), spread) } func (suite *StrategyTestSuite) TestGetSqrtTargetPrice_OneForZero() { @@ -40,8 +40,8 @@ func (suite *StrategyTestSuite) TestGetSqrtTargetPrice_OneForZero() { for name, tc := range tests { suite.Run(name, func() { strategy := suite.setupNewOneForZeroSwapStrategy(tc.sqrtPriceLimit, zero) - actualSqrtTargetPrice := strategy.GetSqrtTargetPrice(tc.nextTickSqrtPrice) - suite.Require().Equal(tc.expectedResult, actualSqrtTargetPrice) + actualSqrtTargetPrice := strategy.GetSqrtTargetPrice(osmomath.BigDecFromSDKDec(tc.nextTickSqrtPrice)) + suite.Require().Equal(osmomath.BigDecFromSDKDec(tc.expectedResult), actualSqrtTargetPrice) }) } } @@ -133,7 +133,7 @@ func (suite *StrategyTestSuite) TestComputeSwapStepOutGivenIn_OneForZero() { "5: custom amounts at high price levels - reach target": { sqrtPriceCurrent: osmomath.BigDecFromSDKDec(sqrt(100_000_000)), sqrtPriceTarget: sqrt(100_000_100), - liquidity: math.GetLiquidityFromAmounts(osmomath.OneDec(), sqrt(100_000_000), sqrt(100_000_100), defaultAmountZero.TruncateInt(), defaultAmountOne.TruncateInt()), + liquidity: math.GetLiquidityFromAmounts(osmomath.OneDec(), osmomath.BigDecFromSDKDec(sqrt(100_000_000)), osmomath.BigDecFromSDKDec(sqrt(100_000_100)), defaultAmountZero.TruncateInt(), defaultAmountOne.TruncateInt()), // this value is exactly enough to reach the target amountOneInRemaining: sdk.NewDec(1336900668450), @@ -208,7 +208,7 @@ func (suite *StrategyTestSuite) TestComputeSwapStepOutGivenIn_OneForZero() { tc := tc suite.Run(name, func() { strategy := suite.setupNewOneForZeroSwapStrategy(types.MaxSqrtPrice, tc.spreadFactor) - sqrtPriceNext, amountInConsumed, amountZeroOut, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketOutGivenIn(tc.sqrtPriceCurrent, tc.sqrtPriceTarget, tc.liquidity, tc.amountOneInRemaining) + sqrtPriceNext, amountInConsumed, amountZeroOut, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketOutGivenIn(tc.sqrtPriceCurrent, osmomath.BigDecFromSDKDec(tc.sqrtPriceTarget), tc.liquidity, tc.amountOneInRemaining) suite.Require().Equal(tc.expectedSqrtPriceNext, sqrtPriceNext) suite.Require().Equal(tc.expectedAmountInConsumed, amountInConsumed) @@ -424,7 +424,7 @@ func (suite *StrategyTestSuite) TestComputeSwapStepInGivenOut_OneForZero() { for name, tc := range tests { suite.Run(name, func() { strategy := suite.setupNewOneForZeroSwapStrategy(types.MaxSqrtPrice, tc.spreadFactor) - sqrtPriceNext, amountZeroOutConsumed, amountOneIn, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketInGivenOut(tc.sqrtPriceCurrent, tc.sqrtPriceTarget, tc.liquidity, tc.amountZeroOutRemaining) + sqrtPriceNext, amountZeroOutConsumed, amountOneIn, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketInGivenOut(tc.sqrtPriceCurrent, osmomath.BigDecFromSDKDec(tc.sqrtPriceTarget), tc.liquidity, tc.amountZeroOutRemaining) suite.Require().Equal(tc.expectedSqrtPriceNext, sqrtPriceNext) suite.Require().Equal(tc.expectedAmountZeroOutConsumed.String(), amountZeroOutConsumed.String()) diff --git a/x/concentrated-liquidity/swapstrategy/swap_strategy.go b/x/concentrated-liquidity/swapstrategy/swap_strategy.go index 9396c541109..bd4213b2b30 100644 --- a/x/concentrated-liquidity/swapstrategy/swap_strategy.go +++ b/x/concentrated-liquidity/swapstrategy/swap_strategy.go @@ -16,7 +16,7 @@ type SwapStrategy interface { // GetSqrtTargetPrice returns the target square root price given the next tick square root price // upon comparing it to sqrt price limit. // See oneForZeroStrategy or zeroForOneStrategy for implementation details. - GetSqrtTargetPrice(nextTickSqrtPrice sdk.Dec) sdk.Dec + GetSqrtTargetPrice(nextTickSqrtPrice osmomath.BigDec) osmomath.BigDec // ComputeSwapWithinBucketOutGivenIn calculates the next sqrt price, the amount of token in consumed, the amount out to return to the user, and total spread reward charge on token in. // This assumes swapping over a single bucket where the liqudiity stays constant until we cross the next initialized tick of the next bucket. // Parameters: @@ -34,7 +34,7 @@ type SwapStrategy interface { // * amountOutComputed is the amount of token out computed. It is the amount of token out to return to the user. // * spreadRewardChargeTotal is the total spread reward charge. The spread reward is charged on the amount of token in. // See oneForZeroStrategy or zeroForOneStrategy for implementation details. - ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent osmomath.BigDec, sqrtPriceTarget, liquidity, amountRemainingIn sdk.Dec) (sqrtPriceNext osmomath.BigDec, amountInConsumed, amountOutComputed, spreadRewardChargeTotal sdk.Dec) + ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent, sqrtPriceTarget osmomath.BigDec, liquidity, amountRemainingIn sdk.Dec) (sqrtPriceNext osmomath.BigDec, amountInConsumed, amountOutComputed, spreadRewardChargeTotal sdk.Dec) // ComputeSwapWithinBucketInGivenOut calculates the next sqrt price, the amount of token out consumed, the amount in to charge to the user for requested out, and total spread reward charge on token in. // This assumes swapping over a single bucket where the liqudiity stays constant until we cross the next initialized tick of the next bucket. // Parameters: @@ -52,7 +52,7 @@ type SwapStrategy interface { // * amountInComputed is the amount of token in computed. It is the amount of token in to charge to the user for the desired amount out. // * spreadRewardChargeTotal is the total spread reward charge. The spread reward is charged on the amount of token in. // See oneForZeroStrategy or zeroForOneStrategy for implementation details. - ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent osmomath.BigDec, sqrtPriceTarget, liquidity, amountRemainingOut sdk.Dec) (sqrtPriceNext osmomath.BigDec, amountOutConsumed, amountInComputed, spreadRewardChargeTotal sdk.Dec) + ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent, sqrtPriceTarget osmomath.BigDec, liquidity, amountRemainingOut sdk.Dec) (sqrtPriceNext osmomath.BigDec, amountOutConsumed, amountInComputed, spreadRewardChargeTotal sdk.Dec) // InitializeNextTickIterator returns iterator that seeks to the next tick from the given tickIndex. // If nex tick relative to tickINdex does not exist in the store, it will return an invalid iterator. // See oneForZeroStrategy or zeroForOneStrategy for implementation details. @@ -82,7 +82,7 @@ type SwapStrategy interface { // relative to the current square root price on one side of the bound // and the min/max sqrt price on the other side. // See oneForZeroStrategy or zeroForOneStrategy for implementation details. - ValidateSqrtPrice(sqrtPriceLimit sdk.Dec, currentSqrtPrice osmomath.BigDec) error + ValidateSqrtPrice(sqrtPriceLimit osmomath.BigDec, currentSqrtPrice osmomath.BigDec) error ZeroForOne() bool } @@ -94,7 +94,7 @@ var ( // New returns a swap strategy based on the provided zeroForOne parameter // with sqrtPriceLimit for the maximum square root price until which to perform // the swap and the stor key of the module that stores swap data. -func New(zeroForOne bool, sqrtPriceLimit sdk.Dec, storeKey sdk.StoreKey, spreadFactor sdk.Dec) SwapStrategy { +func New(zeroForOne bool, sqrtPriceLimit osmomath.BigDec, storeKey sdk.StoreKey, spreadFactor sdk.Dec) SwapStrategy { if zeroForOne { return &zeroForOneStrategy{sqrtPriceLimit: sqrtPriceLimit, storeKey: storeKey, spreadFactor: spreadFactor} } @@ -111,13 +111,18 @@ func GetPriceLimit(zeroForOne bool) sdk.Dec { return types.MaxSpotPrice } -func GetSqrtPriceLimit(priceLimit sdk.Dec, zeroForOne bool) (sdk.Dec, error) { +func GetSqrtPriceLimit(priceLimit sdk.Dec, zeroForOne bool) (osmomath.BigDec, error) { if priceLimit.IsZero() { if zeroForOne { - return types.MinSqrtPrice, nil + return osmomath.BigDecFromSDKDec(types.MinSqrtPrice), nil } - return types.MaxSqrtPrice, nil + return osmomath.BigDecFromSDKDec(types.MaxSqrtPrice), nil } - return osmomath.MonotonicSqrt(priceLimit) + sqrtPriceLimit, err := osmomath.MonotonicSqrt(priceLimit) + if err != nil { + return osmomath.BigDec{}, err + } + + return osmomath.BigDecFromSDKDec(sqrtPriceLimit), nil } diff --git a/x/concentrated-liquidity/swapstrategy/swap_strategy_test.go b/x/concentrated-liquidity/swapstrategy/swap_strategy_test.go index 11693edf372..9e81f4a71fe 100644 --- a/x/concentrated-liquidity/swapstrategy/swap_strategy_test.go +++ b/x/concentrated-liquidity/swapstrategy/swap_strategy_test.go @@ -222,13 +222,13 @@ func (suite *StrategyTestSuite) TestComputeSwapState_Inverse() { for name, tc := range testCases { tc := tc suite.Run(name, func() { - sut := swapstrategy.New(tc.zeroForOne, sdk.ZeroDec(), suite.App.GetKey(types.ModuleName), sdk.ZeroDec()) - sqrtPriceNextOutGivenIn, amountInOutGivenIn, amountOutOutGivenIn, _ := sut.ComputeSwapWithinBucketOutGivenIn(osmomath.BigDecFromSDKDec(tc.sqrtPriceCurrent), tc.sqrtPriceTarget, tc.liquidity, tc.amountIn) + sut := swapstrategy.New(tc.zeroForOne, osmomath.ZeroDec(), suite.App.GetKey(types.ModuleName), sdk.ZeroDec()) + sqrtPriceNextOutGivenIn, amountInOutGivenIn, amountOutOutGivenIn, _ := sut.ComputeSwapWithinBucketOutGivenIn(osmomath.BigDecFromSDKDec(tc.sqrtPriceCurrent), osmomath.BigDecFromSDKDec(tc.sqrtPriceTarget), tc.liquidity, tc.amountIn) suite.Require().Equal(tc.expectedSqrtPriceNextOutGivenIn.String(), sqrtPriceNextOutGivenIn.String()) fmt.Println("amountOutOutGivenIn", amountOutOutGivenIn) - sqrtPriceNextInGivenOut, amountOutInGivenOut, amountInInGivenOut, _ := sut.ComputeSwapWithinBucketInGivenOut(osmomath.BigDecFromSDKDec(tc.sqrtPriceCurrent), tc.sqrtPriceTarget, tc.liquidity, amountOutOutGivenIn) + sqrtPriceNextInGivenOut, amountOutInGivenOut, amountInInGivenOut, _ := sut.ComputeSwapWithinBucketInGivenOut(osmomath.BigDecFromSDKDec(tc.sqrtPriceCurrent), osmomath.BigDecFromSDKDec(tc.sqrtPriceTarget), tc.liquidity, amountOutOutGivenIn) suite.Require().Equal(tc.expectedSqrtPriceNextInGivenOut.String(), sqrtPriceNextInGivenOut.String()) diff --git a/x/concentrated-liquidity/swapstrategy/zero_for_one.go b/x/concentrated-liquidity/swapstrategy/zero_for_one.go index 01247b1be2d..db8e9a5d185 100644 --- a/x/concentrated-liquidity/swapstrategy/zero_for_one.go +++ b/x/concentrated-liquidity/swapstrategy/zero_for_one.go @@ -19,7 +19,7 @@ import ( // With this strategy, we are moving to the left of the current // tick index and square root price. type zeroForOneStrategy struct { - sqrtPriceLimit sdk.Dec + sqrtPriceLimit osmomath.BigDec storeKey sdk.StoreKey spreadFactor sdk.Dec } @@ -31,7 +31,7 @@ func (s zeroForOneStrategy) ZeroForOne() bool { return true } // GetSqrtTargetPrice returns the target square root price given the next tick square root price. // If the given nextTickSqrtPrice is less than the sqrt price limit, the sqrt price limit is returned. // Otherwise, the input nextTickSqrtPrice is returned. -func (s zeroForOneStrategy) GetSqrtTargetPrice(nextTickSqrtPrice sdk.Dec) sdk.Dec { +func (s zeroForOneStrategy) GetSqrtTargetPrice(nextTickSqrtPrice osmomath.BigDec) osmomath.BigDec { if nextTickSqrtPrice.LT(s.sqrtPriceLimit) { return s.sqrtPriceLimit } @@ -57,13 +57,12 @@ func (s zeroForOneStrategy) GetSqrtTargetPrice(nextTickSqrtPrice sdk.Dec) sdk.De // // ZeroForOne details: // - zeroForOneStrategy assumes moving to the left of the current square root price. -func (s zeroForOneStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent osmomath.BigDec, sqrtPriceTarget, liquidity, amountZeroInRemaining sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { +func (s zeroForOneStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent, sqrtPriceTarget osmomath.BigDec, liquidity, amountZeroInRemaining sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { liquidityBigDec := osmomath.BigDecFromSDKDec(liquidity) - sqrtPriceTargetBigDec := osmomath.BigDecFromSDKDec(sqrtPriceTarget) amountZeroInRemainingBigDec := osmomath.BigDecFromSDKDec(amountZeroInRemaining) // Estimate the amount of token zero needed until the target sqrt price is reached. - amountZeroIn := math.CalcAmount0Delta(liquidityBigDec, sqrtPriceTargetBigDec, sqrtPriceCurrent, true) // N.B.: if this is false, causes infinite loop + amountZeroIn := math.CalcAmount0Delta(liquidityBigDec, sqrtPriceTarget, sqrtPriceCurrent, true) // N.B.: if this is false, causes infinite loop // Calculate sqrtPriceNext on the amount of token remaining after spread reward. amountZeroInRemainingLessSpreadReward := amountZeroInRemainingBigDec.Mul(oneBigDec.Sub(osmomath.BigDecFromSDKDec(s.spreadFactor))) @@ -72,13 +71,13 @@ func (s zeroForOneStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent o // If have more of the amount remaining after spread reward than estimated until target, // bound the next sqrtPriceNext by the target sqrt price. if amountZeroInRemainingLessSpreadReward.GTE(amountZeroIn) { - sqrtPriceNext = sqrtPriceTargetBigDec + sqrtPriceNext = sqrtPriceTarget } else { // Otherwise, compute the next sqrt price based on the amount remaining after spread reward. sqrtPriceNext = math.GetNextSqrtPriceFromAmount0InRoundingUp(sqrtPriceCurrent, liquidityBigDec, amountZeroInRemainingLessSpreadReward) } - hasReachedTarget := sqrtPriceTargetBigDec.Equal(sqrtPriceNext) + hasReachedTarget := sqrtPriceTarget.Equal(sqrtPriceNext) // If the sqrt price target was not reached, recalculate how much of the amount remaining after spread reward was needed // to complete the swap step. This implies that some of the amount remaining after spread reward is left over after the @@ -121,13 +120,12 @@ func (s zeroForOneStrategy) ComputeSwapWithinBucketOutGivenIn(sqrtPriceCurrent o // // ZeroForOne details: // - zeroForOneStrategy assumes moving to the left of the current square root price. -func (s zeroForOneStrategy) ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent osmomath.BigDec, sqrtPriceTarget, liquidity, amountOneRemainingOut sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { +func (s zeroForOneStrategy) ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent, sqrtPriceTarget osmomath.BigDec, liquidity, amountOneRemainingOut sdk.Dec) (osmomath.BigDec, sdk.Dec, sdk.Dec, sdk.Dec) { liquidityBigDec := osmomath.BigDecFromSDKDec(liquidity) - sqrtPriceTargetBigDec := osmomath.BigDecFromSDKDec(sqrtPriceTarget) amountOneRemainingOutBigDec := osmomath.BigDecFromSDKDec(amountOneRemainingOut) // Estimate the amount of token one needed until the target sqrt price is reached. - amountOneOut := math.CalcAmount1Delta(liquidityBigDec, sqrtPriceTargetBigDec, sqrtPriceCurrent, false) + amountOneOut := math.CalcAmount1Delta(liquidityBigDec, sqrtPriceTarget, sqrtPriceCurrent, false) // Calculate sqrtPriceNext on the amount of token remaining. Note that the // spread reward is not charged as amountRemaining is amountOut, and we only charge spread reward on @@ -136,13 +134,13 @@ func (s zeroForOneStrategy) ComputeSwapWithinBucketInGivenOut(sqrtPriceCurrent o // If have more of the amount remaining after spread reward than estimated until target, // bound the next sqrtPriceNext by the target sqrt price. if amountOneRemainingOutBigDec.GTE(amountOneOut) { - sqrtPriceNext = sqrtPriceTargetBigDec + sqrtPriceNext = sqrtPriceTarget } else { // Otherwise, compute the next sqrt price based on the amount remaining after spread reward. sqrtPriceNext = math.GetNextSqrtPriceFromAmount1OutRoundingDown(sqrtPriceCurrent, liquidityBigDec, amountOneRemainingOutBigDec) } - hasReachedTarget := sqrtPriceTargetBigDec.Equal(sqrtPriceNext) + hasReachedTarget := sqrtPriceTarget.Equal(sqrtPriceNext) // If the sqrt price target was not reached, recalculate how much of the amount remaining after spread reward was needed // to complete the swap step. This implies that some of the amount remaining after spread reward is left over after the @@ -252,12 +250,10 @@ func (s zeroForOneStrategy) UpdateTickAfterCrossing(nextTick int64) int64 { // zeroForOneStrategy assumes moving to the left of the current square root price. // Therefore, the following invariant must hold: // types.MinSqrtRatio <= sqrtPrice <= current square root price -func (s zeroForOneStrategy) ValidateSqrtPrice(sqrtPrice sdk.Dec, currentSqrtPrice osmomath.BigDec) error { - sqrtPriceBigDec := osmomath.BigDecFromSDKDec(sqrtPrice) - +func (s zeroForOneStrategy) ValidateSqrtPrice(sqrtPrice osmomath.BigDec, currentSqrtPrice osmomath.BigDec) error { // check that the price limit is below the current sqrt price but not lower than the minimum sqrt price if we are swapping asset0 for asset1 - if sqrtPriceBigDec.GT(currentSqrtPrice) || sqrtPrice.LT(types.MinSqrtPrice) { - return types.SqrtPriceValidationError{SqrtPriceLimit: sqrtPriceBigDec, LowerBound: types.MinSqrtPriceBigDec, UpperBound: currentSqrtPrice} + if sqrtPrice.GT(currentSqrtPrice) || sqrtPrice.LT(osmomath.BigDecFromSDKDec(types.MinSqrtPrice)) { + return types.SqrtPriceValidationError{SqrtPriceLimit: sqrtPrice, LowerBound: types.MinSqrtPriceBigDec, UpperBound: currentSqrtPrice} } return nil } diff --git a/x/concentrated-liquidity/swapstrategy/zero_for_one_test.go b/x/concentrated-liquidity/swapstrategy/zero_for_one_test.go index 4b11408839f..9f361a64593 100644 --- a/x/concentrated-liquidity/swapstrategy/zero_for_one_test.go +++ b/x/concentrated-liquidity/swapstrategy/zero_for_one_test.go @@ -10,7 +10,7 @@ import ( func (suite *StrategyTestSuite) setupNewZeroForOneSwapStrategy(sqrtPriceLimit sdk.Dec, spread sdk.Dec) swapstrategy.SwapStrategy { suite.SetupTest() - return swapstrategy.New(true, sqrtPriceLimit, suite.App.GetKey(types.ModuleName), spread) + return swapstrategy.New(true, osmomath.BigDecFromSDKDec(sqrtPriceLimit), suite.App.GetKey(types.ModuleName), spread) } func (suite *StrategyTestSuite) TestGetSqrtTargetPrice_ZeroForOne() { @@ -41,8 +41,8 @@ func (suite *StrategyTestSuite) TestGetSqrtTargetPrice_ZeroForOne() { tc := tc suite.Run(name, func() { sut := suite.setupNewZeroForOneSwapStrategy(tc.sqrtPriceLimit, zero) - actualSqrtTargetPrice := sut.GetSqrtTargetPrice(tc.nextTickSqrtPrice) - suite.Require().Equal(tc.expectedResult, actualSqrtTargetPrice) + actualSqrtTargetPrice := sut.GetSqrtTargetPrice(osmomath.BigDecFromSDKDec(tc.nextTickSqrtPrice)) + suite.Require().Equal(osmomath.BigDecFromSDKDec(tc.expectedResult), actualSqrtTargetPrice) }) } } @@ -202,7 +202,7 @@ func (suite *StrategyTestSuite) TestComputeSwapStepOutGivenIn_ZeroForOne() { for name, tc := range tests { suite.Run(name, func() { strategy := suite.setupNewZeroForOneSwapStrategy(types.MaxSqrtPrice, tc.spreadFactor) - sqrtPriceNext, amountZeroIn, amountOneOut, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketOutGivenIn(tc.sqrtPriceCurrent, tc.sqrtPriceTarget, tc.liquidity, tc.amountZeroInRemaining) + sqrtPriceNext, amountZeroIn, amountOneOut, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketOutGivenIn(tc.sqrtPriceCurrent, osmomath.BigDecFromSDKDec(tc.sqrtPriceTarget), tc.liquidity, tc.amountZeroInRemaining) suite.Require().Equal(tc.expectedSqrtPriceNext, sqrtPriceNext) suite.Require().Equal(tc.expectedAmountOneOut, amountOneOut) @@ -333,7 +333,7 @@ func (suite *StrategyTestSuite) TestComputeSwapStepInGivenOut_ZeroForOne() { for name, tc := range tests { suite.Run(name, func() { strategy := suite.setupNewZeroForOneSwapStrategy(types.MaxSqrtPrice, tc.spreadFactor) - sqrtPriceNext, amountOneOut, amountZeroIn, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketInGivenOut(tc.sqrtPriceCurrent, tc.sqrtPriceTarget, tc.liquidity, tc.amountOneOutRemaining) + sqrtPriceNext, amountOneOut, amountZeroIn, spreadRewardChargeTotal := strategy.ComputeSwapWithinBucketInGivenOut(tc.sqrtPriceCurrent, osmomath.BigDecFromSDKDec(tc.sqrtPriceTarget), tc.liquidity, tc.amountOneOutRemaining) suite.Require().Equal(tc.expectedSqrtPriceNext, sqrtPriceNext) suite.Require().Equal(tc.amountOneOutConsumed, amountOneOut) diff --git a/x/concentrated-liquidity/tick.go b/x/concentrated-liquidity/tick.go index fb52ace4012..5fcb4fdce60 100644 --- a/x/concentrated-liquidity/tick.go +++ b/x/concentrated-liquidity/tick.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/osmoutils/accum" "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/math" @@ -209,7 +210,7 @@ func validateTickRangeIsValid(tickSpacing uint64, lowerTick int64, upperTick int // the first tick (given our precision) that is able to represent this price is -161000000, so we use this tick instead. // // This really only applies to very small tick values, as the increment of a single tick continues to get smaller as the tick value gets smaller. -func roundTickToCanonicalPriceTick(lowerTick, upperTick int64, sqrtPriceTickLower, sqrtPriceTickUpper sdk.Dec, tickSpacing uint64) (int64, int64, error) { +func roundTickToCanonicalPriceTick(lowerTick, upperTick int64, sqrtPriceTickLower, sqrtPriceTickUpper osmomath.BigDec, tickSpacing uint64) (int64, int64, error) { newLowerTick, err := math.SqrtPriceToTickRoundDownSpacing(sqrtPriceTickLower, tickSpacing) if err != nil { return 0, 0, err diff --git a/x/concentrated-liquidity/types/errors.go b/x/concentrated-liquidity/types/errors.go index 30cd0ee4c01..7248094c4b0 100644 --- a/x/concentrated-liquidity/types/errors.go +++ b/x/concentrated-liquidity/types/errors.go @@ -828,7 +828,7 @@ func (e RanOutOfTicksForPoolError) Error() string { } type SqrtRootCalculationError struct { - SqrtPriceLimit sdk.Dec + SqrtPriceLimit osmomath.BigDec } func (e SqrtRootCalculationError) Error() string {