diff --git a/x/concentrated-liquidity/export_test.go b/x/concentrated-liquidity/export_test.go index 4d8e6846033..7daaf328de9 100644 --- a/x/concentrated-liquidity/export_test.go +++ b/x/concentrated-liquidity/export_test.go @@ -55,11 +55,11 @@ func (k Keeper) SendCoinsBetweenPoolAndUser(ctx sdk.Context, denom0, denom1 stri return k.sendCoinsBetweenPoolAndUser(ctx, denom0, denom1, amount0, amount1, sender, receiver) } -func (k Keeper) CalcInAmtGivenOutInternal(ctx sdk.Context, desiredTokenOut sdk.Coin, tokenInDenom string, swapFee sdk.Dec, priceLimit sdk.Dec, poolId uint64) (tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { +func (k Keeper) CalcInAmtGivenOutInternal(ctx sdk.Context, desiredTokenOut sdk.Coin, tokenInDenom string, swapFee sdk.Dec, priceLimit sdk.Dec, poolId uint64) (writeCtx func(), tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { return k.calcInAmtGivenOut(ctx, desiredTokenOut, tokenInDenom, swapFee, priceLimit, poolId) } -func (k Keeper) CalcOutAmtGivenInInternal(ctx sdk.Context, tokenInMin sdk.Coin, tokenOutDenom string, swapFee sdk.Dec, priceLimit sdk.Dec, poolId uint64) (tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { +func (k Keeper) CalcOutAmtGivenInInternal(ctx sdk.Context, tokenInMin sdk.Coin, tokenOutDenom string, swapFee sdk.Dec, priceLimit sdk.Dec, poolId uint64) (writeCtx func(), tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { return k.calcOutAmtGivenIn(ctx, tokenInMin, tokenOutDenom, swapFee, priceLimit, poolId) } diff --git a/x/concentrated-liquidity/internal/math/tick.go b/x/concentrated-liquidity/internal/math/tick.go index 665edb80384..ff7e5e5f44f 100644 --- a/x/concentrated-liquidity/internal/math/tick.go +++ b/x/concentrated-liquidity/internal/math/tick.go @@ -32,8 +32,8 @@ func TicksToPrice(lowerTick, upperTick int64, exponentAtPriceOne sdk.Int) (sdk.D } // TickToPrice returns the price given the following two arguments: -// - tickIndex: the tick index to calculate the price for -// - exponentAtPriceOne: the value of the exponent (and therefore the precision) at which the starting price of 1 is set +// - tickIndex: the tick index to calculate the price for +// - exponentAtPriceOne: the value of the exponent (and therefore the precision) at which the starting price of 1 is set // // If tickIndex is zero, the function returns sdk.OneDec(). func TickToPrice(tickIndex, exponentAtPriceOne sdk.Int) (price sdk.Dec, err error) { diff --git a/x/concentrated-liquidity/model/pool.go b/x/concentrated-liquidity/model/pool.go index fd6e0ef92b1..301ca81a632 100644 --- a/x/concentrated-liquidity/model/pool.go +++ b/x/concentrated-liquidity/model/pool.go @@ -173,9 +173,10 @@ func (p *Pool) UpdateLiquidityIfActivePosition(ctx sdk.Context, lowerTick, upper // lower and upper ticks. // There are 3 possible cases: // -The position is active ( lowerTick <= p.CurrentTick < upperTick). -// * The provided liquidity is distributed in both tokens. -// * Actual amounts might differ from desired because we recalculate them from liquidity delta and sqrt price. -// the calculations lead to amounts being off. // TODO: confirm logic is correct +// - The provided liquidity is distributed in both tokens. +// - Actual amounts might differ from desired because we recalculate them from liquidity delta and sqrt price. +// the calculations lead to amounts being off. // TODO: confirm logic is correct +// // - Current tick is below the position ( p.CurrentTick < lowerTick). // - The provided liquidity is distributed in token0 only. // diff --git a/x/concentrated-liquidity/swaps.go b/x/concentrated-liquidity/swaps.go index 18a39e0f72e..daa1485b7d1 100644 --- a/x/concentrated-liquidity/swaps.go +++ b/x/concentrated-liquidity/swaps.go @@ -138,11 +138,16 @@ func (k Keeper) SwapOutAmtGivenIn( priceLimit sdk.Dec, poolId uint64, ) (calcTokenIn, calcTokenOut sdk.Coin, currentTick sdk.Int, liquidity, sqrtPrice sdk.Dec, err error) { - tokenIn, tokenOut, newCurrentTick, newLiquidity, newSqrtPrice, err := k.calcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, priceLimit, poolId) + writeCtx, tokenIn, tokenOut, newCurrentTick, newLiquidity, newSqrtPrice, err := k.calcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, priceLimit, poolId) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } + // N.B. making the call below ensures that any mutations done inside calcOutAmtGivenIn + // are written to store. If this call were skipped, calcOutAmtGivenIn would be non-mutative. + // An example of a store write done in calcOutAmtGivenIn is updating ticks as we cross them. + writeCtx() + err = k.applySwap(ctx, tokenIn, tokenOut, poolId, newLiquidity, newCurrentTick, newSqrtPrice) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err @@ -159,11 +164,16 @@ func (k *Keeper) SwapInAmtGivenOut( priceLimit sdk.Dec, poolId uint64, ) (calcTokenIn, calcTokenOut sdk.Coin, currentTick sdk.Int, liquidity, sqrtPrice sdk.Dec, err error) { - tokenIn, tokenOut, newCurrentTick, newLiquidity, newSqrtPrice, err := k.calcInAmtGivenOut(ctx, desiredTokenOut, tokenInDenom, swapFee, priceLimit, poolId) + writeCtx, tokenIn, tokenOut, newCurrentTick, newLiquidity, newSqrtPrice, err := k.calcInAmtGivenOut(ctx, desiredTokenOut, tokenInDenom, swapFee, priceLimit, poolId) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } + // N.B. making the call below ensures that any mutations done inside calcInAmtGivenOut + // are written to store. If this call were skipped, calcInAmtGivenOut would be non-mutative. + // An example of a store write done in calcInAmtGivenOut is updating ticks as we cross them. + writeCtx() + err = k.applySwap(ctx, tokenIn, tokenOut, poolId, newLiquidity, newCurrentTick, newSqrtPrice) if err != nil { return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err @@ -179,7 +189,7 @@ func (k Keeper) CalcOutAmtGivenIn( tokenOutDenom string, swapFee sdk.Dec, ) (tokenOut sdk.Coin, err error) { - _, tokenOut, _, _, _, err = k.calcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, sdk.ZeroDec(), poolI.GetId()) + _, _, tokenOut, _, _, _, err = k.calcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, sdk.ZeroDec(), poolI.GetId()) if err != nil { return sdk.Coin{}, err } @@ -193,7 +203,7 @@ func (k Keeper) CalcInAmtGivenOut( tokenInDenom string, swapFee sdk.Dec, ) (tokenIn sdk.Coin, err error) { - tokenIn, _, _, _, _, err = k.calcInAmtGivenOut(ctx, tokenOut, tokenInDenom, swapFee, sdk.ZeroDec(), poolI.GetId()) + _, tokenIn, _, _, _, _, err = k.calcInAmtGivenOut(ctx, tokenOut, tokenInDenom, swapFee, sdk.ZeroDec(), poolI.GetId()) if err != nil { return sdk.Coin{}, err } @@ -203,16 +213,18 @@ func (k Keeper) CalcInAmtGivenOut( // calcOutAmtGivenIn calculates tokens to be swapped out given the provided amount and fee deducted. It also returns // what the updated tick, liquidity, and currentSqrtPrice for the pool would be after this swap. // Note this method is non-mutative, so the values returned by CalcOutAmtGivenIn do not get stored +// Instead, we return writeCtx function so that the caller of this method can decide to write the cached ctx to store or not. func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context, tokenInMin sdk.Coin, tokenOutDenom string, swapFee sdk.Dec, priceLimit sdk.Dec, poolId uint64, -) (tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { +) (writeCtx func(), tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { + ctx, writeCtx = ctx.CacheContext() p, err := k.getPoolById(ctx, poolId) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } asset0 := p.GetToken0() asset1 := p.GetToken1() @@ -231,7 +243,7 @@ func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context, // take provided price limit and turn this into a sqrt price limit since formulas use sqrtPrice sqrtPriceLimit, err := priceLimit.ApproxSqrt() if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("issue calculating square root of price limit") + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("issue calculating square root of price limit") } // set the swap strategy @@ -240,20 +252,20 @@ func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context, // get current sqrt price from pool curSqrtPrice := p.GetCurrentSqrtPrice() if err := swapStrategy.ValidatePriceLimit(sqrtPriceLimit, curSqrtPrice); err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } // check that the specified tokenIn matches one of the assets in the specified pool if tokenInMin.Denom != asset0 && tokenInMin.Denom != asset1 { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenInDenomNotInPoolError{TokenInDenom: tokenInMin.Denom} + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenInDenomNotInPoolError{TokenInDenom: tokenInMin.Denom} } // check that the specified tokenOut matches one of the assets in the specified pool if tokenOutDenom != asset0 && tokenOutDenom != asset1 { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenOutDenomNotInPoolError{TokenOutDenom: tokenOutDenom} + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenOutDenomNotInPoolError{TokenOutDenom: tokenOutDenom} } // check that token in and token out are different denominations if tokenInMin.Denom == tokenOutDenom { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.DenomDuplicatedError{TokenInDenom: tokenInMin.Denom, TokenOutDenom: tokenOutDenom} + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.DenomDuplicatedError{TokenInDenom: tokenInMin.Denom, TokenOutDenom: tokenOutDenom} } // initialize swap state with the following parameters: @@ -280,19 +292,19 @@ func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context, // if no ticks are initialized (no users have created liquidity positions) then we return an error nextTick, ok := swapStrategy.NextInitializedTick(ctx, poolId, swapState.tick.Int64()) if !ok { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("there are no more ticks initialized to fill the swap") + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("there are no more ticks initialized to fill the swap") } // utilizing the next initialized tick, we find the corresponding nextPrice (the target price) nextPrice, err := math.TickToPrice(nextTick, p.GetPrecisionFactorAtPriceOne()) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextPrice", nextTick) + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextTick) } // transform to sqrtPrice nextSqrtPrice, err := nextPrice.ApproxSqrt() if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next price (%v) to nextSqrtPrice", nextPrice) + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextSqrtPrice) } // utilizing the bucket's liquidity and knowing the price target, we calculate the how much tokenOut we get from the tokenIn @@ -317,7 +329,7 @@ func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context, // retrieve the liquidity held in the next closest initialized tick liquidityNet, err := k.crossTick(ctx, p.GetId(), nextTick.Int64()) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } liquidityNet = swapStrategy.SetLiquidityDeltaSign(liquidityNet) // update the swapState's liquidity with the new tick's liquidity @@ -331,7 +343,7 @@ func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context, // beginning of this iteration, we set the swapState tick to the corresponding tick of the sqrtPrice calculated from computeSwapStep swapState.tick, err = math.PriceToTick(sqrtPrice.Power(2), p.GetPrecisionFactorAtPriceOne()) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } } } @@ -344,9 +356,13 @@ func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context, tokenIn = sdk.NewCoin(tokenInMin.Denom, amt0) tokenOut = sdk.NewCoin(tokenOutDenom, amt1) - return tokenIn, tokenOut, swapState.tick, swapState.liquidity, swapState.sqrtPrice, nil + return writeCtx, tokenIn, tokenOut, swapState.tick, swapState.liquidity, swapState.sqrtPrice, nil } +// calcInAmtGivenOut calculates tokens to be swapped in given the desired token out and fee deducted. It also returns +// what the updated tick, liquidity, and currentSqrtPrice for the pool would be after this swap. +// Note this method is non-mutative, so the values returned by calcInAmtGivenOut do not get stored +// Instead, we return writeCtx function so that the caller of this method can decide to write the cached ctx to store or not. func (k Keeper) calcInAmtGivenOut( ctx sdk.Context, desiredTokenOut sdk.Coin, @@ -354,10 +370,11 @@ func (k Keeper) calcInAmtGivenOut( swapFee sdk.Dec, priceLimit sdk.Dec, poolId uint64, -) (tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { +) (writeCtx func(), tokenIn, tokenOut sdk.Coin, updatedTick sdk.Int, updatedLiquidity, updatedSqrtPrice sdk.Dec, err error) { + ctx, writeCtx = ctx.CacheContext() p, err := k.getPoolById(ctx, poolId) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } asset0 := p.GetToken0() asset1 := p.GetToken1() @@ -375,7 +392,7 @@ func (k Keeper) calcInAmtGivenOut( // take provided price limit and turn this into a sqrt price limit since formulas use sqrtPrice sqrtPriceLimit, err := priceLimit.ApproxSqrt() if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("issue calculating square root of price limit") + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("issue calculating square root of price limit") } // set the swap strategy @@ -385,20 +402,20 @@ func (k Keeper) calcInAmtGivenOut( curSqrtPrice := p.GetCurrentSqrtPrice() if err := swapStrategy.ValidatePriceLimit(sqrtPriceLimit, curSqrtPrice); err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } // check that the specified tokenOut matches one of the assets in the specified pool if desiredTokenOut.Denom != asset0 && desiredTokenOut.Denom != asset1 { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenOutDenomNotInPoolError{TokenOutDenom: desiredTokenOut.Denom} + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenOutDenomNotInPoolError{TokenOutDenom: desiredTokenOut.Denom} } // check that the specified tokenIn matches one of the assets in the specified pool if tokenInDenom != asset0 && tokenInDenom != asset1 { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenInDenomNotInPoolError{TokenInDenom: tokenInDenom} + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.TokenInDenomNotInPoolError{TokenInDenom: tokenInDenom} } // check that token in and token out are different denominations if desiredTokenOut.Denom == tokenInDenom { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.DenomDuplicatedError{TokenInDenom: tokenInDenom, TokenOutDenom: desiredTokenOut.Denom} + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, types.DenomDuplicatedError{TokenInDenom: tokenInDenom, TokenOutDenom: desiredTokenOut.Denom} } // initialize swap state with the following parameters: @@ -423,19 +440,19 @@ func (k Keeper) calcInAmtGivenOut( // if no ticks are initialized (no users have created liquidity positions) then we return an error nextTick, ok := swapStrategy.NextInitializedTick(ctx, poolId, swapState.tick.Int64()) if !ok { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("there are no more ticks initialized to fill the swap") + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("there are no more ticks initialized to fill the swap") } // utilizing the next initialized tick, we find the corresponding nextPrice (the target price) nextPrice, err := math.TickToPrice(nextTick, p.GetPrecisionFactorAtPriceOne()) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextPrice", nextTick) + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextTick) } // transform to sqrtPrice nextSqrtPrice, err := nextPrice.ApproxSqrt() if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert nextPrice (%v) to nextSqrtPrice", nextPrice) + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextSqrtPrice) } // utilizing the bucket's liquidity and knowing the price target, we calculate the how much tokenOut we get from the tokenIn @@ -458,7 +475,7 @@ func (k Keeper) calcInAmtGivenOut( // retrieve the liquidity held in the next closest initialized tick liquidityNet, err := k.crossTick(ctx, p.GetId(), nextTick.Int64()) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } liquidityNet = swapStrategy.SetLiquidityDeltaSign(liquidityNet) // update the swapState's liquidity with the new tick's liquidity @@ -472,7 +489,7 @@ func (k Keeper) calcInAmtGivenOut( // beginning of this iteration, we set the swapState tick to the corresponding tick of the sqrtPrice calculated from computeSwapStep swapState.tick, err = math.PriceToTick(sqrtPrice.Power(2), p.GetPrecisionFactorAtPriceOne()) if err != nil { - return sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err + return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, err } } @@ -485,7 +502,7 @@ func (k Keeper) calcInAmtGivenOut( tokenOut = sdk.NewCoin(desiredTokenOut.Denom, amt1) } - return tokenIn, tokenOut, swapState.tick, swapState.liquidity, swapState.sqrtPrice, nil + return writeCtx, tokenIn, tokenOut, swapState.tick, swapState.liquidity, swapState.sqrtPrice, nil } // applySwap persists the swap state and charges gas fees. diff --git a/x/concentrated-liquidity/swaps_test.go b/x/concentrated-liquidity/swaps_test.go index 60188b10fa2..5e3e292e47e 100644 --- a/x/concentrated-liquidity/swaps_test.go +++ b/x/concentrated-liquidity/swaps_test.go @@ -503,9 +503,11 @@ func (s *KeeperTestSuite) TestCalcAndSwapOutAmtGivenIn() { // add positions test.addPositions(s.Ctx, pool.GetId()) + poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId()) + s.Require().NoError(err) + // perform calc - // TODO: Add sqrtPrice check - tokenIn, tokenOut, updatedTick, updatedLiquidity, _, err := s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenInInternal( + _, tokenIn, tokenOut, updatedTick, updatedLiquidity, _, err := s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenInInternal( s.Ctx, test.tokenIn, test.tokenOutDenom, DefaultZeroSwapFee, test.priceLimit, pool.GetId()) @@ -546,6 +548,16 @@ func (s *KeeperTestSuite) TestCalcAndSwapOutAmtGivenIn() { // check that liquidity is what we expected expectedLiquidity := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, lowerSqrtPrice, upperSqrtPrice, test.poolLiqAmount0, test.poolLiqAmount1) s.Require().Equal(expectedLiquidity.String(), updatedLiquidity.String()) + + // check that the pool has not been modified after performing calc + poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId()) + s.Require().NoError(err) + + s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice()) + s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick()) + s.Require().Equal(poolBeforeCalc.GetTotalShares(), poolAfterCalc.GetTotalShares()) + s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity()) + s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing()) } // perform swap @@ -957,9 +969,11 @@ func (s *KeeperTestSuite) TestCalcAndSwapInAmtGivenOut() { // add positions test.addPositions(s.Ctx, pool.GetId()) + poolBeforeCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId()) + s.Require().NoError(err) + // perform calc - // TODO: Add sqrtPrice check - tokenIn, tokenOut, updatedTick, updatedLiquidity, _, err := s.App.ConcentratedLiquidityKeeper.CalcInAmtGivenOutInternal( + _, tokenIn, tokenOut, updatedTick, updatedLiquidity, _, err := s.App.ConcentratedLiquidityKeeper.CalcInAmtGivenOutInternal( s.Ctx, test.tokenOut, test.tokenInDenom, DefaultZeroSwapFee, test.priceLimit, pool.GetId()) @@ -1000,6 +1014,16 @@ func (s *KeeperTestSuite) TestCalcAndSwapInAmtGivenOut() { // check that liquidity is what we expected expectedLiquidity := math.GetLiquidityFromAmounts(DefaultCurrSqrtPrice, lowerSqrtPrice, upperSqrtPrice, test.poolLiqAmount0, test.poolLiqAmount1) s.Require().Equal(expectedLiquidity.String(), updatedLiquidity.String()) + + // check that the pool has not been modified after performing calc + poolAfterCalc, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, pool.GetId()) + s.Require().NoError(err) + + s.Require().Equal(poolBeforeCalc.GetCurrentSqrtPrice(), poolAfterCalc.GetCurrentSqrtPrice()) + s.Require().Equal(poolBeforeCalc.GetCurrentTick(), poolAfterCalc.GetCurrentTick()) + s.Require().Equal(poolBeforeCalc.GetTotalShares(), poolAfterCalc.GetTotalShares()) + s.Require().Equal(poolBeforeCalc.GetLiquidity(), poolAfterCalc.GetLiquidity()) + s.Require().Equal(poolBeforeCalc.GetTickSpacing(), poolAfterCalc.GetTickSpacing()) } // perform swap